Claude Code 源码扒穿了:真正的 Agent 系统,根本不是“Prompt+Tool”那么简单
很多人第一次接触 Claude Code,都会以为它只是一个“更强的 coding agent”:能读代码、改代码、跑命令、调工具,仅此而已。
但如果你真的把它的源码体系拆开看,你会发现,事情完全不是这样。
Claude Code 的底层并不是“一个大模型 + 几个工具 + 一段循环逻辑”这么简单。恰恰相反,它更像一个完整的 Agent Operating System。它有多入口架构,有主循环状态机,有精密的 Prompt 编排系统,有严格的工具治理流水线,有多 Agent 分工,有权限与 Hook 安全层,有 Skill / Plugin / MCP 生态,还有完整的上下文预算与产品化生命周期管理。
而且,这不是一种抽象想象,而是可以从源码规模里直接感受到的系统密度。
Claude Code 的源码素材来自 npm 包中的 cli.js.map,其中 sourcesContent 能还原出接近 4756 个 TypeScript 文件。它的 src 顶层不是几个常见目录,而是包含大量模块:例如 utils 有 564 个文件,components 有 389 个文件,commands 有 207 个文件,tools 有 184 个文件,services 有 130 个文件,hooks 有 104 个文件。几个关键核心文件的规模也非常夸张,比如 main.tsx 有 4683 行,toolExecution.ts 有 1745 行,query.ts 这个主循环有 1729 行,AgentTool.tsx 有 1397 行。
Claude Code 的竞争力,已经不主要来自“模型够不够聪明”,而来自“系统有没有被工程化”。
一、Claude Code 不是单一 CLI,而是一个平台化运行时
很多人做 AI Agent,第一反应是先做一个命令行入口,用户输入一句话,然后模型开始干活。
从入口层看,它同时暴露给 CLI、MCP、SDK、IDE 插件等多个场景使用。同一个 Agent runtime,可以服务不同接入面。更关键的是,它的 CLI 入口不是一上来就把完整系统全加载,而是先做 fast-path 分发。像 –version、daemon、remote-control、ps、logs、attach、kill 这些路径,都会走各自的快捷逻辑;只有没有命中 fast-path 时,才加载 main.tsx,且大量模块采用 dynamic import 按需加载。
这类设计看起来很“工程师”,但背后其实是很强的产品意识。
因为当一个工具被高频调用时,启动成本本身就是体验的一部分。你不能每次只想查个版本号,都把整个 Agent 运行时拉起来。真正的平台化产品,首先考虑的不是“功能能不能跑”,而是“哪些场景根本不该动用完整系统”。
另外,Claude Code 还有超过 100 个命令,命令系统本身不仅是用户操作入口,更是插件命令、技能命令、动态技能和 bundled skills 的统一控制面。换句话说,它的命令层并不是点缀,而是系统的控制台。
二、真正的核心,不是模型,而是 query.ts 这颗“心脏”
如果说 Claude Code 整个系统有一个绝对核心,那就是 query.ts。
“1729 行的状态机”,我觉得这个判断非常准确。Claude Code 并不是简单地“调一次模型、等回复、再决定下一步”,而是用一个 while(true) 的主循环,加上 state 对象驱动整套运行时不断前进。一次请求真正跑起来时,会经历上下文压缩、system prompt 组装、模型调用、流式处理响应、工具执行、错误恢复、stop hooks、token budget 检查、结果注入,然后进入下一轮。
因为很多人做 Agent,关注点停留在“如何让模型会用工具”;而 Claude Code 关注的是“如何让一个复杂任务稳定跑很多轮,而且每一轮都能恢复、能续跑、能处理异常、能控制成本”。
这其实已经不是 Prompt Engineering,而是 Runtime Engineering。
更有意思的是,Claude Code 早期 apparently 还用过递归式 query,但后来改成了 while(true)+state 的状态机方案。原因很朴素:递归在长会话里容易爆栈,而状态机更适合长生命周期任务。代码中甚至有多个 continue 点,对应“为什么要再来一轮”的不同原因,比如下一轮工具调用、reactive compact 重试、max output tokens 恢复、stop hook 阻断、token budget 继续等。
三、Claude Code 最狠的地方,是它把 Prompt 做成了“制度”
很多人把 Prompt 当成一段提示词,Claude Code 则把 Prompt 做成了一个分层、可缓存、可动态注入、可治理的制度系统。
它的 getSystemPrompt() 返回的是字符串数组,每一段都对应一个 section。整套 prompt 明确分为静态部分和动态部分:静态部分包括身份定位、系统规范、做任务规范、风险动作规范、工具使用语法、语气风格、输出效率等;动态部分则按会话实时注入,例如 session guidance、memory、环境信息、语言偏好、MCP instructions、token budget 说明等。中间还专门放了一个 SYSTEM_PROMPT_DYNAMIC_BOUNDARY,用来分隔前缀缓存区和动态区。
因为它说明 Claude Code 已经不只是想“把提示词写得更好”,而是在考虑 Prompt 的经济学。哪些内容稳定不变,应该尽量放在前面,以提高 system prompt 前缀缓存命中率;哪些内容会变,应该放在后面动态注入,否则会破坏缓存。
比如系统明确要求模型:不要加用户没要求的功能;不要过度抽象;不要给没改过的代码补注释;不要做没必要的错误处理;不要面向未来设计复杂抽象;先读代码再改代码;不要轻易创建新文件;不要给时间估计;失败后先诊断,不要盲目重试;没有做过的事情不能假装做过。
这些规则看起来像碎碎念,但任何真正用过 coding agent 的人都知道,这几乎正中所有痛点。
你明明让它修一个 bug,它顺手帮你重构半个模块。
你明明只要一个功能,它额外加出一整套你没要求的兜底逻辑。
你明明问“有没有跑过”,它却习惯性给你一种“应该没问题”的语气。
Claude Code 的高明之处就在于,它不赌模型临场发挥,而是把“好行为”写成制度。
四、42 个工具并不厉害,真正厉害的是“工具治理”
现在很多 Agent 产品都喜欢宣传自己接了多少工具,但 Claude Code 真正值得学的,不是工具数量,而是工具治理。
报告里提到,Claude Code 的工具系统不是一个简单的“函数名+输入输出”模型。Tool 接口除了 call() 之外,还有 inputSchema、validateInput()、checkPermissions()、preparePermissionMatcher()、isReadOnly()、isDestructive()、isConcurrencySafe()、prompt()、toAutoClassifierInput() 等一整套能力定义。也就是说,在 Claude Code 里,一个工具从来不只是“能不能调用”,而是“它是什么性质、是否只读、是否有破坏性、是否可并发、该怎么描述给模型、该如何进入安全分类器”。
它甚至在默认值上都体现出“fail-closed”思路:如果一个工具忘了标注并发安全性,系统默认不安全;忘了声明只读,系统默认它会写;这样就会自动进入更严格的权限路径。
当模型真正调用工具时,中间也不是一句话就能直接执行,而是要经过完整的 14 步执行流水线:找工具、解析 MCP 元数据、做 Zod schema 校验、做工具级输入校验、启动 speculative classifier、执行 PreToolUse hooks、解析 Hook 权限结果、走最终权限决策、修正输入、真正执行、记录 analytics/tracing/OTel、跑成功 hook、构造结构化结果,如果失败还要再跑 PostToolUseFailure hooks。
成熟 Agent 的工具调用,本质上更像“受监管的执行”,而不是“自由发挥的调用”。
五、Claude Code 真正拉开差距的,是多 Agent 分工
如果一个 Agent 同时负责探索、规划、实现、验证,它大概率每件事都做得不够好。
报告提到,它至少内建了 6 类 Agent,包括通用执行 Agent、Explore Agent、Plan Agent、Verification Agent、使用指导 Agent 和状态栏配置 Agent。这里最有代表性的有两个:Explore Agent 和 Verification Agent。
Explore Agent 被裁成了一个只读专家。它不能创建文件,不能修改文件,不能删除文件,也不能运行改变系统状态的命令。可用工具基本局限于 Glob、Grep、FileRead,以及有限的只读 Bash 命令,如 ls、git status、git log。这样的限制听上去很激进,但恰恰因为探索阶段最怕“顺手改了点什么”,所以最朴素有效的办法就是彻底隔离权限。
Verification Agent 更值得所有做 Agent 的团队认真研究。
它的 prompt 有 130 行,核心目标不是“确认代码大致没问题”,而是“想办法搞坏它”。系统明确指出两种常见失败模式:一种是 verification avoidance,只看代码不跑验证;另一种是被前 80% 的表象迷惑,以为测试过了、界面看起来也不错,就忽略剩下 20% 的问题。为了解决这些问题,它要求根据改动类型做不同验证:前端要起 dev server 后用浏览器自动化点;后端要 curl 实测;CLI 要看 stdout、stderr 和 exit code;数据库迁移要验证 up/down 以及既有数据。每一项检查都要求写出实际命令和观察到的输出,最后只能给 PASS、FAIL 或 PARTIAL。
Verification Agent 更值得所有做 Agent 的团队认真研究。
它的 prompt 有 130 行,核心目标不是“确认代码大致没问题”,而是“想办法搞坏它”。系统明确指出两种常见失败模式:一种是 verification avoidance,只看代码不跑验证;另一种是被前 80% 的表象迷惑,以为测试过了、界面看起来也不错,就忽略剩下 20% 的问题。为了解决这些问题,它要求根据改动类型做不同验证:前端要起 dev server 后用浏览器自动化点;后端要 curl 实测;CLI 要看 stdout、stderr 和 exit code;数据库迁移要验证 up/down 以及既有数据。每一项检查都要求写出实际命令和观察到的输出,最后只能给 PASS、FAIL 或 PARTIAL。
Claude Code 把这种分工直接产品化了。它没有奢望“同一个 Agent 又写又验还能保持客观”,而是把验证做成一个独立角色,让它天然带着找问题的偏见。
六、真正成熟的 Agent,一定不是“更强”,而是“更可控”
Claude Code 的安全设计特别值得展开讲。
它的权限层不是一个简单的 allow/deny,而是包含权限模式、规则定义、风险分类、危险命令模式匹配、shell 规则匹配、路径校验等完整模型。更关键的是,Hook 系统不是普通事件钩子,而是一个具备强表达力的运行时策略层。PreToolUse、PostToolUse、PostToolUseFailure 三个时点都可以介入;其中 pre-hook 不仅能记日志,还能直接返回 allow/ask/deny,修改输入,阻断流程,阻止继续执行,或者追加上下文。
报告明确指出,在 resolveHookPermissionDecision() 的规则里,Hook 说 allow,并不意味着 settings 里的 deny/ask 就失效。Hook allow 仍然可能被 deny 规则拦下,仍然可能继续弹窗;而 Hook deny 则会直接生效。这个设计保证了 Hook“足够强大”,却又“不能越权”。
再把 BashTool 的 speculative classifier、Hook policy layer 和最终 permission decision 合在一起看,Claude Code 实际上构建了三层防护网,而且这三层互相配合、互不绕过。
不是你有多少安全能力,而是这些安全能力之间能不能保持职责边界,不相互击穿。
七、生态不是接更多插件,而是让模型“知道自己有什么”
今天很多人谈 Agent 生态,喜欢讲插件、MCP、工具市场。
但大部分系统最大的问题不是“没有生态”,而是“模型不知道生态存在”。
Claude Code 对这个问题理解得非常透。它的 Skill、Plugin、MCP 不是三套孤立机制,而是都会进入模型感知层。比如 Skill 是带 frontmatter metadata 的 markdown workflow package,可以声明 allowed-tools、model、effort hints,并按需注入上下文;系统要求模型在匹配到某个 skill 时必须真正执行 Skill tool,而不是只在嘴上提到它。Plugin 则不仅能加命令、加 hooks、加输出样式、加 MCP 配置,还能影响模型行为,包括改 prompt、增工具、改权限规则。至于 MCP,也不只是注册新工具而已,它还能把 instructions 拼进 system prompt,让模型知道“这是什么工具、什么时候该用、怎么用”。
你给系统接十个插件,如果模型不知道它们存在,不知道该在什么场景调用,那这十个插件就等于不存在。Claude Code 的做法,是通过 skills 列表、agent 列表、MCP instructions、session-specific guidance、command integration 等通道,让模型持续感知自己当前拥有的能力。
八、上下文管理,本质上是成本管理
Claude Code 另一个很强的地方,在于它把上下文问题当成预算问题来处理。
在 query.ts 里,每次模型调用前,消息都要经过四道压缩机制:Snip Compact、Micro Compact、Context Collapse、Auto Compact。它们不是互斥关系,而是分层协作,先做轻量压缩,再做重量压缩。即便四层都不够,API 返回 413 时,还会触发 reactive compact 做一次紧急压缩重试,而且有防循环设计,避免反复重试把系统拖死。
此外,还有 token budget 机制,允许用户给出一个输出 token 目标,系统会追踪每一轮的 token 使用,并在接近目标时给模型注入 nudging message,让它继续工作,而不是“觉得差不多就停”。同时,Skill 是按需注入的,MCP instructions 按连接状态注入,memory 和 skill discovery 可以预取,大型工具结果会持久化到磁盘,只保留摘要进上下文。
九、Claude Code 最值得学的,不是功能清单,而是七条底层原则
我觉得最有价值的部分,不是它列出了多少文件,也不是它展示了多少模块,而是它最终提炼出的几条设计原则。
不信任模型的自觉性。好行为要制度化,而不是指望模型临场想到。
把角色拆开。探索、规划、实现、验证不要混成一个 Agent。
工具调用必须治理。模型说要调工具,不代表系统就该直接执行。
上下文就是预算。能缓存就缓存,能按需就按需,能压缩就压缩。
安全层必须互不绕过。任何一层都不能成为另一层的后门。
生态的关键是模型感知。接入不等于有效,看到并会用才算有效。
产品化在于处理第二天。第一天跑起来谁都能做,真正难的是任务中断如何续、脏状态如何清、进程泄漏怎么办、会话如何恢复。Claude Code 明显在这些“第二天问题”上花了大量工程精力。
结语
复盘完 Claude Code 的源码架构,我最大的感受是:
下一代 AI Agent 的竞争,已经从“模型能力竞争”走向“系统工程竞争”。
真正能落地、能持续、能进入产品形态的 Agent,背后一定不是一个模型加几个工具,而是一个完整的运行时系统。它要处理入口、调度、约束、权限、验证、扩展、预算、生命周期、异常恢复和生态协同。
Claude Code 的厉害,不在于它把这些概念喊了出来,而在于它真的把这些东西写进了系统里。
这也给所有做 AI Agent、OpenClaw、MCP、插件生态、AI IDE、自动化产品的人一个非常直接的提醒:
真正决定你能不能做成产品的,是模型之外的那整套系统能力。
如果你也在做 Agent,Claude Code 这套架构,值得反复拆,反复学。