智能体记忆系统设计:为何移除LLM检索路径并构建确定性基础设施
1. 为什么我决定将LLM从智能体记忆检索路径中彻底移除过去一年半里我接触过的每一个智能体流水线都在重新发明“记忆”这个轮子而且大多数都做得相当糟糕。规划器做出的决策永远无法完整地传递给执行器庞大的提示词在智能体之间作为“上下文”传来传去宝贵的Token被消耗在早已过时的数据上。最让我头疼的是很多系统在记忆检索的关键路径上放置了一个LLM调用——这意味着对于完全相同的查询每次运行都可能返回不同的排序结果。这种非确定性让整个系统变得难以推理更别提进行单元测试了。当我反复看到这个问题后找到的解决方案其实相当“无聊”将记忆视为基础设施而不是提示词工程的一部分。这就是我构建Memwright的核心理念。记忆系统应该像数据库一样可靠、可预测而不是一个充满魔法的黑箱。在智能体架构中记忆是决策的基石如果基石本身是摇晃的那么建立在它之上的任何复杂逻辑都将岌岌可危。2. 剖析LLM在检索路径中的根本性问题很多所谓的“智能体记忆”库在回忆信息时都会调用一次LLM——可能是为了重写查询、重新排序结果或者总结检索到的文本块。这听起来很“智能”但在生产环境中这无异于埋下了一颗定时炸弹。2.1 非确定性调试噩梦的根源LLM的本质是概率模型这意味着相同的输入几乎不可能产生完全相同的输出。在记忆检索场景中这直接导致了非确定性。今天智能体根据记忆A、B、C做出了决策X明天相同的查询可能优先返回了记忆B、C、A导致决策Y。当你试图追踪一个错误决策时你面对的将是一场考古发掘——你需要重现当时的确切系统状态而这在分布式、高并发的生产环境中几乎是不可能的。更糟糕的是这种非确定性破坏了系统的可观测性。你无法确切知道智能体“看到”了什么也就无法理解它“为什么”会做出某个决定。这对于需要审计或合规的场景来说是致命的。2.2 延迟与成本 scalability的隐形杀手将一个LLM调用放在检索的关键路径上意味着每次记忆读取都会增加500到2000毫秒的延迟。对于一个简单的“规划-执行”循环这或许可以接受。但在真实的智能体流水线中一个任务可能涉及数十次甚至上百次的规划、执行、审查步骤。如果每一步都需要等待LLM来“帮助”检索记忆整个系统的延迟将会呈指数级增长用户体验会变得无法忍受。成本是另一个现实问题。每一次检索都是一个付费的API调用。假设你的智能体处理一个复杂任务需要触发50次记忆检索那么你的账单上就会凭空多出50倍的费用。当你的应用开始规模化拥有成千上万的用户时这笔开销将是毁灭性的。2.3 可测试性的彻底丧失作为工程师我们依赖单元测试来保证代码质量。一个理想的记忆系统应该允许我们这样写测试“给定这十条记忆和这个查询返回的前三条结果应该是X、Y、Z。”然而当LLM介入排序后这个断言变得毫无意义——因为LLM的输出是概率性的测试无法稳定通过。这导致了一个恶性循环因为无法编写可靠的单元测试开发者不敢对记忆逻辑进行重构或优化而未经充分测试的系统又更容易在生产环境中出现难以诊断的诡异问题。最终记忆模块变成了代码库中无人敢碰的“黑魔法”区域。注意这里有一个关键的认知转变。许多开发者将LLM视为解决一切模糊性问题的“银弹”。但在基础设施层我们需要的是确定性、可靠性和可预测性。LLM更适合作为应用逻辑的“决策脑”而不应作为数据检索的“过滤器”。3. Memwright的设计哲学记忆即基础设施基于上述痛点Memwright确立了一条核心原则在关键路径上实现零LLM调用。我们的目标是构建一个像PostgreSQL或Redis那样可靠、可预测、可测试的记忆后端专门为多智能体系统设计。3.1 一次写入确定检索在Memwright中所有嵌入向量都在写入时一次性计算完成。我们默认使用sentence-transformers/all-MiniLM-L6-v2模型在本地生成384维的向量。这个模型在性能和质量之间取得了很好的平衡并且完全本地运行无需网络调用。一旦记忆被向量化并存入数据库后续的检索就变成了纯粹的数学运算和图形遍历——快速、廉价且完全确定。这种“计算前置”的策略带来了几个直接好处写入成本可控虽然写入时需要计算资源但每个记忆只计算一次。检索性能极致检索时只需进行简单的向量相似度计算通常在毫秒级别完成。结果完全可复现相同的查询在任何时间、任何运行环境下只要底层数据未变返回的结果排序就是一致的。3.2 五层检索流水线从粗糙到精确的筛选Memwright的检索不是一个简单的向量搜索而是一个五层的流水线每一层都是一个纯函数负责将候选记忆集逐步精炼。这种设计确保了结果既相关又多样同时严格遵循Token预算。查询 ↓ [1] 标签匹配层 —— 使用SQLite的全文搜索进行精确及模糊的标签匹配 ↓ [2] 图扩展层 —— 使用NetworkX进行广度优先搜索从匹配的实体向外扩展两层关系 ↓ [3] 向量搜索层 —— 使用ChromaDB计算384维嵌入向量的余弦相似度 ↓ [4] 融合与排序层 —— 应用倒数排序融合、PageRank算法并加入置信度衰减 ↓ [5] 多样性层 —— 使用最大边界相关性算法和贪心Token打包算法 ↓ Top-K条记忆严格符合你的提示词预算结果确定可单元测试每一层都可以独立进行单元测试。例如你可以创建一个包含10条记忆的测试夹具输入一个查询然后断言经过完整流水线处理后返回的前三条结果的ID顺序是固定的。Memwright的测试套件包含了607个这样的测试用例它们可以在没有Docker容器或外部API密钥的情况下运行这本身就是对系统确定性的一种证明。4. 为多智能体系统设计的一级公民特性大多数记忆库都将智能体视为一个单例。但在真实的复杂流水线中你通常有一个编排器协调一个规划器规划器将任务分发给多个执行器执行器向审查器报告。这些角色不应该共享同一个混乱的记忆池。4.1 基于角色的访问控制Memwright直接对上述场景进行建模内置了六种RBAC角色ORCHESTRATOR 系统大脑拥有全局读写权限用于协调任务流。PLANNER 任务规划者可以读取大部分记忆并写入决策和计划。EXECUTOR 任务执行者通常只能读取与当前任务相关的记忆并写入执行结果和日志。RESEARCHER 信息搜集者拥有广泛的读取权限用于搜集信息并写入知识库。REVIEWER 质量审查者可以读取执行记录并写入审查意见和修正。MONITOR 系统监控者主要拥有读取权限用于系统健康检查和审计。每个角色都有明确定义的读写权限。一个失控的执行器无法用垃圾信息填满整个记忆库因为它的写入配额和可访问的命名空间都受到了限制。4.2 命名空间隔离与数据溯源隔离不是在应用代码中通过if-else实现的而是强制实施在数据层。数据库的每一张表都有一个tenant_id字段每一条查询都会自动附加这个过滤条件从根本上防止了数据越界访问。此外每一条记忆都携带完整的溯源链source_id 标识这条记忆来源于哪个上游任务或事件。content_hash 内容的哈希值用于检测重复和篡改。ingest_timestamp 精确的写入时间戳。agent_role 写入此条记忆的智能体角色。这意味着你可以随时重建“谁在什么时候告诉系统什么”这对于调试复杂问题、进行系统审计至关重要。5. 实现时间正确性记忆不是覆盖而是演进传统数据库的更新操作是“覆盖”。但在动态变化的世界中事实会过时、会被修正。Memwright采用了一种更符合认知的模型它从不覆盖只进行取代。每一条事实性记忆都有一个有效性窗口valid_from,valid_to。当一条新记忆与旧记忆矛盾时我们不会删除旧记忆而是将旧记忆的valid_to设置为新记忆生效的时间点然后插入新记忆。例如上午9:00执行器写入“服务器A的IP是192.168.1.100”valid_from: 9:00,valid_to: NULL。上午11:00监控器发现IP变更写入“服务器A的IP是192.168.1.150”valid_from: 11:00,valid_to: NULL。此时系统会自动将第一条记忆的valid_to更新为11:00。通过recall(as_of10:30)这样的查询你可以“回到过去”查看系统在10:30时所知道的事实即IP仍是192.168.1.100。这对于回答“昨天规划器为什么做出那个决策”或满足监管领域的审计要求“在3月12日系统知道什么”具有无可估量的价值。6. 统一的API多元的后端选择Memwright的核心优势之一是它的可移植性。你可以用完全相同的代码在不同的后端存储上运行。from agent_memory import AgentMemory # 本地模式SQLite ChromaDB NetworkX零配置 mem AgentMemory(./store) mem.add(规划器决定在关键路径上使用Rust, tags[decision, rust, performance]) results mem.recall(我们为关键路径选择了什么技术, k5)上面这段代码在本地开发时运行良好。而当你需要部署到生产环境时只需修改一行配置就可以切换到Postgres 使用pgvector做向量搜索Apache AGE做图遍历。ArangoDB 单引擎支持文档、向量和图数据。AWS ECS ArangoDB 全托管服务适合云原生部署。Azure Cosmos DB 微软云的多模型数据库。DiskANN 针对超高维向量的高性能检索。GCP AlloyDB 集成了pgvector、ScaNN和AGE的谷歌云数据库。项目仓库中提供了Terraform参考配置帮助你一键部署到主流云平台。这种设计让你可以在开发时享受轻量级的便利在部署时获得企业级的扩展能力。7. 性能基准与实战考量在LOCOMO v2一个长上下文记忆基准测试中Memwright的得分是81.2%。作为对比一些其他方案的得分是OpenAI的记忆方案约52.9%Mem0约66.9%Letta约74%Zep约75%MemMachine约84.9%。这个成绩是诚实的竞争性成绩并非业界顶尖。我非常清楚差距在哪里——主要在于我们当前默认使用的嵌入模型all-MiniLM-L6-v2在部分复杂语义匹配任务上还有提升空间。下一个版本我们计划升级嵌入模型预计能显著缩小这一差距。但更重要的是我知道Memwright的每一个得分点来自哪里以及为什么丢失了某些分数。因为整个系统是确定性和可测试的我们可以精准地定位瓶颈进行优化而不是在LLM的非确定性黑箱中盲目调整提示词。8. 如何开始使用与集成安装Memwright非常简单pip install memwright启动一个本地的记忆API服务memwright api --host 0.0.0.0 --port 8080对于Claude Code的用户体验更加无缝直接在Claude Code中键入install agent memory一个MCP服务器会启动交互式安装向导自动配置钩子并运行健康检查。Memwright是一个MIT协议的开源项目。你可以在GitHub上找到完整的源代码、详细的文档以及丰富的示例github.com/bolnet/agent-memory。项目也在Hacker News上引发了热烈的讨论你可以看到其他开发者是如何评价以及他们遇到了哪些问题。我个人最期待的是听到你的故事——当你在真实的智能体项目中使用Memwright时到底是什么地方出现了问题是某个后端适配器的性能瓶颈还是某种特殊的查询模式让流水线表现不佳只有通过社区的实战检验一个基础设施工具才能真正变得坚固和可靠。毕竟记忆系统的终极目标是让智能体忘记“记忆”本身的存在就像我们不会时刻思考呼吸一样让可靠的信息检索成为智能体思维中无声而稳固的背景。