learn claude code第八章
这一章,我们将学习agent的上下文压缩机制。在agent运行过程中,上下文不断变长,当达到上下文窗口的最大限制时,agent就无法继续工作。此时,我们需要一种压缩机制,来压缩上下文。
机制解读
L1:裁掉旧的对话
当agent进行很多轮对话后,中间部分的对话其实和当前的对话内容没有太大关系。当消息数量超过50条时,保留头部的3条作为初始上下文,尾部的47条作为当前工作的上下文,中间部分的消息裁掉。但是设定边界,不可以分开assistant(tool_use)和后面的user(tool_result)。
工具型调用对话中,一条消息序列往往是这样的结构。二者是一对不可分割的整体,否则会破坏语义,逻辑断裂,甚至引起模型api报错。
assistant: 我需要调用一个工具 → (tool_use 请求) user/tool: 工具返回的结果 → (tool_result)
裁掉的是消息本身,如果还是没有达到目的,则进行L2层压缩。
def snip_compact(messages, max_messages=50): if len(messages) <= max_messages: return messages keep_head, keep_tail = 3, max_messages - 3 head_end, tail_start = keep_head, len(messages) - keep_tail if head_end > 0 and _message_has_tool_use(messages[head_end - 1]): while head_end < len(messages) and _is_tool_result_message(messages[head_end]): head_end += 1 if (tail_start > 0 and tail_start < len(messages) and _is_tool_result_message(messages[tail_start]) and _message_has_tool_use(messages[tail_start - 1])): tail_start -= 1 if head_end >= tail_start: return messages snipped = tail_start - head_end return messages[:head_end] + [{"role": "user", "content": f"[snipped {snipped} messages]"}] + messages[tail_start:]
- 当
L2: 旧工具结果占位
设想agent连续读了10个文件,前面读取的文件内容还在上下文里,现在不需要了,我们只需要保留最近3条tool_result的完整内容,将之前的替换为一行占位符。
L3: 大结果落盘
当模型一次工具调用就读了n多个文件时,可以直接把上下文撑满,单条user消息中tool_result很大。此时统计最后一条user消息中的所有工具调用结果总大小,超过200KB时,按照大小排序,从最大的开始落盘,上下文中只保留标记+预览。这样模型看到之后知道完整内容在磁盘中,需要时可以重新读取。
L4: LLM全量摘要(API调用)
当前三层预处理跑完时,如果还是超过token阈值,进行如下三步流程:
1. 保存transcript,模型的活跃上下文中只剩摘要,但是这样可能丢失细节。
2. LLM生成摘要:把对话历史发送给LLM,要求保留当前目标、重要发现、已改文件、剩余工作、用户约束等关键信息。
3. 替换消息列表:所有旧消息替换为一条摘要。
设置熔断器,当连续失败3次后停止重试,防止死循环浪费api调用。
应急
当上下文增长速度快于压缩速度时,触发应急压缩。保留最近5条原始消息,只总结较早的历史,避免留下孤立的工具调用结果。
代码精读

浙公网安备 33010602011771号