不知道你有没有过这种体验——跟AI聊了一整晚,第二天打开对话框,发现它对你讨论过的关键细节一无所知。或者在多个项目间切换时,它像个失忆症患者一样反复问“你指的是哪个API”,害得你不停地重复背景信息。这种“金鱼式记忆”几乎是当前云端AI产品的通病:它们要么只能记住有限的上下文,要么把所有数据都存放在厂商的服务器上。

不过,假如有一个AI助手,能像真正的人类私人助理那样,永远记得你的偏好、你的项目细节,甚至你三个月前提过的小习惯,而且这些记忆完全存储在你自己的电脑上、由你自己掌控呢?
这就是Clawdbot在做的事。作为一款开源的个人AI助手,它在GitHub上已经拿下了超过12.5万个Star。和跑在云端的ChatGPT或Claude不同,Clawdbot直接运行在你的本地机器上,还能集成到你日常使用的聊天平台里(Discord、WhatsApp、Telegram等等)。
它不止是个聊天机器人,更是一个能自主处理实际任务的助手:管理邮件、安排日历、处理航班值机、按计划运行后台任务。但最值得关注的,是它的持久化记忆系统——能实现24/7全天候上下文保持,记住对话内容,并无限期地基于之前的交互进行累积。
如果以前读过关于ChatGPT记忆和Claude记忆的文章,就会知道我对不同AI产品如何处理记忆这个话题一直很着迷。Clawdbot采用了一种完全不同的路径:它不是云端公司控制的记忆,而是把一切都保存到本地,让用户真正拥有自己的上下文和技能数据。
下面就来拆解一下它是怎么做到的。
上下文是如何构建的
在深入讨论记忆之前,先弄清楚模型每次触发请求时能看到什么:
[0] 系统提示词(静态指令 + 条件指令)[1] 项目上下文(引导文件:AGENTS.md、SOUL.md 等)[2] 对话历史(消息、工具调用、压缩摘要)[3] 当前消息
系统提示词定义了Agent的能力和可用工具。与记忆直接相关的是“项目上下文”——里面包含了用户可编辑的Markdown文件,每次请求时都会被注入进来。
这些文件就放在Agent的工作空间里,和记忆文件并存,让整个Agent的配置透明可见、随时可以编辑。
上下文 vs 记忆
搞懂上下文和记忆的区别,是理解Clawdbot的起点。
上下文,是模型在单次请求中能看到的全部内容:
上下文 = 系统提示词 + 对话历史 + 工具结果 + 附件
上下文的特性很鲜明:
- 临时的——只存在于本次请求期间
- 有限的——受限于模型上下文窗口(比如20万token)
- 昂贵的——每个token都消耗API接口成本和影响速度
记忆,则是存储在磁盘上的内容:
记忆 = MEMORY.md + memory/*.md + 会话转录文件
记忆的特性刚好相反:
- 持久的——重启、日复一日、月复一月后依然存在
- 无限的——可以无限增长
- 低成本的——存储不产生API费用
- 可搜索的——建立索引支持语义检索
记忆工具
Agent通过两个专用工具来访问记忆。
1. memory_search
用途:在所有文件中查找相关的记忆
{"name": "memory_search","description": "强制性回忆步骤:在回答关于之前工作、决策、日期、人员、偏好或待办事项的问题之前,对MEMORY.md和memory/*.md进行语义搜索","parameters": {"query": "我们对API做了什么决定?","maxResults": 6,"minScore": 0.35}}
返回结果:
{"results": [{"path": "memory/2026-01-20.md","startLine": 45,"endLine": 52,"score": 0.87,"snippet": "## API 讨论n决定为了简单起见使用REST而不是GraphQL...","source": "memory"}],"provider": "openai","model": "text-embedding-3-small"}
2. memory_get
用途:在找到内容后,读取具体内容
{"name": "memory_get","description": "在使用memory_search后,从记忆文件中读取特定行","parameters": {"path": "memory/2026-01-20.md","from": 45,"lines": 15}}
返回结果:
{"path": "memory/2026-01-20.md","text": "## API 讨论nn与团队讨论API架构。nn### 决策n我们选择REST而非GraphQL,原因如下:n1. 实现更简单n2. 更好的缓存支持n3. 团队更熟悉nn### 端点n- GET /usersn- POST /auth/loginn- GET /projects/:id"}
写入记忆
这里并没有一个专门的memory_write工具。Agent用的是标准的写入和编辑工具——这些工具它本来就在用于处理任何文件。因为记忆就是普通的Markdown,你也可以手动编辑这些文件(它们会自动被重新索引)。
写入位置的决策通过AGENTS.md中的提示来驱动:
在预压缩刷新和会话结束时,也会自动进行写入(后续章节会具体说)。
记忆存储
Clawdbot的记忆系统建立在“记忆就是Agent工作空间里的纯Markdown”这一原则上。
双层记忆系统
记忆位于Agent的工作空间中(默认:~/clawd/):
~/clawd/├── MEMORY.md- 第二层:长期策划的知识└── memory/├── 2026-01-26.md- 第一层:今天的笔记├── 2026-01-25.md- 昨天的笔记├── 2026-01-24.md- ...以此类推└── ...
第一层:每日日志(memory/YYYY-MM-DD.md)
这些是仅追加的每日笔记,Agent在一天中随时写进去。当Agent想记住某件事,或者被明确告知需要记住时,就会写到这里。
# 2026-01-26## 10:30 AM - API 讨论与用户讨论REST vs GraphQL。决策:为了简单使用REST。关键端点:/users、/auth、/projects。## 2:15 PM - 部署将v2.3.0部署到生产环境。没有问题。## 4:00 PM - 用户偏好用户提到他们喜欢TypeScript胜过Ja vaScript。
第二层:长期记忆(MEMORY.md)
这是经过策划的、持久的知识。当发生重大事件、想法、决策、观点和学到的教训时,Agent会写到这里。
# 长期记忆## 用户偏好- 喜欢TypeScript胜过Ja vaScript- 喜欢简洁的解释- 正在做"Acme Dashboard"项目## 重要决策- 2026-01-15:选择PostgreSQL作为数据库- 2026-01-20:采用REST而非GraphQL- 2026-01-26:使用Tailwind CSS进行样式设计## 关键联系人- Alice (alice@acme.com) - 设计负责人- Bob (bob@acme.com) - 后端工程师
Agent如何知道要读取记忆
AGENTS.md文件(会被自动加载)包含以下指令:
## 每次会话在做其他事情之前:1. 阅读 SOUL.md - 这是你是谁2. 阅读 USER.md - 这是你在帮助谁3. 阅读 memory/YYYY-MM-DD.md(今天和昨天)获取近期上下文4. 如果是在主会话中(与你的主人直接聊天),还要阅读 MEMORY.md不要请求许可,直接做。
记忆如何被索引
保存一个记忆文件时,后台会触发一系列动作:文件保存后,文件监视器(Chokidar)检测到变化,经过1.5秒防抖后开始分块——分割成约400 token的块,重叠80 token,保证跨越块边界的事实能被两头捕获。这些块随后被发送给嵌入提供商(OpenAI/Gemini/Local)转成向量,最终存入SQLite数据库,同时还会建立全文搜索索引,并缓存嵌入结果避免重复。
分块大小和重叠值都是可配置的,默认的400/80是通过实践平衡了语义连贯性与粒度后的选择。
记忆如何被搜索
搜索记忆时,Clawdbot会并行运行两种搜索策略。向量搜索(语义)负责找到意思相近的内容,BM25搜索(关键词)负责捕捉包含确切token的内容。
结果通过加权评分合并:
最终得分 = (0.7 * 向量得分) + (0.3 * 文本得分)
70/30的比例是经过考量的——语义相似性是记忆回忆的主要信号,但BM25关键词匹配能捕捉向量可能遗漏的确切术语(比如名称、ID、日期)。低于minScore阈值(默认0.35)的结果会被过滤掉,所有值都可配置。
这样一来,无论你在搜索一个概念(“那个数据库的事情”)还是具体内容(“POSTGRES_URL”),都能拿到不错的结果。
多Agent记忆
Clawdbot支持多个Agent,每个Agent都有完全独立的记忆空间。Markdown文件(事实来源)位于每个工作空间中,而SQLite索引(派生数据)位于状态目录中。每个Agent都有自己的工作空间和索引,记忆管理器通过agentId + workspaceDir来区分,因此不会自动发生跨Agent记忆搜索。
Agent能读取彼此的记忆吗?默认不能。每个Agent只能看到自己的工作空间。但需要注意,工作空间本质上是一个软沙盒(默认工作目录),而不是硬边界。除非启用严格的沙盒机制,否则Agent理论上可以用绝对路径访问另一个工作空间。
这种隔离在分离不同上下文的场景下非常有用。比如,一个用于WhatsApp的“个人”Agent和一个用于Slack的“工作”Agent,各自拥有独立的记忆和性格。
压缩
每个AI模型都有上下文窗口的限制。Claude是20万token,GPT-5.1有100万。长对话最终总会碰到这个天花板。
触顶之后,Clawdbot会使用压缩:把旧对话总结成紧凑的条目,同时保留最近消息的完整性。压缩后的上下文从18万token直接降到4.5万——一个巨大的减负。
自动 vs 手动压缩
自动压缩:接近上下文限制时触发。在详细模式下会看到“自动压缩完成”的提示,原始请求会用压缩后的上下文重试。
手动压缩:使用 /compact 命令。例如:/compact 重点关注决策和未解决的问题。
与某些优化不同,压缩会被持久化到磁盘。摘要写入会话的JSONL转录文件,因此未来的会话会以压缩后的历史开始。
记忆刷新
基于LLM的压缩属于有损过程。重要信息被总结掉后,存在丢失的可能。为了应对这一点,Clawdbot引入了预压缩记忆刷新机制。
当上下文使用量超过软阈值时,系统会静默地触发一轮记忆刷新:Agent审查对话中的重要信息,将关键决策和事实写入记忆文件,如果不存什么内容就回复NO_REPLY。整个过程对用户完全透明——不会弹出任何提示或干扰。
记忆刷新可以在clawdbot.yaml或clawdbot.json文件中灵活配置,包括软阈值token数、系统提示词等参数都可自定义。
剪枝
工具结果有时会非常庞大。某个exec命令可能输出5万个字符的日志。剪枝会修剪这些旧输出,而不重写历史。这是一个有损过程,旧输出无法恢复。
磁盘上的JSONL文件保持不变,完整输出依然在那里。
缓存TTL剪枝
Anthropic会对提示词前缀进行最多5分钟的缓存,用以减少重复调用的延迟和成本。当相同的前缀在TTL窗口内发送时,缓存的token成本降低约90%。但TTL过期后,下一个请求必须重新缓存整个提示词。
问题在于:如果会话在TTL之后闲置,下一个请求会失去缓存,必须以完整的“缓存写入”价格重新缓存整个对话历史。缓存TTL剪枝通过在缓存过期后检测并修剪旧工具结果来解决这个问题,更小的提示词重新缓存意味着更低的成本。
会话生命周期
会话不会永远持续。它们根据可配置的规则进行重置,为记忆创建自然的边界。默认行为是每天重置,但也有其他模式可选。
会话记忆钩子
运行 /new 开始新会话时,会话记忆钩子可以自动保存上下文:从结束会话中提取最后15条消息,通过LLM生成描述性slug,保存到记忆文件中。这样一来,之前的上下文现在就可以通过memory_search搜索了。
总结
Clawdbot的记忆系统之所以有效,是因为它坚持了几个关键原则:
1. 透明优于黑盒。记忆是纯Markdown,可以阅读、编辑、版本控制,没有任何不透明的数据库或专有格式。
2. 搜索优于注入。与其让所有内容塞满上下文,不如让Agent去搜索相关内容,保持上下文聚焦、降低成本。
3. 持久优于会话。重要信息作为文件保存在磁盘上,而不仅仅存在于对话历史中。压缩无法摧毁已经保存的内容。
4. 混合优于单一。纯向量搜索会漏掉精确匹配,纯关键词搜索会漏掉语义。混合搜索两者兼得。
参考资料
- Clawdbot文档(docs.clawd.bot/) - 官方文档,涵盖设置、配置和所有功能
- GitHub仓库(github.com/clawdbot/cl…) - 源代码、问题和社区贡献
