当前位置: 首页 > news >正文

Claude Code 源码分析(四):上下文窗口管理 —— 长对话场景下的 Token 预算与自动压缩

本系列文章基于 Claude Code 2.1.88 版本的 TypeScript 源码进行分析。源码版权归 Anthropic 所有,本文仅用于技术研究。

引言

上下文窗口管理是 AI 应用工程中最核心的挑战之一。Claude Code 作为一个长时间运行的终端助手,单次会话可能持续数小时、涉及数百次工具调用,上下文 token 消耗极易超出模型限制。src/services/compact/目录下的 11 个文件实现了一套完整的上下文预算管理方案,涵盖自动压缩触发、多策略压缩、熔断保护、token 估算等环节。

涉及的核心源码文件:

  • src/services/compact/autoCompact.ts—— 自动压缩触发与熔断
  • src/services/compact/compact.ts—— 压缩策略实现
  • src/services/compact/microCompact.ts—— 缓存级微压缩
  • src/services/compact/sessionMemoryCompact.ts—— 会话记忆压缩
  • src/services/compact/prompt.ts—— 压缩 prompt 模板
  • src/services/tokenEstimation.ts—— 多策略 token 估算
  • src/cost-tracker.ts—— 成本追踪

一、自动压缩触发机制

1.1 阈值计算

系统根据模型的上下文窗口大小动态计算压缩阈值。计算过程分为两步:

第一步,计算有效上下文窗口大小(扣除输出预留):

