和 LLM 交互:messages 数组和 token 里讲过 LLM 是无状态的,要让模型「记住」之前聊了什么,唯一的办法就是把完整对话历史塞进 messages 数组。
这意味着会话越长,每次请求要发的东西就越多。你和 Claude Code 聊一两个小时,messages 数组里塞着几十轮对话、几百次工具调用、读过的文件原文,token 数能轻松冲到十几万。
长上下文不仅贵,还会让模型出现「中间迷失」,关键信息淹没在大量历史细节里,回答质量明显下降。更糟的是上下文满了之后,模型就无法回复了,只能给你一个错误信息。
通用的解法是上下文压缩,把太长的对话历史压一压,腾出空间继续聊。Claude Code 作为一个工业级 Coding Agent,这一篇我们就以它为例,看下它在上下文压缩上有哪些做法值得借鉴。
Claude Code 的压缩有两种触发方式。一种是手动压缩,你随时可以敲 /compact 命令主动触发一次,比如自己感觉聊得太多了想总结一下。另一种是自动压缩,上下文快满时系统自己跑一次压缩,腾出上下文空间让你继续聊。
手动压缩和自动压缩触发时机不一样,但是底层原理是一样的。
压缩的具体做法是什么呢?最朴素的想法是直接丢掉最早的 N 条消息,但这样会丢掉很多关键信息:用户最早提的需求、之前修过的 bug、走过弯路的 debug 痕迹,这些信息里随便丢一条,都可能让模型在后面犯一样的错。
更聪明的做法是让 LLM 把整段对话压成一份摘要,再基于这份历史对话的摘要继续聊,这样信息的密度更高,关键意图也不会丢。
Claude Code 走的就是这条路,当触发上下文压缩时,它就会把当前 session 所有对话历史,以及一段压缩 Prompt 发送给模型,要求模型基于会话内容总结一份摘要。然后新开一个上下文窗口,仅保留这份摘要,你就可以继续聊了。
但这条路还有几个工程问题要解决:哪些信息要保留,哪些需要去除?摘要写成什么样效果才最好?
说白了就是,压缩 Prompt 要怎么写,才能尽可能保留关键信息,让模型流畅地继续执行任务?
我们不妨直接参考 Claude Code,看看它是怎么写压缩命令的,完整 prompt 如下: