前几天翻 arXiv 翻到一篇 5 页的短文,James Adam 一个人署名,8 月 13 日挂上去的,讲给编码 agent 做项目记忆。说实话一开始没抱期待,这个方向的论文一年几十篇,大部分是把 RAG 换个说法再讲一遍。但有个数字把我钉住了:否定类问题上,生产级向量记忆工具的 top-k 检索,答案完整度只有 6% 到 27%;作者自己的系统是 0.98 到 1.00。这个差距不是调参能解释的,是方法本身的差距。这篇笔记记一下我拆开看到的东西,以及为什么我觉得每个在给 agent 配记忆的人都该翻一遍。
先说系统。作者做的东西叫 MOOSEDev,思路是项目记忆不走向量库,走知识图谱——把架构决策、踩过的坑、约束条件、当时的理由,都作为有类型的记录存进图里,再通过 MCP 接口暴露给 agent。查询这层用的是他自己的一个神经符号引擎,叫 MOOSE,符号层是主推理基础。也就是说,agent 问「哪些方案被否掉了、为什么」,走的是符号推理,不是相似度排序。
那 6% 到 27% 是怎么来的。作者在一个中立的公共语料库上做对比,语料库里有 835 条类型化记录,基线是生产级的向量记忆工具。测试问题分了几类,最扎眼的两类是替代关系(「除了 X 还有什么能替代 Y」)和集合完整性(「把所有满足某条件的记录都列出来」)。这两类问题有个共同点:要的是完整答案集,不是「最相关的几条」。而 top-k 检索天生只给你最像的 k 条,剩下的要么没进上下文,要么排后面被截掉。否定类问题更惨,因为「不满足某条件」这件事在 embedding 空间里几乎没有几何结构——不相似的东西散落在整个空间里,你没法靠「离得近」把它们捞齐。
我拿一个很土的办法验证了一下这个直觉。假设有五条记录,三条是「我们试过 Redis 做缓存,因为成本问题否掉了」,两条是「最后选了本地内存缓存」。现在问 agent「有哪些方案是被否掉的」:
方案 A:把五条记录全部向量化,top-k 取 3,问"被否掉的方案有哪些"
方案 B:给每条记录打上 {status: rejected | adopted, reason: ...} 的结构化标签,查询时按 status 过滤
方案 B 不需要任何检索技巧,一个过滤就完了,而且永远不会漏。方案 A 的表现完全取决于被否掉的那三条在 embedding 空间里抱团抱得多紧、以及 k 取多大。这不是假设,论文里那个 6% 就是这种结构失败落到实数上的样子。
有意思的是,作者没借这个结果宣称向量检索不行。普通的相关性和召回率指标上,两套系统基本打平,token 成本也相当。也就是说,你为结构化记忆付出的代价不大,买到的是一类 top-k 天然答不好的问题上的可用性。这个 trade-off 的呈现方式我觉得挺诚实的——换别的论文,标题大概就是「向量记忆已死」了。
论文里还有两个我觉得比主实验更有参考价值的部分。一个是作者拿 MOOSEDev 自己代码库的提交历史做引导,自己吃自己的狗粮;另一个是一项预注册的现场试验,也就是先登记好实验设计再跑,不给自己留事后挑结果的空间。经验教训部分也写进去了,5 页能塞下这些,说明作者没把版面浪费在背景介绍上。
当然我得坦白一点保留意见。835 条记录的语料库不算大,生产项目里记忆条目上去了之后,图的维护成本、schema 的演化、谁来保证打标签的一致性,这些论文里只能点到为止。我之前记过另一篇关于 CLAUDE.md 的笔记,当时的心得是「规则写得再细,不如放对位置加验证生效」——结构化记忆面临同一个问题:结构本身不难设计,难的是长期往里写的时候不变形。这一点论文没解决,我也不指望一篇 5 页的工业轨道论文解决。
但这不影响核心结论。我读完的判断是:如果你的 agent 记忆目前只有向量检索一条路,那「替代关系」和「集合完整性」这两类问题你现在是答不好的,只是可能还没人问到。验证方式可以很朴素,你可以照这个顺序试一遍:
- 把你项目记忆里的记录数一遍,数数有多少条本质上是「某方案被否掉了、理由是什么」;
- 拿这类问题去问你的 agent,看它漏不漏;
- 漏了的话,先别急着换系统,试试给这部分记录加个最简单的结构化标签,看看能不能用过滤代替检索。
第三步不一定要 MCP 加知识图谱这么重的方案,一个 JSON 文件加几个字段可能就够当前用了。论文的 arXiv 编号是 2608.13662,被 NeSy 2026 的工业轨道收了,会出在 PMLR 第 284 卷,感兴趣可以自己翻一遍,5 页很快能读完。
划重点:第一,top-k 检索在「要完整集合」和「要否定」的问题上有结构性短板,6% 这个数字值得记一下;第二,结构化记忆在这类问题上的优势不是靠牺牲成本换来的,token 开销基本持平;第三,验证自己有没有这个坑,不需要复现整个系统,数一数记录类型再问一句就够。这篇就记到这里,等我在自己的项目里把第 3 步跑一遍,如果踩到别的坑,回来补一条。
