为什么说 Wiki 和 Reflection 对 Agent Memory 很重要?

很多 AI 记忆系统,最后都会变成同一种形状:把聊天记录、用户信息、上传文档、工作流结果,全部切成 chunk,塞进向量库里,等下一次需要的时候再 RAG 出来。
这当然有用。
但问题是,“记得更多”不等于“记得更好”。
真正难的是:不同类型的记忆,本来就不该被放在同一个抽屉里。
用户主动上传的一份 PDF,和一次对话里顺手提到的偏好,不是同一种东西。
前者更像参考资料,是 agent 可以查阅、引用、下钻的外部文档;后者更像经验,是 agent 在长期互动中逐渐形成的认知。
如果全都扁平化成向量片段,短期看实现简单,长期看会越来越难解释:这条信息从哪里来?它还有效吗?它和旧信息冲突时谁说了算?agent 为什么引用了这个 chunk,而不是另一段?
EverOS 最近做的两块能力,其实是在重新划这条边界:
Knowledge Wiki 负责外部资料。
Reflection 负责对话经验。
一个让资料可以按需展开,一个让经验可以自我整理。
—
Knowledge Wiki:参考资料不应该只是一堆 chunk
EverOS 原来有 users/ 和 agents/ 两类记忆,现在新增了 knowledge/,和前两者平级。
这个设计点很关键。
knowledge/ 专门承载用户主动上传的外部文档,比如 PDF、HTML、Markdown、Office 文档、图片、音频、email、CSV 等。它不是从对话里自动抽出来的“经验”,而是用户明确交给 agent 的“参考资料”。
这意味着 agent 在使用它时,应该像查一个知识库,而不是像翻一堆聊天残片。
传统 RAG 的做法通常是把文档切成等长 chunk,然后做向量搜索。这个方案直接,但它会把文档结构抹平:标题、章节、主题、上下文,都变成了一堆相似长度的片段。
EverOS Knowledge Wiki 走的是另一条路:渐进性披露。
它把文档组织成三层:
L0 是分类,比如体育、医疗、金融、教育、法律等。
L1 是文档,包含标题和摘要。
L2 是 Topic,包含主题摘要和必要时可展开的全文。
agent 不需要一上来吞掉所有内容。它可以先看全局分类,判断资料大概在哪个领域;再看文档级摘要,判断哪份文档可能相关;最后只下钻到真正需要的 topic。
这更接近人读资料的方式。
我们不会随机打开一本书的第 37 页,也不会把所有书切成纸条再搜索。我们会先看书架、再看书名和目录,最后才读具体章节。
对 agent 来说,这件事的价值很直接:信噪比更高,token 更省,引用路径也更清楚。
好的知识库不是把所有信息一次性交给模型,而是让模型知道下一步应该展开哪里。
—
分类要可预期,而不是神秘地聚类
Knowledge Wiki 里的 L0 分类没有采用无监督聚类。
它使用一个可编辑的分类表 .taxonomy.md。系统内置 20 个领域分类,LLM 只负责从候选列表里选择最匹配的分类;如果用户上传时指定分类,也可以手动覆盖;没有命中的统一归入 Others。
这个选择看起来不“炫”,但我觉得很务实。
因为长期知识库最怕的不是分类不够智能,而是分类不可预期。
如果系统今天自己聚出一个簇,明天又把边界调整了,用户很难理解文档为什么去了那里,agent 也很难形成稳定的路由策略。
用 Markdown 管分类表的好处是:用户可以直接改,下次文档操作立即生效,不需要重启,也不需要重建整套索引。
当文档分类被修改时,文件目录也会跟着迁移,路径和分类保持一致。
这让分类结果变成一件可以审计、可以干预、可以解释的事。
—
Markdown 是真相源,索引只是派生物
EverOS 还有一个我很喜欢的取舍:所有层级内容最终都落成 Markdown 文件,保存在 knowledge/ 目录里。
SQLite 记录状态,LanceDB 做向量索引,但它们不是最终真相源。
Markdown 才是。
这和很多“把记忆锁进数据库”的系统很不一样。用户可以直接打开文件阅读,也可以手动编辑。文件变化之后,Cascade 会通过 SHA-256 内容哈希检测变更,只同步真正修改过的部分,没变化的内容不会重复算 embedding。
这使得知识库不是一个黑箱。
它既能给机器检索,也能给人检查。
上传流程也保持同一套结构:文档上传之后,先经过 Parser 解析;多模态文件会先被模型转成文本;然后 TopicTreeExtractor 抽取主题树;再 DFS 展平;最后落成 Markdown,并异步同步 SQLite 和 LanceDB。
换句话说,PDF、Office、HTML、图片、音频、email,最终都会进入同一条主题抽取流水线。
这里的原则很清楚:EverAlgo 保持无状态,持久化交给 Markdown,索引由后台异步追上。
这样做不一定是最省事的实现,但它让系统长期可维护。
—
检索也不再是扁平向量搜索
Knowledge Wiki 的检索同样不是简单的“向量 top-k”。
它先做混合召回:Dense 负责语义相似,BM25 负责关键词匹配,而且 BM25 会同时查 topic 摘要和全文,取最高分。
两路结果用 RRF 融合,先拿到一批候选。
然后系统会根据召回结果估计分类概率,给 category 做软 boost。
注意这里是软 boost,不是硬过滤。
如果查询很明确,某个分类明显领先,分类信号可以多帮一点;如果查询本身很歧义,top1 和 top2 分类差距不大,boost 就会自动衰减。
最后再用 cross-encoder rerank,把相关性和分类置信度合成最终分数。
这个设计的重点不是多堆几个检索组件,而是把“分类”当成一个有置信度的假设,而不是绝对规则。
结果默认也只返回 topic 摘要,并附带 L1 文档标题和摘要。agent 先拿到足够判断的信息;如果真的需要全文,再通过 topic_id 拉取。
这和三层架构是同一个思想:先判断,再展开。
—
Reflection:记忆不应该像录音机
Knowledge Wiki 解决的是外部资料。
但 agent 还有另一类更麻烦的记忆:对话中逐渐积累的经验。
人类的记忆不是录音机。我们不会把每一句话原封不动堆在脑子里,然后每次都从头检索。我们会回想、合并、修正、形成一段更稳定的叙事。
AI 记忆系统如果只会“边聊边存”,很快就会遇到碎片化问题。
比如同一件事可能被记成三条:
「Andrew 还没养宠物」
「Andrew 领养了 Toby」
「Andrew 又领养了 Buddy」
这三条在各自发生的时间点都对,但一起拿出来就很别扭。第一条已经过期,后两条又不完整。
如果用户问“Andrew 养宠物的情况”,agent 不应该把三块碎片直接扔给模型,让模型临场猜。
EverOS Reflection 做的事,是在后台把这些相关记忆碎片定期反思成一条更清楚的叙事:
「Andrew 起初没有宠物,后来领养了一只叫 Toby 的狗,接着又领养了 Buddy。」
这里的变化不是简单总结,而是一次状态整理。
它保留事实,理清时间线,用最新状态消解旧冲突,并在结尾说明截至目前事情到了哪里。
—
旧记忆不删除,只是退到幕后
Reflection 不是实时对话链路上的同步步骤。
它是离线后台能力,默认关闭,可以配置开关和运行频率,也支持热更新。在线对话只负责快速记录,后台再慢慢整理。
我觉得这个取舍很重要。
记忆整理是慢活,不应该阻塞用户当前对话。
第一次整理之后,如果同一话题又出现新信息,Reflection 也不会从头推翻重来,而是把新碎片并进已有叙事。
所以一件事在记忆里不会无限繁殖成很多条,而是随着新信息逐渐变得更完整。
更关键的是,旧记忆不会被直接删除。
被整理掉的原始碎片会退到幕后,不再污染默认记忆视图,但原件仍然留存,并记录它被哪条新记忆取代。
每一次整理都会留下操作痕迹:哪些碎片被合并,产生了哪条新记忆,哪些信息被归档。
这让 Reflection 和“粗暴覆盖”有本质区别。
覆盖会让系统看起来干净,但也会丢失来龙去脉。
Reflection 让默认视图变干净,同时保留追溯能力。
对一个长期托付记忆的系统来说,这一点非常关键:AI 可以整理你的记忆,但你应该始终知道它动了什么。
—
两件事合起来,才更像真正的 agent memory
我更愿意把 Knowledge Wiki 和 Reflection 看成一组互补能力。
Knowledge Wiki 面向外部资料:它关心结构、分类、按需展开、可读可改。
Reflection 面向内部经验:它关心时间线、状态变化、冲突消解、原件追溯。
一个解决“资料怎么被正确使用”,一个解决“经验怎么越记越清楚”。
这比单纯扩大 context,或者把更多内容塞进向量库,要更接近长期 agent 产品真正需要的基础设施。
因为 agent 的记忆最终不是存储问题,而是治理问题。
它要知道信息属于哪一类,从哪里来,当前是否有效,什么时候应该只看摘要,什么时候需要展开全文,什么时候应该把旧碎片沉淀成新叙事。
如果只追求“能搜到”,系统会越来越像一个杂乱的仓库。
如果能做到渐进性披露、人类可读、确定性分类、离线反思、原件留存,记忆才有可能变成一套可以长期信任的系统。
这也是我觉得 EverOS 这次设计有意思的地方:
它没有把 AI 记忆简化成一个 retrieval feature,而是把它拆成了 reference、experience、reflection 三个层次。
往后看,agent 的差异可能不只在模型能力,也在它如何管理自己的长期上下文。
能记住不难。
难的是记得清楚、用得克制、改动可追溯。

