git-lrc 工具展示如何在每次提交自动运行AI代码审查,实现记忆管理的最佳实践。
给用户的分层记忆管理建议
你好,我是 Maneshwar。我正在开发 git-lrc,这是一个会在每次提交时运行的 Micro AI 代码审查工具。它完全免费,源代码可在 Github 上查看。欢迎给 git-lrc 点个 Star,帮助更多开发者发现这个项目。也请亲自试用,并分享你的反馈。
这是 context engineering 系列的第二篇。第一篇介绍了整个领域的全貌。这次要讨论的是其中较难的一块——如何在不丢掉主线的前提下,有原则地丢弃信息。
每个构建长时间运行 Agent 的人,都会遇到这样的情况。
对话进行到第 10 轮时,它聪明得惊人。
敏锐、迅速,清楚记得你的每项要求,面对棘手的 bug 也能精准找到解决路径。
你感觉自己就像个巫师。
到了第 80 轮,它却像变了一个物种。
它会再次提出一个早已被你否决的修复方案。
它“忘记”了自己二十轮之前编辑过的文件。
它会推翻你们一开始共同做出的决定。
明明是同一个模型、同一个 prompt、同一个任务,却不知为何,知道得越多反而变得越笨。
这不是模型的 bug。
只是桌面被堆满了。
在第一篇中,我提出过一个观点:context window 是 RAM,而不是硬盘——它是一种存在明确容量上限的工作记忆。
模型能够推理的一切内容,都必须放在这张桌子上。
所谓长对话,就是你不断把纸张堆到桌面上,却从来不清理的结果。
最终,那张重要的纸被四百行工具输出埋在下面,而模型就像在一场派对上站在雪崩般的纸堆里替你报税。
Compaction,就是在不把那张重要纸张扫进垃圾桶的情况下,清理桌面的办法。
第一篇介绍了四种操作——写入、检索、压缩、隔离。Compaction 是其中最容易被人信心满满地做错的一项。
因为它表面上看起来很简单:“总结一下对话就行了。”于是,人们做出了一个 summarizer,接着他们的 Agent 就开始悄无声息地丧失理智。
下面来看看正确的做法。
Compaction 是针对语义的有损压缩。
你把一段漫长、发散的历史记录,替换成一种更短的表示形式:保留下一步真正需要的内容,丢弃不需要的内容。
其中的“有损”,才是整件事的关键。
如果它是无损的,就起不到任何作用——你只不过是用另一种字体保存了同样数量的 token。
Compaction 之所以有效,恰恰是因为它会丢弃信息。
真正的技巧,在于决定丢掉什么。
有两件事并不等同于 Compaction。混淆它们,只会伤害你的 Agent:
Clearing 就是失忆。/clear 会清空历史记录并重新开始。切换任务时很有用,但在任务进行途中使用将是灾难性的。Trimming 则是机械操作:按照一条硬性规则,删除最早的 N 条消息,完全不需要模型参与。便宜、快速,但愚笨。它不知道最早的那条消息,可能正是整个任务赖以成立的关键决定。
Compaction 位于二者之间:比 trimming 聪明,又不像 clearing 那么具有破坏性。
它使用模型判断哪些内容值得保留,再把其余部分改写成高度浓缩的信息。
朴素的 Compaction 会以一些值得明确命名的方式失败,因为只有说得清这些问题,你才能有针对性地设计防御机制。
Drew Breunig 对长 context 如何腐化给出了一套简洁的分类,而草率的 Compaction 可能引入其中的每一种问题:
Poisoning:某个 hallucination 被写进摘要,从此变成支撑后续推理的基础。模型会把自己先前犯下的错误当作既定事实,并继续在上面构建。Compaction 可能把一个猜测洗成一项“决定”。
Distraction:摘要保留了太多内容,以至于原封不动地重现了最初的信息膨胀。恭喜,你把一段 50K 的对话压缩成了 48K。
Confusion:多余的细节在删减后幸存下来,并把模型引向无关的工作。
Clash:摘要与当前仍然存在的消息互相矛盾,模型不得不充当裁判,在两个不同版本的现实之间做出裁决。
此外,反复执行 Compaction 还有一种特有的失败模式,也是最令人担忧的一种:累积侵蚀。
每次 Compaction 都是有损的。
对 Compaction 的结果再次执行 Compaction,就会再多丢失一点信息。
在一场马拉松式会话里重复五次,你就相当于拿自己的任务玩了一场传话游戏:Agent 此时依赖的是摘要的摘要的摘要,而你在第 3 轮设定的具体约束(“绝对不要修改 auth module”),已经与原文相隔了三代转述。
这才是自动 Compaction 在任务中途触发后,Agent 会“脱轨”的真正原因:这个边界带来的不只是 token 数量减少,更是一次行为上的断裂。
从某种实际意义上说,边界另一侧的 Agent 已经是一个略有不同的 Agent,只能依据一份稍差一些的笔记继续工作。
你无法彻底消除这个问题。
你只能有意识地减缓它发生的速度。
那么,哪些内容应该在删减后保留下来?有一条启发式原则,几乎经受住了所有严肃实现的考验:保留决定和状态,丢弃产生这些结果的过程。
还记得第一篇中的例子吗?Agent 搜索数据库后,发现用户的数据表是 documents_v2。当时我让你记住这一点。现在你会明白原因。
优秀的 Compaction 会保留:“用户的数据表是 documents_v2。”
优秀的 Compaction 会丢弃:模型为了得出这个结论而翻阅的 400 行 JSON。
这句话就是整个理念的微缩版本。
事实持久有效,而且体积很小。
用来证明这个事实的证据极其庞大,如今却已毫无用处——你已经从中提取出了价值。
继续保留 JSON,就等于永远为一份已经兑现过价值的信息支付租金。
将这一原则推广开来,你就能得到一份所有优秀交接摘要最终都会趋同的检查清单:
其中,约束这一项尤其值得强调:用户约束是丢失后代价最高、却也最容易被遗漏的信息。
“决定使用 Postgres”看起来像一条值得保留的事实。
“用户说绝对不要修改 auth module”看起来却像过时的对话噪声。
但一旦第二条丢失,你的 Agent 就会信心十足地去做那件它明确被告知不能做的事。
这些约束应该原封不动地通过每一次 Compaction,绝不能被转述。
有两个生产级 coding Agent 值得拿来对比,因为它们对问题本身看法一致,却选择了不同的处理方式。
Claude Code 更依赖自动化。
它提供了手动执行的 /compact 命令,但其核心行为是:当 context window 使用率达到约 95% 时,自动触发 Compaction。它会总结完整的任务轨迹,并以该摘要为起点重新开始。
你可以对它进行引导(/compact "focus on the open TODOs"),而且它与 /clear 是两种不同的操作。
值得注意的是,社区的普遍看法是:95% 已经太晚了。等到 context 填得这么满,对话质量早已开始下降,因此人们通常会在达到触发阈值之前,提前手动执行 Compaction。
OpenAI 的 Codex CLI 则更偏向“交接”。它的 prompt 将 Compaction 描述为一个检查点,要求生成一份提供给“另一个将接手任务的 LLM”的摘要,并指示下一个模型在现有工作的基础上继续推进,而不是把工作重做一遍。
它会在达到 token 阈值时触发,在摘要之外原样保留最近的用户消息,并且当 Compaction 调用本身失败时,通过带退避机制的重试来处理。(Compaction 本身也是一次 LLM 调用。LLM 调用会失败。你必须为此做好准备。)
把前面的内容归纳成你实际需要做出的决定:
触发时间要比你以为的更早。95% 是一个警示案例,不是推荐值。
在 85%~90% 左右执行,可以保证进行 Compaction 时,context 的质量仍然足以生成一份良好的摘要。
先裁剪,再总结。先执行一次成本低廉的机械清理,删除已经过时的工具输出。
Summarization 是一种昂贵且有损的工具,不要把它浪费在 400 行可以直接删除的 JSON 上。
原样保留最近几轮对话。压缩遥远的过去,保留正在发生的现在。
模型需要当前任务进展中鲜活且未经转述的对话脉络。
固定用户约束,并告诉用户发生了 Compaction。让用户约束以原文形式通过每一次 Compaction,因为这些内容一旦丢失,造成的破坏最大。
此外,如果一次静默执行的 Compaction 在任务中途改变了行为,用户只会觉得 Agent 莫名其妙地变差了。加上一行提示(“已压缩历史记录以释放 context 空间”),就能把一个谜团变成一项清晰的权衡。
你还需要一个起始 prompt,可以参考下面这个:
Create a handoff summary so this coding session can continue in a fresh context.
The summary will be the ONLY history available, so preserve:
1. Completed work — what's done and verified (one line each)
2. Current state — files modified and their status
3. In progress — what is being worked on right now
4. Next steps — concrete actions to take
5. Constraints — user preferences and requirements, quoted exactly
6. Critical references — table names, IDs, file paths, key decisions and the why
Be dense. Drop deliberation, raw tool output, and anything already superseded.
Do not invent or assume anything not present in the conversation.
最后一行——不要编造——是防范 Poisoning 成本最低的手段。
Summarizer 的工作是压缩,而不是创作。
它一旦开始自行填补空白,就是在制造一个 hallucination,而第 80 轮的 Agent 会把这个 hallucination 奉为真理。
Compaction 迫使你承认一件事,而技术栈的其他部分让你得以回避它:你无法保留一切,因此必须决定允许你的 Agent 忘记什么。
外部记忆和检索机制让你可以逃避这个问题——先把信息存起来,以后再取回。
但在一个持续时间很长的任务内部,面对一张容量有限的桌面,你已经无处可逃。
总有一些东西必须被丢弃。Compaction 的意义,就是主动选择哪些内容能够幸存下来,而不是任由 context window 替你做决定,悄无声息地把最重要的约束挤出注意力的边界。
最好的 Compaction 与最好的工程实践一样,本质上主要是做减法。
它会保留 documents_v2,烧掉那些 JSON;让一行约束的寿命超过一千行闲聊。
第一篇中的那句箴言,在这里变得更加锋利:最好的 token,就是那个你根本不必发送的 token。
Compaction 帮你找出这些 token,而你需要有勇气把它们删除。
免责声明:本文由我本人撰写;AI 仅用于修正语法并提升可读性。
AI Agent 编写代码的速度很快。但它们也会在不通知你的情况下,悄悄删除逻辑、改变行为并引入 bug——而你往往要到生产环境中才会发现。
git-lrc 可以解决这个问题。它会接入 git commit,在每一处 diff 正式落地之前进行审查。60 秒即可完成设置,完全免费。
欢迎提供任何反馈,也欢迎贡献者参与!它已上线,源代码可供查看,任何人都可以直接使用。
| 🇩🇰 Dansk | 🇪🇸 Español | 🇮🇷 Farsi | 🇫🇮 Suomi | 🇯🇵 日本語 | 🇳🇴 Norsk | 🇵🇹 Português | 🇷🇺 Русский | 🇦🇱 Shqip | 🇨🇳 中文 | 🇮🇳 हिन्दी |
|---|
AI Agent 编写代码的速度很快。但它们也会在不通知你的情况下,悄悄删除逻辑、改变行为并引入 bug——而你往往要到生产环境中才会发现。
git-lrc 可以解决这个问题。它会接入 git commit,在每一处 diff 正式落地之前进行审查。60 秒即可完成设置,完全免费。
看看 git-lrc 如何发现严重的安全问题,例如凭据泄露、高成本的云操作,以及日志语句中出现的敏感信息。
🤖 AI Agent 会悄悄破坏代码:代码被删除、逻辑被修改、边界情况消失。直到问题进入生产环境,你才会注意到。
🔍 在发布之前发现问题。由 AI 驱动的行内评论会准确指出发生了哪些变化,以及哪些地方看起来存在问题。
部分评论可能只有登录后的访客才能看到。请登录以查看全部评论。
如果需要采取进一步行动,你可以考虑屏蔽此人和/或举报滥用行为。