我把 Claude Code 51 万行源码拆了一遍,读懂了这 5 个工程设计

156 阅读9分钟

3月31日 Claude Code 源码泄露,51万行 TypeScript 被扒了个底朝天。全网都在分析架构,但大部分文章只是"翻译源码"。我想换个角度——用我这两个月的实战经验,去印证源码里的设计决策:它为什么这么做,以及这些设计在真实场景里到底好不好使。


背景:泄露了什么

3月31日,有人发现 Claude Code 的 npm 包里保留了完整的 source map。不是被黑,是 Anthropic 自己忘了剥离——一个构建层面的低级失误。

被扒出来的数据:

指标数值
总代码量~512,000 行 TypeScript
源文件数1,902 个
内置工具~40 个
运行时Bun(不是 Node.js)
终端 UIReact + Ink

全网在分析架构的时候,我正在用 Claude Code 开发一个全自动化测试 Skill。两个月下来,踩了不少坑,也摸到了一些规律。看到源码的那一刻,很多之前"知其然不知其所以然"的体验,突然就对上了。

这篇文章不做源码翻译——那些文章已经够多了。我只聊 5 个让我"原来如此"的设计,每个都结合我的实战体感来说。

image.png

设计一:Agentic Loop——一个 while(true) 撑起整个系统

源码揭示的 Claude Code 核心,简单到让人意外:

while (true) {
  1. 组装上下文(System Prompt + 对话历史 + 工具定义)
  2. 调用 LLM
  3. 解析响应(纯文本 or 工具调用?)
  4. 如果是工具调用 → 执行工具 → 结果追加到对话历史 → 继续循环
  5. 如果是纯文本 → 输出给用户 → 结束
}

就这么简单。没有复杂的状态机,没有 DAG 编排,没有工作流引擎。

image.png

实战体感

我做谛听 Skill 的时候,让 Claude Code 执行一个完整的测试流程:读需求 → 侦察页面 → 生成用例 → 逐条执行 → 输出报告。这个流程在 Agentic Loop 里就是:LLM 决定"接下来该调哪个工具" → 调用 → 拿到结果 → LLM 再决定下一步。

它的强大不在于循环本身,而在于让 LLM 自己做路由决策。 我的 Skill 描述文件就是一份"操作手册",LLM 按手册一步步走,每步自己决定该调什么工具。不需要我写 if-else 来编排流程。

这个设计的代价是:你没法精确控制执行顺序。 LLM 偶尔会跳步或重复步骤。我在 Skill 里加了大量"必须先做 X 再做 Y"的约束,就是在补这个确定性缺口。


设计二:Prompt Cache 三层分段——成本控制的命脉

这是源码里最让我感慨的设计。

Claude Code 把 System Prompt 按变化频率切成三段:

内容变化频率
第一段角色定义、工具 Schema、基础规则几乎不变
第二段CLAUDE.md 内容、项目规则会话内不变
第三段环境信息(git status、当前文件等)每轮可能变

Anthropic API 支持 Prompt Cache:如果请求的前缀和上次一样,直接从缓存读,成本降低 90%。

这三段设计的意思是:不变的放前面,会变的放后面,最大化前缀命中长度。

实战体感

我现在理解了为什么 CLAUDE.md 这么重要——它不只是"配置文件",它是 Prompt Cache 的第二层缓存锚点

我在 CLAUDE.md 里写了大量的 Skill 规则和项目约定。以前以为这只是"方便 AI 理解项目",现在知道了:这些内容被注入到 System Prompt 的第二段,整个会话期间都会命中缓存。写得越好,AI 理解越准,而且不额外花钱。

反过来也解释了一个现象:当我频繁改 CLAUDE.md 的时候,响应似乎变慢了——因为缓存被频繁失效了。

还有一个细节:子代理(Subagent)共享父代理的 Prompt Cache。 这就是为什么 Claude Code 派生子代理的速度那么快、成本那么低。我用 Agent 工具并行搜索代码的时候,体感确实比串行快很多,而且 token 消耗没有翻倍。


设计三:四层权限纵深防御——为什么它总在问你"确认吗"

用 Claude Code 的人都有个体感:它隔三差五就弹确认框。rm 要确认、git push 要确认、写文件也要确认。有时候觉得烦。

看了源码才知道,这背后是四层安全设计:

机制作用
第一层Prompt 约束告诉 LLM "不要做危险操作"
第二层工具级权限每个工具声明安全等级(safe / confirm / dangerous)
第三层白名单/黑名单用户配置允许/禁止的命令列表
第四层沙箱隔离文件限制在项目目录、命令有超时

关键设计原则:Fail-closed(默认拒绝)

大部分开源 Agent 框架是 fail-open——默认放行,出了事再说。Claude Code 反过来:拿不准就拒绝,让用户确认。

实战体感

我做谛听 Skill 的时候,需要调用 Dima API 自动提 Bug 单。第一次跑的时候直接报权限拒绝——因为 MCP 工具默认需要确认。我得去 settings.local.json 里手动加白名单才行。

