Claude Code CLI 源码深度解析:从 Prompt 缓存到工业级 AI Agent 架构
最近,Claude Code CLI 的源码意外泄露。
看完源码才发现:这不是”Prompt 工程”那么简单,而是缓存架构 + 自我进化记忆 + 多模式编排的完整基础设施。
这才是为什么 Claude Code 能支持无限长对话,为什么删除几百条消息后响应速度还是那么快,为什么 Agent 能从”记录对话”进化到”学习知识”。
这不是 prompt 写得好不好的问题,是整个系统架构为长对话、自主工作、持续进化优化到了极致。
一、两层 Prompt 缓存架构
大部分 AI 应用的 prompt 是一整块发给模型的。每次对话都要重发,浪费 token 也浪费钱。
Claude Code 把 prompt 切成两层:
1.1 静态前缀(scope: ‘global’)
Anthropic 后端跨用户、跨组织共享缓存。所有人的所有会话都复用同一份。这部分内容几乎不变:
- 身份定义(Intro)
- 系统规则(System)
- 任务规范(Doing Tasks)
- 操作安全(Actions)
- 工具使用指南(Using Tools)
- 风格要求(Tone & Style)
- 效率要求(Output Efficiency)
1.2 动态部分(scope: null)
每个会话独立,只在 /clear 或 /compact 时失效。包含会话特定的:
- 会话指引(Session Guidance)
- 记忆(Memory)
- 环境信息(Env Info)
- MCP 指令(MCP Instructions)
- 语言偏好(Language)
- 输出风格(Output Style)
- 草稿本(Scratchpad)
- Token 预算(Token Budget)
1.3 分界线(BOUNDARY MARKER)
这是整个设计的关键。分界线确保动态部分变化时,静态部分的缓存不会失效。两者完全解耦。
为什么这样设计?
- 静态部分大约 5-8K token,但可以跨所有用户共享
- 动态部分每次会话不同,通常也是 5-10K token
- 分界线让两者解耦,动态变化不影响静态缓存
- 节省的不是绝对数量,而是跨数百万用户共享这个乘数效应
1.4 缓存管理机制
动态部分不是每次重算,而是用 systemPromptSection() 注册 + memoize,只在 /clear 或 /compact 时清缓存。
例外: MCP Instructions 使用了 DANGEROUS_uncachedSystemPromptSection,因为 MCP 服务器会中途连接/断开,需要实时更新。
效果:
- Claude Code 启动几乎是瞬间的
- 新会话只需要发送动态部分
- 长对话的成本显著降低
二、四层递进的压缩策略
Claude Code 的压缩不是单一机制,而是四层递进的压缩策略,根据上下文压力逐级升级。
上下文接近上限
↓
Layer 1: MicroCompact(轻量清理)
├── 缓存已冷 → 直接清空旧 tool_result
└── 缓存还热 → cache_edits 增量删除
↓ 不够?
Layer 2: SessionMemoryCompact(会话记忆压缩)
├── 保留最近 10K-40K token 的消息
└── 用 Session Memory 替代旧对话
↓ 还不够?
Layer 3: Full Compact(全量压缩)
├── Fork 一个 agent 做摘要
├── 复用主对话的 prompt cache
└── 图片替换为 [image] 标记
↓ 还不够?
Layer 4: PTL Retry(终极兜底)
└── 从头部砍掉最旧的消息组,最多砍 20%
2.1 Layer 1: MicroCompact + Cache Edits(黑科技)
这是 Anthropic API 的未公开功能,核心是缓存不失效的增量删除。
问题场景:
长对话中,旧的 tool_result(工具调用结果)会占满上下文。一个典型的长对话可能有 100K+ token 的 tool_result。
传统做法有两种:
- 直接删掉旧消息 → 整个 prompt cache 失效 → 下一轮全部重发 → 费用飙升($1+ 一轮)、延迟明显(5-10 秒)
- 不删除 → 上下文溢出,对话中断
为什么删除旧消息会导致缓存失效?
这是理解 Cache Edits 价值的关键。
Prompt Cache 的工作原理:前缀完全匹配
假设你的消息序列是这样的:
[System Prompt] + [消息 1] + [消息 2] + [消息 3] + [消息 4] + [消息 5]
Claude 会把这整个序列缓存起来。下一轮对话,你发送:
[System Prompt] + [消息 1] + [消息 2] + [消息 3] + [消息 4] + [消息 5] + [消息 6]
Claude 发现前面的部分和缓存完全一致,直接复用缓存,只处理新的【消息 6】。
但如果你删掉了消息 2:
[System Prompt] + [消息 1] + [消息 3] + [消息 4] + [消息 5] + [消息 6]
Claude 发现从消息 1 之后,序列就对不上了,缓存失效,整个序列需要重新处理。
Cache Edits 的解法:
不修改本地消息,在 API 层发送删除指令:
{
"type": "cache_edits",
"edits": [
{ "type": "delete", "cache_reference": "tool_use_id_A" },
{ "type": "delete", "cache_reference": "tool_use_id_B" }
]
}
工作原理(3 步):
- 给每个块贴上 ID — 每个 tool_result 发送时带上 cache_reference,就像给缓存中的每个块贴上条形码
- 告诉服务端”跳过这些块” — 通过 cache_edits 发送删除指令,告诉服务端”把这些块标记为不可见”
- 保存标记指令,供后续请求使用 — 因为缓存里的原始数据还在(只是被标记为跳过),所以每一轮都需要重新发送 cache_edits
效果:
- 缓存前缀没变 → 下一轮还是命中
- 模型看到的上下文变短了 → 省 token
- 原始数据还在服务端 → 只是被标记为”跳过”
2.2 Layer 2: SessionMemoryCompact — 外科手术式的精确切割
当 MicroCompact 清理完 tool_result 还不够时,就要动真格的了:切掉旧对话。
但这不是简单的”砍前半段”。Claude Code 的做法是外科手术式的精确切割,确保不会把一个完整的交互拆散。
核心规则:
- 保留最近 10K-40K token 的消息(根据上下文压力动态调整)
- 用一条 Session Memory 替代旧对话(”之前我们讨论了……”)
- 绝不拆散 tool_use 和 tool_result — 工具调用和结果必须成对出现
- 绝不拆散 thinking 块和同轮的 tool_use — 思考过程和执行动作必须在一起
为什么这样设计?
如果你把 tool_use 留下但删掉 tool_result,模型会以为工具调用还没执行完,陷入等待状态。如果你把 thinking 块删掉但留下 tool_use,模型会不知道为什么要调用这个工具。
所以 Claude Code 的切割逻辑是:从保留区的起点向后扩展,直到满足最小 token 数和最小消息数,并且不破坏任何完整的交互组。
这是一个”宁可多留一点,也不能拆散”的保守策略,确保上下文的语义完整性。
2.3 Layer 3: Full Compact — 复用缓存的摘要魔法
当前两层都不够时,就要祭出大招了:Fork 一个 agent 做全量摘要。
但这里有个精妙的设计:摘要 agent 的 system prompt + tools + model 和主对话完全一致。
为什么?因为这样可以直接命中主对话的 prompt cache,大幅降低 token 成本。
工作流程:
主对话上下文快满了
↓
Fork 一个摘要 agent(复用主对话的 system prompt)
↓
图片清理 — 把所有 image/document 块替换为 [image]/[document] 标记
↓
摘要 agent 读取对话历史,生成摘要
(因为 system prompt 一致,直接命中缓存)
↓
摘要完成后,自动注入关键上下文:
- 最近 5 个文件的最新内容(每文件 ≤5K token,总预算 50K)
- 已激活的 Skills(每个 ≤5K token,总预算 25K)
- MCP Instructions Delta
↓
主对话继续,上下文变短了,但关键信息没丢
为什么要自动注入文件和 Skills?
因为压缩后,模型会忘记之前读过哪些文件、激活过哪些技能。如果不自动恢复,下一轮对话模型会说”我需要先读取 xxx 文件”,浪费一轮交互。
自动注入的逻辑是:把最近操作过的文件和技能重新喂给模型,但控制总量(文件 50K,Skills 25K),不会让上下文再次爆掉。
这是一个”压缩后恢复”的闭环设计,确保模型不会因为压缩而丢失工作记忆。
2.4 Layer 4: PTL Retry — 最后的保险机制
即使是摘要请求本身,也可能触发 prompt_too_long。
这种情况通常发生在极端场景:对话历史太长,连摘要 agent 都塞不下。
Claude Code 的兜底策略是:从头部砍掉最旧的消息组,砍到够为止。
规则:
- 每次最多砍 20%
- 最多重试 3 次
- 砍的单位是”消息组”(user + assistant 成对删除),不会留下孤立的消息
这是最后的保险机制,确保即使在极端情况下(比如用户一次性粘贴了几十万 token 的日志),对话也能继续。
三、Proactive 模式:从”被动响应”到”主动执行”
普通的 Claude Code 是”被动响应”的:你输入,它回复。
但当激活 PROACTIVE 或 KAIROS 模式时,会切换到一套完全不同的 System Prompt,让 Agent 变成”自主工作”模式。
3.1 终端焦点感知
这是 Proactive 模式中最前瞻的设计。Agent 通过 terminalFocus 字段知道用户是否在看终端:
Unfocused(用户离开):
- 进入自主模式
- 主动做决定
- 直接提交代码
- 不需要等待确认
Focused(用户在看):
- 进入协作模式
- 先问再做
- 等待用户反馈
- 保持交互式对话
这是一个非常聪明的设计:Agent 的自主程度不是固定的,而是根据用户的注意力动态调整。当你专注工作时,Agent 安静地在后台干活;当你回来看终端时,Agent 立刻切换到协作模式,向你汇报进展并征求意见。
3.2 Token Budget:用 token 量驱动的自主工作
用户可以指定 token 预算,Agent 会持续工作直到接近预算:
"+500k" → 500,000 tokens
"+2m" → 2,000,000 tokens
"use 1b tokens" → 1,000,000,000 tokens
闭环机制:
用户指定预算
→ agent 持续工作
→ 每轮检查进度
→ 接近 90%?停止,报告完成
→ 收益递减?停止(连续 3 轮增量 <500 token)
→ 未到 90%?注入 nudge 继续工作
关键设计:
- System prompt 中的 token_budget section 是缓存的
- 每轮对话结束后自动注入 nudge 消息
- 收益递减检测:连续 3 轮以上,且最近两轮增量都 <500 token,自动停止
这是一个用 token 量驱动的自主工作模式 — 用户说”花 500K token”,Agent 就一直干到花完为止。
四、多 Agent 协作体系
Claude Code 的多 Agent 体系不是简单的”多开几个进程”,而是一套完整的分布式协作基础设施。
4.1 三种协作模式
1. Fork:后台执行,不污染主对话
创建一个”分身”,继承你的完整上下文(对话历史 + system prompt + 工具池),在后台干活。结果出来后,只把最终结论告诉你,中间过程不污染主对话。
关键设计:Cache 继承
Fork 不重新生成 system prompt,而是直接复制父级已经渲染好的字节。
为什么?因为如果重新生成,可能会触发 Feature Flag 的重新计算。直接复制父级的字节,确保 Fork 和父级的 system prompt 完全一致,缓存继续命中。
2. Subagent:专家顾问,独立上下文
创建一个”专家顾问”,有自己的 system prompt、工具池、对话历史。它不是父级的”分身”,而是一个独立的专家。
内置的专家类型:
- explore — 代码库探索、深度研究
- verification — 对抗性验证(只在内部版本开放)
- 自定义 agent — 用户可以定义自己的专家
3. Swarm:持久化团队,分布式协作
创建一个”团队”,每个成员是独立的 Agent,但通过邮箱系统通信。
核心创新:分布式权限管理
Swarm 最精妙的设计是权限冒泡。
假设你有 4 个 Worker Agent 在并行工作。它们都需要删除文件、修改配置。如果每个 Agent 都在自己的终端弹出权限对话框,你需要在多个 pane 之间来回切换审批。
Swarm 的解法:
所有 Worker 的权限请求都通过邮箱系统发给 Leader,Leader 在终端展示统一的权限对话框。你只需要盯着 Leader 的终端,所有权限请求都会在那里出现。
Worker 遇到权限提示
↓
发送 permission_request 到 Leader 邮箱
↓
Leader 在终端展示对话框(用户审批)
↓
Leader 发送 permission_response 到 Worker 邮箱
↓
Worker 收到响应,继续或中止
这是一个分布式权限系统 — 多个 Agent 的权限请求全部汇总到 Leader 终端,用户不需要在多个 pane 之间切换。
五、自我进化记忆系统
Claude Code 有一个隐藏的”反思”机制:每 24 小时 + 累积 5 个会话后,自动 fork 一个后台 agent 做”反思”。
5.1 四层记忆体系
1. Auto Memory(自动记忆)
- 路径:
~/.claude/projects/<path>/memory/ - 触发:每轮对话结束自动写入
- 机制:extractMemories 实时提取
- 特点:短期工作记忆,快速访问
2. Team Memory(团队记忆)
- 路径:auto memory 的子目录
- 作用:团队共享的知识库
- 特点:跨用户共享,协作场景
3. Agent Memory(Agent 专属记忆)
- 路径:自改进 agent 的专属目录
- 作用:Agent 自己的长期知识库
- 特点:配合 autoDream 定期整合
5.2 从短期到长期的转化
实时提取(extractMemories)
↓
短期工作记忆(Auto Memory)
↓
定期整合(autoDream)
↓
长期知识库(Agent Memory)
这套体系让 Agent 不仅能”记住”,还能”学习”和”进化”。
六、工业级遥测体系
Claude Code 的遥测不是”能关就关”,而是有三条并行的数据通道,每条都有不同的目的。
6.1 三条数据通道
通道 1:API Header(每次必发,无法关闭)
每次 API 请求都会带上一个 x-anthropic-billing-header,注入到 system prompt 的第一块:
cc_version=1.0.0; cc_entrypoint=cli; cch=00000; cc_workload=cron
通道 2:1P Event Logging → BigQuery(主通道,可关闭)
这是最核心的遥测通道,包含五层递进的元数据收集。
通道 3:Datadog(白名单事件,可关闭)
只有 30+ 种特定事件会发到 Datadog:API 成功/失败、OAuth 流程、工具使用授权/拒绝、Compact 失败、模型 fallback、未捕获异常。
6.2 五层元数据
Layer 1: Core Metadata — 你在用什么功能
- model、sessionId、userType、entrypoint、isInteractive
- agentId / parentSessionId / agentType / teamName — 多 Agent 追踪
- subscriptionType、rh(仓库指纹)
Layer 2: Env Context — 你的开发环境
- platform / arch、terminal(20+ 种检测)
- packageManagers、runtimes
- deploymentEnvironment(30+ 种云平台)
- linuxDistroId / linuxKernel
Layer 3: Process Metrics — 你的资源使用
- uptime、rss / heapTotal / heapUsed
- cpuUsage / cpuPercent
Layer 4: User Metadata — 你是谁
- deviceId — randomBytes(32).hex,存在 ~/.claude/.config.json,终身不变
- email、accountUuid / organizationUuid
- subscriptionType / rateLimitTier
Layer 5: PII 特权字段 — 只走 BigQuery
- skill_name、plugin_name、marketplace_name
- 这些字段在发送到 Datadog 前会被清除,确保 PII 不会泄露
七、安全分层:20+ 道检查流水线
Bash 安全分类器(2592 行代码)不是简单的”黑名单”,而是一个 20+ 道安全检查的流水线。
核心检查:
- Shell 元字符检测 — $() “ {} <> 等
- 命令替换模式 — <() >() =() $( 等
- 危险变量检测 — $IFS、$PATH 等
- 输入/输出重定向检测
- 花括号展开检测 — {a, b, c} 绕过参数检查
- 反斜杠转义运算符 — ; | & 等
- 引号反同步 — “x”y” ; echo ~/.ssh/id_rsa
- 控制字符 + Unicode 空白字符
- jq 系统函数检测 — system()/exec/…
- /proc 文件系统访问 — /proc/self/environ 等
Zsh 专属防御:
Zsh 的攻击面比 Bash 大,源码专门维护了 ZSH_DANGEROUS_COMMANDS 集合:
- zmodload → 加载危险模块
- emulate → eval 等价物
- zpty → 伪终端执行命令
- ztcp → TCP 连接外泄数据
- zf_rm → 绕过 rm 权限检查
八、设计哲学:Cache 感知 + 基础设施感知
Claude Code 的每个设计决策都在考虑两件事:
8.1 Cache 感知
- Fork 直接复制父级渲染后的 system prompt 字节,避免 Feature Flag 冷→热切换导致缓存失效
- Agent 根据缓存过期时间(5 分钟 TTL)决定 sleep 时长
- 连 Agent 的创建方式都要考虑缓存命中率
8.2 基础设施感知
- Agent 感知缓存 TTL、token 预算、终端焦点状态
- 据此调整行为节奏,避免无效唤醒
- 让 Agent 理解基础设施的约束,而不是盲目执行
九、对 AI 开发者的启示
9.1 分层思维
不要试图用单一方案解决所有问题。设计分层系统,便宜方案处理常见情况,昂贵方案处理边缘情况。
9.2 预防优于治疗
Claude Code 的设计哲学:预防上下文溢出比溢出后修复更便宜。Layer 1-3 都是预防措施。
9.3 增量维护
持续维护 session memory 比紧急总结更高效。这类似于数据库的增量备份 vs 全量备份。
9.4 Cache 是第一公民
在 LLM 应用中,prompt cache 应作为核心设计考虑,而非事后优化。
9.5 后台处理
“梦境”系统展示了后台 consolidation 的价值——用户离开时做繁重工作,用户返回时系统已准备好。
结语
Claude Code 的核心竞争力不是单个功能,而是这套缓存架构 + 自我进化记忆 + 多模式编排的完整基础设施。
特别是 cache_edits 和分层缓存,是让无限上下文对话在商业上可行的关键。没有这套机制,长对话的成本会让产品无法规模化。
这才是工业级 AI Agent 的设计哲学。
本文基于公开泄露的 Claude Code CLI 源码分析,不代表 Anthropic 官方立场。
感谢阅读!我是 Rowan,。如果本文对你有所启发或帮助,不妨 **推荐、分享,并关注我** ❤️。你的每一次互动,都是我持续分享优质内容的强大动力。
💬 欢迎在评论区留言,分享你的想法或遇到问题~
夜雨聆风