# 第四阶段 · 模块四 · 第二节:上下文压缩机制
上下文压缩是如何工作的?autoCompact 的触发条件是什么?压缩后的消息格式是什么样的?
Claude Code 全局架构
┌─────────────────────────────────────────────────────────────────────┐
│ 查询引擎层 │
│ │
│ query() │
│ └── autoCompact() ──> 上下文压缩 ← 本节 │
└─────────────────────────────────────────────────────────────────────┘
问题:上下文长度有限制
限制:
- Claude Opus: 200K tokens
- Claude Sonnet: 200K tokens
- Claude Haiku: 200K tokens
长时间对话会耗尽上下文。
解决方案:compact
- 将历史消息压缩为摘要
- 保留关键信息(决策、结论)
- 释放上下文空间
┌─────────────────────────────────────────────────────────────────────┐
│ 原始消息历史 │
│ │
│ [用户] Hello │
│ [助手] Hi! How can I help? │
│ [助手] Let me read the file... │
│ [工具] File content... │
│ [助手] The file contains... │
│ ... (100+ messages) │
└─────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ 压缩后的消息 │
│ │
│ [系统] Conversation summary: User asked about the codebase... │
│ [助手] The file contains... │
│ ... (最新消息) │
└─────────────────────────────────────────────────────────────────────┘
源码位置:`src/services/compact/compact.ts`
// 触发阈值
const AUTO_COMPACT_THRESHOLD = 0.8; // 80%
// 检查函数
function shouldAutoCompact(contextUsage: number): boolean {
return contextUsage > AUTO_COMPACT_THRESHOLD;
}
问 1:为什么不等到 100% 再压缩?
// 问题:API 需要预留空间给:
// 1. 助手的新回复
// 2. 工具调用的结果
// 3. 系统提示词
// 如果等到 100%:
// - 可能无法生成完整回复
// - 工具结果可能放不下
// - 需要紧急压缩,用户体验差
// 80% 阈值留出缓冲空间
问 2:如何检测上下文使用量?
// 计算当前上下文使用的 token 数
async function getContextUsage(): Promise<number> {
const messages = mutableMessages;
const tokenCount = await countTokens(messages);
const modelLimit = getModelLimit();
return tokenCount / modelLimit;
}
问 3:用户可以禁用 autoCompact 吗?
// 环境变量禁用
process.env.DISABLE_AUTO_COMPACT = '1';
// 命令行标志
/claude --no-auto-compact
问 4:autoCompact 和 /compact 的区别?
| 方面 | autoCompact | /compact |
| 触发 | 自动 | 手动 |
| 时机 | 上下文达到 80% | 用户决定 |
| 提示 | 无 | 有 |
问 5:压缩会丢失信息吗?
// 压缩策略:保留关键信息
interface CompressionStrategy {
preserve: [
'decisions', // 关键决策
'conclusions', // 结论
'preferences', // 用户偏好
'current_work', // 当前工作
];
summarize: [
'discussion', // 讨论过程
'exploration', // 探索过程
'refinement', // 迭代过程
];
}
function evaluateMessageImportance(message: Message): number {
// 高重要性:包含决策、结论
if (containsDecision(message)) return 1.0;
if (containsConclusion(message)) return 1.0;
// 中重要性:用户指令、工具结果
if (message.type === 'user') return 0.8;
if (message.type === 'tool_result') return 0.6;
// 低重要性:讨论过程
if (isDiscussion(message)) return 0.3;
return 0.5; // 默认
}
async function generateSummary(messages: Message[]): Promise<string> {
// 调用模型生成摘要
const summary = await model.generate({
system: 'Summarize the conversation concisely. Include: decisions made, current state, and key conclusions.',
messages: messages,
});
return summary;
}
问 1:压缩后的消息格式?
// 创建压缩边界消息
interface SystemCompactBoundaryMessage {
type: 'system';
subtype: 'compact_boundary';
content: string; // 摘要内容
timestamp: number;
}
// 添加到消息历史
mutableMessages = [
{
type: 'system',
subtype: 'compact_boundary',
content: 'Summary: User asked about... Assistant analyzed...',
timestamp: Date.now(),
},
// 最新消息
];
问 2:工具调用的结果如何保留?
// 工具结果通常很重要,优先保留
function shouldPreserveToolResult(message: Message): boolean {
// 读取文件的结果保留
if (message.tool_name === 'Read') return true;
// 写入/修改文件的结果可能关键
if (message.tool_name === 'Write') return true;
// 搜索结果可以压缩
if (message.tool_name === 'Grep') return false;
return true;
}
问 3:压缩会改变消息顺序吗?
// 不改变消息顺序
// 只在开头添加摘要消息
[messages before compact]
↓
[{summary}, ...messages_after_boundary]
↓
[messages after compact - only new messages]
// 压缩前
User: "Read the file"
Assistant: "The file contains..."
User: "Now explain it"
Assistant: "The file describes..."
// 压缩后
[Summary] User asked about the file. Assistant read and analyzed it.
User: "Now explain it"
Assistant: "The file describes..."
问 1:模型能区分压缩前后的消息吗?
// 通过摘要告诉模型上下文
{
type: 'system',
subtype: 'compact_boundary',
content: 'Earlier in the conversation, you read a file and analyzed it...'
}
问 2:压缩后能回退吗?
// 不支持回退
// /clear 不可恢复
// /compact 不可恢复
// 建议用户:如果要保留历史,使用 /resume
问 3:压缩的成本?
// 压缩本身需要一次 API 调用
// 成本:约 100-500 tokens(摘要生成)
// 收益:释放 50-80% 的上下文空间
// 总体来看是值得的
答案:
try {
await compact();
} catch (error) {
// 如果压缩失败,尝试部分压缩
await partialCompact();
// 或者提示用户
displayWarning('Context is full. Please use /clear to continue.');
}
答案:
1. 增量压缩:只压缩超过阈值的内容
2. 智能摘要:保留关键信息
3. 分块压缩:分段压缩,避免单次大量丢失
答案:
// 工具执行结果在压缩前被评估
// 重要的结果被保留在摘要中
// 示例:
// Read('a.txt') → 保留在摘要
// Grep('pattern') → 可能被压缩
| 文件 | 核心内容 |
| `src/services/compact/compact.ts` | 压缩实现 |
| `src/commands/compact/` | /compact 命令 |
下一节我们将深入 上下文与工具调用:
- 工具结果如何影响上下文
- 上下文中的工具历史
- 工具调用与状态管理
*- 第一轮:□ 事实准确性*
*- 第二轮:□ 深度与洞见*
*- 第三轮:□ 可读性与价值*