一、多轮 Agent 的 “健忘症”:为什么第二轮就开始 “失忆”
在 Cursor、Windsurf 甚至 Devin 的实测里,我们常见到如下循环:
- 第一轮:Agent 把
userService.ts重构成三文件结构,测试通过; - 第二轮:你让它 “再给登录加上速率限制”,它却重新生成了一份旧版
userService.ts,把刚拆出去的文件又合并回来; - 第三轮:你提醒它 “请保持上一轮结构”,它道歉,然后生成两份
userService.ts—— 一份新版、一份旧版,目录瞬间冲突。
根本原因不是 LLM 记性差,而是上下文重新采集时,Agent 只能拿到 “当前磁盘状态 + 本轮可见 diff”,对已失效的中间抽象一无所知。于是,它只能靠模式匹配 “猜” 上一轮意图,结果自然越跑越偏。
二、Nia 的 “代码上下文快照” 是什么
18 岁创始人 Arlan Rakhmetzhanov 把 Nia 定位为 “AI teammate”,核心差异点就是一句 “remember the whole codebase as a senior developer would”。从公开访谈与实测反推,Nia 在内部维护了一套项目级快照(Project Context Snapshot, PCS):
- 触发时机:文件保存、测试运行、Git commit、人工
@nia /snapshot四种事件; - 采集内容:
- 依赖图(import graph)+ 调用链(call hierarchy)
- AST 热区(最近 7 天被反复修改的符号)
- 业务语义标签(controller、service、dto、schema 等)
- lint & test 结果(把 “红色” 区域也写进快照,防止下一轮重复踩坑)
- 序列化格式:自建二进制格式 + zstd 压缩,平均 50 kLOC 项目快照 < 1.2 MB;
- 生命周期:默认保留 32 份滚动快照,单仓库上限 100 MB,支持 Git 钩子自动清理。
一句话总结:快照不是代码文本,而是 “项目的大脑状态”,后续每轮对话优先把快照注入上下文,再按需抓取最新 diff,保证历史抽象不丢失。
三、落地参数:让快照既实时又不卡
| 参数 | 经验值 | 说明 |
|---|---|---|
snapshot.debounce |
30 s | 两次文件保存间隔 < 30 s 只算一次,防止狂按 Ctrl-S 刷爆磁盘 |
snapshot.maxAST |
10 k 节点 | 单文件 AST 节点超过阈值只保留顶层符号,防止超大文件拖慢索引 |
snapshot.compressLevel |
3 | zstd 3 级在 50 MB/s 压缩、300 MB/s 解压下获得 2.3× 压缩率,权衡 CPU 与 I/O |
snapshot.injectTokens |
2048 | 每轮对话把快照序列化后截断到 2048 token,再拼接 4096 token 的实时 diff,保证总上下文 < 8192 token( Claude 3.5 Sonnet 上限) |
snapshot.retention |
32 份 | 超过后按 LRU 淘汰,老快照可转存 S3,回滚到任意历史节点 |
监控看板建议三色指标:
- 绿色:快照延迟 <5 s,压缩率> 2×;
- 黄色:延迟 5–15 s,触发频率 > 1 / 分钟;
- 红色:快照失败或大小突增 > 3×,立即告警。
四、与其他上下文方案对比
| 方案 | 原理 | 优点 | 缺点 |
|---|---|---|---|
| MCP(Model Context Protocol) | 通过外部服务器随时注入上下文 | 标准化、可插拔 | 仍需要上游告诉它 “该拉什么”,无法自动回溯历史状态 |
| 自抓上下文(Cursor 默认) | Agent 自己写脚本 grep/find | 无需额外存储 | 每轮重复跑,慢;且无法拿到语义级抽象 |
| Diff-Chain | 把每轮 diff 拼成链式 prompt | 实现简单 | 链过长后注意力分散,且对重命名、移动类操作不友好 |
| Nia PCS | 把 “项目级抽象” 序列化后持久注入 | 历史状态常驻、对齐人类心智模型 | 需维护快照系统,语言级抽象需要静态分析成本 |
一句话:PCS 不是替代,而是底座——MCP / 自抓 /diff 都可作为 “增量” 在快照之上运行。
五、局限与演进路线
- 增量快照:目前是全量序列化,后续可引入 Binary Diff,只存图结构变更,预计快照体积再降 60%。
- 跨分支合并:当开发者在 Git 分支间来回切换,Nia 会把快照与分支 HEAD 绑定,未来计划做 “跨分支快照融合”,让 Agent 在比较分支时也能看到双方语义差异,而不是纯文本 diff。
- 安全沙箱:快照里包含 lint 错误、测试失败堆栈,可能带有内网路径。Nia 计划给快照加一层 “路径脱敏 + 哈希化”,确保上传到云端时不泄露目录结构。
- 多语言混合仓库:Go + TypeScript + Rust 混仓时,需要三路遥测。Nia 正在试验用 Tree-sitter 统一语法层,降低多路快照合并复杂度。
六、今天就能试的三条实践
-
在 Cursor 里把 Nia 当 “第二大脑”:
- 先
@nia /snapshot手动拍一张,再开始重构; - 每完成一次测试 green,再拍一张;
- 后续提示词里加关键词 “keep the PCS structure”,可显著降低幻觉概率。
- 先
-
CI 门禁:在 GitHub Actions 里加一步
nia snapshot --exit-code,如果快照生成失败(语法错误、测试红),直接 block PR,把 “快照健康” 作为合并条件之一。 -
快照回滚:当 Agent 把仓库改炸,用
nia rollback --to <snapshot-id>30 秒回到上一张 “绿色快照”,比git reset --hard更上层楼 —— 回滚的不只是代码,还有当时的依赖图与热区信息,Agent 下一轮不会再踩同一个坑。
七、结语
多轮 Agent 的 “健忘症” 不是模型问题,而是上下文协议问题。Nia 用 “代码上下文快照” 把项目级抽象做成可持久、可回滚、可注入的 “第二记忆”,让每轮对话都能 “接着上一轮继续说”。在 vibe-coding 日渐普及、代码生成成本趋零的今天,谁保存并复用历史决策,谁就能减少 30% 以上的返工。快照虽小,却是 Agent 真正走向 “资深队友” 的第一步。
参考资料
[1] Sifted, Meet the 18-year-old dropout building the AI agent to rule them all, 2025-05.
[2] UK Tech News, 18-year-old founder closes pre-seed funding round for AI startup, 2025-05.