腾讯AI应用开发一面 · Chapter 01

记忆系统:介质、压缩与跨会话关联

起点章给出 15 题全景与考察脉络,本章处理其中记忆系统方向的三道原题——存储介质选型(Q1)、跨会话压缩(Q2)、跨会话关联(Q5),每题按"参考答案 → 加分点 → 追问预判"展开。

Q1记忆模块的数据存在哪种介质上?

面试官在考什么

候选人是否把"记忆"当成一个有分层、有取舍的存储设计问题,而不是一句"存数据库"带过。

参考答案

第一刀切在上下文内与上下文外。上下文窗口(context window)相当于工作记忆(working memory,模型一次推理能直接读到的全部内容):随会话结束即失效,容量有界,且每个 token 都有成本。任何需要跨会话存活的内容,都必须落到外部持久介质。

外部介质按记忆类型选型,对应认知科学的三个类别:程序性记忆(procedural memory,"该怎么做事"的指令与约定)、语义记忆(semantic memory,关于用户与世界的事实)、情景记忆(episodic memory,"哪次对话发生了什么"的经历记录)。

四类外部介质 × 记忆类型
介质适配的记忆类型代表系统机制与代价
文件 / Markdown 程序性记忆:指令、约定、偏好 Claude Code 的 CLAUDE.md 与 memory 目录 agent 直接读写,零基础设施;整体加载,不支持相似度召回
向量库(Qdrant / pgvector / Milvus) 语义事实、历史对话片段 MemGPT archival、Mem0 主存储 embedding 相似度召回;表达不了多跳关系
关系型 DB / Redis KV 结构化用户画像(user profile)、session 状态、checkpointer 快照 LangGraph BaseStore(可插 Postgres / Redis) 精确查询、事务保证;schema 需预先设计
知识图谱 实体关系 + 时间维度 Zep / Graphiti(Neo4j 底座) 图遍历原生支持多跳;写入要先做实体抽取,延迟更高
记忆类型 介质 程序性记忆 语义记忆 情景记忆 结构化用户画像 实体关系 文件 / Markdown 向量库 关系型 DB / KV 知识图谱 CLAUDE.md Mem0 MemGPT archival LangGraph Store Zep / Graphiti
图 1记忆介质选型:左侧按认知类别划分的记忆类型,映射到右侧四类存储介质,每条映射标注一个代表系统。

机制再往下讲一层。向量库通过把文本投影成 embedding、按相似度召回,做到"语义相近即可命中",代价是只剩"相似"这一种关系——"A 的同事在哪家公司"这类两跳问题答不上来。知识图谱反向取舍:写入时先抽取实体与关系,查询时沿边遍历,多跳成为原生能力,代价是每条消息都要付一次实体抽取的延迟与错误率。Zep 的 Graphiti 在图之上加 bitemporal(双时间轴)标注:valid_at / invalid_at 记录事实在现实世界中的有效区间,created_at / expired_at 记录系统得知与作废的时刻——四个时间戳让过期事实被标记失效而非物理删除。

文件介质看似原始,却在持续升级:2025 年 10 月 Anthropic 发布 memory tool 与 context editing,把基于文件的记忆读写做成 Claude API 的一等能力,印证"agent 自编辑的文件即程序性记忆"这条路线。

60 秒口头版本

「记忆介质先分两层:上下文窗口本身是工作记忆,易失、有界;要跨会话就必须落外部存储。外部介质按记忆类型选:指令和约定这类程序性记忆放文件,比如 Claude Code 的 CLAUDE.md,agent 自己能读写、零基础设施;语义事实和对话片段放向量库,按相似度召回,Mem0、MemGPT 都是这个路子;结构化画像和会话状态放关系型库或 KV,LangGraph 的 Store 可以插 Postgres 或 Redis;要回答实体之间的多跳关系就上知识图谱,Zep 用 Neo4j 底座再加双时间轴。生产系统通常按查询类型组合使用,而不是单选一种。」

加分点

Insight

① Mem0 实际是 hybrid 架构:向量为主,外加 KV 与 SQL,图为可选模块——"单一介质"论述在追问下站不住。

② 介质选择决定可回答的查询类型:向量答不了多跳关系,图要付实体抽取的写入延迟。先问"业务需要什么查询",再反推介质。

③ 记忆与 RAG 的分界不在检索技术而在写入路径:记忆由对话自动沉淀,RAG 由外部文档导入;检索侧两者高度重合。

追问预判

追问 1:为什么不全部用向量库,架构更统一?

应对方向:向量检索只有"相似"一种关系。结构化精确查询(如"该用户的会员等级")与多跳关系查询都覆盖不了;程序性指令需要整体加载而非片段召回,切碎进向量库反而破坏指令的完整性与优先级。

追问 2:记忆系统和 RAG 是不是一回事?

应对方向:检索侧重合,分界在写入路径。记忆由对话自动沉淀,写入时伴随抽取与冲突消解,且随用户状态持续更新;RAG 由外部文档批量导入,相对静态。记忆还要处理"同一用户的事实随时间变化"这一 RAG 不面对的问题。

