Claude Code 源码设计分析一、事件起因2026 年 3 月 31 日Claude Code v2.1.88 的完整源码因 npm 包中遗留了一个 59.8MB 的cli.js.map文件而意外曝光涉及 1906 个 TypeScript 源文件、51.2 万行代码。这不是第一次——2025 年 2 月发生过完全相同的事故同一个坑同一份 Source Map。Source Map 是 JavaScript 生态的调试工具能把压缩混淆后的代码还原成原始源码。正常发布 npm 包时应在.npmignore或package.json的files字段里过滤掉Anthropic 两件事都没做。根因在于项目使用 Bun 作为构建工具而非运行时Bun 在打包时自动生成了这份 Source Map配置层面没有拦截。用户侧运行的仍是 Node.js 兼容的编译产物不需要安装 Bun。这份泄露对竞争对手来说相当于一份免费的技术蓝图。至于 Anthropic——一家把 AI Safety 写进公司使命的企业同一个工程细节连续翻车两次说明他们确实把绝大部分工程注意力放在了模型和架构上打包流程的细节反而成了盲区。二、架构哲学Harness而不是 Agent理解 Claude Code 的设计要从它的核心主张入手系统工程只负责提供环境不试图干预模型的推理过程。它不强加固定工作流不用复杂决策树干预模型判断只提供工具、上下文管理和权限边界然后让模型自由执行。剥掉所有细节架构本质是一个 Agent 循环 工具集bash / read / write / edit / grep … 按需技能加载 上下文压缩 子 Agent 派生 任务依赖图 工作树隔离并行 权限治理技术选型也遵循这个思路语言用 TypeScript 保证类型安全终端 UI 用 React Ink 把组件化状态管理搬进终端CLI 框架用 Commander.jsSchema 校验用 Zod v4。整个代码库有 30 服务模块、40 内置工具、50 斜杠命令。React Ink 的选型有其合理性——对于需要实时渲染流式输出和工具调用状态的复杂 CLI组件化比手写 ncurses 高效得多。但泄露源码也暴露了执行层面的问题存在长达 5000 余行、嵌套 22 层 JSX、堆叠数十个 Hooks 的单一 React 组件。这不是 React Ink 技术栈的问题而是快速迭代下没有管控组件边界导致的维护债。整体架构示意Claude Code — Agent HarnessCLI 入口main.tsx · 975 行QueryEngineAsyncGenerator 流式Prompt Cache静态段 / 动态段cache_edits 墓碑化Tool 系统40 工具 · 按需加载四层权限管道Coordinator规划 · 调度Subagent隔离执行 · 结论回传task-notification记忆系统9段式压缩 · MEMORY.mdMCP 扩展层外置工具 · 解耦高变动项三、核心引擎AsyncGenerator 流式管道QueryEngine.ts1295 行是整个系统的核心。submitMessage()是一个AsyncGeneratorSDKMessage每次yield一个消息片段上层通过for await...of消费。这个设计让流式响应、工具调用、中断恢复的处理方式统一了——都是生产者-消费者模型不用单独处理每种情况。入口文件main.tsx有几个冷门但有价值的工程细节在任何import语句执行前先通过副作用触发 MDM 配置读取和 macOS 钥匙串预取利用后续模块加载约 135ms 的时间窗口并行完成这些操作实测节省约 65ms 启动时间。还内置了 Feature Flag 系统KAIROS、PROACTIVE、TORCH 等未公开功能的开关都硬编码在这里。四、Prompt Cache字节级的成本控制这是 Claude Code 与普通 AI 套壳应用差距最显著的地方整个系统对缓存的处理几乎达到了精细化的程度。分段策略示意静态段高命中率模型身份定义 · 系统安全规则 · 代码风格约束 · 工具基础指南整个会话周期内不变缓存前缀稳定SYSTEM_PROMPT_DYNAMIC_BOUNDARY动态段低命中率当前工作目录 · Git 状态 · MCP 指令 · 用户配置每次请求可能变化不强制缓存cache_edits — 墓碑化机制旧消息标记 skipped保留占位不破坏缓存前缀哈希连续性分段策略提示词被切成两段之间用硬编码标记SYSTEM_PROMPT_DYNAMIC_BOUNDARY分隔。静态段包含模型身份定义、系统安全规则、代码风格约束、工具基础指南整个会话内容几乎不变缓存命中率极高。动态段包含当前工作目录、Git 状态、MCP 指令、用户配置每次请求可能变化。System Prompt 优先级链是 Override Coordinator Agent Custom Default不同模式注入不同层级的指令。确定性排序传给模型的工具描述严格按字母表排序内置工具前缀在前MCP 工具后缀在后。这个细节不起眼但很关键工具描述是 prompt 的一部分如果顺序每次不同prompt 哈希就变了缓存直接失效。配置文件路径同样使用基于内容的哈希值映射避免路径字符串变化导致缓存击穿。状态外置当前可用的 Agent 列表原来写在工具描述里Agent 列表每次变化就得重建整个 prompt 缓存。源码里把这个列表剥离出来转移到消息附件Attachments中。仅这一项减少了约 10.2% 的 Cache Creation Tokens 消耗。cache_edits 墓碑化机制这个机制在上面几项之外是维持长对话性能不退化的关键。长对话上下文超出阈值时旧消息不会被物理删除而是被标记为skipped。模型推理时跳过这些消息但消息依然占据 prompt 中的位置因此缓存前缀的哈希连续性没有被打断。这解释了为什么 Claude Code 在数小时的长对话中响应速度不会明显降级。需要说明的是哈希连续性完整保留取决于 Anthropic 后端 KV Cache 的具体实现上述逻辑是从代码设计意图上的推断而非对后端行为的直接确认。五、工具系统与四层权限四层权限管道工具执行四层权限管道第一层Config Rules.claude/settings.json 用户自定义 allow / deny 规则静态匹配第二层语义分析tree-sitter 解析命令 AST分析读写路径是否在工作目录范围内AST 语义层第三层AI Classifier侧查询小模型异步判断命令安全性Auto Mode投机性预检模型流式输出参数时并行启动消除等待小 AI 监管大 AI第四层用户手动确认弹出 Allow / Deny选择可记忆为 alwaysAllow / alwaysDeny兜底决策工具抽象Tool.ts792 行定义了完整的工具接口包含 20 个方法名称、执行函数、Zod Schema 校验、权限检查、是否只读、是否可并发、结果大小上限等。StreamingToolExecutor负责协调将工具调用分区为并发批次和串行批次isConcurrencySafe()决定一个工具能否并行跑。按需加载ToolSearch把 40 工具的描述全塞进 prompttoken 消耗会很可观。解法是非核心工具标记defer_loading: true模型默认看不到具体定义只知道有ToolSearch可用需要时传入关键词动态加载。这和 Web 开发的 Code Splitting 是同一个思路。四层权限管道工具执行不是简单的允许/拒绝而是四层递进Config Rules.claude/settings.json中的用户自定义规则静态匹配语义分析tree-sitter 解析命令 AST检查读写路径是否在工作目录范围内“宁可误杀不可漏放”AI Classifier侧查询一个更小的 LLM 异步判断命令安全性Auto Mode 下生效结果是结构化 JSON 并用 Zod Schema 校验。分类器超时或失败时fallback 策略是 ask——无法证明安全就弹窗询问用户手动确认前三层都通过后命令仍不在白名单内才弹窗用户的选择可记忆为 alwaysAllow / alwaysDeny投机性预检startSpeculativeClassifierCheck是一个值得单独提的优化当模型还在流式输出 BashTool 的参数时系统就已经并行启动分类器了。模型输出完成时分类结果可能已经就绪消除了串行等待。网络工具的权衡网络检索工具不是通用搜索而是对约 85 个主流技术文档域React、Vue 等前端框架及基础设施设置白名单进行全量抽取非白名单域只提取短摘要解析 DOM 时直接丢弃head中的结构化数据只保留body内容。这是以牺牲通用性换取上下文稳定性的工程取舍在需要控制输入质量的 Agent 场景里很典型。六、Coordinator Subagent隔离探索长任务中AI Agent 的上下文会被探索性操作污染。探索方案 A 产生的大量中间输出会挤占上下文窗口干扰后续判断所有长任务 Agent 都面临这个问题。Claude Code 的解法是 Coordinator Fork Subagent 两层架构。Coordinator 被剥夺了直接操作文件的权限只保留Agent派生子代理、SendMessage和TaskStop三个工具负责规划和调度。Worker 携带具体工具描述被派生出来执行实际任务在独立上下文窗口运行。三个关键机制子 Agent 继承父对话的 Prompt Cache共享缓存前缀不是复制新上下文创建成本低探索产生的所有中间输出限制在子 Agent 上下文里不污染主对话子 Agent 完成后通过 XML 格式task-notification把提炼后的结论传回 Coordinator不是把整个对话历史丢回去系统支持 6 种任务类型local_bash、local_agent、remote_agent、in_process_teammate、local_workflow、dream。其中in_process_teammate允许主进程平行唤醒多个 Agent 同时执行不同任务。源码里还集成了 iTerm2 和 Terminal.app 的 AppleScript 控制指令派生新 Teammate 时自动切分终端窗格权限请求通过内部通道permissionSync.ts桥接给 Leader Agent 处理。MCP 在这里也是解耦的重要手段把高变动频率的工具集剥离为主进程之外的 MCP Server核心 Harness 代码保持稳定外部扩展无缝接入。七、记忆系统短期压缩长对话超出上下文窗口时触发 Compact把之前的对话压缩成严格的 9 段式摘要序号内容1会话目标2已完成任务3未完成任务4关键决策和理由5代码变更摘要6发现的问题7待验证的假设8用户偏好9上下文关键信息每段有明确格式要求压缩后模型能快速恢复上下文状态。长期记忆记忆系统完全基于本地文件系统没有用向量数据库核心是MEMORY.md。源码里src/services/autoDream/对应内部代号 KAIROS 的功能准确定位是常驻自治后台 AgentDaemon而不只是记忆整合工具。它包含 consolidation prompt 和 consolidation lock能在系统空闲时进行记忆巩固设计上还能持续监听外部事件流如 GitHub Webhooks 或 Slack 消息并在用户离开时响应。src/services/teamMemorySync/包含secretScanner.ts在同步团队记忆时扫描敏感信息这说明 Anthropic 已在为多人协作场景下的 Agent 记忆做准备。八、工程痛点代码质量在整个代码库里参差不齐。架构层面的设计思路是清晰的但部分实现的质量明显跟不上。5000 行单组件、22 层 JSX 嵌套是最典型的例子这不是技术选型的锅是高速迭代下组件边界失控的结果。还有一个细节能说明问题services/api/claude.ts是核心 API 调用逻辑一个文件 3419 行。这种体量的文件不太可能有良好的可测试性。两次 Source Map 泄露事件加上这些代码质量问题指向同一个现象Anthropic 的工程资源高度集中在模型和架构创新上基础工程卫生打包配置、代码审查边界的优先级明显靠后。对于一个年化收入占公司总收入 18% 的产品来说这个分配方式是否合理值得讨论。小结Claude Code 的核心价值在于它的克制没有试图把 AI 做成一个特别聪明的调度系统而是老老实实地把环境做好——工具、权限、上下文、记忆——然后信任模型本身的推理能力。Prompt Cache 的精细化管理、四层权限管道、Coordinator 隔离探索这几个设计对任何在做 AI Agent 工程的人来说都有参考价值和用什么模型无关。代码质量的参差不齐是另一面。它更像是一个快速生长的生产级产品该有的样子而不是一个精心打磨的开源示范项目。看源码的时候两面都值得留意。