深度拆解:Claude Code 源码揭秘!它为什么是目前最强的 AI 程序员?
最近,Claude Code 意外泄露了 map 文件,导致其源码文件被完整还原。我下载了 npm 包里的 cli.js.map,从中提取出了 4756 个源码文件。沿着入口、提示词、工具、权限、Agent 调度、插件、Hook 一路拆解下去,我发现了一个令人震惊的事实:
大家津津乐道的 Claude Code 的 System Prompt,其实只是冰山露出水面的一小块。
这篇文章,我会把冰山下面的部分摊开给你看。你不需要是做 Agent 产品的硬核工程师,也能从里面看到一套顶级的系统设计思路。看完之后,你再去看市面上任何一个 AI Agent 产品,都会比之前多一层极其敏锐的判断力。
一、大多数人对 Claude Code 的理解,停在了表面
现在网上流传的关于 Claude Code 的分析,绝大部分只聚焦在两件事:它的 System Prompt 写了什么?它调了哪些工具?
这两件事确实重要,但它们只是这个系统的“皮肤”。如果你拿到同样的 Prompt,接上同样的工具,照猫画虎写一遍,出来的东西和 Claude Code 的实际体验差距依然会非常大。
差在哪?差在 Prompt 背后有一整套编排机制,工具背后有一整条治理流水线,Agent 背后有一套分工和调度系统,生态扩展背后有一套让模型“知道自己能干什么”的感知通道。
这些东西加在一起,才构成了你用 Claude Code 时感受到的那个“稳”。这个稳,不是来自某段神奇的文案,而是来自极其扎实的工程底座。
二、源码结构第一眼:这不是 CLI 工具,这是一个运行平台
从 src/ 目录的顶层看,Claude Code 至少包含了这些核心模块:
-
入口层 (entrypoints) -
常量与提示词 (constants) -
工具定义 (tools) -
运行时服务 (services) -
命令系统 (commands) -
协调器 (coordinator) -
记忆系统 (memdir) -
插件与 Hook 系统 (plugins / hooks) -
任务系统 (tasks)
光看这个目录结构就能感觉到,这不是一个简单的“把大语言模型(LLM)接到终端里”的套壳项目。
入口层更能说明问题。它有四个入口:CLI、初始化流程、MCP 模式、SDK。这意味着同一个 Agent 运行时,可以服务四种不同的交互界面。这是典型的平台化设计标志。
命令系统也不是点缀。它注册了 /mcp、/memory、/permissions、/plan、/agents 等十几个系统级命令。而且,命令系统不只加载内建命令,还统一加载插件命令、技能命令。所以,命令系统本身就是整个生态的入口。
回头想想,大部分开源 Coding Agent 的目录长什么样?通常是一个 main 文件,一个 prompt 文件,几个 tool 文件,再加一个 utils。Claude Code 的目录结构跟它们完全不在一个量级,这个量级差异不是为了好看,是因为它要解决的工程问题本身就更多、更深。
三、Prompt 不是一段话,是一台“动态组装机器”
这可能是整个源码里最反直觉的部分。
大多数人以为 System Prompt 是一大段固定文本,启动时塞给模型就完了。Claude Code 完全不是这样。它的 System Prompt 是由一个叫 getSystemPrompt() 的函数动态拼装出来的。
这个函数做的事,更像一个编排器。它先拼一组静态模块,再根据当前会话状态拼一组动态模块。
- 静态部分(宪法):
包括身份定位、系统规范、做任务的哲学、风险动作规范、工具使用规范、语气风格等。不管什么会话,这些底线规则都不变。 - 动态部分(当期政策):
根据你这次用的工具、连了哪些 MCP、用的什么语言、开没开 brief 模式,动态注入 session guidance、环境信息、token budget 等。
💡 核心亮点:Token 经济学与缓存边界
源码里有一个叫 SYSTEM_PROMPT_DYNAMIC_BOUNDARY 的标记,注释里写得很清楚:边界之前的内容尽量保持 Cache 友好,边界之后是用户和会话特定的内容,不能乱改,否则会破坏缓存。
这意味着 Anthropic 在管理 System Prompt 的时候,已经在算经济账了。边界之前的内容因为稳定,可以被 API 层缓存,不用每次都重新计算;边界之后的内容因为会变,所以放在后面,不影响前面的缓存命中。
大部分人写 Prompt,根本不会想到这一层。但当你的产品每天要处理海量请求,每个 Token 都有成本的时候,这种设计直接决定了产品的商业可行性。
四、行为规范:怎么训一个 AI 工程师“不乱来”
Claude Code 有一个叫 getSimpleDoingTasksSection() 的模块,这可能是整个系统里最不起眼但最有用的部分。它做的事很简单:告诉模型什么该做,什么不该做。而且列得极其具体:
-
不要加用户没要求的功能。 -
不要过度抽象,不要瞎重构。 -
不要做不必要的错误处理和兜底逻辑。 -
先读代码再改代码,不要轻易创建新文件。 -
方法失败时先诊断原因再换策略。 -
结果要如实汇报,不能假装自己测试过了。
如果你用过其他 Coding Agent,你一定遇到过这些崩溃瞬间:让它改个 Bug,它顺手给你重构了半个文件;让它加个功能,它给你加了三层抽象;让它测一下,它说“测试通过了”,但其实根本没跑代码。
这些问题的根源不是模型笨,是模型的行为没有被约束。Claude Code 解决这个问题的方式,不是靠更聪明的模型,是靠把行为规范写成制度。
风险动作规范也是同样的思路。系统定义了什么叫“需要确认的风险动作”(如破坏性操作、修改共享状态等),并强调:不要用破坏性操作当捷径,遇到陌生状态先调查。这种设计的思路是把 Blast Radius(爆炸半径)意识编进系统。你不能指望 AI 每次都自己想到操作的后果,但你可以在系统层面强制它停下来确认。
五、多 Agent 分工:为什么一个人做不好所有事
源码里确认了至少六个内建 Agent:General Purpose、Explore、Plan、Verification、Guide、Statusline Setup。
这个设计选择不是为了炫技,它背后有一个很清晰的判断:让一个 Agent 同时做研究、规划、实现、验证,最后每件事都会做成一锅粥。
- Explore Agent(纯只读模式):
不能创建、修改、删除文件,不能运行改变系统状态的命令。它只能用 Glob、Grep、FileRead 探索代码。为什么要这么做?因为探索阶段如果不小心改了代码,后面的实现阶段就会出 Bug。把探索和实现的权限彻底隔离,是一种极其有效的安全设计。 - Plan Agent(架构师):
也是只读。它的职责是理解需求、探索架构、输出逐步实现计划。规划和实现分开,保证了 AI 在写代码前能专心想清楚怎么做,而不是急于动手。
六、Verification Agent:整个系统里最值钱的设计
Verification Agent(验证 Agent)的 Prompt,在整个源码里可能是写得最“狠”的一个。
它的核心方向根本不是“确认实现看起来没问题”,它的方向是:Try to break it(想办法搞坏它)!
Prompt 开头就点出了 LLM 最容易犯的两类验证失败模式:
- Verification avoidance(逃避验证):
只看代码不跑检查,写个 PASS 就走了。 - 被前 80% 迷惑:
UI 看起来还行,测试也过了,就忽略剩下 20% 的深层问题。
为了反制这种惰性,Prompt 强制要求了一系列硬核验证动作:必须跑 build、跑测试套件、跑 linter;前端改动要跑浏览器自动化;后端改动要用 curl 实测响应;数据库迁移要测 up/down 和已有数据。更狠的是,它要求做 adversarial probes(对抗性探测),主动去找边界情况和破绽,最后必须给出明确的 VERDICT(结论)。
这个设计解决了 LLM 验证工作中最常见的问题:“差不多就算了”。写代码的 Agent 往往会觉得自己写得没问题(自我确认偏见),但独立的验证 Agent 没有这个偏见,它的 KPI 就是找茬。这种“实现者和验证者分离”的思路,在传统软件工程里是常识,但在 AI Agent 系统里,Claude Code 是少有的真正落地的产品。
七、Agent 调度链:14 步 Pipeline 绝不是过度设计
一个子 Agent 从被触发到执行完成,在 Claude Code 里要经过一条长达 14 步的完整流水线:
-
主模型决定调用 Agent 工具 -
AgentTool.call() 解析输入并判断类型 -
选择 Agent 定义并构造 Prompt messages -
构造或继承 System Prompt -
组装工具池并创建专属 ToolUseContext -
注册 Hooks、Skills、MCP servers -
调用 runAgent() 内部调用 query() 进入主循环 -
产出消息流,记录 transcript,处理生命周期,清理资源…
这看起来繁琐,但每一步都在解决具体问题。比如 Fork 路径与 Normal 路径的区分:当你 fork 一个子任务时,它会继承主线程的 System Prompt 和完整对话上下文。为什么?为了让 API 请求的前缀保持字节级一致,从而完美复用主线程的 Prompt Cache。
普通人做子 Agent 调度,想的是“子任务能跑起来就行”;Claude Code 想的是“子任务能跑起来,而且要尽量复用主线程的缓存,绝不白烧用户的 Token”。
八、工具执行:不是一步到位,是一条治理流水线
当模型决定调用一个工具时,Claude Code 绝不是简单粗暴地直接执行对应的函数。它的实际链路是:
解析 Metadata -> Zod schema 输入校验 -> 跑 validateInput -> 风险预判 (speculative check) -> 运行 PreToolUse Hooks -> 权限决策 -> 真正执行 -> 记录追踪 -> 运行 PostToolUse Hooks
这里面最精妙的是 Hook 系统。Hook 不只能记日志,它能改写输入,能直接放行或拒绝,能补充上下文信息。但 Hook 的权力是受控的:Hook 说 allow,不一定能绕过系统设置里的 deny 规则;如果工具要求用户交互,Hook 没提供替代输入,依然要乖乖走权限流程。
整条链路的设计哲学非常清晰:默认假设事情会出问题。模型可能乱传参数(所以有校验),操作可能有风险(所以有权限),执行可能失败(所以有失败 Hook)。提前把“可能出问题”的地方都堵住,系统才会抗打。
九、生态扩展:关键是让模型“知道”
Claude Code 有三套扩展机制:Skill(工作流包)、Plugin(行为扩展单元)、MCP(模型上下文协议)。
很多平台也有插件系统,但最大的问题是:模型本身不知道这些东西存在。就像你给一个人配了一整套顶级工具箱,但他根本不知道箱子里有什么。
Claude Code 的做法是,通过各种通道(如动态注入 System Prompt),把工具箱的清单和使用说明都放到模型看得见的地方。让模型感知到自己当前有哪些扩展能力、什么时候该用、怎么用。这才是生态真正能发挥作用的前提。
十、产品化的最后一公里:生命周期管理
在 runAgent() 的源码里,有大量不起眼但极其重要的代码:recordSidechainTranscript()、cleanupAgentTracking()、killShellTasksForAgent()。
后台 Agent 有独立的控制器,支持异步完成和通知;前台 Agent 可以转后台。这说明 Anthropic 把日志记录、性能追踪、资源清理、会话恢复、前后台切换,都当成了运行时生命周期的正式组成部分。
大部分开源 Agent 系统只管“跑起来”,但任务中断了怎么续?脏状态怎么清?这些问题不解决,产品永远只能是个 Demo。Claude Code 跨越了这道鸿沟,完成了产品化的最后一公里。
💡 总结:你能从中学到什么?
拆解完这 4756 个源码文件,我们可以把 Claude Code 强大的秘密提炼为 5 条核心设计原则。这不仅适用于 Coding Agent,也适用于几乎所有需要 LLM 做复杂任务的系统:
- 不要信任模型的自觉性:
好行为要写成制度(Prompt),坏行为要用 Runtime(运行时)去硬限制。 - 把角色拆开:
至少把“做事的人”和“验收的人”分开,用对抗性验证打破 LLM 的自我确认偏见。 - 工具调用要有治理:
从输入校验到风险预判,再到事后处理,必须形成完整的流水线,而不是裸调函数。 - 上下文就是预算:
每个 Token 都有成本,要精打细算,善用动态边界和缓存复用。 - 生态的关键是模型感知:
必须让模型明确知道自己有什么能力、什么时候该用。
夜雨聆风