第04课:三层上下文压缩机制(Claude Code核心亮点)

张开发
2026/4/14 11:01:49 15 分钟阅读

分享文章

第04课:三层上下文压缩机制(Claude Code核心亮点)
一、前言上一节课我们讲了上下文管理的基础策略截断、优先级排序但这些策略有一个明显的缺陷简单截断会丢失有用信息而完全保留又会导致Token超限。Claude Code的核心亮点之一就是“三层上下文压缩机制”——它不是简单的“删减”而是“信息提纯”在保证Agent能记住关键信息的前提下将上下文压缩到合理长度兼顾性能和效果。本节课我们深入拆解这三层压缩的设计逻辑、实现细节以及触发机制这也是工业级Agent与普通Agent的核心区别之一。二、三层压缩的核心设计思想核心原则从浅到深、从快到慢、从无损耗到有损耗优先使用低成本、无损耗的压缩方式只有在必要时才使用高成本、有损耗的压缩最大限度保证信息完整性和性能。三层压缩的触发顺序微压缩 → 会话压缩 → 全量压缩只有当前一层压缩无法将Token降到阈值以下时才触发下一层。触发阈值Token占用达到93%可配置由TokenTracker监控触发。三、第一层微压缩Micro Compact—— 本地快速压缩无API调用1. 核心特点- 无API调用纯本地字符串处理速度最快毫秒级- 无信息损耗只截断冗余的工具结果不修改核心信息- 适用场景上下文轻度膨胀主要是工具结果过多导致Token超限。2. 实现逻辑Claude Code源码解析微压缩的核心类是com.claudecode.core.compact.MicroCompact其逻辑是“按时间和数量截断工具结果”public class MicroCompact implements Compressor { // 保留最近的工具结果数量默认6个 private static final int MAX_TOOL_RESULTS 6; // 时间阈值默认10分钟超过该时间的工具结果只保留2个 private static final long TIME_THRESHOLD 10 * 60 * 1000; // 10分钟 Override public CompactionResult compact(ConversationMemory memory) { ListToolResult toolResults memory.getToolResults(); int originalSize toolResults.size(); // 1. 按时间筛选超过10分钟的工具结果只保留最近2个 ListToolResult recentResults new ArrayList(); long currentTime System.currentTimeMillis(); for (ToolResult result : toolResults) { if (currentTime - result.getTimestamp() TIME_THRESHOLD) { recentResults.add(result); } } // 超过10分钟的结果保留最近2个 if (recentResults.size() 2) { recentResults.addAll(toolResults.subList(Math.max(0, toolResults.size() - 2), toolResults.size())); } // 2. 按数量筛选保留最近6个工具结果 if (recentResults.size() MAX_TOOL_RESULTS) { recentResults recentResults.subList(recentResults.size() - MAX_TOOL_RESULTS, recentResults.size()); } // 3. 更新记忆中的工具结果 memory.setToolResults(recentResults); // 计算压缩效果 int compressedSize recentResults.size(); int reducedCount originalSize - compressedSize; return new CompactionResult(微压缩完成, reducedCount, false); } }3. 关键设计点- 时间感知近期的工具结果更可能被后续推理使用所以保留更多远期结果只保留少量核心- 只压缩工具结果不触碰系统提示词、用户目标、历史对话保证核心信息不丢失- 无API调用避免因压缩增加LLM成本和延迟。四、第二层会话压缩Session Memory Compact—— AI摘要压缩1次API调用1. 核心特点- 有API调用调用LLM对历史对话和工具结果进行摘要中等速度秒级- 低信息损耗LLM会提炼核心信息删除冗余描述保留关键数据- 适用场景微压缩后Token仍超限上下文包含大量冗余的历史对话和工具结果。2. 实现逻辑Claude Code源码解析会话压缩的核心类是com.claudecode.core.compact.SessionMemoryCompact其逻辑是“让LLM生成上下文摘要”public class SessionMemoryCompact implements Compressor { // 摘要后的Token范围10K-40K private static final int MIN_SUMMARY_TOKENS 10000; private static final int MAX_SUMMARY_TOKENS 40000; // LLM客户端用于生成摘要 private final LlmClient llmClient; Override public CompactionResult compact(ConversationMemory memory) { // 1. 提取需要压缩的内容历史对话工具结果 String contentToCompact buildContentToCompact(memory); int originalTokens tokenizer.countTokens(contentToCompact); // 2. 调用LLM生成摘要提示词工程很关键 String prompt buildSummaryPrompt(contentToCompact); String summary llmClient.generateSummary(prompt); // 3. 校验摘要长度确保在合理范围 int summaryTokens tokenizer.countTokens(summary); if (summaryTokens MIN_SUMMARY_TOKENS) { summary addDetails(summary, memory); // 补充细节 } else if (summaryTokens MAX_SUMMARY_TOKENS) { summary truncateSummary(summary); // 进一步截断 } // 4. 更新记忆用摘要替换原始历史对话和工具结果 memory.setHistory(List.of(summary)); memory.setToolResults(List.of()); // 工具结果已融入摘要 // 计算压缩效果 int reducedTokens originalTokens - summaryTokens; return new CompactionResult(会话压缩完成, reducedTokens, true); } // 构建需要压缩的内容 private String buildContentToCompact(ConversationMemory memory) { StringBuilder content new StringBuilder(); content.append(历史对话).append(memory.getHistory()).append(\n); content.append(工具结果).append(memory.getToolResults()).append(\n); return content.toString(); } // 构建摘要提示词关键告诉LLM如何提炼核心信息 private String buildSummaryPrompt(String content) { return 请你作为AI助手对以下内容进行摘要要求 1. 保留用户的核心目标和所有关键工具结果数据 2. 删除冗余的对话和重复的描述 3. 保持逻辑连贯让后续推理能基于摘要继续推进任务 4. 摘要长度控制在10K-40K Token之间。 需要摘要的内容 content; } }3. 关键设计点- 提示词工程摘要的质量取决于提示词必须明确告诉LLM“保留什么、删除什么”- 摘要范围控制避免摘要过短丢失信息或过长压缩无效- 核心信息保留系统提示词和用户目标不参与压缩只压缩历史对话和工具结果。五、第三层全量压缩Full Compact—— 兜底压缩多次API调用1. 核心特点- 多次API调用对整个上下文除系统提示词进行全量重写速度最慢数十秒- 一定信息损耗优先保留用户目标和核心工具结果删除所有非必要信息- 适用场景会话压缩后Token仍超限属于极端情况如长时间运行、大量工具调用。2. 实现逻辑Claude Code源码解析全量压缩的核心类是com.claudecode.core.compact.FullCompact其逻辑是“按API轮次分组逐步丢弃非核心信息”public class FullCompact implements Compressor { // 熔断器连续3次压缩失败停止压缩防止无限调用API private static final int MAX_RETRY 3; private final LlmClient llmClient; private int retryCount 0; Override public CompactionResult compact(ConversationMemory memory) { if (retryCount MAX_RETRY) { return new CompactionResult(全量压缩失败熔断器触发, 0, false); } try { // 1. 提取全量上下文除系统提示词 String fullContext buildFullContext(memory); int originalTokens tokenizer.countTokens(fullContext); // 2. 按API轮次分组每轮调用为一组 ListString contextGroups groupByApiRound(fullContext); // 3. 逐步丢弃早期非核心分组生成全量摘要 ListString keptGroups new ArrayList(); int currentTokens 0; // 从后往前保留分组近期分组更重要 for (int i contextGroups.size() - 1; i 0; i--) { String group contextGroups.get(i); int groupTokens tokenizer.countTokens(group); if (currentTokens groupTokens MAX_SUMMARY_TOKENS) { keptGroups.add(0, group); // 插入到前面保持顺序 currentTokens groupTokens; } else { // 对当前分组进行摘要再尝试加入 String groupSummary llmClient.generateSummary(提炼以下内容的核心信息 group); if (currentTokens tokenizer.countTokens(groupSummary) MAX_SUMMARY_TOKENS) { keptGroups.add(0, groupSummary); currentTokens tokenizer.countTokens(groupSummary); } else { break; // 无法再加入停止保留 } } } // 4. 生成最终全量摘要更新记忆 String fullSummary String.join(\n, keptGroups); memory.setHistory(List.of(fullSummary)); memory.setToolResults(List.of()); // 计算压缩效果 int reducedTokens originalTokens - tokenizer.countTokens(fullSummary); retryCount 0; // 重置重试次数 return new CompactionResult(全量压缩完成, reducedTokens, true); } catch (Exception e) { retryCount; return new CompactionResult(全量压缩失败重试次数 retryCount, 0, false); } } // 按API轮次分组每一次LLM调用为一轮 private ListString groupByApiRound(String fullContext) { // 解析上下文按API Round X分组逻辑略... return new ArrayList(); } }3. 关键设计点- 熔断器保护避免因LLM异常导致多次无效API调用浪费成本- 分组保留按API轮次分组优先保留近期分组符合Agent的推理逻辑- 兜底策略只有在前面两层压缩无效时才触发是最后的保障。六、三层压缩的触发流程总结TokenTracker监控Token数量 → 达到93%阈值 ↓ 调用AutoCompactManager.autoCompactIfNeeded() ↓ 1. 先调用MicroCompact微压缩 ↓ 压缩后Token仍超限 2. 再调用SessionMemoryCompact会话压缩 ↓ 压缩后Token仍超限 3. 最后调用FullCompact全量压缩 ↓ 压缩后仍超限 触发异常提示用户“上下文过长无法继续执行”七、实操练习实现简单的微压缩和会话压缩结合本节课所学实现微压缩本地截断和会话压缩简化版用固定摘要模拟LLM调用。public class SimpleCompactManager { // 微压缩保留最近3个工具结果 public ListString microCompact(ListString toolResults) { if (toolResults.size() 3) { return toolResults; } // 保留最近3个 return toolResults.subList(toolResults.size() - 3, toolResults.size()); } // 会话压缩简化版模拟LLM摘要 public String sessionCompact(ListString history, ListString toolResults) { // 模拟LLM摘要提炼核心信息 StringBuilder summary new StringBuilder(); summary.append(用户目标帮我写一个字符串反转工具类\n); summary.append(工具执行记录\n); for (String result : toolResults) { if (result.contains(读取文件)) { summary.append(- 读取文件成功确认项目为Spring Boot架构\n); } else if (result.contains(编码规范)) { summary.append(- 检查编码规范符合要求\n); } } summary.append(历史对话用户要求编写工具类Agent已完成前期准备\n); return summary.toString(); } // 测试 public static void main(String[] args) { SimpleCompactManager manager new SimpleCompactManager(); // 测试微压缩 ListString toolResults new ArrayList(); toolResults.add(读取文件1成功); toolResults.add(读取文件2成功); toolResults.add(读取文件3成功); toolResults.add(读取文件4成功); ListString compactedTools manager.microCompact(toolResults); System.out.println(微压缩后工具结果 compactedTools); // 测试会话压缩 ListString history new ArrayList(); history.add(用户帮我写一个字符串反转工具类); history.add(Agent好的我需要先读取你的项目结构); history.add(Agent已读取文件正在检查编码规范); String summary manager.sessionCompact(history, compactedTools); System.out.println(\n会话压缩后摘要 summary); } }八、本课重点总结1. 三层压缩的核心是“从浅到深、兼顾性能和信息完整性”避免简单截断导致的信息丢失2. 微压缩本地、无损耗→ 会话压缩AI摘要、低损耗→ 全量压缩兜底、有损耗逐步升级3. 关键设计点时间感知、提示词工程下节课预告第05课工具调用系统设计Tool Calling—— Agent的“手脚”如何设计可扩展的工具系统让Agent能执行文件操作、Shell命令、网络搜索等对应tool包下的接口和实现类源码解析。、熔断器保护这也是Claude Code压缩机制的优势所在。

更多文章