constMAX_OUTPUT_TOKENS_FOR_SUMMARY=20_000exportfunctiongetEffectiveContextWindowSize(model:string):number{constreservedTokensForSummary=Math.min(getMaxOutputTokensForModel(model),MAX_OUTPUT_TOKENS_FOR_SUMMARY)letcontextWindow=getContextWindowForModel(model,getSdkBetas())// 支持环境变量覆盖(用于测试)constautoCompactWindow=process.env.CLAUDE_CODE_AUTO_COMPACT_WINDOWif(autoCompactWindow){contextWindow=Math.min(contextWindow,parseInt(autoCompactWindow,10))}returncontextWindow-reservedTokensForSummary}

20,000 token 的预留基于生产数据——源码注释指出"p99.99 of compact summary output being 17,387 tokens"。

第二步,在有效窗口基础上扣除缓冲区:

exportconstAUTOCOMPACT_BUFFER_TOKENS=13_000exportfunctiongetAutoCompactThreshold(model:string):number{returngetEffectiveContextWindowSize(model)-AUTOCOMPACT_BUFFER_TOKENS}

1.2 多级警告

系统设置了四个递进的警告级别:

exportconstWARNING_THRESHOLD_BUFFER_TOKENS=20_000exportconstERROR_THRESHOLD_BUFFER_TOKENS=20_000exportconstMANUAL_COMPACT_BUFFER_TOKENS=3_000exportfunctioncalculateTokenWarningState(tokenUsage,model){return{percentLeft,// 剩余百分比isAboveWarningThreshold,// 距上限 20K tokensisAboveErrorThreshold,// 距上限 20K tokensisAboveAutoCompactThreshold,// 触发自动压缩isAtBlockingLimit,// 距上限 3K tokens(阻止新请求)}}

当 token 用量达到阻塞阈值(距上限仅 3,000 tokens)时,系统会阻止新的请求,强制用户手动压缩。

1.3 递归保护

自动压缩本身也是一次 API 调用,因此需要防止递归触发:

exportasyncfunctionshouldAutoCompact(messages,model,querySource){// 会话记忆提取和压缩本身不触发自动压缩if(querySource==='session_memory'||querySource==='compact'){returnfalse}// 上下文折叠代理不触发自动压缩if(feature('CONTEXT_COLLAPSE')){if(querySource==='marble_origami')returnfalse}}

源码注释解释了marble_origami(上下文折叠代理)被排除的原因:如果它的上下文膨胀触发了自动压缩,runPostCompactCleanup会调用resetContextCollapse(),而这会销毁主线程的已提交日志(因为是模块级共享状态)。


二、熔断机制

这是整个压缩系统中最具工程价值的设计之一。

constMAX_CONSECUTIVE_AUTOCOMPACT_FAILURES=3exportasyncfunctionautoCompactIfNeeded(messages,toolUseContext,...){// 熔断器:连续失败 N 次后停止重试if(tracking?.consecutiveFailures>=MAX_CONSECUTIVE_AUTOCOMPACT_FAILURES){return{wasCompacted:false}}try{constcompactionResult=awaitcompactConversation(...)return{wasCompacted:true,consecutiveFailures:0}// 成功则重置}catch(error){constnextFailures=(tracking?.consecutiveFailures??0)+1if(nextFailures>=MAX_CONSECUTIVE_AUTOCOMPACT_FAILURES){logForDebugging(`autocompact: circuit breaker tripped after${nextFailures}consecutive failures — skipping future attempts this session`)}return{wasCompacted:false,consecutiveFailures:nextFailures}}}

源码注释中记录了这一设计的数据驱动背景:

// BQ 2026-03-10: 1,279 sessions had 50+ consecutive failures // (up to 3,272) in a single session, wasting ~250K API calls/day globally.

在引入熔断器之前,当上下文不可恢复地超出限制时,系统会在每个 turn 都尝试压缩,最多一个会话内连续失败 3,272 次,全局每天浪费约 25 万次 API 调用。熔断器将最大重试次数限制为 3 次。


三、多策略压缩

3.1 压缩优先级

autoCompactIfNeeded中的压缩策略有明确的优先级:

// 优先尝试会话记忆压缩constsessionMemoryResult=awaittrySessionMemoryCompaction(messages,toolUseContext.agentId,threshold)if(sessionMemoryResult){// 会话记忆压缩成功,跳过传统压缩return{wasCompacted:true,compactionResult:sessionMemoryResult}}// 回退到传统对话压缩constcompactionResult=awaitcompactConversation(messages,...)

会话记忆压缩优先于传统压缩,因为它基于记忆提取而非简单截断,能保留更多有价值的上下文信息。

3.2 传统压缩的预处理

compact.ts中的传统压缩在调用 API 之前会进行多步预处理:

// 剥离消息中的图片内容functionstripImagesFromMessages(messages:Message[]):Message[]{...}// 清理重复注入的附件functionstripReinjectedAttachments(messages:Message[]):Message[]{...}// 针对 prompt-too-long 错误的紧急头部截断functiontruncateHeadForPTLRetry(messages:Message[]):Message[]{...}

3.3 微压缩

microCompact.ts实现了缓存级别的细粒度压缩,维护了 pending 和 pinned 两个编辑队列:

functionconsumePendingCacheEdits():CacheEdit[]{...}functiongetPinnedCacheEdits():PinnedCacheEdits[]{...}functionpinCacheEdits(edits:CacheEdit[]):void{...}

微压缩在 API 请求层面操作,通过编辑缓存中的内容来减少 token 消耗,粒度比对话级压缩更细。

3.4 按轮次分组

grouping.ts将消息按 API 轮次分组,确保压缩时不会在一个轮次的中间截断:

functiongroupMessagesByApiRound(messages:Message[]):Message[][]{...}

四、Token 估算

tokenEstimation.ts提供了多层次的 token 计数策略,在精度和性能之间做了梯度权衡。

4.1 API 精确计数

asyncfunctioncountTokensWithAPI(messages,model,systemPrompt):Promise<number>{...}

调用 Claude API 的 token counting 端点,精度最高但有网络延迟。

4.2 Haiku 回退

asyncfunctioncountTokensViaHaikuFallback(messages,systemPrompt):Promise<number>{...}

当主模型不可用时,使用 Haiku 模型估算。Haiku 的 tokenizer 与主模型相近,但调用成本更低。

4.3 粗略估算

functionroughTokenCountEstimation(text:string):number{// 默认 4 bytes per token}functionbytesPerTokenForFileType(fileExtension:string):number{// 不同文件类型的 bytes-per-token 比率不同// 代码文件通常比自然语言文本有更高的 bytes-per-token}

粗略估算按字节数计算,并根据文件类型调整比率。这是最快的估算方式,用于不需要精确计数的场景。

4.4 Bedrock 计数

asyncfunctioncountTokensWithBedrock({messages,model}):Promise<number>{...}

针对 AWS Bedrock 部署的专用计数端点。


五、成本追踪

cost-tracker.ts实现了按模型的 token 用量和费用追踪。

5.1 核心功能

functionaddToTotalModelUsage(model,inputTokens,outputTokens){...}functionaddToTotalSessionCost(cost){...}functionformatModelUsage():string{...}// 格式化各模型用量functionformatTotalCost():string{...}// 格式化总费用functionformatCost(cost,maxDecimalPlaces):string{...}

5.2 会话恢复

functiongetStoredSessionCosts(sessionId):StoredCosts|null{...}functionrestoreCostStateForSession(sessionId):boolean{...}functionsaveCurrentSessionCosts(fpsMetrics?):void{...}

成本状态支持跨会话持久化和恢复,确保用户在恢复会话时能看到累计的费用统计。


六、Prompt Cache 感知

压缩系统与 prompt cache 机制紧密集成。每次压缩后都会通知 cache 检测系统:

if(feature('PROMPT_CACHE_BREAK_DETECTION')){notifyCompaction(querySource??'compact',toolUseContext.agentId)}

源码注释解释了这一设计的必要性:

// Reset cache read baseline so the post-compact drop isn't flagged // as a break. BQ 2026-03-01: missing this made 20% of // tengu_prompt_cache_break events false positives

压缩会导致 prompt cache 命中率下降,如果不重置基线,cache 监控系统会将这种正常下降误报为 cache 中断。在引入这一修复之前,20% 的 cache 中断告警是误报。


七、与其他系统的协同

7.1 与上下文折叠的互斥

当上下文折叠(Context Collapse)功能启用时,自动压缩会被禁用:

if(feature('CONTEXT_COLLAPSE')){const{isContextCollapseEnabled}=require('../contextCollapse/index.js')if(isContextCollapseEnabled())returnfalse}

源码注释详细解释了原因:上下文折叠在 90% 时提交、95% 时阻塞,而自动压缩在约 93% 时触发。两者会竞争,自动压缩通常先触发,会销毁折叠系统正在保存的细粒度上下文。

7.2 与会话记忆的协同

压缩完成后会重置会话记忆的状态:

// Reset lastSummarizedMessageId since compaction replaces all messages// and the old message UUID will no longer existsetLastSummarizedMessageId(undefined)

压缩会替换消息列表,旧的消息 UUID 不再存在,因此记忆系统的"上次总结位置"标记需要重置。


八、总结

Claude Code 的上下文窗口管理系统展示了一套经过生产验证的方案。其核心设计决策可以归纳为:

其一,数据驱动的参数选择。20,000 token 的输出预留基于 p99.99 统计,熔断阈值 3 次基于全局 API 调用浪费的量化分析。这些参数不是拍脑袋决定的,而是来自生产环境的持续监控。

其二,多策略梯度降级。从会话记忆压缩到传统压缩,从 API 精确计数到粗略估算,系统在每个环节都提供了降级方案,确保在各种条件下都能正常工作。

其三,系统间的协同设计。压缩系统与 prompt cache、上下文折叠、会话记忆等系统之间有明确的协同规则和互斥关系,避免了多个系统同时操作上下文导致的冲突。

其四,熔断保护防止级联故障。当压缩持续失败时,熔断器及时止损,避免了无效的 API 调用浪费。这种防御性编程在 AI 应用中尤为重要,因为 API 调用既有延迟又有成本。

对于正在构建长对话 AI 应用的团队,这套系统最值得借鉴的是熔断机制的设计——在 AI 应用中,"知道何时停止重试"与"知道何时触发操作"同样重要。

http://www.jsqmd.com/news/575053/

相关文章:

  • 如何快速实现手机号码定位查询:3步掌握号码地理位置追踪技术
  • 二分法(Binary Search)
  • 【IDEA插件开发】实战指南系列01 从零构建你的第一个Action插件
  • 如何3分钟搞定Windows苹果驱动:终极免费解决方案
  • OpenClaw本地知识库整合:百川2-13B-4bits模型增强问答准确性
  • Bash脚本并行执行命令的3种实战方法对比(含性能测试)
  • Phi-4-mini-reasoning开源镜像部署:免配置一键启动数学推理服务
  • 解锁Windows全版本安装自由:MediaCreationTool.bat实战指南
  • MRIcroGL:3步掌握开源医学影像3D可视化工具,让诊断更直观
  • 像素风AI终端作品集:Ostrakon-VL-8B在餐饮门店清洁度评估中的实际效果
  • 深度解析MediaCreationTool.bat:Windows部署自动化的架构设计与实现原理
  • 案例5_1:单位数码管显示
  • OpenClaw多终端同步:Qwen2.5-VL-7B任务状态跨设备查看
  • 阿里小云KWS模型多语言支持实战:中英文混合唤醒
  • 5个强力技巧让D3KeyHelper成为你的暗黑3自动化好帮手
  • Java函数计算监控告警体系搭建(Prometheus+OpenTelemetry+自定义TraceID透传),全链路可观测性终极方案
  • KeyarchOS适配seren-0.0.21-1
  • 像素史诗效果展示:支持插入SVG矢量图与交互式图表的研报输出样例
  • Windows Cleaner深度技术解析:Python驱动的系统优化解决方案
  • Phi-4-mini-reasoning惊艳效果:自然语言→一阶逻辑→Z3可验证表达式转换
  • 如何在Linux和Windows上安装配置WPS-Zotero插件:科研工作者的终极解决方案
  • 次元画室与IDE高效联动:在VSCode或IDEA中快速预览生成结果
  • 3步打造智能家居音乐自由:给爱好者的开源方案详解
  • 快速验证openclaw抓取能力:用快马一键生成部署原型
  • 新手福音:在快马平台用ai生成代码轻松学透can协议基础
  • 文墨共鸣使用避坑指南:避免这3个误区让分析更准确
  • 马上深挖!!!三段逆置如何实现数组轮转?!用最简单的话让你秒懂
  • 3个步骤实现Office文档在线预览:解决Web应用中的文件查看难题
  • 新手入门:在快马平台生成代码,理解智能应用控制警告的模拟实现
  • Graphormer多场景教程:学术论文配图生成、课程教学演示、项目原型开发