浩子的小站

深度揭秘 Claude Code:为什么它是最强大的 AI 编程助手?

字数统计: 3.5k阅读时长: 12 min
2026/04/03

基于 Claude Code v2.1.88 还原源码分析


前言

如果你把市面上的 AI 编程工具都用一遍,会很快发现一个区别:

有些工具第一回合看起来很惊艳,但任务一复杂、会话一拉长、工具一并发,就开始变钝、变乱、变得需要你不停接管。

Claude Code 不一样。

它不一定总是“最会炫技”的那个,但往往是那个最稳、最顺、最像能长期干活的系统

我最近把 Claude Code v2.1.88 的还原源码完整过了一遍。看完之后,我的判断比以前更明确了:

Claude Code 的优势,并不主要来自模型本身,而来自它把 Agent 做成了一套完整 runtime。

这篇文章我不再停留在“它很好用”的层面,而是回答三个更具体的问题:

  1. 它到底在哪些源码层面做得更好?
  2. 这些设计为什么会直接影响日常使用体验?
  3. 如果你也在做自己的 Agent,到底该抄它哪些作业?

先说结论:Claude Code 强在“运行时”,不是强在某个单点功能

很多人总结 Claude Code,会列一串功能:

  • 工具多
  • 命令多
  • 权限做得细
  • 会话更稳
  • 支持多代理

这些都对,但还不够准确。

更准确的说法是:

Claude Code 真正强的,是它把“工具调用、上下文治理、权限控制、异常恢复、多代理隔离”都收敛进了同一套运行时。

换句话说,它不是“模型 + 一堆工具”的拼装,而是已经很接近一个 Agent OS。

Claude Code 的运行时蓝图

如果你只盯着某个文件,比如最大的 query.ts,很容易看得很累。

