S05: Context Compression 上下文压缩
"Context is finite, but conversation is infinite" -- 压缩是长对话的生存之道。
Harness 层: Compact -- 让对话突破上下文限制。
🎯 问题
Agent Loop 持续累积消息:
- 模型有上下文窗口限制 (200K tokens)
- 消息累积会超出限制
- 重要信息可能被截断
- API 成本随 token 增长
💡 解决方案
Claude Code 实现了多层压缩策略:
Token Usage
│
├── < Warning ──────── 提醒用户
│
├── < AutoCompact ──── 自动压缩
│
└── < Error ────────── 强制压缩
📐 阈值计算
// 源码位置: src/services/compact/autoCompact.ts
const MAX_OUTPUT_TOKENS_FOR_SUMMARY = 20_000
const AUTOCOMPACT_BUFFER_TOKENS = 13_000
function getAutoCompactThreshold(model: string): number {
const contextWindow = getContextWindowForModel(model)
const effectiveWindow = contextWindow - MAX_OUTPUT_TOKENS_FOR_SUMMARY
return effectiveWindow - AUTOCOMPACT_BUFFER_TOKENS
}
🔑 压缩类型
Auto Compact
自动触发压缩
Manual /compact
用户手动触发
Micro Compact
特定消息压缩
Memory Compact
会话记忆压缩
📊 压缩流程
// 源码位置: src/services/compact/compact.ts
async function compact(
messages: Message[],
config: CompactConfig
): Promise {
// 1. 执行预压缩 hooks
await executePreCompactHooks(messages)
// 2. 分析上下文
const analysis = analyzeContext(messages)
// 3. 生成摘要
const summary = await generateSummary(messages, analysis)
// 4. 创建压缩边界消息
const boundaryMessage = {
role: 'system',
type: 'compact_boundary',
content: summary,
originalMessages: messages,
tokenStats: { before, after, saved }
}
// 5. 替换历史
const newMessages = [boundaryMessage, ...messages.slice(-keepRecent)]
return { messages: newMessages, stats }
}