我一直认为,做好一个Agent,记忆模块的设计是最重要的。
正好,借助Clawdbot看看它的记忆设计哲学。
Clawdbot的整个设计逻辑,存在大量的软件工程思维:Clawdbot背后的软件工程思维和品味。
以往的一些框架,如Langchain都在疯狂堆叠、抽象,这也是我自己不太喜欢这些框架的原因,所以我自己手撸了一个框架,去伪存真,去掉了大量不必要的抽象:复刻一个java版的Langgraph落地Agent
Clawdbot采用了最原始的unix哲学:大量使用文件系统和本地进程,重构了Agent的记忆和编排逻辑。
作为一款Agent,最重要的是统一用户身份,即User identity,而以往的很多Agent其实是以sessionId为核心的,这导致用户脱离了这个session,似乎慢慢的“变傻”了。
首先,它的设计哲学是本地优先。
在记忆层面,Clawdbot抛弃了很多Agent依赖复杂向量数据库设计记忆的方式,转而采用了最原始的Unix哲学:everything is file,用文件系统进行记忆实现。
好处是,你不会因为一个记忆维护庞杂的数据库或向量数据库集群了,而是一个简单的markdown文件即可实现Agent长期记忆。
很多人简单的把Agent的记忆设计为:长期记忆、短期记忆。
这个划分维度我是存疑的,你不能简单的把时间久的会话看做长期记忆。
其实可以类比我们人类,我们在处理任务时,其实会调用起很久之前的一些记忆,而这些记忆以前就会被无脑归类为“长期记忆”,而这些看起来长期的记忆,在一些任务处理时,反而是需要可被立即检索的。
其实记忆应该是具有具体目标的,比如它是用户偏好的记忆,还是项目背景的记忆,还是关键决策的记忆。
所以记忆值得按照目的进行划分,并制定相对应的数据结构、分层、写入、检索、遗忘的逻辑。
比如我自己的框架,最基本的将记忆分为三类:用户画像、任务状态(已经验证了什么、下一步计划是什么)、项目知识、工具日志、工作日志(过程记忆,用于记录记忆生成轨迹),这三类记忆存取得到的噪声不同,处理逻辑也不同。
在每次会话之后,都会重新渲染、整理、merge记忆。
每条记忆的生成,都是必须可审计的,即这条记忆从哪轮会话来,何时写入的,这样用户问你刚才删了哪些文件,它是可以拿出证据回答的。宁可少记,也不乱记,宁可不注入,也别注入矛盾记忆。
每条记忆都必须是可逆的,比如要求对某条记忆删干净,那么相关的记忆生成线索也应该一并清理,
比如用户偏好改变了,旧的记忆还在,Agent就会精神分裂了。
简单来说,每条记忆都应该有它的生命周期。
具体实现上,需要考虑谁来写、写什么、写到哪。
需要去噪、做冷热分层、压缩归档。
压缩记忆不是简单的把10轮变为100个字,而是要保证信息密度和噪音低。
记忆压缩时,则需要回答压什么、怎么压、压到什么粒度。
比如压缩摘要的数据结构要包含:压缩的目的、约束、决策依据、理由、未决问题、下一步、证据索引(指向的原始事件id),这样可以实现回溯和检索。
它将记忆分为两层:事实层和认知层。
这样可以把噪声和精选事实隔开了,看似保守,但其实非常工程思维的方案。
事实层,包含了一系列不可改变的客观事实信息,比如用户的交互query、tool的调用、执行结果等信息,这些信息没有价值观,全部围绕于不可变的事实信息。
认知层,则是基于Agent的人设提取的相关信息,比如Agent会基于自己的人设“刻意的记住一些事情”,如果想让Agent改变记忆,只需要显示的修改memory.md文件。
需要做一个准入机制,即将被价值观筛选过的重要信息,计入到认知层。
Clawdbot做了一个很简单的实现,即对文件变动做监听,当某个文件有了更新(人为改动,或者append信息)后台自动触发向量索引更新。
这是我一直推荐的记忆实现的方式,它肯定是一个被内聚到记忆模块的功能,它会基于所有事实数据按价值观自动提取它认可的信息,我们人也是这么做的。
反观很多照抄Agent概念的人,他们会觉得记忆是功能的一部分,这就错了,功能主要围绕于事实信息,而记忆是有价值观的。
当要提取记忆时,最简单和可用的方式就是多路召回,或者叫混合检索,即用语义+关键词的方式召回,再结合Agent记忆价值观,适当的决定使用哪些信息,丢弃哪些信息。
检索记忆,要区分能搜到和能用,这是两回事。
很多检索系统问题是,检索了一堆看似相关的,但完全没有相关价值的信息片段。
可以参考传统搜索工程的做法,首先做候选召回,即按照向量、关键词、结构化过滤多种记忆信息。
之后做重排,结合时间衰减、来源置信度、记忆类型权重进行排序。
最后是注入Prompt,即将检索的信息,拆分按结构注入Prompt,记忆如何打散,塞到哪里。
Skill的渐进式披露就是类似的,它是按照相关度逐步将记忆注入到Prompt,这比简单的top-k全塞靠谱多了。
随着复杂任务的推进,记忆内容会爆炸,Clawdbot设计了一套严格的上下文组装流程,而不是简单将历史记录append进Prompt。
首先是一个模型解析器,它可以根据当前任务,动态的选择适合的模型,比如deepseek-v3用于推理,而gpt-4o用于tool调用。
这个其实很容易理解,就像人一样分为左脑和右脑,大脑会基于任务,自动将任务分配给对应的脑区进行处理。
之后是提示词构建器,它会将系统指令、可用工具集、技能以及从memory.md中召回的相关记忆拼装到一起。

这些上下文在后续的任务中都是必需的,避免了无上下文的盲目操作,而且上下文加载是模块化的,便于后续重构。
之后是历史记忆加载器,它会从历史记忆文件中,智能的截取上下文。
在时间维度可以选取最近n轮的对话,在语义维度,可以通过语义相似度解析,筛选出与当前任务相关的历史片段,之后会进行重复信息的合并与压缩,提炼核心观点。
最后是一个熔断机制,即在token溢出前,强制触发summary动作,防止上下文崩溃。
Clawdbot主要价值在于work,而非chat,所以对于如何完成工作,进行了一些设计。
比如在完成工作时,为了避免并发问题,Agent执行时采用的是最简单的串行工作方式。
虽然听起来效率很低,但在涉及一些重操作时,副作用更小,可靠性更高。
对应的编排流程大概是这样的:
1、环境感知:用户query+memory上下文+系统状态;
2、任务规划:llm进行cot,决定是否调用工具,如果是复杂任务,可以派生出子Agent;
3、行动:llm输出结构化tool call,进行工具调用;
5、反思机制:工具的输出回传给llm,判断任务是否完成,还是说需要重新规划+执行+反思的循环;
所以你会发现,设计一个好的Agent,和大模型相关的认知是非常少的,更多是软件工程的品味和认知。
比如云端存储一定好于本地文件存储吗?显然不是。复杂的向量数据库一定好于关键词匹配吗?也不是。文件系统+串行执行也能发挥更大的价值,构建出好用且稳定的Agent。
所以Clawdbot对Context Engineering的处理方式,值得大家学习,事实上做一个Agent非常简单。