Claude 的上下文窗口有限 (200K tokens)。当对话变长时,必须智能压缩以保持工作效率。
一、核心问题
对话开始: [System(5K)] [User(1K)] [Assistant(2K)] = 8K tokens ✅ 轻松
50 轮后: [System(5K)] [50轮对话(180K)] [新消息(15K)] = 200K tokens ❌ 溢出!
|
解决方案: 自动检测 → 压缩 → 继续工作
二、压缩系统架构
services/compact/ ├── autoCompact.ts — 自动压缩触发逻辑 ├── compact.ts — 压缩核心算法 (1706 行) ├── microCompact.ts — 微压缩 (单条消息级别) ├── apiMicrocompact.ts — API 侧微压缩 ├── grouping.ts — 消息分组策略 ├── prompt.ts — 压缩用的 prompt 模板 ├── postCompactCleanup.ts — 压缩后清理 ├── sessionMemoryCompact.ts — 会话记忆压缩 ├── compactWarningHook.ts — 压缩警告 hook └── compactWarningState.ts — 警告状态管理
|
三、阈值计算
const AUTOCOMPACT_BUFFER_TOKENS = 13_000; const WARNING_THRESHOLD_BUFFER_TOKENS = 20_000; const MAX_OUTPUT_TOKENS_FOR_SUMMARY = 20_000;
export function getEffectiveContextWindowSize(model: string): number { const contextWindow = getContextWindowForModel(model); const reserved = Math.min(getMaxOutputTokensForModel(model), MAX_OUTPUT_TOKENS_FOR_SUMMARY); return contextWindow - reserved; }
export function getAutoCompactThreshold(model: string): number { return getEffectiveContextWindowSize(model) - AUTOCOMPACT_BUFFER_TOKENS; }
|
Token 警告阈梯
0 ────────────────────────── 100% ├─────────────────────────┤ │ │ │ 正常工作区域 │ │ │ ├─────────────────────────┤ ← 自动压缩阈值 (~83.5%) │ 自动压缩触发区域 │ ├─────────────────────────┤ ← 警告阈值 (~90%) │ ⚠️ 警告:空间即将耗尽 │ ├─────────────────────────┤ ← 错误阈值 (~90%) │ ❌ 错误:必须立即压缩 │ └─────────────────────────┘ ← 200K (上下文窗口)
|
四、压缩算法 (compact.ts)
4.1 核心流程
export async function compactConversation( messages: Message[], context: CompactContext, ): Promise<CompactionResult> {
const activeMessages = getMessagesAfterCompactBoundary(messages);
const summaryPrompt = buildCompactPrompt(activeMessages, context);
const summary = await runForkedAgent(summaryPrompt, { model: context.model, maxTokens: COMPACT_MAX_OUTPUT_TOKENS, });
const compactedMessages = buildPostCompactMessages( messages, summary, activeMessages, );
await runPostCompactCleanup(compactedMessages, context);
return { compactedMessages, removedCount: activeMessages.length, savedTokens: estimateTokensSaved(activeMessages, summary), }; }
|
4.2 压缩 Prompt 策略
function buildCompactPrompt(messages: Message[]): string { return ` 请将以下对话历史压缩为一个简洁但完整的摘要。
要求: 1. 保留所有重要的技术决策和代码变更 2. 保留文件路径和关键代码片段 3. 保留当前工作状态和未完成的任务 4. 保留用户的偏好和约束条件 5. 丢弃冗余的工具输出和中间步骤 6. 如果有被拒绝的操作,保留拒绝原因
当前对话包含 ${messages.length} 条消息, 请将其压缩为一个清晰的摘要。 `; }
|
4.3 压缩后消息结构
压缩前: [System] [User1] [Asst1] [Tool1] [User2] [Asst2] ... [User50] [Asst50]
压缩后: [System] [CompactBoundary: "以下是之前对话的摘要: ..."] [User50] [Asst50] └─ 包含前 49 轮的精华摘要
CompactBoundary 消息格式: { type: 'system', subtype: 'compact_boundary', content: "## 对话摘要\n\n### 已完成的工作\n- 修复了 X bug...\n### 当前状态\n- 正在处理 Y..." }
|
五、微压缩 (Micro-Compact)
大型工具结果的就地压缩,不触发完整的对话压缩:
export function microCompactToolResult( toolResult: string, maxTokens: number, ): string { if (tokenCount(toolResult) <= maxTokens) { return toolResult; }
return truncateWithContext(toolResult, maxTokens); }
|
六、上下文分析
export function analyzeContext(messages: Message[]): ContextAnalysis { return { totalTokens: tokenCountWithEstimation(messages), messageCount: messages.length, toolCallCount: countToolCalls(messages),
breakdown: { systemPrompt: systemPromptTokens, userMessages: userTokens, assistantMessages: assistantTokens, toolResults: toolResultTokens, attachments: attachmentTokens, },
largestMessages: findLargestMessages(messages, 10),
recommendation: totalTokens > threshold ? 'compact_now' : 'ok', }; }
|
七、Snip 机制 (HISTORY_SNIP feature)
一种更激进的压缩方式——直接裁剪历史:
function snipHistory(messages: Message[], keepRecent: number): Message[] { const snipPoint = messages.length - keepRecent; const tombstone = createTombstoneMessage(`Snipped ${snipPoint} messages`); return [tombstone, ...messages.slice(snipPoint)]; }
|
八、自动压缩的断路器
const MAX_CONSECUTIVE_AUTOCOMPACT_FAILURES = 3;
|
九、Recompaction (再压缩)
type RecompactionInfo = { isRecompaction: boolean; previousSummary: string; turnsSinceLastCompaction: number; };
|
十、Session Memory Compact
export async function trySessionMemoryCompaction( messages: Message[], summary: string, ): Promise<void> { }
|