【AI Agent面试系列】AI Agent记忆机制知识点2 上一篇文章主要讲了如何设计Agent记忆系统本文主要介绍如何定位记忆系统效果不好的问题原因、如何评测记忆系统等。1、记忆系统效果不好你怎么定位是哪个环节的问题记忆系统是一条流水线任何一段坏了最终表现都是答得不对。但不同环节坏掉症状不同。做法先按症状分类再用对照实验和自检索测试快速排除最后才逐段深挖。优先怀疑抽取和覆盖最后才怀疑向量检索——因为前者出错概率高得多而后者一旦配好就很少出问题。对照实验关掉改写只做原始 query 检索。如果关掉改写后效果变好说明改写有害直接下线。如果效果不变说明改写无效白付成本。如果效果变差改写才有价值再去看它具体哪里改错了。定位顺序按成本从低到高1. 关改写对照实验 —— 5 分钟排除一整类问题 2. 自检索测试 —— 10 分钟验证索引是否可用 3. 抽取离线评测 —— 需要标注集但能定位漏抽/错抽 4. 覆盖状态检查 —— 查库看是否有双活跃记录 5. 注入排除法 —— 喂完美结果看是否还错具体说明如下1.1、先看症状属于哪一类按照写入 - 检索 - 注入流程顺序主要症状表现如下症状出问题环节可能原因该记的没记住写入被门控过滤、抽取问题记住了旧值新值没生效写入覆盖问题记住了但检索不到检索Query改写有问题答得对但很慢/很贵检索检索top_k 过大、无过滤时好时坏不稳定检索改写需要上下文检索到了但答错注入注入问题比如位置靠中间等需要先排除非记忆系统问题比如回答慢、检索到了但答错等也可能是模型问题。1.2、逐段隔离测试1.2.1、抽取测法拿一批已知答案的对话只看抽取输出不看检索结果。# 输入对话文本 # 期望输出应该抽出的记忆列表人工标注 # 实际输出系统抽出的记忆列表 # 指标召回率漏抽多少、准确率错抽多少关键这一步必须脱离检索单独测。如果抽取漏了后面检索再好也检不到但你会误以为是检索问题。常见故障漏抽显式声明“记住…”没被识别 → 规则没覆盖错抽把临时状态“这次先用 A”当决策 → 缺排除规则槽位错preference.tone 和 preference.length 混用 → 词表没约束1.2.2、写入测法给定抽取结果检查写入后的库状态。# 输入抽取出的记忆 # 检查库里是否多了一条旧记录 superseded_by 是否设了 # 指标写入成功率、覆盖正确率常见故障唯一约束误伤(key, scope) 冲突导致新记录被拒覆盖没生效superseded_by 没设新旧两条都活跃 → 检索返回旧值置信度阈值过高inferred 类全被过滤1.2.3、索引测法绕过检索直接算向量相似度。# 给定一条已知记忆用它的标准问法去检索 # 看它自己能不能排进 top_1 这是自检索测试self-retrieval用记忆本身生成 query看能否检回自己。 如果连自己都检不回索引一定有问题。常见故障embedding 文本构造错只 embed 了 value“Go”语义太短key 的点没换空格project.tech_stack 被切碎payload 缺 superseded_by失效记录占满 top_k1.2.4、改写测法对比改写前检索和改写后检索的结果差异。# 指标 # - 改写前后结果相同 → 改写无效白做 # - 改写后结果变差 → 改写有害 # - 改写后空结果率上升 → 改写过度收窄关键改写是唯一一个可能让效果变差的环节。其他环节坏了是没帮上忙改写坏了是帮倒忙。常见故障补全指代补错把那个方案补成 A实际是 B推断式改写替用户提问检索方向被悄悄改掉过度收窄加了太多 filter把正确结果过滤掉1.2.5、注入测法给定正确的检索结果看最终回答对不对。# 输入人工构造的完美检索结果 # 输出模型回答 # 如果这样还答错 → 注入或生成的问题与检索无关 这一步是排除法如果喂了正确答案还答错说明问题不在检索链路在上下文组织或生成。常见故障注入位置错记忆放在长上下文中间被忽略格式混乱多条记忆无结构拼接模型分不清哪条是当前值缺时间信息模型不知道哪条更新2、你怎么评估记忆系统好不好评估记忆系统要分层归因——L1 抽取看召回和误收L2 存储看双活跃率L3 检索看自检索和改写增益L4 端到端必须做对照实验。不要用回答看起来对不对当主指标那评估的是模型不是记忆系统。记忆系统的评估必须分层、可归因——每个指标要能指向具体环节。评估的四个层次:L1 抽取质量 —— 该记的记住了吗不该记的记了吗 L2 存储正确性 —— 存进去的东西结构对吗覆盖对吗 L3 检索质量 —— 需要的时候找得到吗找得准吗 L4 端到端效果 —— 最终回答变好了吗必须按照L1-L4的顺序评估。如果 L1 就漏了L4 再差也说明不了检索有问题。反过来L4 好也不代表系统好——可能只是这次问题简单记忆没起作用也答对了。L1 抽取质量需要一个人工标注集给定对话标出应该抽出哪些记忆。指标定义关注点召回率抽出的 / 应抽出的漏抽是最致命的漏了后面全白搭准确率正确的 / 抽出的错抽会污染库且难以清理槽位准确率key 归对的 / 抽出的槽位错会导致覆盖判断失效误收率临时信息被收进库的比例“这次先用 A” 这类不该进误收率要单独看。它和准确率不是一回事准确率看抽出来的对不对误收率看压根不该抽的抽了没。后者错了代价更大因为临时信息进库后靠 expires_at 补救并不可靠。L2 存储正确性这一层不需要人工标注查库就能算指标检查方式双活跃率(key, scope) 下 superseded_bynull 的记录数 1 的比例应为 0覆盖及时率新值写入后旧记录 superseded_by 被设置的比例版本链完整率superseded_by ! null 时 superseded_at 也非空的比例置信度合规率source_typeexplicit 时 confidence1.0 的比例孤儿向量率向量索引里有、主库没有的 id 比例双活跃率是最重要的一个。它一旦 0检索就会返回旧值而且症状看起来像排序错极难定位。这个指标应该做成监控告警不是事后评估。L3 检索质量自检索测试最便宜先做这个用记忆本身生成 query看能否检回自己。for rec in sample(memories, 200): query generate_query_from(rec) # 用 quote 或 keyvalue 生成问法 results retrieve(query, top_k10) hit rec[id] in [r[id] for r in results]指标含义健康值Recall1自己排第一的比例 70%Recall10自己进前十的比例 95%Recall10 95%说明索引构造有问题embedding 文本太短、key 没换空格、payload 过滤错不用往下测了。端到端检索评测需要标注这个问题应该检索到哪几条记忆。指标含义Recallk应检索到的记忆里实际返回的比例Precisionk返回结果里相关的比例MRR正确结果排名的倒数均值空结果率返回空的比例高 改写过度收窄或索引缺失假阳性率返回了不相关记忆的比例高 改写过度扩展空结果率和假阳性率要一起看。只看 Recall 会掩盖问题把 top_k 调到 100Recall 一定高但假阳性也高注入上下文后反而干扰模型。改写增益必测指标 检索质量(改写后) - 检索质量(改写前) 增益 ≈ 0 → 改写无效白付成本应下线 增益 0 → 改写有害立即下线 增益 0 → 改写有价值再看具体哪类 query 受益这个指标最容易被跳过但它是唯一能证明改写该不该存在的指标。L4 端到端效果对照实验唯一可信的方法A 组有记忆系统 B 组无记忆系统或记忆置空 同一批问题比较回答质量必须做对照。只测有记忆时答对率 85%没有意义——可能无记忆时也有 83%记忆只贡献了 2 个点不值得这套复杂度。分场景看不要只看总分场景记忆应有的贡献跨会话偏好“还是用简洁格式”高无记忆必失败项目配置“部署在哪台机器”高无记忆必失败单轮事实问答零记忆不该有影响需要推理的问题低记忆只提供素材如果单轮事实问答场景下记忆系统让效果变差了说明注入的记忆在干扰模型——这是很常见的隐性损失总分看不出来。成本也要算进去指标说明每次请求额外 token注入的记忆占多少上下文额外延迟检索 改写耗时存储增长速率每天新增多少条其中多少是垃圾记忆系统的隐性成本是库越来越脏。如果误收率高半年后检索质量会自然下降而单次评测看不出来。所以要监控库的构成活跃记录数、失效记录数、从未被检索到的记录比例。一个反直觉但重要的指标:从未被检索到的记忆占比如果库里 60% 的记录从来没被任何 query 命中过说明要么抽取过度记了太多没用的要么检索覆盖不到索引或改写有问题要么这些记忆本来就该在会话内解决不该进跨会话库这个指标直接反映记忆系统的信噪比。库越大、这个比例越高系统越接近存了一堆用不上的东西。评估的最小可行方案双活跃率监控查库零成本防最严重的静默错误自检索 Recall10200 条样本10 分钟验证索引可用改写开关对照实验改个配置验证改写是否值得存在这三项覆盖了最容易出问题、且最难通过看回答发现的三类故障。端到端人工评测放最后做因为它最贵、最不可归因而且容易被模型本身很强掩盖。3、记忆和 RAG 的边界在哪技术实现上记忆是 RAG 的特例但语义上它们是两套不同的系统——RAG 管外部知识怎么找记忆管用户状态怎么维护。边界不在向量库在谁产生数据、谁决定写入、失效意味着什么。混用基础设施可以混用语义模型不行。3.1、表面看它们几乎一样环节RAG记忆切分文档切 chunk对话切记忆条目索引embedding 向量库embedding 向量库检索query → top_kquery → top_k注入拼进 prompt拼进 prompt所以很多人认为记忆就是 RAG 的一个特例。这个看法在实现层成立但在语义层会误导设计——因为两者的关键差异恰恰在那些看起来一样的环节里。3.2、三个真正的边界边界 1数据来源——谁产生的RAG外部语料。文档、网页、知识库。用户不产生它只是查询它。记忆用户自己说的话。用户既是生产者也是消费者。这条差异的后果很实际RAG 的语料是只读的记忆是可写的。可写意味着要处理覆盖、冲突、版本、失效——这些 RAG 完全不需要考虑。边界 2写入时机——谁决定存什么RAG离线批量入库。存什么由语料本身决定系统不做筛选。记忆在线增量写入。存什么由抽取策略决定系统必须主动判断这条值不值得记。这条差异导致两者的错误模式完全不同错误模式RAG记忆主要风险检索不到召回不足记错了污染错误可逆性高补文档即可低错误记忆会持续影响后续所有对话需要人工介入少多要清理、要纠正记忆系统的核心难题是写什么RAG 的核心难题是怎么找。 这是两者最本质的分工差异。边界 3失效语义——什么时候该消失RAG文档过期了重新入库覆盖。失效是内容问题。记忆信息被新信息取代旧值要标记 superseded_by。失效是状态问题。这条差异最容易被忽略但它是记忆系统复杂度的主要来源。RAG 里同一份文档的两个版本是运维问题记忆里同一事实的两个值是语义问题——必须判断哪个是当前值、哪个是历史、变更发生在什么时候。RAG和记忆对照表维度RAG记忆数据来源外部文档用户对话写入方式离线批量在线增量写入决策语料决定抽取策略决定可写性只读可写核心难题召回写什么 覆盖失效语义内容过期状态被取代主要风险检索不到记错污染错误可逆性高低需要版本化文档版本事实版本superseded_by评估重点Recall / Precision抽取召回 双活跃率