☰
Claude Code源码剖析 - 上下文压缩机制与compact触发链路拆解
2026/9/29 20:25:17 网站建设 项目流程

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 为什么需要 TaoToken

Claude Code 本身是一个 CLI 工具,它需要调用 Anthropic 的模型 API。如果你直接用自己的账号,配置和计费都比较麻烦。TaoToken 提供的是兼容 Anthropic 协议的 API 接入层,你只需要把 base URL 和 API Key 配好,Claude Code 就能正常跑起来。

官网地址是 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_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 Code

Claude Code 通过 npm 安装,命令如下:

npm install -g @anthropic-ai/claude-code

安装完成后验证一下版本:

claude --version

如果提示找不到命令,检查一下 npm 全局 bin 目录是否在 PATH 里。macOS 和 Linux 一般是/usr/local/bin或~/.npm-global/bin,Windows 的话看 npm 的 prefix 配置。

2.4 配置环境变量

Claude Code 读取的是 Anthropic 标准的环境变量。你可以在 shell 配置文件里加上:

export ANTHROPIC_BASE_URL="https://taotoken.net/api" export ANTHROPIC_API_KEY="你的API Key"

Windows PowerShell 的话用:

$env:ANTHROPIC_BASE_URL="https://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 .claude

3.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 + ' ', k=80)) + '\n') " done

这样会生成 20 个大约 400KB 的文本文件。然后在/tmp/compact-test目录下启动 Claude Code:

cd /tmp/compact-test claude

4.2 触发读取并观察

在 Claude Code 里输入:

请依次读取 bigfile_1.txt 到 bigfile_20.txt,每读完一个告诉我文件里大概有多少行。

Claude Code 会开始一轮一轮地调用 Read 工具。你注意观察几个现象:

第一,当读取到一定数量后,界面可能会提示 “Compacting conversation” 或者类似的字样。这就是 autocompact 被触发了。

第二,压缩之后,你再问它 “刚才第一个文件有多少行”,它可能答不上来,因为那部分历史已经被 summary 替代了。

第三,如果你开了 verbose 模式,能看到 token 计数的变化。启动时加--verbose:

claude --verbose

4.3 手动触发 compact

除了自动触发,你也可以手动触发。在 Claude Code 里输入:

/compact

这会立即对当前会话做一次压缩。如果你想在压缩时附加说明,可以带上参数:

/compact 重点保留文件读取的结论,可以丢掉原始内容

这个 customInstructions 会传给 compact prompt,影响 summary 的生成方向。

4.4 观察 compact boundary

压缩发生后,会话里会插入一条 compact boundary 消息。这条消息在 UI 上可能显示为 “Conversation compacted”,但它的本质是一条 system message,subtype 是compact_boundary。

你可以通过查看 transcript 文件来确认。Claude Code 的会话记录一般存在~/.claude/projects/下面,按项目路径分目录。找到对应的 jsonl 文件,搜索compact_boundary:

grep -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_WINDOW=180000,但模型实际窗口只有 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_source=taotoken_aicg_blog_end&utm_content=coding_plan&utm_campaign=rewrite ,适合长期编码和 Agent 场景。按量计费在压缩频繁触发的时候成本波动比较大,包月方案更可控。

第四,接入文档在 https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite ,里面有针对 Claude Code 的详细配置说明,包括不同操作系统的环境变量设置和常见问题。如果你在配置过程中遇到本文没覆盖的问题,可以先查文档。

最后提醒一点:压缩机制的核心目标是让 Agent Loop 能持续运行,而不是单纯省 token。所以你在调参的时候,优先保证任务能跑完,其次才考虑成本优化。把maxConsecutiveFailures设得太低会导致压缩失败后直接放弃,反而影响任务完成率。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询