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条原始消息,只总结较早的历史,避免留下孤立的工具调用结果。

代码精读

 

posted @ 2026-08-05 16:25  我是球啊  阅读(9)  评论(0)    收藏  举报