引言:AI对话中的“金鱼记忆”问题
你是否曾遇到过这样的情况——与AI交流正顺畅时,它突然来一句“我不记得你之前说过什么”?
这种对话上下文丢失的情形以前较为常见,如今各大产品应该都已优化处理了。
用户: 我正在开发一个 React 项目
AI: 好的,有什么我可以帮助你的?
用户: 帮我优化一下代码
AI: 什么代码?
这正是典型的“金鱼记忆”——短短几秒就遗忘,每次对话都像从零开始。
在 mini-cc 项目里,我们也将长期记忆功能作为重点攻关方向。先研究了 Claude Code 的处理方式,又查阅了多篇相关文章,最终总结出了一套可行方案。
今天就来聊聊如何为 mini-cc 赋予记忆能力,实现AI对话上下文持续跟踪。
设计思路
说实话,最初也想过接入向量数据库、使用Embedding模型,打造一套高大上的记忆系统。
后来仔细一想——过于复杂了。目标很纯粹:只需让它记住几件关键事情,没必要动用复杂的技术栈。(后续会评估是否需要支持更复杂的记忆功能)
最终选择了最朴素的方案:直接用文件系统存储记忆。
.ai_memory/
├── MEMORY.md # 索引文件,相当于目录
├── project_stack.md # 项目技术栈
├── coding_style.md # 编码风格
└── api_endpoints.md # API 配置
简单、直接、透明可见。即使 mini-cc 崩溃,也能直接打开文件查看其中记录的信息。
核心功能一:让 AI 学会“记笔记”
我们设计了一个 remember 技能,让AI能够主动将重要信息持久化存储。
如何使用?
用户: 记住,我的项目名称叫 mini-cc
AI: 好的,我已经记住了你的项目名称是 mini-cc。
(过了很久,另起一个对话)
用户: 帮我启动我的项目
AI: 根据记忆,你的项目是 mini-cc,正在帮你启动...
存储机制是怎样的?
采用“两步走”策略:
- 详细内容 写入独立的
.md文件 - 一句话摘要 写入
MEMORY.md索引文件
例如:
# MEMORY.md(索引文件)
- [project_stack](./project_stack.md): 项目使用 TypeScript + React
- [coding_style](./coding_style.md): 使用 2 空格缩进
# project_stack.md(详细内容)
---
type: architecture
description: 项目技术栈说明
---
项目使用 TypeScript + React 架构,采用函数式编程风格。
主要依赖:
- React 18
- TypeScript 5
- Vite
防爆机制
初期未限制索引文件大小,结果AI不断写入,积累到几百行。后来添加了限制——索引最多保留10行,超出则截除最早的部分。
这个“防爆机制”在多次测试中发挥了关键作用,避免了内存溢出或响应超时。
核心功能二:记忆扫描与检索
记忆条目增多后,如何快速找到相关内容?我们设计了扫描与检索机制。
扫描逻辑
- 遍历
.ai_memory目录下所有.md文件 - 读取每个文件的 frontmatter,提取
type和description字段 - 按修改时间排序,最新文件排在最前
- 最多返回200个文件(防止数量过多撑爆内存)
检索逻辑
当前采用关键词匹配——简单直接但足以满足多数场景。
例如用户询问“我的 API 配置是什么”,系统会在记忆描述中查找“API”关键词,返回相关记忆供AI参考。
未来计划接入Embedding模型实现语义搜索,但目前关键词匹配已能覆盖约90%的查询场景,暂以此为准。
核心功能三:消息压缩
此功能专门应对“对话过长”的问题。
与AI长时间交流后,对话历史会不断膨胀,最终超过模型上下文窗口限制,导致错误或性能下降。
压缩策略
第一步:剥离图片
将消息中的图片块替换为 [image] 占位符。单张图片可能占用数千个tokens,替换为6个字符的占位符可大幅节省上下文空间。
第二步:头部截断
若仍超出限制,则直接丢弃最早的消息。默认丢弃比例为20%。
最初考虑调用AI进行智能摘要,但发现速度太慢——用户无法等待。直接截断虽然简单,但响应迅速。
第三步:保底策略
至少保留一轮完整对话,确保AI仍能正常响应。
这套“逃生舱”机制虽然不够优雅,但在紧急情况下非常实用,做到了简单粗暴且有效。
尚未实现的功能
会话管理
计划提供 /new 创建新会话、/sessions 切换会话的功能,目前暂未实现,已排入开发日程。
语义搜索
关键词匹配能满足大部分需求,但不够智能。未来希望集成Embedding模型,实现真正的语义级记忆检索。
自动记忆提取
当前需要用户主动说“记住xxx”,AI才会存储。理想状态下,AI应能自动识别关键信息并主动记忆。
经验体会
在构建这套记忆系统的过程中,有几点深刻体会:
- 简单优于完美。最初计划采用向量数据库,后来发现文件系统完全够用。避免过度设计,优先从简单方案入手。
- 防爆机制必不可少。AI写内容没有节制,必须设置上限防止失控。
- 关键词匹配已够用。语义搜索听起来高大上,但实际场景中80%以上的需求通过关键词即可满足。
- 压缩速度至关重要。用户无法等待智能摘要生成,直接截断虽粗暴,但保证了实时性。
源码在哪里?
如果感兴趣,可以查看以下文件:
- 记忆管理:
src/memdir/MemoryManager.ts - 记忆扫描:
src/memdir/memoryScan.ts - 相关性查找:
src/memdir/findRelevantMemories.ts - 消息压缩:
src/services/compact/compact.ts - Remember 技能:
src/skills/built-in/remember.ts
最后问一句:大家觉得AI的记忆系统还需要哪些功能?欢迎交流分享你的想法。