更有效的阅读方式,是先建立这张脑内地图:

  • main.tsx 负责启动、预热、装配
  • QueryEngine.ts 负责 session lifecycle
  • query.ts 负责主循环
  • services/tools/* 负责工具调度和执行
  • services/compact/* 负责上下文治理
  • useCanUseTool.tsx 和 permissions 相关服务负责权限链路
  • AgentTool / coordinator/* / remote/* 负责多代理和隔离执行

这也是 Claude Code 和很多 Agent 工具最大的差别:
后者往往是“哪里需要逻辑就往哪里塞”,而它更像一套职责明确的系统。

如果你今天就要开始读这份源码,我建议不要一上来啃最大的文件,而是按“启动装配 -> 会话生命周期 -> 主循环 -> 工具执行 -> 治理链路”这条主线往下走。

Claude Code 源码阅读顺序

更具体一点:

  • 先看 main.tsx,搞清楚启动阶段到底装了哪些能力
  • 再看 QueryEngine.ts,理解一次 session 是怎么被收口成统一入口的
  • 然后进 query.ts,看真正的 agent loop 怎样处理流式输出、工具调用和恢复逻辑
  • 接着顺着 StreamingToolExecutor / toolOrchestration.ts 往下,理解它为什么能在复杂任务里保持工具执行秩序
  • 最后再看 compact 和 permissions 相关代码,理解它为什么不会越聊越乱、越跑越危险

这个阅读顺序的好处是,你会先建立系统模型,再去看实现细节。否则很容易一头扎进 query.ts 以后,只看到大量分支,却看不清这些分支为什么存在。

一、它不是把模型塞进终端,而是把会话生命周期从 UI 里抽了出来

这是 Claude Code 最值得学的一点。

很多 Agent 工具一开始就把自己写死在 UI 或 CLI 交互层里:

  • 输入框状态在组件里
  • 工具执行在某个回调里
  • 权限确认是个弹窗逻辑
  • 会话恢复是另一个补丁

短期能跑,但一旦你要支持:

  • Headless 模式
  • SDK 接入
  • 子代理
  • 远程执行
  • 自动恢复

整个结构就会开始打架。

Claude Code 的解法是:先定义运行时,再定义交互层。

源码里最关键的分工就是:

  • main.tsx 负责启动阶段的装配和预热
  • QueryEngine.ts 负责把一次会话的生命周期串起来
  • query.ts 负责进入真正的 agent loop

这背后的实际价值非常大。

因为它意味着:

  • UI 不承担核心业务状态
  • REPL 和 SDK 复用同一套执行路径
  • 工具调用、消息回写、权限拒绝、压缩、fallback 都能挂在统一 runtime 上

从工程上说,这几乎就是一句话:

不要把 Agent 写成“聊天界面调模型”,要把它写成“交互界面调用运行时”。

如果你自己在做 Agent,这是一条优先级极高的建议。
因为一旦这层没抽干净,后面加再多能力都会越来越乱。

二、Claude Code 真正拉开差距的,不是工具数量,而是工具调度系统

很多 Agent 工具都会宣传:

  • 能读文件
  • 能改文件
  • 能执行命令
  • 能联网

但真正复杂任务里的问题从来不是“有没有工具”,而是:

  • 哪些工具能并发?
  • 哪些工具必须串行?
  • 某个工具失败后,兄弟任务还要不要继续?
  • 用户打断后,是取消还是等待安全收尾?
  • 工具结果该不该立刻写回上下文?

Claude Code 在这件事上做得非常重。

一次请求如何穿过 Claude Code

1. 批次级调度,不是简单顺序执行

services/tools/toolOrchestration.ts 里,你能看到一个很关键的思想:

工具调用先被按语义分批,再决定执行顺序。

核心判断是 isConcurrencySafe

这意味着 Claude Code 并不是默认:

  • 全部串行
  • 或全部并发

而是会先看工具的副作用语义:

  • 读操作、查询操作,更适合并发
  • 写操作、有状态修改的操作,更适合串行

很多工具做不稳,不是因为模型笨,而是因为它们把“调度”问题错误地交给了模型自己解决。

Claude Code 没这么做。
它把“工具是不是并发安全”上升成了运行时知识。

2. StreamingToolExecutor 处理的是“执行中的世界”,不是“执行前的想象”

更关键的一层,在 StreamingToolExecutor

这里真正处理的是一个更现实的问题:

模型的输出是流式的,工具调用也是动态到达的。
所以运行时要处理的不是“拿到一组完整工具调用后怎么执行”,而是:

  • 工具边到达边进入队列
  • 有的已经开始执行
  • 有的还在等待
  • 有的可能需要取消
  • 有的已经完成但不一定该立即暴露

源码里能看到它明确区分这些状态:

  • queued
  • executing
  • completed
  • yielded

同时还处理:

  • sibling abort
  • interrupt behavior
  • fallback 时丢弃未完成结果
  • 某个工具失败时如何传播取消

这已经不是“tool calling”,而是接近一个 action scheduler。

如果你自己做 Agent,我会建议你优先补两层:

  1. 工具语义声明
  2. 运行时调度器

不要幻想 prompt 自己就能把这件事解决掉。

三、长会话为什么不容易崩:它把上下文当成受控资源来治理

很多 Agent 第一次用都不错,真正拉开差距的是第十次、第二十次回合以后。

这时会暴露两个问题:

  • 上下文越来越乱
  • 错误恢复越来越差

Claude Code 在这块下了很重的功夫,而且不是简单一句“超长了就总结一下”。

Claude Code 如何避免长任务失控

services/compact/* 相关代码里,你能看到它至少做了这些事情:

  • 估算有效上下文窗口
  • 为 compact summary 预留 token
  • 设置 warning threshold / error threshold / blocking limit
  • 区分 reactive compact、micro compact、trim compact 等不同处理方式
  • 在连续失败时熔断,避免 session 无限重试

这套设计最值得学的地方在于:

它把上下文溢出视为系统故障,而不是普通异常。

这和很多 Agent 工具的思路完全不同。

后者的逻辑通常是:

“超长了?那就随便总结一下吧。”

Claude Code 的逻辑更像:

“上下文是受控资源,需要像内存一样治理。”

这也直接解释了为什么它在长会话里更稳。
不是因为模型突然更聪明,而是因为运行时在持续控制上下文债务。

四、权限系统为什么“既不放任,也不烦人”

很多 Agent 工具在权限这件事上会走两个极端:

  • 全放开,结果很危险
  • 全询问,结果很烦

Claude Code 比较成熟的地方在于,它没有把权限做成一个 UI 弹窗功能,而是做成一条运行时链路。

源码里至少可以看到这些层:

  • allow / deny / ask 规则
  • 工具粒度匹配
  • MCP server 级匹配
  • sandbox override
  • working directory 限制
  • hooks 决策
  • classifier 辅助决策

useCanUseTool.tsx 则把这整套链路真正串起来,并根据运行模式区分:

  • 交互式会话怎么处理
  • 子代理怎么处理
  • swarm / coordinator worker 怎么处理
  • headless / SDK 怎么处理

这背后的启发很明确:

权限不是“操作前问一句”,而是“运行时是否允许进入下一步”的统一判定。

如果你把权限只做成弹窗,后面一旦要支持后台代理、远程代理、多代理协作,整个权限体系很容易立刻崩掉。

五、最有指导意义的一点:它已经在为“真正的软件代理”做地基

如果你继续往下看,就会发现 Claude Code 早就不只是一个本地 CLI。

源码里能看到非常多信号:

  • AgentTool 支持 background / teammate / remote / worktree 等不同执行后端
  • coordinator/* 在处理多代理协作
  • remote/* 在处理远程运行
  • plugins / skills / MCP 形成分层扩展体系
  • main.tsx 启动阶段已经在预取远程托管配置和能力注册信息

最关键的是,它并不是把这些能力都塞进一个“大插件系统”。

它的做法更像分层装配:

  • commands 解决用户入口
  • tools 解决能力执行
  • skills 解决可复用工作流
  • plugins 解决本地扩展
  • MCP 解决外部能力接入

这套分层有两个直接好处:

  1. 用户入口清晰,不会所有能力都混成一种东西
  2. 不同能力类型可以走不同的安全与权限策略

这也是为什么我会说:Claude Code 不是在做一个“更强的聊天助手”,而是在做一个软件代理基础设施

六、如果你也在做 Agent,最值得先抄哪几块作业?

这是看完源码以后,我觉得最有现实意义的部分。

因为大多数团队并不需要一次性做出 Claude Code 的全部能力,但非常值得先抄这四块。

做自己的 Agent 该先抄哪四块作业

1. 先把运行时和交互层分开

第一优先级,不是多加一个工具,而是把:

  • 会话生命周期
  • 工具调用
  • 消息回写
  • 权限判定
  • 上下文治理

从 UI 里抽出来。

如果这一步不做,后面一旦加 Headless、自动化、子代理,代码会迅速失控。

2. 给工具加“语义”,不要只加 schema

很多团队做工具时,只定义:

  • 名称
  • 入参
  • 出参

但真正决定稳定性的,是工具的运行时语义,比如:

  • 是否可并发
  • 是否有副作用
  • 是否可以打断
  • 失败后是否影响兄弟任务

Claude Code 强就强在这里。
它不是只知道“怎么调用工具”,而是知道“该怎么运行工具”。

3. 把上下文当成资源管理问题

不要把上下文管理理解成“写个总结 prompt”。

更稳的做法是:

  • 先算预算
  • 再设阈值
  • 然后定义 warning / blocking / compact 策略
  • 最后加失败熔断

这会极大改善长会话稳定性。

4. 权限一定要走统一判定链

如果未来要支持:

  • 子代理
  • 远程执行
  • 自动化 worker

那权限系统必须是一条统一 runtime 链路,而不是各处散落的 if / confirm。

这件事越晚补,成本越高。

七、隐藏功能值得看,但它们不是 Claude Code 最核心的竞争力

源码里确实还能看到很多有意思的东西:

  • Undercover mode
  • Buddy 宠物系统
  • KAIROS 自主代理模式
  • 语音模式
  • 远程托管设置
  • 大量 feature flags

这些都说明 Claude Code 的产品边界远比表面看起来大。

但如果只把注意力放在这些“彩蛋”上,会错过真正重要的部分:

Claude Code 最核心的竞争力,不是它藏了多少功能,而是它已经把 Agent 的基本盘做对了。

也就是:

  • runtime 抽象
  • 工具调度
  • 上下文治理
  • 权限链路
  • 多代理隔离

这些才是决定它为什么能长期稳定工作的东西。

最后一句

如果你今天还把 Agent 理解成“一个会聊天、会写代码的大模型外壳”,那你看到的还是第一阶段。

Claude Code 源码真正让我确认的一件事是:

下一代 Agent 的竞争,拼的已经不是“谁更会回答”,而是:

  • 谁更像一个运行时
  • 谁更像一个系统
  • 谁更能在复杂任务里保持稳定、可控、可扩展

Claude Code 之所以更好用,不是因为它更会说,
而是因为它更会工作。


源码信息

  • 分析版本:Claude Code v2.1.88
  • 代码量:约 163,000 行 TypeScript
  • 文件数:1,884 个文件
  • 主要语言:TypeScript 6.0+ / Bun
  • 终端 UI:React + Ink

源码仓库:

注:本文仅供学术研究与教育目的。使用者应自行遵守相关法律法规及服务条款。

CATALOG
  1. 1. 深度揭秘 Claude Code:为什么它是最强大的 AI 编程助手?
    1. 1.1. 前言
    2. 1.2. 先说结论:Claude Code 强在“运行时”,不是强在某个单点功能
    3. 1.3. 一、它不是把模型塞进终端,而是把会话生命周期从 UI 里抽了出来
    4. 1.4. 二、Claude Code 真正拉开差距的,不是工具数量,而是工具调度系统
      1. 1.4.1. 1. 批次级调度,不是简单顺序执行
      2. 1.4.2. 2. StreamingToolExecutor 处理的是“执行中的世界”,不是“执行前的想象”
    5. 1.5. 三、长会话为什么不容易崩:它把上下文当成受控资源来治理
    6. 1.6. 四、权限系统为什么“既不放任,也不烦人”
    7. 1.7. 五、最有指导意义的一点:它已经在为“真正的软件代理”做地基
    8. 1.8. 六、如果你也在做 Agent,最值得先抄哪几块作业?
      1. 1.8.1. 1. 先把运行时和交互层分开
      2. 1.8.2. 2. 给工具加“语义”,不要只加 schema
      3. 1.8.3. 3. 把上下文当成资源管理问题
      4. 1.8.4. 4. 权限一定要走统一判定链
    9. 1.9. 七、隐藏功能值得看,但它们不是 Claude Code 最核心的竞争力
    10. 1.10. 最后一句
    11. 1.11. 源码信息