追问 3:图谱方案最大的成本在哪?

应对方向:在写入路径。每条消息都要经过实体抽取与关系判定,延迟与抽取错误都会沉淀进图。Zep 用后台异步构建缓解写入阻塞,以此换取读路径的低延迟。

Q2如何跨会话压缩对话并保留关键信息?

面试官在考什么

候选人能否给出从简单到精细的策略谱系,并说清"保留什么、丢弃什么"的判断标准。

参考答案

按工程复杂度由低到高,压缩策略分四个层次:

  1. 滑动窗口:只保留最近 N 轮。实现成本最低,代价是早期信息直接丢失,且无任何挽回手段。
  2. 递归摘要(recursive summarization,旧摘要与新内容反复合并的滚动式摘要):旧消息被挤出窗口前压成一段摘要,后续内容不断并入。MemGPT 的 FIFO 队列即此:队列溢出时触发摘要,摘要本身再参与下一轮摘要。
  3. 结构化事实抽取:LLM 把对话压成原子事实写入外部记忆,写入时与既有记忆做冲突消解——Mem0 对每条新事实执行 ADD / UPDATE / DELETE / NOOP 四选一,避免重复与自相矛盾。LoCoMo 长对话基准上准确率约 92.5%,每次查询仅注入约 7K token。
  4. 分层分页:装不下的内容换出到 recall / archival 存储,需要时由模型通过 tool call 换回。MemGPT 称之为虚拟上下文管理,类比操作系统的虚拟内存——上下文窗口是物理内存,外部存储是磁盘,模型自己发起换页。

落地实例是 Claude Code 的 auto-compact。compaction(把长上下文压实成短摘要并替换原文的操作)在会话接近窗口容量时自动触发(官方未公布精确阈值):保留任务目标、关键决策、文件状态、最近的工具结果;丢弃中间推理、被否决的方案、重复的文件读取。/compact focus on X 可指定定向保留的主题。

保留策略一句话:决策与事实保留,过程性 token 丢弃。

框架层面,LangGraph 采用双轨制:checkpointer 在单 thread 内做全量短期持久化(机制详见 02 章),摘要节点在消息超限时压缩历史,跨 thread 的长期记忆走独立的 Store。短期求全、长期求精,两轨各司其职。

前沿方向上,Letta(MemGPT 团队)于 2025 年提出 sleep-time compute:后台第二个 agent 在对话间隙整理、改写主 agent 的记忆,把压缩从"对话时被动触发"变成"空闲时主动维护"。

60 秒口头版本

「压缩有四个档位:最简单是滑动窗口,只留最近几轮,早期信息直接丢;第二档是递归摘要,旧消息挤出去之前压成滚动摘要,MemGPT 的 FIFO 队列就是这么做的;第三档是结构化抽取,把对话压成原子事实写进外部记忆,Mem0 写入时还做 ADD、UPDATE、DELETE、NOOP 冲突消解,LoCoMo 基准约 92.5%、每次查询只注入约 7K token;最完整的是分层分页,装不下的换出到外部存储、要用时 tool call 换回,类比操作系统的虚拟内存。保留标准一句话:决策和事实留下,过程性 token 丢掉——Claude Code 的 auto-compact 就是这条标准的落地。」

加分点

Insight

① 压缩必然有损,评判标准不是"摘要写得全",而是"下游任务还缺什么"——以查询为锚的压缩优于以内容为锚的压缩。

② 成本视角:全量上下文与 Mem0 式抽取在长对话上的 token 开销相差一个数量级,压缩同时是延迟与成本优化,不只是容量手段。

③ 行业话语已从 prompt engineering 转向 context engineering——窗口内放什么、何时换入换出,被当作一等工程问题(Anthropic 2025 年发布同名工程实践文章)。

追问预判

追问 1:摘要把关键细节压丢了怎么办?

应对方向:分层兜底。摘要只承担索引职责,原始消息换出到 archival 存储而非删除,需要时可换回;高价值事实另走结构化抽取通道,与摘要形成双通道冗余。

追问 2:压缩在什么时机触发?

应对方向:三类触发器——容量阈值(Claude Code auto-compact)、轮次或 token 计数(LangGraph 摘要节点)、任务边界(子任务完成即沉淀结论)。任务边界触发的信息密度最高,因为压缩发生在语义完整的断点上。

追问 3:怎么评估一套压缩策略的好坏?

应对方向:双轴评估——长对话基准(LoCoMo、LongMemEval)上的下游 QA 准确率 × 每查询 token 成本。只报准确率不报成本的评估是不完整的。

Q5用户今天问 A、三天后问 B,如何关联两次提问?

面试官在考什么

记忆系统的端到端设计能力:键的分层、写入时机、检索信号、实体关联,缺任何一环都接不住这道场景题。

参考答案

