小模型蒸馏实验揭出记忆评测漏洞
作者用 Qwen2.5-7B 生成事实抽取标签,尝试训练参数量小约14倍的0.5B模型,以降低智能体记忆处理成本。小模型初测召回率降至83%,排查却发现原先98%的成绩部分依赖偶然因素,暴露了基准测试的问题。
AI 深度解读
把每条用户消息交给 7B 模型提取事实,再存进 AI Agent 的记忆,效果不错,成本也高。作者想用小 14 倍的模型接替这份工作,第一次测试却从 98% 跌到 83%。继续排查才发现,原来的高分部分依赖一句措辞偶然占优的记忆。
这次实验最有价值的,是它拆开了三个容易混在一起的问题:模型有没有提取对、记忆系统有没有存取对、评测有没有奖励错东西。做 Agent、RAG 或模型替换,这几层都需要分别验证。
模型缩小 14 倍,为什么老师也一起掉分
作者此前用 agent-memory-bench 比较记忆策略:提取事实的策略平均找回 98% 的相关信息,简单相似度检索是 62%。前者让每条消息经过 qwen2.5:7b,生成带键名的事实,例如 payment_service.region = sa-east-1。
为了降低逐条调用成本,作者用 Qwen2.5-7B-Instruct 当老师,生成训练标签,再用 LoRA 微调学生 Qwen2.5-0.5B-Instruct。LoRA 通过训练附加的小矩阵完成适配,无须更新全部原始权重。这次训练能放进 Kaggle 免费 T4,耗时约 10 至 20 分钟。
训练集有 3000 条葡萄牙语模板消息,覆盖服务区域变更、数据库选择、团队规则、无关闲聊,以及包含助手指令的外部内容。自动测试会排除与 benchmark 消息过于相似的样本,降低数据泄漏风险。
第一次完整测试,学生的恢复率掉到 83%,但老师也掉到了 83%;未经训练的学生,结果又与训练后的学生接近。
老师和学生一起掉分时,应该先查共同经过的系统路径。
两轮之间,推理服务从本地 Ollama 换成 Kaggle 的 vLLM,embeddings 实现和连接 benchmark 的适配器也变了。作者保留了旧实验逐条提取的原始输出,因此可以把相同输出送进新路径,在 CPU 上按 5 个 seeds、5 个噪声等级、5 个时间间隔重新测试。
新路径准确复现了旧结果。问题因此收敛到提取器生成的文本,而不是基础设施变化。
提供的原文缺少多张结果表,无法还原所有配置的精确成绩;正文明确披露的数据,足以支持这条排查逻辑。
一条长期规则,怎样被无关消息挤掉
问题集中在「稀有规则」场景。八周模拟对话里,用户只在第一周说过一次:永远不要对 main 做 force push。后来用户问,本地 main 做过 rebase,push 被拒绝,该运行什么命令,记忆系统需要找回这条约束。
Kaggle 上的老师模型仅在 33.7% 的相关提问中找回规则,背后有两个独立故障。
首先,提取器会凭空更新旧键。它原本正确生成 coding_rules.force_push = never,收到支付服务迁往 sa-east-1 的消息后,却额外输出:
coding_rules.force_push = false ("The force push rule is disabled for this project.")
注意 false:消息没有提到 git,这个值却会覆盖已有规则。原因是提取器能看到现有键列表,偶尔会给无关键填入任意新值。875 次规则提问里,275 次的上下文出现了这条错误事实。
学生也继承了老师的问题。初次审查 3000 条标签,作者发现 217 条、约 7% 滥用无关旧键,469 条、约 16% 违背要求写成英文,285 条、约 10% 的事实类型与模板预期不符。这些类别不能直接相加。
其次,正确规则会输给重复噪声。检索按 embedding 的余弦相似度选前五条记忆,越接近 1,文本越相似。一条每周重复的噪声消息,可以独占五个位置。
旧实验里,老师碰巧把规则写成中英混杂的句子,相似度高于噪声;作者比较的规范表述却都低于噪声的 0.635。Kaggle 老师生成的英文规则只有 0.537,更容易落选。
此前公布的稀有规则恢复率 92%,因此部分依赖一句偶然有利的措辞。平均 98% 的漂亮成绩,也藏着这个脆弱点。
修复存取规则,比继续追模型分数更关键
作者新增 v5_guarded 策略,从写入和读取两端修复。
写入时,新事实要替换旧事实,来源消息与旧事实的相似度必须至少达到 0.55。区域迁移消息与 force push 规则只有 0.39,因此被拦截;benchmark 中合法替换的相似度是 0.72 和 0.75。
读取时,相同文本只占一个检索位置,重复噪声无法继续包揽前五名。
恢复率提升主要来自去重。写入保护虽然把错误事实出现次数从 275 降为零,却没有提高原有指标:只要原始规则仍在上下文里,benchmark 就算答对,即使旁边还有一条相反指令。
正确记忆进入上下文,不代表上下文足以支持正确回答。
训练数据也做了清洗:丢弃无关旧键更新和英文事实,按模板修正事实类型,并增加「消息涉及有规则的项目领域,但不应修改规则」的样本。第二轮剔除 242 条键误用标签、325 条英文标签,修正另外 298 条类型,最终留下 2433 条训练样本。
在包含未见领域和规则的独立提取测试中,清洗后训练的学生约快五倍,相对模板答案的质量略好于老师。未经训练的模型则在几乎所有本应返回空列表的消息中都提取了事实。这说明「不该记时不记」需要单独考察。
本地运行采用 Ryzen 7 5825U、无 GPU、4 bit 量化,学生每条消息约耗时 0.20 秒,占用约 550 MB 内存。这些是该配置的实测值。
学生在 v2 达到 100% 仍有偶然性:它把规则写成 Nunca realizar forcer push na main.,拼写错误让相似度达到 0.673,修正后是 0.649,与噪声的 0.635 相距很近。作者更信任 v5,但未经训练的模型在 v5 也达到 97.6%,说明这一层更适合评价记忆策略,区分提取器应看独立提取指标。
我的判断
这篇最可靠的经验,是保留老师、未训练学生和原始输出,避免把端到端分数直接归因于模型。只比较换模型前后的总分,很容易修错地方。
去重也有明确收益:检索名额有限,重复文本会压缩信息覆盖。但实现只处理完全相同的文本,改写后的噪声仍会竞争位置。语义去重或重排可以作为替代方向,原文没有对照实验,不能断言哪种更好。
写入阈值的证据更有限。0.55 只根据 benchmark 内三次替换校准,换语言、embedding 或业务词汇,都需要重测。它证明了语义检查能挡住本例错误,还不足以成为通用更新规则。
测试集也只有 131 条消息,其中 35 条不同,单个错误就可能影响多个百分点。训练模板词汇有限,且实验只测记忆是否进入 prompt,没有测 Agent 最终回答。小模型能否接替老师,应限定在这套葡萄牙语事实提取任务内判断。
能拿来做什么
- 给 Agent 替换提取模型时,同时保留老师、未训练学生和训练后学生,分别测提取质量与记忆恢复率,先定位差异出在哪一层。
- 在 Node 记忆服务中检查重复文本是否占满检索结果,并为规则更新增加来源相关性校验;阈值要用自己的真实消息校准。
- 清洗蒸馏标签时,把无关旧键更新、语言不符、类型错误和应返回空列表的消息分别检查,避免学生继承老师的错误。
- 保存逐条输入、提取结果和检索上下文。作者第一轮因 Kaggle 会话结束丢失报告,第二轮改为执行结束后上传 Hugging Face dataset;可复查的中间结果应成为实验产物。