当时觉得麻烦,现在觉得这个设计是对的。如果默认放行,万一 AI 误判把正常功能当成 Bug 提了单,那就是生产事故。宁可多确认一次,不能多提一个假单。

源码还揭示了一个细节:子代理的权限范围严格小于等于父代理。 这解释了为什么我用 Agent 工具派生的子代理有时候会报"权限不足"——它不能做父代理没有权限做的事。安全,但偶尔不方便。


设计四:CLAUDE.md 四层记忆——文件系统就是最好的数据库

这个设计最"朴素",也最让我佩服。

Claude Code 的记忆系统没有向量数据库,没有 RAG,没有 embedding。就是 Markdown 文件 + 文件系统:

层级位置作用域
全局~/.claude/CLAUDE.md所有项目通用
项目{project}/.claude/CLAUDE.md当前项目
本地{project}/.claude/local/CLAUDE.md当前机器,不入 Git
自动记忆MEMORY.md + 子文件跨会话自动积累

每次会话启动时,按层级从全局到本地依次加载,注入 System Prompt。

实战体感

我现在的 MEMORY.md 已经有 50+ 行了,包含:用户偏好、项目结构、认证机制、踩坑记录、Skill 开发进展。

最大的好处是:记忆是可编辑的。 我可以直接改 MEMORY.md 来修正 AI 的"记忆偏差"。如果用向量数据库,我怎么改?我连存了什么都看不到。

还有一个好处是可 Git 管理。项目级的 CLAUDE.md 可以提交到仓库,团队共享。这意味着测试规范、项目约定不只是活在某个人脑子里,而是变成了所有人(和 AI)都能用的工程资产。

这个设计让我反思了一个常见误区:不是所有 AI 应用都需要向量数据库。 当你的记忆量不超过几千行文本(大部分项目都是这样),文件系统就是最好的方案——简单、可控、可调试、零额外依赖。


设计五:Coordinator + Subagent——不是多 Agent 噱头,是分工

源码揭示了三种多代理模式:

  • Fork:从父代理分叉出子代理,共享上下文和缓存,适合并行探索
  • Coordinator:协调者只有"派生子代理"和"发消息"两个工具,不能直接操作文件
  • Swarm:带 Team Lead 的团队模式,多代理并行

最有意思的是 Coordinator 模式的设计:协调者被故意"削弱"了——它不能读文件、不能写文件、不能执行命令。它唯一能做的就是拆分任务、派生子代理、汇总结果。

实战体感

我在谛听 Skill 里用 Agent 工具做并行搜索:同时搜索多个文件、同时查多个页面状态。体感是真的快。

现在看源码知道了原因:Fork 模式的子代理共享父代理的 Prompt Cache,所以并行的边际成本很低。不是多花 N 倍钱开 N 个代理,而是几乎只多花执行工具的钱。

Coordinator 模式的设计也让我理解了为什么 Claude Code 的"大任务"完成质量比"一个大 prompt 塞所有要求"要好——它把规划和执行分开了。 协调者专注于想"该做什么",子代理专注于做"具体怎么做"。关注点分离,质量更高。


给测试人的 3 个启发

看完源码,除了技术细节,我更关注这些设计背后的工程思想,因为这些思想可以直接用在我们做测试工具和 Skill 开发中:

1. 极简内核 + 丰富外围

Claude Code 的核心就是一个 while-true 循环。所有复杂性——缓存、权限、多代理、记忆——都是在这个内核之上叠加的独立层。

对测试的启发:做测试 Skill 也应该先把核心流程跑通(侦察→执行→报告),再逐步加能力(自愈、提单、截图内联)。我的谛听 Skill 就是这么迭代的——V1 只有 180 行,V3 变成 466 行,但核心循环没变。

2. 缓存不是优化,是架构

Prompt Cache 不是事后加的性能优化,而是在架构设计阶段就决定了的。System Prompt 的分段方式、CLAUDE.md 的加载时机、子代理的上下文继承——都是围绕"如何最大化缓存命中"来设计的。

对测试的启发:做 Skill 的时候,把稳定的规则放在 CLAUDE.md 里(命中缓存),把变化的参数放在每次调用时传入。这样既省钱又稳定。

3. 安全不是限制,是信任基础

Fail-closed 设计表面上让操作变麻烦了,但它建立了用户信任。我现在敢让 Claude Code 操作我的代码仓库,就是因为我知道它不会偷偷 git push --force

对测试的启发:做全自动化测试工具的时候,缺陷提单、环境操作这类动作必须留人工确认点。谛听 Skill 里用例确认和缺陷确认两个卡点,就是这个思路。


最后

Claude Code 51 万行源码里,我印象最深的不是某个具体实现,而是一个工程哲学:

朴素的核心 + 极致的工程包装。

一个 while-true 循环,包上 12 层工程能力,就变成了 2026 年最受欢迎的开发工具(46% 开发者好感度,远超 Cursor 的 19%)。

这对我们做测试工具的人来说,是最好的参考样本——不要追求酷炫的架构,先把核心流程跑通,再一层层叠加工程能力。

image.png


更多 AI + 测试实战,关注公众号「测试进化论」—— 测试不会消失,只会进化。