Claude Code 源码深度解析:五层架构与核心设计模式
全景导图
%%{init: {'theme':'base', 'themeVariables': {'primaryColor':'#e3f2fd','primaryTextColor':'#1565c0','primaryBorderColor':'#1976d2','lineColor':'#42a5f5','secondaryColor':'#fff3e0','tertiaryColor':'#f3e5f5','fontSize':'14px'}}}%%
flowchart TD
A[Entrypoints 入口层] --> B[Runtime 运行时层]
B --> C[Engine 推理引擎层]
C --> D[Tools & Caps 能力层]
D --> E[Infrastructure 基础设施层]
C --> C1[QueryEngine 单例]
C --> C2[AsyncGenerator 循环]
C --> C3[静态/动态提示词分界]
C --> C4[五级上下文压缩]
D --> D1[40+ 内置工具]
D --> D2[多智能体编排]
D --> D3[MCP 集成]
D --> D4[Skills 三层加载]
D --> D5[Hooks 9 类事件]
E --> E1[Auth / Storage]
E --> E2[Cache / Telemetry]
E --> E3[Bridge 传输抽象]
E --> E4[apiPreconnect 启动优化]
模式总览
本文覆盖的可迁移架构模式:
| # | 模式名称 | 一句话口诀 | 覆盖场景 |
|---|---|---|---|
| 1 | Harness 护城河 | 模型提供智力,Harness 提供能力边界 | AI 编程工具架构设计 |
| 2 | 生成器驱动 | AsyncGenerator 替代状态机 | Agent 控制流设计 |
| 3 | 上下文预算 | 静态/动态分界 + 四个 breakpoint + 五级压缩 | LLM 上下文窗口管理 |
| 4 | 多智能体编排 | 文件系统 Team + 异步 Mailbox + worktree 隔离 | 多 Agent 协调通信 |
| 5 | 工具即能力 | 注册-校验-执行-聚合流水线 | Agentic AI 安全模型 |
| 6 | 缓存继承 | model: inherit 共享提示词缓存 | 子智能体性能优化 |
| 7 | 切面式 Hook | harness 强制执行 vs 模型选择 | LLM 应用确定性切面 |
| 8 | 权限路径锚定 | deny > ask > allow,每段独立判规则 | Agentic AI 命令执行安全 |
源码概览:约 1,900 个文件的技术版图
2026 年 3 月 31 日,Claude Code 的完整 TypeScript 源码通过 npm source map 意外暴露——cli.js.map 文件约 59.8 MB,社区随后发现 source map 内嵌的 Cloudflare R2 bucket URL 可直接拉取 bundled 源码(CSDN 程序员鱼皮分析)。共计约 1,900 个文件、512,000 行 TypeScript。社区随即产生了一批分析文章,redreamality 通读了全部目录,ThreeFish-AI 完成了系统性逆向工程,Pragmatic Engineer 与 Sebastian Raschka 在采访 Anthropic 工程师后给出了官方背书的解读。2026 年 5 月 MBZUAI 发表的学术论文则从工程系统视角形式化了 Claude Code 的 harness 抽象,把它拆成了七个可复用组件——四支独立竞争的 AI 编程工具团队最终都收敛到了几乎相同的架构骨架。
源码揭示的核心事实:Claude Code 不是带工具访问的聊天机器人,而是一个完整的 AI 辅助软件开发操作系统——包含多智能体运行时、插件市场、跨会话记忆系统和多层安全模型。源码中能找到具体的真实生产数据:源码注释提到曾出现 1,279 个会话连续 50+ 次自动压缩失败的事故,每天浪费约 25 万 API 调用,最终通过 MAX_CONSECUTIVE_AUTOCOMPACT_FAILURES = 3 熔断常量解决(CSDN 程序员鱼皮)。
Harness Engineering:2026 年 AI 工程的第三阶段
Faros AI 在 2026 年 5 月的一篇行业综述中提出了一个有用的分期框架:
| 阶段 | 焦点 | 代表工具/方法 |
|---|---|---|
| Phase 1 · Prompt Engineering | 调教单次 LLM 调用 | few-shot, CoT, system prompt 模板 |
| Phase 2 · Context Engineering | 把对的信息塞进上下文窗口 | RAG, embedding 检索, 长上下文模型 |
| Phase 3 · Harness Engineering | 构建模型周围的执行环境 | Claude Code, Codex CLI, Cursor Agent, Devin |
Phase 3 是 2026 年 AI 工程投资的主轴:模型本身正在快速商品化,但模型外层的 harness——permission gating、tool dispatch、context compaction、subagent isolation、hook lifecycle——才是真正决定 Agent 在生产环境能否长时运行而不漂移的关键。按 TechTimes 对 MBZUAI 论文的工业转述,结论可以浓缩成一句:绝大部分可靠性差异来自 harness,而不是模型权重(TechTimes 标题里的"98%"是工业稿的概数提法,论文原文是对细分维度做的多组对比,具体百分比以论文为准,URL 见文末参考资料)。论文的事实基础是:四支独立团队(Anthropic Claude Code、OpenAI Codex CLI、Cursor、Devin)在没有相互参考的前提下,各自独立设计的 agent harness 在功能边界上几乎完全重合。这一现象指向一个结论:这些组件不是 Anthropic 的特定选择,而是 agentic 系统在生产化过程中被迫收敛到的自然形状。
[PATTERN] Harness 护城河模式:AI 编程工具的真正壁垒不在模型能力,而在 Harness(智能体编排层)。模型提供智力,Harness 提供能力边界、上下文管理、确定性切面与执行环境。换句话说:“The model reasons; the harness mediates every action.”(mer.vin)
三种主流架构观的对照
社区与学术界对 Claude Code 的架构切分有三种经典视角,本文统一在五层视图下展开,但读者可以按下表互查:
| 视角 | 切分方式 | 来源 | 适用场景 |
|---|---|---|---|
| 5 层架构 | Entrypoints / Runtime / Engine / Tools&Caps / Infrastructure | 本文(基于 ThreeFish-AI 与 redreamality 源码逆向) | 自顶向下理解工程实现 |
| 6 层 Harness | Input / Knowledge / Execution / Integration / Multi-agent / Observability | mer.vin(基于官方文档) | 围绕模型的能力边界视角 |
| 7 组件抽象 | UI / Agent Loop / Permissions / Tools / State&Persistence / Execution Env / Telemetry | MBZUAI 论文 | 学术形式化与跨工具对比 |
三个视角讲的是同一件事,只是切分粒度不同。本文为了照顾"看一篇文就懂"的目标,会在每一层的开头点出它在另外两种视角下的对应位置。
关于本文出处:Claude Code 源码本身闭源,本文涉及内部命名(常量名、函数名、模块代号)的断言全部来自 2026 年 3-4 月 source map 泄露后的社区逆向工程报告,以及 2026 年 5 月之后社区与学术界发表的二次分析(mer.vin、jidonglab、MBZUAI 论文等)。多源交叉验证的断言会标注「多源」,仅一处来源的会显式标注「据某某分析」,请读者结合证据强度阅读。
五层架构:从入口点到基础设施
源码显示 Claude Code 采用清晰的五层分层设计:
| 层级 | 职责 | 关键组件 |
|---|---|---|
| Layer 1: Entrypoints | 多端入口 | CLI / Desktop / Web / SDK / IDE Extensions / Headless |
| Layer 2: Runtime | 运行时核心 | REPL loop / Hook system / Permission engine / State manager |
| Layer 3: Engine | 推理引擎 | QueryEngine / Context coordinator / Compact pipeline / Streaming demux |
| Layer 4: Tools & Caps | 能力层 | 40+ tools / Plugin / MCP / Skill / Sub Agent / Hooks |
| Layer 5: Infrastructure | 基础设施 | Auth / Storage / Cache / Bridge transport / Telemetry / Sandbox |
这种架构的哲学是:Claude Code 是一个平台运行时,恰好附带了一个终端界面。同一个核心引擎驱动桌面应用、Web 客户端、IDE 扩展和程序化 SDK。Bridge 层抽象了传输协议,引擎永远不需要知道是哪个前端在驱动它——这是为什么 Anthropic 能在不重写核心的前提下,三个月内把一个 CLI 扩张成跨四个端的工具家族。
架构上更接近 VS Code 的扩展宿主或 Emacs 的 Lisp 核心,而非典型的 AI 包装器。Layer 3 是模型可见的边界——之上对模型透明,之下模型完全感知不到;Layer 2 是 harness 真正的控制权所在,Hook 与 permission 在这里强制执行。
核心引擎:QueryEngine 与 AsyncGenerator 循环
在 6 层 harness 视图下,本节对应"Agent Loop"中心;在 MBZUAI 7 组件视图下,对应"Agent Loop"组件。这是模型可见的边界——之上对模型透明,之下模型完全感知不到。
QueryEngine 单例
整个对话由一个 QueryEngine 单例驱动,它维护一个对话状态数组——这是所有对话状态的唯一事实来源(据 redreamality 分析,源码中具体命名为 mutableMessages,单源信息)。所有工具结果、压缩决策、子智能体协同都围绕这个数组的演进发生。
为什么用单例而非每次新建?关键考量是 prompt cache 命中:cache 是按字节级前缀匹配的,每次都从同一个 mutable array 末尾追加可以保证前缀稳定,不会因为对象重建造成对象哈希变化击穿缓存。这是个不起眼但关键的工程决策——把"对话历史"做成 mutable state 而非每轮 immutable diff。
AsyncGenerator 核心循环
Anthropic 工程团队对这个循环的官方描述是出奇地简单:“gather context → take action → verify results, repeat until done”。同一个三段式被显式刻在了源码里、Agent SDK 的文档里、以及 Anthropic Engineering 博客的 effective agents 文章里——这种跨载体的重复不是巧合,而是 Anthropic 内部对"什么是一个 agent"的共识。
核心循环是一个异步生成器(async generator):
1 | |
sequenceDiagram
participant U as User
participant Q as QueryEngine
participant A as Anthropic API
participant T as Tool Registry
participant H as Hook System
U->>Q: prompt
Q->>Q: 拼接 system + dynamic + history
loop until end_turn / maxTurns / maxBudget
Q->>A: stream messages.create
A-->>Q: content_block_delta (token)
Q-->>U: yield token
A-->>Q: tool_use(name, input)
Q->>H: PreToolUse(name, input)
alt deny
H-->>Q: tool_result(error)
else allow
Q->>T: execute(name, input)
T-->>Q: tool_result
Q->>H: PostToolUse(name, input, result)
end
Q->>Q: append tool_result to mutableMessages
end
生成器模式带来的关键优势:
- 原生流式:token 通过
yield流动,而非回调 - 工具调用递归:
tool_use → tool_result → continue只是另一次迭代 - 干净的中断:
AbortController取消生成器,无需复杂的清理逻辑 - 预算控制简单:在每次迭代边界检查
maxTurns或maxBudget
大多数 AI 工具框架使用状态机或事件循环。Claude Code 的生成器方法更简单、更可组合,这一选择也直接体现在了 claude-agent-sdk-python 与 claude-agent-sdk-typescript 中——SDK 的 query() 函数就是一个 AsyncGenerator/AsyncIterator,使用者用 async for message in query(...) 接收每一条事件。
Agent SDK 的两种入口:query() vs ClaudeSDKClient
Anthropic 后来把"Claude Code SDK"重命名为"Claude Agent SDK"——这不是文字游戏,而是承认这套 harness 的能力远超编码场景:邮件助手、调研 Agent、客服机器人、金融分析都用同一套循环。SDK 暴露了两个入口,分别对应不同的使用模式(jidonglab 整理):
1 | |
1 | |
ResultMessage 的 subtype 字段区分四种结束态:success / error_max_turns / error_max_budget_usd / error_*——这让"预算感知"成为工程任务而非赌博。
与原始 Anthropic Client SDK 的关键差异:用 Client SDK 你必须自己实现 tool loop(检查 stop_reason、执行工具、追加结果、再次发请求),用 Agent SDK 这一切由 Claude Code 的 harness 自动完成。两者对外的 API 形态相同(都是 streaming + tool_use),但生命周期管理由谁负责决定了你写多少代码。
流式事件的官方时序
Anthropic Messages API 的 SSE 流式响应有严格的事件时序:
1 | |
工具调用的 tool_use 块通过 input_json_delta 流式传递——partial_json 是字符串片段,需要客户端累积后整体解析。这就是为什么生成器模式天然契合:每个 content_block_delta 是一个 yield 节点,工具参数累积完整后再触发权限检查、执行工具、把 tool_result 作为下一轮 user message 追加,重新进入生成器循环。
工程上更隐蔽的细节是只读工具的并行执行。Tool annotation 里的 readOnlyHint: True 让 harness 可以把 Read / Glob / Grep / WebFetch 一批工具调用并行起来;mutating 工具(Edit / Write / Bash)则严格串行,避免文件竞态。这是为什么 Claude Code 在"先大量探索再做修改"的任务上看起来很快——前半段被 harness 自动并行了,模型完全不感知。
[PATTERN] 生成器驱动模式:用 async generator 替代状态机/事件循环,天然支持流式、中断、递归和预算控制。这是 Agent 框架的最优控制流设计。SDK 把这个模式直接暴露给开发者,意味着 Anthropic 把这视为对外的稳定 API 抽象。
提示词工程架构:静态/动态分界与缓存优化
Claude Code 最具工程价值的设计之一,是将系统提示词拆分为静态部分和动态部分,并围绕 Anthropic API 的 prompt caching 机制构建了完整的缓存优化策略。
静态提示词:可缓存的跨用户共享内容
源码中的系统提示词不是单一字符串,而是由多个 section 函数返回的字符串数组拼装而成(CSDN 程序员鱼皮的源码片段显示文件路径为 constants/prompts.ts,内含 sections = [...] 数组)。其中静态部分大致包括:
| Section 类别 | 内容 |
|---|---|
| 身份定义 | Claude Code 作为交互式代理的基本身份与角色 |
| 系统规则 | 输出格式、工具调用被拒绝后的处理、prompt injection 防护 |
| 任务执行规范 | 不要过度设计、读文件后再改代码、避免安全漏洞 |
| 工具使用规范 | 并行调用、权限检查、错误重试 |
| 语气与风格 | 终端友好的简洁输出、避免 emoji、不主动总结 |
| 输出效率控制 | 模型可见的 token 预算与简洁度规则 |
这些 section 在缓存策略中按"全局可缓存"标记,跨所有用户共享。
动态提示词:会话特定的实时生成内容
在静态部分之后,源码通过一个关键标记 __SYSTEM_PROMPT_DYNAMIC_BOUNDARY__ 明确划定静态/动态分界线(多源确认:CSDN、Dev.to ishaaan)。边界之后的内容在每次查询时实时生成:
1 | |
mcp_instructions 因为每个用户配置不同,无法被缓存,会在源码中被显式标记为不可缓存(社区文章常以"DANGEROUS"前缀的辅助函数描述这一约定,但具体函数名在多源交叉中未被确认,本文不引用具体标识符)。命名约定本身是值得借鉴的设计——用名字而非注释来传达架构约束。
五级覆盖优先级
构建有效系统提示词的过程支持五级覆盖机制,优先级从高到低:
| 优先级 | 来源 | 场景 |
|---|---|---|
| 0 | Override system prompt | 调试/测试时的完全覆盖 |
| 1 | Coordinator system prompt | 多智能体协调器的专用提示词 |
| 2 | Agent system prompt | 特定智能体(如 explore、plan)的提示词 |
| 3 | Custom system prompt | 用户自定义提示词 |
| 4 | Default system prompt | 默认系统提示词 |
此外,appendSystemPrompt 始终追加在末尾,不受优先级影响。
CLAUDE.md 的加载时机
CLAUDE.md 文件作为 userContext 注入——注意:是 user message 而非 system prompt。这是一个常被忽视的细节,意味着 Claude 对 CLAUDE.md 的"遵守"是模型行为而非 harness 强制——官方文档原文是 there's no guarantee of strict compliance。CLAUDE.md 不是无条件每次重读:主 Agent 的项目级 CLAUDE.md 默认每次查询时重新读取,但 sub agent 由 omitClaudeMd 标志位控制(GitHub issue #59309 显示 v2.1.84+ 的子智能体不继承 CLAUDE.md,可大幅节省 token)。
加载顺序覆盖整个文件树:managed policy → user 级 ~/.claude/CLAUDE.md → 项目级(沿目录树自下而上)→ 同目录 CLAUDE.local.md。@path import 支持递归,最大 5 层。子目录的 CLAUDE.md 不在启动时加载,是 Claude 读那个子目录文件时按需加载——这就是 Claude Code 感觉"项目感知"的机制。
围绕 cache_control 构建的两层缓存
Anthropic API 的 prompt caching 通过 cache_control 字段实现前缀缓存:
1 | |
每个请求最多 4 个 cache_control 断点,每个断点回看 20 个 block。低于模型阈值(Sonnet 4.x 1024 tokens、Opus 4.5+ 与 Haiku 4.5 4096 tokens)的请求会被静默地不缓存。响应的 usage 字段返回三个关键值:cache_read_input_tokens(命中缓存)、cache_creation_input_tokens(写入新缓存)、input_tokens(最后一个 breakpoint 之后的增量——不是总输入)。
价格结构是这套设计能跑通的根因:cache read = 0.1×, cache write 5min = 1.25×, cache write 1h = 2×, base input = 1×。写一次省一万次。Claude Code 围绕这个比例构建了两层缓存:
| 缓存层级 | 范围 | 内容 |
|---|---|---|
| Global Cache | 跨用户共享 | DYNAMIC_BOUNDARY 之前的所有静态 section |
| Session Cache | 会话级 | 动态 section + 对话历史 |
工程上的关键约束:提示词的排列顺序至关重要。前缀匹配是字节级的——任何在前缀中发生的细微改变,都会击穿该位置之后的所有缓存。tool 定义改了,整条都失效;system 改了,messages 部分失效;改 tool_choice 或加图片,则 system 之后的部分全部失效。
据 Dev.to ishaaan 估算,Claude Code 这套两层缓存策略在长会话中能让 token 成本下降约 50–70%。
子智能体的缓存继承
model: 'inherit' 的核心价值在于:Fork 出的子智能体继承父智能体的完整对话上下文,通过 byte-identical copies 实现提示词缓存共享。子任务必须使用和父对话相同的 prompt prefix,才能复用父对话的缓存。这使得生成 5 个并发子智能体的成本仅略高于 1 个。inherit 的解析有四级优先级:环境变量 CLAUDE_CODE_SUBAGENT_MODEL → 调用时显式 model 参数 → frontmatter 的 model → 主对话 model。
[PATTERN] 缓存继承模式:子智能体不要"另起炉灶"——通过 model: 'inherit' 字节级对齐父对话 prompt prefix,复用父对话已经付费写入的缓存。把"派生子智能体"做成"复用上文",5 个并发的成本接近 1 个。
[PATTERN] 上下文预算模式:LLM 应用的上下文窗口是稀缺资源,必须像管理内存一样管理它。静态/动态分界 + 四个 breakpoint + 五级压缩是 Claude Code 的核心工程策略。SYSTEM_PROMPT_DYNAMIC_BOUNDARY 这个标记本身就是一个值得借鉴的设计模式——用命名约定而非文档来传达架构约束。
上下文压缩:受控降级流水线
在 6 层 harness 视图下,本节对应"Knowledge"层中"context survival"的部分;它是 LLM 应用最难做对的工程之一。
上下文窗口是有限的。Claude Code 通过分层压缩系统处理。社区分析对压缩级数说法不一:redreamality 描述为四级(autoCompact / apiMicrocompact / reactiveCompact / snip),CSDN 与 Dev.to 描述为五级(含 Tool Result Budget 与 Context Collapse),claudefa.st 描述为五种 distinct approaches。源码中确实存在的标识符包括 Autocompact、Microcompact、Snip、hasAttemptedReactiveCompact、Context Collapse 等:
| 层级 | 命名(社区) | 触发时机 | 影响 |
|---|---|---|---|
| 1 | Tool Result Budget | 单次 tool_result 超预算时裁剪 | 仅截断当前工具输出,不动历史 |
| 2 | Microcompact (apiMicrocompact) | API 原生 context_management 触发 |
裁掉最旧的若干 tool_result |
| 3 | Snip | 紧急丢弃图片、调试 trace 等非关键内容 | 优先剥离体积大、信息密度低的 block |
| 4 | Autocompact | 上下文接近软限制时主动调用 LLM 摘要 | 把历史对话凝练成摘要,保留关键引用 |
| 5 | Reactive Compact | API 返回 context-too-large 错误后兜底 | 最激进的丢弃,会丢早期对话语义 |
Autocompact 流程的三段式
Autocompact 流程不是"丢一半旧消息"那么粗暴,而是一个三段式:
flowchart LR
A[触发条件:<br/>上下文 > 软限制] --> B[剥离非文本:<br/>图片 / 大型 trace]
B --> C[调用 LLM 摘要:<br/>对话历史 → 概要]
C --> D[恢复文件引用 +<br/>skill 状态]
D --> E[保留 preservedSegment:<br/>近 N 轮原文]
E --> F[继续主循环]
preservedSegment 是关键设计——压缩后,最近 N 轮(社区估计 5-10 轮)保留原文,更早的内容被 LLM 摘要替换。这避免了"刚说过的事下一句就忘了"的体验。同时关键文件引用(“我们正在改 auth.py”)和 skill 状态(“已加载 pdf-processing skill”)被白名单恢复——压缩不能让 agent 失忆到不知道自己在干什么。
PreCompact / PostCompact Hook 的工程意义
Agent SDK 暴露的 PreCompact 和 PostCompact hook 让用户可以介入压缩边界——这是 OMC、Superpowers、各类自定义 framework 都重度依赖的扩展点:
1 | |
这个模式很像数据库的 WAL(write-ahead log)——压缩是"checkpoint",PreCompact hook 是"在 checkpoint 之前先把 redo log 落盘"。少了它,长会话的 transcript 永久丢失,事后审计就没了。OMC 的 notepad 系统就是基于这个 hook 实现"压缩前自动保存关键笔记"。
熔断与失败重试
源码中还有熔断保护:MAX_CONSECUTIVE_AUTOCOMPACT_FAILURES = 3——这是在踩过"1,279 sessions 连续 50+ 次失败、每天浪费约 25 万 API 调用"的真实事故后加上的(CSDN 引用源码注释)。
事故的根因是:autocompact 调用本身也是一次 LLM 调用,如果上下文已经爆到压缩 API 都拒绝,重试无穷次只会无限计费。MAX_CONSECUTIVE_AUTOCOMPACT_FAILURES = 3 之后会强制走 Reactive Compact 的激进丢弃路径——优雅降级 > 死循环重试,这是对 LLM 应用工程的关键启示。
compaction 与 mutableMessages 的字节级影响
一个常被忽略的细节:压缩会重写 mutableMessages 数组——这意味着压缩之后的所有 prompt cache 都会失效,下一次请求要重新支付 cache write 成本。这就是为什么 Autocompact 不能太激进:每次压缩都是一次"全量 cache 重建",频繁压缩反而比放任上下文增长更贵。源码中 autocompact 的触发阈值据 ThreeFish-AI 分析约在 75-80% 上下文容量,留出余量避免过早压缩。
这比"截断旧消息"复杂得多——这是一个受控降级流水线。
Hook 系统:harness 的确定性切面
在 6 层 harness 视图下,本节对应"Observability"层;在 MBZUAI 7 组件视图下,对应"Telemetry"组件。
Hook 是 Claude Code agent loop 中由代码强制执行而非"模型可能选择做"的事——它把不应该交给 LLM 决定的逻辑(autoformat、permission 拦截、telemetry)从 prompt 里搬到 shell 命令。Hook 在固定生命周期事件触发,由 harness(不是模型)同步执行。
mer.vin 总结的口诀很到位:“Hooks fire at fixed lifecycle points—unlike skills, they are deterministic, not model-chosen.” Skill 是模型可以选择不调用的工具入口,Hook 是模型选择不到的强制切面——一个治"愿不愿意",一个治"能不能"。
9 类核心事件 + Agent SDK 的十余个细粒度事件
官方文档列出的核心 hook 事件包括:SessionStart / UserPromptSubmit / PreToolUse / PostToolUse / Notification / Stop / SubagentStop / PreCompact / PermissionRequest(社区交叉确认)。Agent SDK 把这一组进一步细化到十余个生命周期回调(下表列出 16 个有公开文档支持的事件;jidonglab 的整理给出的总数偏高,差异可能落在实验阶段的若干文件 hook 上),覆盖几乎每一个可介入的边界点:
| 节奏 | 事件 | 用途 |
|---|---|---|
| 会话级 | SessionStart / SessionEnd |
启动/结束钩子,注入欢迎语、收尾归档 |
| 用户输入 | UserPromptSubmit / UserPromptExpansion |
提交前重写、@import 展开后注入 |
| 工具调用 | PreToolUse / PostToolUse / PostToolBatch |
拦截/审计/格式化;批量工具结束后再走一次 |
| 权限 | PermissionRequest |
用户被弹权限请求时触发 |
| 子智能体 | SubagentStart / SubagentStop |
子任务边界,常用于结果聚合 |
| 压缩 | PreCompact / PostCompact |
压缩前归档、压缩后回灌摘要 |
| 通知 | Notification |
工具调用阻塞时 ding 一下用户 |
| 停止 | Stop |
模型 end_turn 时的最后一钩 |
| 文件 | FileEdit / FileWrite 后置 |
autoformatter / linter 整合 |
事件按节奏分三档:
flowchart LR
subgraph A[每会话一次]
SS[SessionStart] --> SE[SessionEnd]
end
subgraph B[每轮一次]
UPS[UserPromptSubmit] --> ST[Stop]
UPS --> SAS[SubagentStop]
end
subgraph C[每次工具调用]
PRE[PreToolUse] --> POST[PostToolUse]
PRE --> PR[PermissionRequest]
end
subgraph D[压缩边界]
PC[PreCompact] --> POSTC[PostCompact]
end
A -.触发.-> B
B -.触发.-> C
Hook Handler 的五种类型
Hook 不止能挂 shell 命令——官方文档列出的 handler types 共有 5 类(mer.vin 整理):
| Handler 类型 | 说明 | 典型用途 |
|---|---|---|
| Shell command | stdin 喂 JSON,stdout/exit code 决定行为 | autoformat、git pre-commit 风格的拦截 |
| HTTP webhook | POST 到指定 URL,body 是同样的 JSON | 把事件推到 Slack / 内部审计系统 |
| MCP tool | 复用已注册的 MCP 工具 | 用一个 LLM 写的 MCP 工具做语义判断 |
| Prompt judge | 用一段 prompt 让 LLM 当裁判 | “这个 commit message 够清晰吗?” |
| Agent verifier(实验) | 用一个独立 sub-agent 跑深度验证 | 安全审计、TDD 验证 |
后三种是 2026 年 Q2 上线的新形态——把 hook 从"shell 脚本切面"扩展到"用 LLM 当切面",意味着 hook 不再只能做规则判断,也可以做语义判断。代价是延迟:prompt judge 通常 1-3 秒,async hook(async_: True)让它不阻塞主循环。
Hook 执行模型
每个 hook 通过 stdin 接收 JSON 输入(session_id / transcript_path / cwd / permission_mode / hook_event_name / tool_name / tool_input 等),通过 exit code 与 stdout JSON 决定后续行为。一个常见误区:
For most hook events, only exit code 2 blocks the action. Claude Code treats exit code 1 as a non-blocking error and proceeds with the action, even though 1 is the conventional Unix failure code.
也就是说,写"非 0 即失败"的 hook 是错的——只有 exit 2 真正阻塞。exit 2 时 Claude Code 忽略 stdout 和任何 JSON,把 stderr 当错误消息回喂给模型。
JSON 输出与 exit code 是互斥的——选择 JSON 输出意味着精细化控制:
1 | |
permissionDecision 取 allow / deny / ask / defer。additionalContext 字段会被 Claude Code 包成 system reminder 注入到对话——所有 hook 输出(含 additionalContext)截断在 10,000 字符。
双层输出设计:hookSpecificOutput vs systemMessage
Agent SDK 的 hook 协议有一个常被忽略的精巧设计——两层输出分别面向 harness 与模型(jidonglab):
1 | |
hookSpecificOutput控制当前操作:allow / deny / 修改 inputsystemMessage注入对话上下文:以 system reminder 形式告诉模型"为什么"被阻塞,让它换条路而不是死循环重试
没有第二层,模型可能 5 次都试着写同一个 .env;有了第二层,模型读到"用 env.example 代替"的提示后会主动改方向。这是个小细节但效果很大——区分了"控制流决策"和"模型上下文注入"两个责任。
Matcher 与 deny-wins 链式语义
多个 hook 注册到同一个事件时,按注册顺序串行执行,任何一个返回 deny 就立刻停止后续 hook 并阻塞操作——这就是 deny-wins 语义。Matcher 用正则筛选要不要触发:
1 | |
这种"matcher + 链 + deny-wins"的设计直接对应 Linux iptables 的 chain 模型——hook 不只是 LLM 应用的工具,本质上是经典系统工程的"过滤器链"模式被搬到 agent loop 里。
从 1,279 sessions 事故看 Hook 治理价值
回到本文开头那个事故:1,279 个会话连续 50+ 次自动压缩失败、每天浪费约 25 万 API 调用。这个事故能被发现是因为 telemetry hook 把 PreCompact / PostCompact 失败计数推到了内部 dashboard——没有 hook,这种慢性出血是看不见的。最终的修复 MAX_CONSECUTIVE_AUTOCOMPACT_FAILURES = 3 也是 hook 风格的:在 harness 里加一个熔断常量,比让模型"自己注意不要无限重试压缩"靠谱一万倍。
[PATTERN] 切面式 Hook 模式:把"模型可能做"变成"代码强制做"——autoformat、permission、policy、telemetry 都不该让模型选择。Hook 与 Skill 互补:Skill 是模型可选择的工具入口,Hook 是模型选择不到的强制切面。把 hook 的输出拆成 hookSpecificOutput(控制流)+ systemMessage(上下文)两层,避免模型在被拦截后死循环重试。
多智能体架构:三种隔离级别与七种任务类型
在 6 层 harness 视图下,本节对应"Multi-agent"层。这一层的核心问题是:如何让一个 agent 派生子任务而不污染自己的上下文。
为什么需要 Sub Agent:上下文污染问题
主 agent 的 mutableMessages 数组是稀缺资源——每多塞 1 万 token,下一次模型推理就贵 1 万 token,且击穿 cache 的概率指数级上升。"Read 整个目录树"或"grep 全仓库"这类探索性操作动辄消耗 5-10 万 token,但绝大多数内容主 agent 用完就不再需要。
Sub Agent 的核心价值是让子任务在独立上下文窗口里运行,只把摘要带回来。mer.vin 的描述很到位:“Subagents run in isolated context windows and return summaries—so a research pass does not dump thousands of tokens into the parent thread.” 主 agent 拿到 200 字符的摘要,子 agent 内部消耗的 50,000 token 上下文就被丢弃了。
这是 Claude Code 在大型仓库里依然保持低成本的关键工程手段。Anthropic 工程师在采访中提到:“主 agent 的账单一大半其实花在『找路』上”——加 sub agent 之后,"找路"开销转移到不计费(因为子任务结束就被丢弃)的临时上下文里。
智能体分类
Claude Code 有完整的智能体类型分类:
| 类型 | 来源 | 示例 |
|---|---|---|
| BuiltInAgent | 硬编码 | Explore(Haiku,只读)/ Plan(继承,只读,给 plan mode)/ general-purpose(继承,全工具) |
| CustomAgent | 设置文件 | 用户或项目级 .claude/agents/*.md |
| PluginAgent | 插件包 | 市场分发的智能体 |
内置的 Explore/Plan 默认是只读的——这是为什么 sub agent 上的 omitClaudeMd 默认开启能在整个集群每周节省 5–15 GTok(据 redreamality 估算):只读 agent 不需要 CLAUDE.md 里那些"修改文件应该如何"的规范。
Sub Agent 定义格式
.claude/agents/code-reviewer.md 的 frontmatter 字段决定了它的能力边界:
1 | |
工具子集生效顺序:disallowedTools 先减、tools 后限定(“If both are set, disallowedTools is applied first, then tools is resolved against the remaining pool”)。isolation: worktree 让 sub agent 跑在独立 git worktree(无修改自动清理)——这是 OMC 风格 worktree 工作流的官方原生对应物。
七种任务类型
下表来自 redreamality 分析(单源信息,其它逆向工程文章未提及完整 7 种命名):
| 任务类型 | 隔离级别 | 用途 |
|---|---|---|
| InProcessTeammate | AsyncLocalStorage | 同进程,共享终端 |
| LocalAgentTask | 异步后台 | 非阻塞子智能体 |
| RemoteAgentTask | 远程 CCR | 云端执行 |
| LocalShellTask | 子进程 | Shell 命令 |
| DreamTask | 后台 | 记忆整合 |
| LocalWorkflowTask | 后台 | 工作流脚本 |
| MonitorMcpTask | 后台 | MCP 服务器监控 |
Team 协调模型
多个智能体通过基于文件的 Team 系统协调:
1 | |
通信通过 Mailboxes 异步进行——每个队友有独立的消息队列。协议支持结构化消息:shutdown_request、plan_approval_response、权限冒泡。
关键设计决策:
model: 'inherit'确保子智能体共享父智能体的提示词缓存——字节级对齐缓存命中- 据 redreamality 分析,源码中的
TEAMMATE_MESSAGES_UI_CAP = 50防止内存泄漏(同分析提到此限制前曾在 292 个智能体下达到 36.8GB 内存——单源信息,未在其它社区分析中复现) - 只读智能体(Explore、Plan)上的
omitClaudeMd节省可观 token(每周 5-15 GTok 是 redreamality 估算) AsyncLocalStorage提供隐式上下文隔离,无需显式参数传递
[PATTERN] 多智能体编排模式:Agent 不是单打独斗,而是通过文件系统的 Team 配置 + 异步 Mailbox 消息队列协调。model: 'inherit' 是缓存优化的关键,isolation: worktree 是修改隔离的关键。
工具系统:40+ 内置工具与权限模型
在 6 层 harness 视图下,本节对应"Execution"层;在 MBZUAI 7 组件视图下,对应"Tools Layer"和"Execution Environment"。
源码中的工具列表读起来像一个小型 IDE:
- 文件操作:
BashTool,FileReadTool,FileEditTool,FileWriteTool,GlobTool,GrepTool - 网络能力:
WebFetchTool,WebSearchTool - 笔记本支持:
NotebookEditTool - 智能体调度:
AgentTool,SendMessageTool,TaskCreate/Get/List/Update - 团队协作:
TeamCreate/Delete - MCP 集成:通过标准协议接入外部服务
工具系统的设计原则:Agent 能做什么,完全由它拥有的工具集决定。系统中没有任何"后门"让模型绕过工具系统直接执行操作。
Agent SDK 的 9 个核心内置工具
Anthropic 把 Claude Code 内置工具中最核心的 9 个稳定 API 暴露给 Agent SDK 用户(jidonglab 整理)——这是 Agent SDK 与 LangGraph、CrewAI、OpenAI Agents SDK 拉开差距的关键:别的框架都从空工具集起步,每个工具都要从头实现;Agent SDK 直接把生产级工具塞给你。
| 工具 | 类型 | 默认权限 |
|---|---|---|
Read |
只读 | 自动允许 |
Glob |
只读 | 自动允许 |
Grep |
只读 | 自动允许 |
WebSearch |
只读 | 自动允许 |
WebFetch |
只读 | 自动允许 |
AskUserQuestion |
交互 | 自动允许 |
Write |
写 | 需审批 |
Edit |
写 | 需审批 |
Bash |
副作用 | 需审批 |
"扫描所有 TODO 注释并汇总"这种任务在 Agent SDK 里只要 5 行——allowed_tools=["Read", "Glob", "Grep"] 就开干。在 LangGraph 里同样的任务要 80 行:实现 file reading function、写 shell wrapper、集成 glob 库——这是 Agent SDK 的直接竞争优势。
Tool annotations 与并行执行
工具定义里有一组 annotation 字段,决定 harness 如何调度(jidonglab):
1 | |
readOnlyHint: True 让 Claude Code 把多个只读工具调用打包成并行批次——典型场景下从 5 串行 × 200ms = 1 秒缩短到 200ms。这是 Claude Code 看起来"敏捷"的另一个隐藏机制。
自定义工具:内嵌 MCP Server
Agent SDK 的自定义工具实现机制揭示了 MCP 的设计深度:当你用 @tool 装饰器定义一个工具时,SDK 在内部把它包成一个 in-process MCP server——同一个进程,零网络开销,但走 MCP 协议(jidonglab):
1 | |
工具命名遵循 mcp__{server}__{tool} 模式(如 mcp__weather__get_temperature)——这是为什么 hook matcher 用 ^mcp__ 一行就能拦截所有 MCP 工具:内置工具和自定义工具走同一个命名空间。
错误处理上有一个关键工程设计:handler 抛未捕获异常会导致整个 agent loop 崩溃,但如果 catch 后返回 {"is_error": True, ...},Claude 会把错误当数据,可以重试或换路径。生产代码必须永远 catch-and-return,永远不要 throw。
权限是双层防御
权限有两层独立机制:
- Claude Code 客户端规则:
deny → ask → allow,deny 永远胜出 - OS-level Sandboxing:filesystem / network 隔离(仅作用于 Bash 及其子进程)
Permission 模式有六个:default(首用提示)、acceptEdits(自动接受编辑、mkdir/touch/mv/cp)、plan(只读探索)、auto(背景 classifier 审核)、dontAsk(除预批准外全拒)、bypassPermissions(全跳过,但 rm -rf / 和 rm -rf ~ 仍提示作 circuit breaker——bypass 不是无防护)。
命令解析的两个隐藏陷阱
陷阱一:复合命令分治授权。Bash(safe-cmd *) 不会授权 safe-cmd && other-cmd,因为 &&|/||/;/|/|&/&/换行 都被拆开独立判规则。Process wrapper(timeout/time/nice/nohup/stdbuf + 无 flag 的 xargs)会被预先剥离,所以 Bash(npm test *) 能匹配 timeout 30 npm test。但环境运行器(devbox run / npx / docker exec)不在剥离名单——这是文档专门警告的语义陷阱。
陷阱二:/path 路径锚定。这是新手 deny rule 写错最高频的点:
| 写法 | 含义 |
|---|---|
//path |
文件系统绝对路径 |
~/path |
用户 home 目录 |
/path |
项目根(不是文件系统根!) |
path |
当前工作目录 |
Symlink 走双路径检查:allow 要两端都过,deny 任一命中即拦——这就是项目内 symlink 仍能拦住 ~/.ssh/id_rsa 的机制。
URL 过滤极其脆弱:Bash(curl http://github.com/ *) 挡不住 -X 前置选项、HTTPS 协议、-L 重定向、变量、多空格等变体——文档明确建议改用 PreToolUse hook。
[PATTERN] 工具即能力边界模式:Agentic AI 的能力不取决于模型智能,而取决于工具集的设计。注册-校验-执行-聚合的流水线决定了 Agent 的能力上限。
[PATTERN] 权限路径锚定模式:在 Agentic 系统的 allowlist/denylist 设计中,//abs / ~/home / /project-root / relative 四类锚定语义必须在文档与实现里同时表达,否则用户写出的规则与意图不一致——这是"deny 不生效"类 bug 的高频源。
MCP 集成:开放协议把外部世界接进来
在 6 层 harness 视图下,本节对应"Integration"层。MCP 是 Claude Code 与"外部世界"的接口——也是 Anthropic 在 2026 年 AI 工程生态里下的最大注。
MCP(Model Context Protocol)是 Anthropic 牵头的开放标准,把"模型 ↔ 工具"的连接抽象为三类原语:tools(可调用函数)、resources(可读上下文)、prompts(可复用模板)。MCP 服务器与本地 BashTool/Edit 等内置工具是平级关系——所有暴露的工具最终都进同一个 tool registry,模型在 tool selection 时不区分来源。
MCP Tool Search:按需加载工具 schema
一个常被忽略的工程细节:MCP 工具的 schema 默认不全量加载。如果 Claude Code 启动时把所有注册的 MCP 服务器(GitHub、Slack、Notion、Linear、PayPal……)的所有工具 schema 全塞进 system prompt,每个会话的初始 token 就会爆炸——10 个 MCP 服务器轻松吃掉 30k token。
解决方案是 MCP Tool Search(mer.vin):harness 只在 system prompt 里注入 MCP 服务器的"目录"(每个服务器一段简短描述),具体工具 schema 在模型决定调用某个服务器时才按需加载。这跟 Skill 的三层渐进披露是同一思路——把"能做什么"和"怎么做"分到两个加载时机。
Claude Code 通过三种 transport 连接 MCP:
| Transport | 状态 | 适用场景 |
|---|---|---|
| HTTP(也叫 streamable-http) | 推荐 | 远程服务的主流方式 |
| SSE | 已 deprecated | 仅向后兼容 |
| stdio | 当前 | 本地子进程 |
配置存三个作用域,按精度递减:local(~/.claude.json 内当前项目段)→ project(.mcp.json,可入版本库)→ user(~/.claude.json 全局段)。HTTP/SSE 服务器掉线后自动指数退避重连(最多 5 次,初始 1 秒翻倍);stdio 不自动重连(本地进程语义)。
1 | |
1 | |
环境变量 MCP_TIMEOUT 控启动超时,MAX_MCP_OUTPUT_TOKENS 控单次工具输出上限(默认 10k token 警告阈值)。
Skills:渐进式披露的三层加载
在 6 层 harness 视图下,本节对应"Knowledge"层;Skill 是 CLAUDE.md 的进化版——把"程序性知识"(procedural knowledge)从内联 prompt 中分离出来。
Anthropic 在 2026 年初把 Skills 推为开放标准 Agent Skills,目标是让 PDF 处理、Excel 编辑、品牌规范这类"专家技能"在 Claude Code、Claude Desktop、第三方 Agent 之间通用。MIT 许可,规范公开——这是 Anthropic 在生态层面对 LangChain Tool 抽象的反击:Tool 是函数,Skill 是带文档的工程包。
Skills 是文件系统目录,至少包含一个 SKILL.md,前置 YAML frontmatter 提供 metadata。三级渐进披露是核心设计:
flowchart TD
L1["Level 1 · Metadata<br/>仅 name + description(合计 1,536 字符上限)<br/>启动时全量加载到 system prompt<br/>每个 Skill 约 100 token"]
L2["Level 2 · Instructions<br/>Claude 根据 description 判断匹配后<br/>通过 Read 加载 SKILL.md 正文<br/>建议 5k token 以内"]
L3["Level 3 · Resources<br/>references/*.md / scripts/*.py<br/>仅在 SKILL.md 显式引用时按需加载<br/>scripts 通过 bash 执行,源码不进 context"]
L1 -- 触发 --> L2
L2 -- 按需加载 --> L3
1 | |
字段约束:name 必填,≤64 字符,仅小写字母/数字/连字符,禁用 “anthropic” “claude”。description 必填,≤1024 字符。其它字段(allowed-tools / when_to_use / hooks 等)是 Claude Code 与社区生态的扩展约定。
Skills 与其它机制的边界:
| 谁触发 | 何时加载 | 例子 |
|---|---|---|
| Hook | harness 强制 / 事件触发 | autoformat / permission 拦截 |
| Skill | Claude 选择 / 调用时全量 | pdf-processing / superpowers |
| Sub Agent | Claude 委派 / 独立 context | code-reviewer / explore |
| CLAUDE.md | 用户写 / 启动时全量 | 项目编码规范 |
Custom commands have been merged into skills.(官方表态)
.claude/commands/foo.md 与 .claude/skills/foo/SKILL.md 都创建 /foo,老路径仍然有效。
记忆系统:跨会话持久化
在 6 层 harness 视图下,本节对应"Knowledge"层中"context survival"和"persistent instructions"的部分。
源码暴露了跨会话记忆机制:
| 记忆类型 | 存储位置 | 用途 |
|---|---|---|
| 短期记忆 | 会话内对话状态数组 | 当前对话上下文 |
| 中期记忆 | ~/.claude/memory/ |
用户偏好、常用命令模式 |
| 长期记忆 | DreamTask 后台整合 | 跨项目经验积累 |
记忆系统让 Agent 在后续会话中自动加载历史偏好,表现出"越来越懂你"的行为。/memory 命令读写 MEMORY.md,约定首 200 行或 25KB 加载——和 CLAUDE.md 同样以 user message(不是 system prompt)形式注入。
Auto Dream:REM-Sleep for Agents
claudefa.st 在 2026 年 5 月详细记录了 Anthropic 在 v2.1 系列推出的 Auto Dream 功能——这是 Claude Code 第一次有"睡眠时整理记忆"这样的拟人化机制。
工作流程:
flowchart LR
A[会话结束 / Stop hook] --> B[DreamTask 入队]
B --> C[后台异步执行]
C --> D[读取所有 memory/*.md]
D --> E[LLM 摘要 + 去重]
E --> F[合并相关条目]
F --> G[剪掉 >7 天的过时条目]
G --> H[更新 MEMORY.md 索引]
设计哲学是直接拟人:“像 REM 睡眠一样合并洞察、剪枝陈旧笔记”——这不是修辞,而是工程目标。如果记忆只能 append,1 年后会有 5000 条互相冲突的 note;Auto Dream 让记忆系统自我修复,避免老化。
Anthropic 把 Dream 实现为独立的 sub agent task(DreamTask),而非主 agent 的扩展——这意味着:
- 主 agent 上下文不被占用(dream 是后台进程)
- 主 agent 不知道 dream 在跑,避免"我应该启动 dream 吗"的元思考
- 用户可以独立控制
OMC_DREAM_ENABLED这类开关
KAIROS:从被动响应到主动协作的实验
源码中还发现了代号 KAIROS 的模块(多源确认存在,但定位社区描述分歧):claudefa.st 描述为 “autonomous daemon”,CSDN 描述为 “long-term assistant mode + AutoDream”,redreamality 描述为 “append-only logs”。比较一致的部分是:源码注释将其描述为长期/守护态助手模式(custom system prompt, brief responses, persistent),具备主动心跳、睡眠机制和追加式记忆,能够以 24/7 守护进程的方式监控代码库变化——类似贾维斯的角色。
KAIROS 的关键差异:
| 普通 Claude Code | KAIROS |
|---|---|
| 用户问,Claude 答 | 系统主动 ping 用户 |
| 会话结束即释放 | 会话从不真正结束 |
| 上下文是对话历史 | 上下文是"代码库当前状态" |
| 计费 = token 用量 | 计费 = 守护进程时长 |
这代表了 Claude Code 从"被动响应"向"主动协作"演进的实验性方向。是否会成为产品形态尚未公开——但源码里已经为这种形态准备了基础设施(心跳、睡眠、追加式日志),意味着 Anthropic 在押注这条路径。
隐藏功能:源码中的工程文化彩蛋
BUDDY:终端虚拟宠物系统
BUDDY 模块是 Claude Code 在 2026 年 4 月 1 日(约在 v2.1.x 系列)正式发布的终端虚拟宠物系统。用户在终端输入 /buddy 命令即可孵化一个 ASCII 像素宠物,系统基于用户 ID 的 hash 确定性分配 18 种物种(CSDN 列出全名:duck / goose / blob / cat / dragon / octopus / owl / penguin / turtle / snail / ghost / axolotl / capybara / cactus / robot / rabbit / mushroom / chonk),每种拥有 5 个稀有度分级(Common 到 Legendary)、属性系统(SNARK、WISDOM 等 stats)和装饰系统(帽子等)。宠物会根据任务执行进度表现出不同的情绪状态动画。
技术彩蛋:claudefa.st 提到 capybara 物种代号在源码中用 hex 编码绕过 build scanner——这是个工程文化的小细节,说明发布前曾被严格的命名审查检查过。
训练数据投毒防护:ANTI_DISTILLATION_CC
源码显示 Claude Code 在工具定义中注入了虚假的工具签名和参数描述——由 ANTI_DISTILLATION_CC 标志控制(多源确认)。但有作用域限制:源码中的逻辑仅在 entrypoint === 'official-cli' 或 USER_TYPE === 'ant'(Anthropic 自家员工)以外的场景注入。当该标志激活时,虚假工具定义会被注入到系统提示词中。目的是污染从公开代码库爬取的训练数据:如果竞争对手录制 Claude Code 的 API 流量来蒸馏训练自己的模型,这些虚假工具会污染其训练集。
Undercover 模式:USER_TYPE === ‘ant’
CSDN 与 claudefa.st 双源确认:Anthropic 自家员工(USER_TYPE === 'ant')向公开仓库提 commit 时自动剥离署名和模型代号,注释明确写着"There is NO force-OFF"。这是反向蒸馏外的另一条数据卫生策略——避免内部使用 pattern 通过 git blame 泄漏给外部观察者。
Wizard rules:源码注释中的工程师吐槽
CSDN 提到源码里有大量带有"工程踩坑笔记"性质的注释,譬如警告违反某些 prompt 工程约束的人将面对"a full day of debugging and hair-pulling",又譬如 DIR_EXISTS_GUIDANCE 字符串解释为什么 Claude 在写文件前会反复 ls/mkdir -p 浪费回合——这些直接揭示了 Anthropic 工程师踩过的真实 prompt 工程坑。把"为什么这样写"写在源码注释里而不是单独的 ADR 文档里,是有意识地降低阅读成本的工程文化。
启动延迟优化:apiPreconnect 与 earlyInput
CLI 启动延迟工程化:apiPreconnect.ts 在 module load 同时就开始 TCP+TLS 预握手,earlyInput.ts 让用户在启动过程中就能开始输入。两个机制重叠节省约 100–200ms(CSDN)。--version 短路命中也是同类优化。这是把"工具响应感"做到极致的小细节——LLM 应用通常忽视的边角,Anthropic 把它当成产品体验的一部分。
实践启示
给"构建 Agentic AI 系统"的开发者
- 静态/动态提示词分界:用边界标记明确划分可缓存和不可缓存的内容,最大化 prompt cache 命中率;价格 0.1× vs 1.25× / 2× 的比例决定了"写一次省一万次"的工程口诀
- 采用 AsyncGenerator 模式:替代状态机,获得原生流式、中断和预算控制;Anthropic 把它做成 SDK 的对外 API 抽象就是认可
- Hook 不是模型选择:要让某件事一定发生(autoformat、permission、telemetry),写 Hook 而不是 prompt 规则——但记住"非 0 即失败"是错的,只有 exit 2 真正阻塞
- 权限路径锚定要文档化:
/path是项目根而不是文件系统根这种语义差异必须在 README 中显式说明 - 复合命令分治授权:
&&/||/;/|拆开评估,allowlist 不能假设整行命令是原子的 - 五级覆盖优先级:让不同来源的上下文可组合、可覆盖,而非简单拼接
- 受控降级压缩流水线:从单 tool_result 裁剪到全对话摘要分级处理,优雅降级而非粗暴截断;为压缩失败加
MAX_FAILURES熔断常量 - 文件系统的 Team 协调:轻量、持久、可调试的多智能体通信
model: 'inherit'缓存优化:子智能体通过 byte-identical copies 共享父智能体提示词缓存- isolation: worktree:副作用密集的 sub agent 给一个独立 git worktree,完成自动清理
- Skill / Sub agent / CLAUDE.md / Hook 边界要清晰:谁触发 × 何时加载这两个维度决定了选哪一个,不要让一个机制承担所有事
给"使用 Claude Code 的工程师"
- 投资 harness 而不是 prompt:mer.vin 总结的金句——“Tool descriptions, permissions, CLAUDE.md, and hooks often beat prompt tweaking”。改 prompt 是一次性收益,改 harness 是结构性收益
- 能用 workflow 就别用 agent:Anthropic 自己的 effective agents 文章建议——“Default to workflows when steps are known; use full agent loops only when exploration is required”。Agent 看似聪明但不可预测,工作流可控但需要你写 DAG
- 设预算上限:
max_turns与max_budget_usd是两个核武器,生产环境必须设。事故案例:1,279 sessions 跑 50+ 轮 autocompact 失败,每天烧 25 万 API 调用——不是模型出错,是没设上限 - 把规则写在 CLAUDE.md,不要写在 chat 里:压缩会丢 chat,CLAUDE.md 自动重读。所有"以后都这样做"的指令必须 commit 到 CLAUDE.md
- 想象自己只看到上下文窗口的最后一屏:mer.vin 的建议——“if you would be lost with only the last screenshot and tool output, the model will be too”。Agent 也是只能看到上下文,预测它能否完成任务的最简方法就是站在它的位置上看
给"评估竞品 AI 编码工具"的人
MBZUAI 论文的发现是关键工具:四支独立团队(Anthropic / OpenAI / Cursor / Devin)在没有相互参考的前提下,agent harness 的 7 个组件几乎完全重合——这意味着:
- 比较 harness 完整度,而不是模型聪明度:模型在快速商品化,每 6 个月排名洗牌;harness 是结构性工程,差距更稳定
- 看 hook 系统:是否覆盖十余类生命周期事件(会话/输入/工具/权限/子智能体/压缩/文件等节奏)、是否支持 deny-wins 链、是否能拦截 LLM-as-judge——这是工程化深度的标尺
- 看上下文管理:是否有多级压缩、是否暴露 PreCompact 钩子、是否有 cache write/read 比例的可观测性
- 看权限模型:deny > ask > allow 的三层链是基线,复合命令分治、symlink 双路径检查是工程化标志
- 看 SDK 是否对外稳定:Anthropic 把 Agent SDK 做成 Python/TypeScript 双 SDK,意味着 harness 设计已经成熟到可以承诺兼容性。还在频繁重命名内部抽象的工具说明设计还没收敛
看完这一篇之后
如果你只能记住三句话:
- Claude Code 不是 LLM CLI,是个 harness 系统——模型外面那一圈(permission / hook / compaction / sub-agent / cache)才是真正决定它好不好用的地方
- AsyncGenerator + mutableMessages 是核心抽象——一个生成器吐 token,一个数组累积历史,所有复杂功能都是绕着这两个抽象长出来的
- harness engineering 是 2026 年 AI 工程的主战场——MBZUAI 论文已经把"四个团队独立收敛到同一架构"的现象量化了。如果你在做 Agent 产品,应该把投资从 prompt 转向 harness
参考资料
官方文档(2026 年 docs.anthropic.com 已迁移到 platform.claude.com / code.claude.com)
- Prompt caching - Claude Docs
- Streaming Messages - Claude Docs
- Agent Skills overview - Claude Docs
- Connect Claude Code to tools via MCP
- Claude Code Hooks
- Claude Code Sub Agents
- Claude Code Permissions
- Claude Code Memory
- Model Context Protocol
- Equipping agents for the real world with Agent Skills - Anthropic Engineering
社区源码逆向工程
- Claude Code Leak: A Deep Dive into Architecture - redreamality.com
- The Claude Code Source Code Leak - Marco Kotrotsos - Medium
- Inside Claude Code’s Prompt Architecture - Marco Kotrotsos - Medium
- Claude Code Source Code Exposed — Every System Explained - dev.to
- How Claude Code is built - Pragmatic Engineer
- Claude Code’s Real Secret Sauce - Sebastian Raschka
- 我用 Claude Code 深度解读 51 万行 Claude Code 源码 - 知乎
- 从 Harness 角度对 Claude Code 源码深度解读 - 51CTO
- Claude Code 源码分析笔记 - 腾讯云
- 程序员鱼皮 - Claude Code 隐藏的 11 个秘密 - CSDN
- ThreeFish-AI/analysis_claude_code - GitHub
- Piebald-AI/claude-code-system-prompts
- liuup/claude-code-analysis
- HackerNoon - Hidden Pixel Pet System
- claudefa.st - Claude Code Source Leak Everything Found
2026 年 5 月后的二次分析与学术化
- Claude Code Architecture Explained: Six Harness Layers Beyond the LLM - mer.vin(六层 harness 视图的官方文档对照)
- Claude Agent SDK Deep Dive - jidonglab(query/ClaudeSDKClient 入口、18 hook 事件、9 内置工具、自定义工具的 in-process MCP 包装)
- Claude Code 98% Harness: Four Competing Teams Built Same Agent Harness - TechTimes(MBZUAI 论文的工业转述,七组件抽象与"独立收敛"现象)
- The Claude Code Harness: 7 Components Explained - claudefa.st(七组件的工程师视角解读)
- Harness Engineering: Making AI Coding Agents Work in 2026 - Faros AI("AI 工程第三阶段"的行业框架)
- Claude Code Auto Dream - claudefa.st(Auto Dream 机制详解)
- Claude Code Context Window - claudefa.st(多级压缩管理)
- System Architecture - DeepWiki for anthropics/claude-code(自动生成的系统架构索引)
- Agent System & Subagents - DeepWiki(子智能体与 worktree 隔离的工程细节)
- Claude Code 的隐秘成长史与一个 AI Agent 的进化密码 - 知乎(从 Boris Cherny 的 MVP 到现在的进化路径)
- Claude Code 与 Codex Harness 设计对比:一种加法,一种减法 - openeuler.csdn.net(与竞品的设计哲学对比)
- jeffreygao/claude-code-source-code - GitHub(v2.1.88 反编译归档)


