07 Context Compact
Context Compact — 上下文总会满要有办法腾地方参考资料https://github.com/shareAI-lab/learn-claude-code核心思想便宜的先跑贵的后跑— 四层压缩策略从零成本操作到按需调用LLM再到紧急兜底。问题背景Agent在大型项目中工作时会不断累积工具调用结果、文件内容、命令输出到messages列表中读一个1000行文件 → ~4000 token读30个文件 跑20条命令 → 大量token累积上下文窗口有限 → API返回prompt_too_long不压缩Agent根本无法在大项目里持续工作。四层压缩管线执行顺序实际执行顺序是budget → snip → micro → auto层级名称触发方式API成本信息损失作用L3tool_result_budget每轮自动0中落盘大工具结果落盘留预览L1snip_compact每轮自动0中裁对话裁掉无关的旧对话中间部分L2micro_compact每轮自动0低占位旧工具结果替换为简短占位符L4compact_history超阈值触发1次API高摘要LLM全量摘要压缩L1: snip_compact — 裁掉无关的旧对话Agent跑了80轮对话最早的帮我创建hello.py和当前工作几乎无关。消息数超过50条 → 保留头部3条 尾部47条特殊保护不能把assistant(tool_use)和后面的user(tool_result)拆开defsnip_compact(messages,max_messages50):iflen(messages)max_messages:returnmessages head_end,tail_start3,len(messages)-(max_messages-3)# 保护 tool_use ↔ tool_result 完整性if_message_has_tool_use(messages[head_end-1]):whilehead_endlen(messages)and_is_tool_result_message(messages[head_end]):head_end1# ... 插入占位符L2: micro_compact — 旧工具结果占位Agent连续读了10个文件第1-7次的完整内容早就不需要了。只保留最近3条tool_result的完整内容更旧的替换为一行占位符[Earlier tool result compacted. Re-run if needed.]KEEP_RECENT_TOOL_RESULTS3defmicro_compact(messages):tool_resultscollect_tool_result_blocks(messages)iflen(tool_results)KEEP_RECENT_TOOL_RESULTS:returnmessagesfor_,_,blockintool_results[:-KEEP_RECENT_TOOL_RESULTS]:iflen(block.get(content,))120:block[content][Earlier tool result compacted. Re-run if needed.]returnmessagesL3: tool_result_budget — 大结果落盘模型一次读了5个大文件单条tool_result加起来500KB。统计最后一条user消息里所有tool_result总大小超过200KB→ 按大小排序从最大的开始落盘到.task_outputs/tool-results/上下文只留persisted-output标记 前2000字符预览deftool_result_budget(messages,max_bytes200_000):# 统计最后一条user消息中所有tool_result# 超过阈值 → 落盘最大的替换为预览L4: compact_history — LLM全量摘要前三层跑完后token仍然超阈值 → 触发LLM摘要保存transcript完整对话写入.transcripts/JSONL格式LLM生成摘要保留当前目标、重要发现、已改文件、剩余工作、用户约束替换消息列表所有旧消息 → 一条摘要消息defcompact_history(messages):transcript_pathwrite_transcript(messages)# 先保存完整对话summarysummarize_history(messages)# LLM 生成摘要return[{role:user,content:f[Compacted]\n\n{summary}}]熔断器连续失败3次后停止重试防止死循环浪费API调用。应急: reactive_compact当API返回prompt_too_long413错误时触发比compact_history更激进从尾部回退但仍要避免留下孤立的tool_result重试上限默认1次defreactive_compact(messages):transcriptwrite_transcript(messages)summarysummarize_history(messages)tail_startmax(0,len(messages)-5)# 保护 tool_result 完整性if_is_tool_result_message(messages[tail_start])and_message_has_tool_use(messages[tail_start-1]):tail_start-1return[{role:user,content:f[Reactive compact]\n\n{summary}},*messages[tail_start:]]执行顺序为什么不能换CC源码query.ts中的真实顺序applyToolResultBudgetL3— 先处理大结果确保完整内容落盘snipCompactL1— 裁中间消息microcompactL2— 旧结果占位contextCollapse上下⽂折叠由 Feature Flag控制的实验性可选功能将已完成的⼯具调⽤结果折叠为⼀⾏摘要。⼀个返回了3000 ⾏⽂件内容的 read_file 调⽤如果后续已经基于这个⽂件完成了编辑就折叠为 [已读取并编辑 config.yaml] 。autoCompactL4— LLM全量摘要顺序不能换的原因L3budget必须在L2micro前面因为micro_compact会把旧的tool_result替换成一行占位符budget必须在那之前把完整内容落盘。在源码中Context Collapse 作为独⽴模块存放在src/services/contextCollapse/ ⽬录下包含 index.ts 、 operations.ts 、 persist.ts 三个⽂件。从 autoCompact.ts 中的引⽤关系可以看到当 Context Collapse 功能启⽤时它会取代⾃动压缩成为主要的上下⽂管理策略——在90% 上下⽂占⽤时开始提交折叠95% 时阻⽌新的⼦ Agent ⽣成。这意味着 Context Collapse 的精确⼿术⼑优先于 AutoCompact 的全⾯摘要只有当 Collapse ⽆法处理时才退回到传统的 LLM 摘要压缩。⚖️ 核心区别对比特性Context Collapse (上下文折叠)MicroCompact (微压缩)核心策略折叠与投影将早期对话“折叠”成摘要投影清理与去重移除冗余、过时的“垃圾”信息操作对象有价值的完整对话轮次冗余的重复消息、旧工具结果等触发时机上下文压力达到高水位90%/95%时每一次 API 调用前都会执行信息可逆性可恢复。原始数据保留只是创建了“投影”不可逆。被识别为冗余的信息会被直接移除主要目的系统性管理上下文窗口为重要信息腾出空间通过低成本方式清除“垃圾”优化上下文质量总结一下MicroCompact 是流水线中靠前的、非常廉价的清理步骤而 Context Collapse 则是更靠后、更具战略性的管理手段。当 Context Collapse 启用时它会取代 AutoCompact 成为主要的上下文管理策略体现了系统“先做便宜的事再做昂贵的事”的设计哲学。整体流程defagent_loop(messages):reactive_retries0whileTrue:# 三个预处理器0 API 调用messages[:]tool_result_budget(messages)# L3: 大结果落盘messages[:]snip_compact(messages)# L1: 裁中间messages[:]micro_compact(messages)# L2: 旧结果占位# 还不够LLM摘要1 API 调用ifestimate_token_count(messages)THRESHOLD:messages[:]compact_history(messages)try:responseclient.messages.create(...)exceptPromptTooLongError:ifreactive_retriesMAX_REACTIVE_RETRIES:messages[:]reactive_compact(messages)# 应急reactive_retries1continueraise# ... 工具执行 ...核心设计原则便宜的先跑贵的后跑三层零API操作先执行仍不够才调用LLM摘要分层降级防御从无损到有损再到紧急丢弃保护消息完整性不能拆开tool_use和tool_result配对有损压缩不可逆压缩时先保存transcript备份但Agent不会主动翻旧档案局限性有损压缩不可逆摘要质量取决于LLM判断重要细节可能被丢弃需要独立记忆系统补偿压缩管的是当前会话台面整洁度跨会话长期知识由Memory系统负责