完整链路分四步:

  1. 记忆按键分层。session_id 标识单次会话,user_id 标识跨会话的同一个人;跨会话关联的前提是记忆按 user_id 分区存储。Mem0 即按 user_id 分区,三天后问 B 时以同一 user_id 检索,即召回问 A 时沉淀的事实。
  2. 写入时沉淀。问 A 的当天就完成事实抽取与用户画像更新,而不是等问 B 时回头翻三天前的原始日志——原始日志噪声大、token 成本高,且偏好、背景这类画像信息只有经过抽取才能被结构化命中。
  3. 检索时召回。单一向量相似度不够,生产系统叠加多信号:向量语义相似 + BM25 关键词 + 实体匹配。A 与 B 字面不相似但语义或实体相关时,仍能命中。
  4. 实体链接 + 图。实体链接(entity linking,把文本里的提及解析到同一个实体节点)让 A、B 共享实体时可通过图遍历做多跳关联。Zep 把记忆组织成 episode → entity → community 三层子图,检索时取相关子图注入;LongMemEval 基准上较全量上下文基线提升 18.5%,注入 token 从 115K 压到 1.6K,延迟降低约 90%。
DAY 0 用户问 A 事实抽取 / 画像更新 写入(user_id 为键) 记忆库 按 user_id 分区 召回 Day 0 沉淀的事实 DAY 3 用户问 B user_id 检索 + 实体链接 注入上下文 回答关联 A 与 B
图 2跨会话关联时序:Day 0 问 A 后立即抽取并按 user_id 写入;Day 3 问 B 时以 user_id 检索 + 实体链接召回旧事实,注入上下文后回答即可关联两次提问。
60 秒口头版本

「核心是四步:第一,记忆的键要分层,session_id 管单次会话,user_id 管跨会话,问 B 时拿 user_id 去检索,就能召回 A 沉淀的内容;第二,沉淀必须发生在写入时,问 A 当天就抽取事实、更新画像,不能等问 B 再翻原始日志;第三,检索用多信号,向量相似加 BM25 关键词加实体匹配,字面不相似也能命中;第四,A 和 B 共享实体时,实体链接加图遍历能做多跳关联,Zep 的 episode、entity、community 三层子图在 LongMemEval 上比全量上下文基线高 18.5%,注入 token 从 115K 降到 1.6K,延迟降九成。」

加分点

Insight

① 区分两条沉淀路径:情景记忆回答"那次对话发生了什么",语义记忆回答"由此推断用户是谁"。A 的原始问题进情景层,从 A 推断出的偏好进语义层,问 B 时两层共同参与召回。

② 时间正确性:三天前抽取的事实此刻未必仍有效(用户换了城市、改了需求)。bitemporal 标注(见 Q1)让系统区分"何时为真"与"何时得知",避免把陈旧事实当新鲜事实注入。

追问预判

追问 1:A 与 B 表面毫不相干,系统怎么决定关联不关联?

应对方向:不做二值判定。检索按相关性打分,低分记忆自然衰减出 top-k;实体链接提供字面相似之外的关联信号;召回宁可略宽,由生成端在上下文中取舍——代价是多付一些 token。

追问 2:抽取出的画像事实后来发现是错的,怎么修正?

应对方向:写入路径的冲突消解(UPDATE / DELETE)负责修正;bitemporal 方案则标记 invalid_at 使其失效而非物理删除,同时保留审计轨迹。

追问 3:user_id 分区之外,隐私与删除请求怎么处理?

应对方向:分区即隔离边界与删除边界——合规删除对应清空该 user_id 分区;由该用户事实推导出的语义层画像同样要随删除请求一并清除。

本章自测

  1. 四类外部介质(文件、向量库、关系型/KV、图谱)各自最不擅长回答哪类查询?
    查看答案

    文件不支持相似度召回,只能整体加载;向量库答不了多跳关系与精确结构化查询;关系型/KV 答不了开放式语义相似查询;图谱对 schema 之外的模糊查询弱,且要付实体抽取的写入延迟。

  2. Mem0 写入新事实时的四个操作是什么?合起来解决什么问题?
    查看答案

    ADD 新增、UPDATE 修正旧事实、DELETE 作废矛盾事实、NOOP 丢弃冗余信息。合起来解决记忆的重复堆积与自相矛盾——写入即消解冲突,而不是把矛盾留给检索端。

  3. Claude Code 的 compaction 触发时保留哪些内容、丢弃哪些内容?
    查看答案

    保留:任务目标、关键决策、文件状态、最近的工具结果。丢弃:中间推理、被否决的方案、重复的文件读取。一句话:决策与事实保留,过程性 token 丢弃。

  4. 跨会话关联为什么必须"写入时沉淀",而不是查询时翻原始日志?
    查看答案

    原始日志噪声大、token 成本高,且画像类信息未经抽取无法被结构化命中。写入时抽取把成本摊到每次会话结束的低峰时刻,使查询路径保持轻量、低延迟。

延伸阅读