ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Claude Code源码剖析 - 上下文压缩机制与compact触发链路拆解

Claude Code源码剖析 - 上下文压缩机制与compact触发链路拆解 1. 为什么你的 Claude Code 会话会突然“失忆”如果你用 Claude Code 跑过稍长的任务大概率遇到过这种场景前面聊得好好的让它读几个文件、跑几轮 Bash、再改点代码突然某一轮它开始答非所问或者干脆报一个 prompt too long 的错误。很多人第一反应是“模型不行了”其实这跟模型能力没关系是上下文窗口被塞满了。Claude Code 的上下文压缩机制就是专门解决这个问题的。它不是简单地把旧消息删掉而是在 Agent Loop 每一轮调用模型之前动态整理一份“模型真正能看到的上下文视图”。这份视图要同时满足几个约束不能超过上下文窗口、不能破坏 tool_use 和 tool_result 的配对、不能丢掉文件状态和技能状态、还要尽量复用 prompt cache 省成本。这套机制对谁有用如果你只是偶尔问几句代码问题感知不强。但只要你用 Claude Code 做长期编码、跑 Agent 任务、或者接 MCP 工具链压缩行为就会直接影响你的体验和账单。本文会从 compact 的触发条件切入把 prompt cache 和压缩策略的协作关系讲清楚最后给你一份可复制的 settings.json 配置骨架和验证步骤让你在本地就能复现压缩行为、观察上下文变化。需要先说明一点Claude Code 的部分压缩模块在公开快照里实现文件不完整比如 contextCollapse、snipCompact、reactiveCompact 这几个。所以本文对这些模块只依据真实调用点和注释解释它们在架构里的位置不编造内部实现。能验证的部分我会给你可跑的步骤不能验证的部分我会明确标注。2. 前置准备TaoToken 接入与 Claude Code 环境2.1 为什么需要 TaoTokenClaude Code 本身是一个 CLI 工具它需要调用 Anthropic 的模型 API。如果你直接用自己的账号配置和计费都比较麻烦。TaoToken 提供的是兼容 Anthropic 协议的 API 接入层你只需要把 base URL 和 API Key 配好Claude Code 就能正常跑起来。官网地址是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 端点是 https://taotoken.net/api 。注意 API 地址后面不加 UTM 参数直接用它就行。2.2 获取 API Key打开 https://taotoken.net/api-keys 登录后创建一个新的 API Key。建议给这个 Key 起个能识别的名字比如 “claude-code-local”方便后面排查问题时区分。创建完复制出来后面配置要用。如果你还没决定用哪个模型可以先到 https://taotoken.net/models 看看当前支持的模型列表。Claude Code 对模型有要求不是所有模型都能跑 Agent Loop选的时候注意看说明。2.3 安装 Claude CodeClaude Code 通过 npm 安装命令如下npm install -g anthropic-ai/claude-code安装完成后验证一下版本claude --version如果提示找不到命令检查一下 npm 全局 bin 目录是否在 PATH 里。macOS 和 Linux 一般是/usr/local/bin或~/.npm-global/binWindows 的话看 npm 的 prefix 配置。2.4 配置环境变量Claude Code 读取的是 Anthropic 标准的环境变量。你可以在 shell 配置文件里加上export ANTHROPIC_BASE_URLhttps://taotoken.net/api export ANTHROPIC_API_KEY你的API KeyWindows PowerShell 的话用$env:ANTHROPIC_BASE_URLhttps://taotoken.net/api $env:ANTHROPIC_API_KEY你的API Key配完之后开一个新终端跑claude看看能不能正常进入交互界面。如果报认证错误先检查 Key 有没有复制完整再检查 base URL 有没有多余斜杠。3. 可复制配置settings.json 骨架与压缩相关参数3.1 settings.json 的位置Claude Code 的配置文件分几个层级。项目级配置放在项目根目录的.claude/settings.json用户级配置放在~/.claude/settings.json。压缩相关的参数建议放在项目级这样不同项目可以有不同的策略。先创建目录mkdir -p .claude3.2 压缩相关配置骨架下面这份配置可以直接复制我逐段解释每个参数的作用{ env: { ANTHROPIC_BASE_URL: https://taotoken.net/api, ANTHROPIC_API_KEY: 你的API Key, CLAUDE_CODE_AUTO_COMPACT_WINDOW: 180000, CLAUDE_AUTOCOMPACT_PCT_OVERRIDE: 85 }, autoCompact: { enabled: true, bufferTokens: 13000, maxConsecutiveFailures: 3 }, microCompact: { enabled: true, keepRecent: 2, gapThresholdMinutes: 30 }, permissions: { allow: [ Read, Grep, Glob ] } }CLAUDE_CODE_AUTO_COMPACT_WINDOW这个环境变量用来覆盖模型默认的上下文窗口大小。比如模型本身支持 200k你设成 180000那 effective context window 就会按 180k 来算。这个值在你用第三方接入、实际可用窗口和标称不一致时特别有用。CLAUDE_AUTOCOMPACT_PCT_OVERRIDE是按百分比触发压缩。设成 85 表示用到 effective window 的 85% 就触发。注意源码里这个百分比阈值会和默认的 buffer 阈值取较小值所以设太高可能不生效。autoCompact.bufferTokens对应源码里的AUTOCOMPACT_BUFFER_TOKENS默认 13000。这个 buffer 是为了防止临界点附近反复触发压缩。microCompact.keepRecent控制 time-based microcompact 至少保留几个最近的工具结果。源码里是Math.max(1, config.keepRecent)所以设 0 也会至少保留 1 个。microCompact.gapThresholdMinutes是判断 prompt cache 是否已经冷掉的时间阈值。如果距离上一条 assistant 消息超过这个分钟数就认为 cache 冷了可以直接替换本地工具结果内容。3.3 验证配置是否生效配好之后在项目目录下启动 Claude Code然后输入/config它会列出当前生效的配置项。检查一下 autoCompact 和 microCompact 相关的值是不是你设的。如果没生效可能是配置文件路径不对或者 JSON 格式有语法错误。可以用python -m json.tool .claude/settings.json验证一下 JSON 合法性。4. 验证请求复现 compact 触发并观察上下文变化4.1 构造一个会触发压缩的场景要观察压缩行为最直接的办法是人为把上下文撑大。你可以创建一个测试项目里面放几个大文件然后让 Claude Code 反复读取。先造几个大文件mkdir -p /tmp/compact-test for i in $(seq 1 20); do python3 -c import random, string with open(/tmp/compact-test/bigfile_$i.txt, w) as f: for _ in range(5000): f.write(.join(random.choices(string.ascii_letters , k80)) \n) done这样会生成 20 个大约 400KB 的文本文件。然后在/tmp/compact-test目录下启动 Claude Codecd /tmp/compact-test claude4.2 触发读取并观察在 Claude Code 里输入请依次读取 bigfile_1.txt 到 bigfile_20.txt每读完一个告诉我文件里大概有多少行。Claude Code 会开始一轮一轮地调用 Read 工具。你注意观察几个现象第一当读取到一定数量后界面可能会提示 “Compacting conversation” 或者类似的字样。这就是 autocompact 被触发了。第二压缩之后你再问它 “刚才第一个文件有多少行”它可能答不上来因为那部分历史已经被 summary 替代了。第三如果你开了 verbose 模式能看到 token 计数的变化。启动时加--verboseclaude --verbose4.3 手动触发 compact除了自动触发你也可以手动触发。在 Claude Code 里输入/compact这会立即对当前会话做一次压缩。如果你想在压缩时附加说明可以带上参数/compact 重点保留文件读取的结论可以丢掉原始内容这个 customInstructions 会传给 compact prompt影响 summary 的生成方向。4.4 观察 compact boundary压缩发生后会话里会插入一条 compact boundary 消息。这条消息在 UI 上可能显示为 “Conversation compacted”但它的本质是一条 system messagesubtype 是compact_boundary。你可以通过查看 transcript 文件来确认。Claude Code 的会话记录一般存在~/.claude/projects/下面按项目路径分目录。找到对应的 jsonl 文件搜索compact_boundarygrep -r compact_boundary ~/.claude/projects/ | head -5你应该能看到类似这样的结构{ type: system, subtype: compact_boundary, content: Conversation compacted, compactMetadata: { trigger: auto, preTokens: 152340, messagesSummarized: 47 } }trigger字段告诉你这次是手动还是自动触发的preTokens是压缩前的 token 数messagesSummarized是被总结掉的消息数量。这三个字段是验证压缩行为最直接的证据。4.5 验证 prompt cache 协作prompt cache 和压缩的协作关系体现在 microcompact 的两种路径上。cache 热的时候走 cached microcompact只发 cache_edits 给服务端本地消息不动cache 冷的时候走 time-based microcompact直接替换本地工具结果内容。要观察这个差异你可以这样做先让 Claude Code 读几个文件然后立刻间隔小于 gapThresholdMinutes再让它读几个这时候 cache 是热的。然后再等超过阈值时间再读几个这时候 cache 应该已经冷了。在 verbose 输出里你能看到 cache 相关的统计比如 cache read tokens 和 cache creation tokens。cache 热的时候 cache read 会很高冷的时候会看到 cache creation 重新出现。5. 本篇常见错排查5.1 配置了但压缩不触发最常见的原因是 effective context window 算出来比你想的大。比如你设了CLAUDE_CODE_AUTO_COMPACT_WINDOW180000但模型实际窗口只有 100k那Math.min会取 100k再减去 summary 预留的 20k 和 buffer 13k实际触发阈值只有 67k 左右。排查方法在 Claude Code 里跑/config看它报告的 context window 是多少。如果和你预期不符检查环境变量有没有被 shell 覆盖或者 settings.json 里的 env 有没有被更高优先级的配置覆盖。5.2 压缩后工具调用报错如果你看到类似 “tool_result references non-existent tool_use” 的错误说明压缩时切断了 tool_use 和 tool_result 的配对。正常情况下 Claude Code 的adjustIndexToPreserveAPIInvariants会防止这种情况但如果你的配置里keepRecent设得太小或者手动 compact 时 customInstructions 让模型丢掉了关键配对信息就可能出问题。解决办法把microCompact.keepRecent调到 3 以上手动 compact 时不要让它丢掉工具调用相关的消息。如果已经出错了用/compact重新压一次或者直接开新会话。5.3 连续压缩失败源码里有MAX_CONSECUTIVE_AUTOCOMPACT_FAILURES 3的熔断机制。如果你看到日志里连续出现 compact 失败然后就不再尝试压缩了说明已经触发了熔断。常见失败原因有两个一是 compact 请求自己就 prompt too long这时候源码会尝试truncateHeadForPTLRetry截断头部重试二是 summary 生成时模型返回了错误。如果是后者检查一下你的 API Key 额度是否充足或者模型是否支持长输出。5.4 session memory compact 不生效session memory compact 是实验路径需要 feature flag 开启。如果你配了相关参数但没看到效果先确认shouldUseSessionMemoryCompaction()返回的是不是 true。这个函数依赖 feature flag 和 session memory 文件的存在。排查方法检查~/.claude/下面有没有 session memory 相关的文件。如果没有说明 session memory 还没被初始化自然走不了这条路径。这时候会回退到传统的compactConversation属于正常行为。5.5 cache_edits 没生效cached microcompact 需要模型支持 cache editing。如果你用的模型不支持isModelSupportedForCacheEditing(model)会返回 false然后直接跳过 cached 路径。排查方法在 verbose 日志里搜索 “cachedMicrocompact” 或 “cache_edits”。如果完全没出现说明要么模型不支持要么isMainThreadSource(querySource)返回了 false比如你在子 agent 里跑。这种情况下压缩会走 time-based 路径或者直接交给 autocompact。6. 继续深入从验证到长期使用把上面的步骤跑通之后你对 Claude Code 的压缩机制应该有了直观感受。接下来如果想长期用这套东西做编码有几个方向可以继续。第一把压缩策略和你的工作流对齐。如果你经常做长会话重构可以把bufferTokens调大一点让压缩触发得晚一些保留更多原始上下文。如果你更在意成本可以把CLAUDE_AUTOCOMPACT_PCT_OVERRIDE调低让压缩更早发生。第二关注 prompt cache 的命中率。cache 命中率高的时候cached microcompact 能帮你省不少 token。你可以在 verbose 输出里定期看一下 cache read 和 cache creation 的比例如果 cache creation 一直很高说明 cache 频繁失效可能需要调整会话节奏。第三如果你要跑 Agent 任务建议用 Coding Plan 而不是按量计费。Coding Plan 的入口在 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding_planutm_campaignrewrite 适合长期编码和 Agent 场景。按量计费在压缩频繁触发的时候成本波动比较大包月方案更可控。第四接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 里面有针对 Claude Code 的详细配置说明包括不同操作系统的环境变量设置和常见问题。如果你在配置过程中遇到本文没覆盖的问题可以先查文档。最后提醒一点压缩机制的核心目标是让 Agent Loop 能持续运行而不是单纯省 token。所以你在调参的时候优先保证任务能跑完其次才考虑成本优化。把maxConsecutiveFailures设得太低会导致压缩失败后直接放弃反而影响任务完成率。
返回列表