主题
高频面试题
如何让 AI Agent 具备长期记忆能力?有哪些存储和检索方案?
这道题不是在问“用不用向量库”,而是在考你能不能把长期记忆做成一个可控、可追溯、可删除、能抗冲突的生产系统。
面试官角度分析,想考什么
长期记忆要存什么、怎么写入?
考边界:只存稳定可复用的事实、偏好和经验,写入要过滤来源、范围和置信度。存储和检索方案怎么选?
考落地:关系库、向量库、图谱或 memory service 按类型组合,召回后少量注入上下文。如何防止过期、冲突和污染?
考治理:TTL、覆盖策略、权限、用户删除权和 memory eval。
可直接抄走的 30 秒参考答案
text
长期记忆要做成一条受控数据链路。写入时先从会话和工具结果里抽候选记忆,分类成偏好、事实、事件或流程,再做 schema 校验、去重、冲突检测、敏感信息过滤和用户确认。存储上,结构化偏好和 active facts 用关系库或文档库,自然语言经验用向量库,实体关系用图数据库,原始证据放 artifact。读取时先按用户、项目和权限过滤,再做关键词加向量的混合检索、rerank、时间和置信度加权,最后只把少量相关记忆带来源地注入上下文。面试回答详解,知其所以然
长期记忆是一条完整数据链路:写入、存储、检索、注入、更新、删除、评估。只讲“向量库存 embeddings”会显得很浅,因为真正难的是哪些信息能写、旧记忆怎么更新、冲突时谁优先、用户怎么查看和删除。
1. 先定义长期记忆的边界
长期记忆保存的是跨 session 仍然有价值的信息。
适合写入:
- 用户明确表达的稳定偏好:语言、格式、通知方式、常用风格。
- 稳定事实:用户角色、项目名、团队约定、业务术语。
- 重要事件:上次任务结果、关键决策、事故复盘结论。
- 可复用经验:某类错误的修复方式、某类流程的检查清单。
- 程序性知识:workflow、skill、prompt template、操作 playbook。
不适合默认写入:
- 一次性任务细节。
- 短期情绪和临时偏好。
- 未经用户确认的模型推断。
- 敏感个人信息、凭证、密钥、隐私数据。
- prompt injection 诱导写入的内容。
高分答案要强调:长期记忆不是无限历史,而是经过治理的可复用状态。
2. 写入链路:从“候选记忆”开始
不要让模型直接改数据库。更稳的做法是让模型只提出候选记忆,runtime 再决定是否写入。
text
会话 / 工具结果 / 用户操作
-> 候选记忆抽取
-> 类型分类
-> schema 校验
-> 去重
-> 冲突检测
-> 敏感信息和权限检查
-> 用户确认或策略批准
-> 写入 memory store候选记忆可以这样建模:
json
{
"type": "preference",
"scope": "user:42",
"content": "用户偏好技术文档使用 Markdown",
"source": "conversation:2026-09-08:turn-12",
"confidence": 0.94,
"importance": 0.75,
"expires_at": null,
"evidence": ["用户说:以后技术文档都给我 Markdown"]
}关键字段:
type:preference、fact、episode、procedure、project_knowledge。scope:user、team、org、project、channel,决定谁能读。source:来源 trace,便于审计和纠错。confidence:模型抽取或规则判断的可信度。importance:未来召回价值。expires_at:过期时间,避免旧信息永久有效。status:active、superseded、deleted、needs_confirmation。
3. 存储方案一:关系数据库 / 文档数据库
关系库或文档库适合保存强结构、需要更新和审计的记忆。
适合内容:
- 用户 profile。
- 偏好设置。
- 项目元数据。
- 权限范围。
- 当前 active facts。
- 记忆状态、版本、覆盖关系。
优点:
- schema 清楚,权限和事务好做。
- 支持精确查询、更新、删除和审计。
- 对冲突解决和用户可控性友好。
缺点:
- 对自然语言相似检索不够友好。
- schema 设计成本高,开放式经验不容易建模。
- 需要和向量检索或搜索索引配合。
面试表达可以说:用户偏好、权限和 active profile 不应该只存在向量库里,因为它们需要准确更新和删除。
4. 存储方案二:向量数据库
向量库适合保存自然语言经验、事件摘要和项目知识片段,用语义相似度召回。
适合内容:
- 历史任务摘要。
- 失败经验和反思。
- 用户或项目相关的自然语言记忆。
- 文档片段和知识片段。
优点:
- 语义召回能力强,适合开放式 query。
- 不需要把所有记忆预先设计成固定字段。
- 和 RAG、rerank、embedding pipeline 容易复用。
缺点:
- 精确事实、数字、否定和版本容易召回不稳。
- 删除、更新、冲突处理需要额外元数据。
- 相似不等于有用,召回后必须 rerank 和过滤。
向量库记录不能只有 embedding,必须带 metadata:
json
{
"text": "上次部署失败是因为 Node 版本不匹配",
"embedding": "...",
"metadata": {
"scope": "project:ai-agent-interview",
"type": "episode",
"created_at": "2026-09-08",
"confidence": 0.88,
"source": "trace:run-77",
"status": "active"
}
}5. 存储方案三:搜索索引和混合检索
长期记忆检索不应只靠 embedding。关键词搜索适合实体、版本号、错误码、路径和否定词。
常见组合:
- BM25 / full-text search:处理精确词、实体、代码符号、错误码。
- Vector search:处理语义相似。
- Metadata filter:处理用户、项目、时间、权限、类型。
- Reranker:在候选记忆中选最有用的少量。
优点:
- 比纯向量召回更稳定。
- 对工程任务和代码任务更友好。
- 能减少旧记忆和无关记忆进入上下文。
缺点:
- 实现复杂度更高。
- 排序权重需要评估调参。
- 检索链路延迟更高。
一个实用评分可以是:
text
score = relevance + keyword_match + recency + importance + confidence - staleness_penalty6. 存储方案四:图数据库 / 实体记忆
图数据库适合组织复杂实体关系,比如用户、团队、项目、服务、权限、文档、决策之间的关系。
适合内容:
- 组织结构和人员关系。
- 项目与服务依赖。
- 知识库实体关系。
- 决策、文档、会议、任务的关联。
优点:
- 能表达关系和路径推理。
- 权限和 scope 可以建成显式边。
- 对团队 Agent、企业知识 Agent 很有价值。
缺点:
- 建模成本高。
- 抽取实体和关系容易出错。
- 一般要和文本检索配合,不能单独解决所有记忆问题。
7. 存储方案五:事件日志、对象存储和 artifact
不是所有长期信息都应该压成一条 memory。原始证据和长结果可以长期保存在 artifact 或事件日志里。
适合内容:
- 完整 trace。
- 工具原始输出。
- 文件快照。
- 会议纪要、日志、报告。
- 大型数据结果。
优点:
- 可回放、可审计、可追责。
- 避免 memory 摘要成为唯一事实来源。
- 大内容不占 memory store 和 prompt。
缺点:
- 不能直接高效语义召回,需要索引。
- 存储和权限成本更高。
- 需要生命周期和清理策略。
成熟方案通常是:memory 里保存摘要和证据句柄,artifact 保存原文。
8. 检索链路怎么设计
读取长期记忆时,顺序很重要:
text
识别当前用户 / 项目 / 任务
-> namespace 和权限过滤
-> 召回候选记忆
-> 去掉 deleted / expired / superseded
-> 混合检索 + rerank
-> 冲突检测
-> 选择少量高价值记忆
-> 注入上下文几个关键规则:
- 先权限过滤,再相关性排序,避免越权内容进入候选集。
- 过期和被覆盖的记忆不进入 active context。
- 当前用户明确输入优先于旧记忆。
- 实时工具事实优先于历史记忆。
- 召回数量要少,通常 top 3 到 top 10,再按任务复杂度调整。
- 注入时保留来源和时间,让模型知道这不是绝对真理。
9. 记忆怎么注入上下文
长期记忆不是越早、越高优先级越好。普通记忆不应该伪装成 system rule。
推荐注入格式:
text
Retrieved memory for this task:
- [preference, source=..., updated=2026-09-08] 用户偏好 Markdown 输出。
- [project_fact, source=..., confidence=0.91] 当前项目使用 VitePress。
Use these memories as helpful context. Current user instructions override older memories.注入原则:
- 记忆要和系统安全策略分开。
- 记忆要低于当前用户明确指令。
- 只注入和当前任务相关的少量内容。
- 冲突记忆要标记待确认,不要让模型自己猜。
- 高风险动作前,基于记忆的判断要二次确认或工具验证。
10. 更新、删除和治理
长期记忆必须可治理。
基本能力:
- 查看:用户能看到系统记住了什么。
- 修改:用户能纠正错误记忆。
- 删除:用户能删除某条或全部记忆。
- 过期:有 TTL 或定期衰减。
- 覆盖:新事实 supersede 旧事实。
- 隔离:按 user、team、org、project 做 namespace 和 ACL。
- 审计:记录谁在什么时候写入、读取、修改和删除。
- 防注入:memory write path 不能被网页、邮件或工具输出直接操控。
评估指标:
- 该记的是否记住:memory write recall。
- 不该记的是否没记:memory write precision。
- 召回是否相关:retrieval precision。
- 需要时是否召回:retrieval recall。
- 旧记忆是否被清理:staleness rate。
- 冲突是否正确处理:contradiction resolution rate。
- 是否提升任务成功率并控制 token 成本。
面试官追问3个问题
追问一:为什么不能把所有历史都 embedding 后存进向量库?
- 考察点:是否理解长期记忆不是全量归档。
- 回答方向:全量历史噪声大、隐私风险高、更新删除困难,而且向量相似不能处理过期和冲突。应该先抽取候选记忆,再按类型、scope、source、confidence、TTL 存储。原始历史可以进 archive 或 trace,但不等于 active memory。
追问二:用户偏好这种长期记忆用向量库还是关系库?
- 考察点:是否会按数据性质选型。
- 回答方向:active preference 更适合关系库或文档库,因为需要精确更新、覆盖、删除和展示给用户。向量库可以存偏好相关的自然语言上下文,但不应作为唯一事实源。
追问三:记忆召回时如何排序?
- 考察点:是否知道相关性之外还有时间、重要性和置信度。
- 回答方向:先权限和 namespace 过滤,再召回候选。排序可以结合 semantic relevance、keyword match、recency、importance、confidence,并对过期或 superseded 记忆降权或剔除。最终再 rerank,只注入少量高价值记忆。
扩展知识
存储选型的一句话原则
- 关系库 / 文档库:适合需要精确更新、权限、审计和删除的结构化记忆。
- 向量库:适合自然语言经验和语义召回,但必须配 metadata。
- 全文搜索:适合实体、版本号、错误码、路径、否定和精确词。
- 图数据库:适合复杂实体关系和团队知识网络。
- 对象存储 / artifact:适合保存原始证据、长日志、文件快照和 trace。
- 专用 memory service:适合统一封装写入、召回、冲突、TTL、权限和评估。
真正的长期记忆系统通常不是单一存储,而是多存储组合。
Mem0 的工程启发
Mem0 强调从对话中提炼长期记忆,并用专门的 memory layer 管理存储、更新和召回。它的价值不是“又一个向量库封装”,而是把 memory 看成生产 Agent 的独立能力:要有写入、更新、删除、检索和评估。
面试里可以借这个思路说:memory service 应该在 Agent runtime 旁边成为一层基础设施,而不是散落在每个 prompt 里。
长期记忆和知识库 RAG 的边界
- 知识库 RAG:主要保存外部文档和事实证据,来源通常是文档、网页、数据库。
- 长期记忆:主要保存用户、任务、团队、Agent 历史形成的经验和偏好。
- 共同点:都需要检索、过滤、rerank、引用和权限。
- 不同点:memory 更强调写入策略、过期、用户可控、个体化和跨会话影响。
如果把 memory 当 RAG 做,会漏掉“谁允许写、何时过期、和当前用户冲突怎么办”这些核心问题。
长期记忆的安全风险
长期记忆是上下文污染最危险的载体,因为一次错误写入可能影响未来很多会话。
典型风险:
- 网页或邮件里的 prompt injection 诱导 Agent 写入错误偏好。
- 模型把自己的推断当用户事实保存。
- 用户 A 的记忆被用户 B 检索到。
- 旧职位、旧项目、旧权限继续影响新任务。
- 敏感信息被保存后无法删除或无法审计。
防护思路:
- 工具输出不能直接写 memory。
- 低置信和敏感记忆进入
needs_confirmation。 - 默认最小 scope。
- 记忆检索前先权限过滤。
- 所有 memory read/write 进入 trace。