基于 Claude Code v2.1.88 还原源码分析
市面上的 AI 编程工具不少,但如果把它们都用一遍,很快就能发现一个关键区别。
有些工具在第一轮对话里很惊艳,可一旦任务变复杂、会话被拉长、或者需要并发调用多个工具,它们就开始变钝、变乱,到最后总是需要你频繁介入接管。
但 Claude Code 给人的感觉不一样。它不一定每次都做出最炫酷的操作,却往往是最稳定、最顺手、最像能长期投入实际工作的那个系统。
在完整梳理了 Claude Code v2.1.88 的还原源码后,我的判断更加清晰了:Claude Code 的核心优势,并非主要源于模型本身,而在于它将 Agent 真正做成了一套完整的运行时(Runtime)系统。
这篇文章不会停留在“它很好用”的层面,而是尝试回答三个更具体的问题:
- 它在哪些源码层面的设计做得更出色?
- 这些设计如何直接转化为我们日常使用的顺畅体验?
- 如果你也在构建自己的 Agent,最值得借鉴它的哪些部分?
核心结论:Claude Code 强在“运行时”,而非单点功能
很多人总结 Claude Code 时会罗列一系列功能点:工具多、命令丰富、权限精细、会话稳定、支持多代理等等。这些都对,但还不够深入。
更准确的说法是:Claude Code 真正强大的地方,在于它将“工具调用、上下文治理、权限控制、异常恢复、多代理隔离”等一系列复杂问题,都收敛并统一到了同一套运行时框架中。
换句话说,它不仅仅是“一个强大的模型加上一堆工具”的简单拼装,其架构已经非常接近一个为 Agent 设计的操作系统(Agent OS)。

如果你一上来就只盯着最大的文件,比如 query.ts,阅读体验会非常吃力。
更有效的阅读方式是先建立一张系统架构的思维地图:
main.tsx:负责启动、预热、装配。
QueryEngine.ts:负责管理会话生命周期(session lifecycle)。
query.ts:负责主代理循环(agent loop)。
services/tools/*:负责工具的调度与执行。
services/compact/*:负责上下文的治理与压缩。
useCanUseTool.tsx 及权限相关服务:负责整个权限判定链路。
AgentTool / coordinator/* / remote/*:负责多代理协作和隔离执行。
这也正是 Claude Code 与许多其他 Agent 工具最大的区别:后者往往是“哪里需要逻辑就往哪里塞”,导致代码结构松散;而 Claude Code 从一开始就按照一套职责明确的系统来设计。
如果你今天就要开始阅读这份源码,我的建议是,不要一上来就硬啃最大的文件。按照“启动装配 -> 会话生命周期 -> 主循环 -> 工具执行 -> 治理链路”这条主线来推进,思路会清晰很多。

具体来说:
- 先看
main.tsx,搞清楚启动阶段装配了哪些核心能力。
- 再看
QueryEngine.ts,理解一次会话是如何被抽象和收口为统一执行入口的。
- 然后进入
query.ts,观察真正的 Agent Loop 如何处理流式输出、工具调用和状态恢复。
- 接着顺着
StreamingToolExecutor 和 toolOrchestration.ts 往下,理解它如何在复杂任务中维持工具执行的秩序。
- 最后再看
compact 和权限相关的代码,理解它为何不会在长会话中“越聊越乱”或“越跑越危险”。
这个顺序的好处在于,你先建立对整个系统的宏观认知,再去深入实现细节。否则很容易一头扎进 query.ts 的大量条件分支里,却看不清这些分支为何存在,其设计目的又是什么。
设计一:抽离会话生命周期,而非将模型硬塞进终端
这是 Claude Code 在工程架构上最值得学习的一点。许多 Agent 工具在初期设计时,就把业务逻辑与 UI 或 CLI 交互层紧密耦合在一起:
- 输入框状态管理在 React/Vue 组件里。
- 工具执行逻辑写在某个 UI 事件回调里。
- 权限确认变成一个模态弹窗的专属逻辑。
- 会话恢复则可能是后期打上的另一个补丁。
短期内这样确实能跑起来,但一旦你需要支持更丰富的场景,比如 Headless 模式、SDK 接入、子代理、远程执行或自动恢复时,整个代码结构就会开始“打架”,变得难以维护和扩展。
Claude Code 的解决方案非常清晰:先定义运行时,再定义交互层。
在源码中,最关键的分工体现在这三个核心文件上:
main.tsx 负责启动阶段的装配和预热。
QueryEngine.ts 负责将一次会话的完整生命周期串联和管理起来。
query.ts 则负责进入并执行真正的 Agent 循环。
这背后的工程价值巨大。因为它意味着:
- UI 不再承载核心的业务状态,只负责渲染和交互。
- REPL(交互式命令行)、SDK 甚至未来的新交互方式,都可以复用同一套底层的执行路径。
- 工具调用、消息回写、权限拒绝、上下文压缩、失败回退等所有行为,都能挂载在统一的运行时上被妥善处理。
从工程哲学上说,这几乎可以总结为一句话:不要把 Agent 写成“一个会调模型的聊天界面”,而要把它写成“各种交互界面(UI/CLI/SDK)共同调用的一个运行时服务”。
如果你正在构建自己的 Agent,这是优先级极高的一条建议。因为一旦这层抽象没做干净,后续每增加一项新能力,代码的复杂度和混乱度都会呈指数级上升。
设计二:拉开差距的是工具调度系统,而非工具数量
许多 Agent 工具的宣传重点在于功能清单:能读文件、能改文件、能执行命令、能联网搜索等等。然而,在真实复杂的编程任务中,真正的问题从来不是“有没有这个工具”,而是:
- 哪些工具可以安全地并发执行?
- 哪些工具因为副作用必须严格串行?
- 某个工具执行失败后,它关联的“兄弟任务”是否还要继续?
- 用户中途打断时,运行时是立即取消,还是等待当前工具安全收尾?
- 工具执行产生的结果,是否应该立刻写回上下文供模型参考?
Claude Code 在这套“工具调度系统”上投入了非常重的设计。

1. 基于语义的批次级调度
在 services/tools/toolOrchestration.ts 中,可以看到一个关键设计思想:工具调用会先按照其语义被分批,然后才决定执行顺序。
核心的判断依据是 isConcurrencySafe(是否并发安全)。这意味着 Claude Code 并非采用简单的“全部串行”或“全部并发”策略,而是会先审视工具本身的副作用语义:
- 读操作、查询类操作,更适合并发以提高效率。
- 写操作、有状态修改的操作,则更适合串行以保证安全。
很多工具用起来感觉“不稳”,并非因为模型不够聪明,而是因为它们错误地把“调度”这个复杂的系统级问题,完全甩给了模型通过 Prompt 去理解和解决。Claude Code 没有这样做,它将“工具是否并发安全”提升为运行时应掌握的一等知识(First-class Knowledge)。
更具深度的设计在 StreamingToolExecutor。这里处理的是一个更贴近现实的挑战:模型的输出是流式的,工具调用请求也是动态产生并陆续到达的。
因此,运行时要处理的不是一个静态的、已知的“工具调用列表”,而是一个动态的、充满不确定性的“执行中的世界”:
- 工具调用边到达,边进入执行队列。
- 有的工具已经开始执行。
- 有的还在队列中等待调度。
- 有的可能因为兄弟任务失败或用户打断而需要被取消。
- 有的已经执行完成,但其结果不一定适合立即暴露给模型。
在源码中,可以看到它对工具执行状态的明确区分:queued(排队中)、executing(执行中)、completed(已完成)、yielded(已产出)。同时,它还需要妥善处理 sibling abort(兄弟任务中止)、interrupt behavior(中断行为)、fallback 时丢弃未完成的结果,以及在某个工具失败时如何将取消信号正确传播给其他关联任务。
这已经超出了简单的 “tool calling” 范畴,更接近一个功能完善的 action scheduler(动作调度器)。
如果你在构建自己的 Agent,我会强烈建议优先补齐这两层基础设施:
- 工具语义声明层(定义并发性、副作用等)。
- 运行时调度器(管理动态执行流)。
不要幻想仅靠精心设计的 Prompt 就能彻底解决工具调度的稳定性问题。
设计三:长会话稳定的秘诀——将上下文视为受控资源
很多 Agent 在初次使用时体验都不错,真正的分水岭出现在第十轮、第二十轮对话之后。这时通常会暴露两个致命问题:上下文越来越杂乱无章,错误恢复能力越来越差。
Claude Code 在这方面下了重功夫,其策略远非一句简单的“超长了就总结一下”那么简单。

在 services/compact/* 相关的代码中,可以看到它至少做了以下几件事:
- 预算估算:动态估算有效的上下文窗口大小。
- 预留资源:为后续的压缩摘要(compact summary)预先保留一部分 Token 预算。
- 分层阈值:设置警告阈值(warning threshold)、错误阈值(error threshold)和阻塞上限(blocking limit)。
- 策略分化:区分响应式压缩(reactive compact)、微压缩(micro compact)、修剪(trim compact)等不同场景的处理方式。
- 失败熔断:在连续多次压缩尝试失败后启动熔断机制,避免会话陷入无限重试的死循环。
这套设计最值得借鉴的地方在于其根本思路:它将上下文溢出视为一种需要严肃对待的系统故障,而不是一个可以随意处理的普通异常。
这与很多 Agent 工具的思路截然不同。后者的典型逻辑是:“上下文超长了?那就让模型试着总结一下吧,总结成啥样算啥样。”
而 Claude Code 的逻辑更像是:“上下文是一种和内存、CPU 类似的受控资源,必须像治理基础设施一样进行精细化管理。” 这也直接解释了为何它在长会话中表现更稳——并非因为模型突然变得更聪明,而是因为运行时在持续、主动地管理和控制着上下文的“债务”,防止其失控。
设计四:既不放任也不烦人的权限系统
在权限处理上,很多 Agent 工具容易走向两个极端:要么全部放开,导致安全隐患巨大;要么步步询问,让用户体验极其烦躁。
Claude Code 显得更为成熟,因为它没有把权限做成一堆散落在 UI 里的确认弹窗,而是将其构建为一条贯穿运行时的统一判定链路。
从源码中可以看到这个权限系统的多层结构:
- Allow / Deny / Ask 三层基础规则。
- 工具粒度的权限匹配。
- MCP (Model Context Protocol) Server 级别的权限控制。
- 沙箱(sandbox)环境下的权限覆写。
- 工作目录(working directory)的访问限制。
- 通过 Hooks 进行的自定义决策干预。
- 甚至还有分类器(classifier)辅助进行更智能的权限判断。
而 useCanUseTool.tsx 及相关服务,则将这条完整的权限判定链路串联起来,并能根据不同的运行模式进行适配:
- 交互式会话如何处理。
- 子代理(sub-agent)的权限如何继承和隔离。
- 集群(swarm)或协调器(coordinator)中的 Worker 如何鉴权。
- Headless 模式或 SDK 调用时权限如何生效。
这背后的启示非常明确:权限不应该只是“操作执行前弹窗问一句”,而应该是“运行时在决定是否允许进入下一步”的统一、核心的判定逻辑。
如果你的权限系统只是一堆散落在各处的 confirm() 调用,那么一旦未来需要支持后台自动代理、远程代理或多代理协作,整个权限体系会立刻崩塌,几乎无法扩展。
设计五:为“真正的软件代理”奠定基础
如果你深入源码,会发现 Claude Code 的野心早已不限于做一个本地命令行工具。
代码中充满了为未来铺路的信号:
AgentTool 支持 background(后台)、teammate(队友)、remote(远程)、worktree(工作树)等多种执行后端。
coordinator/* 目录下的代码在处理多代理间的协作与通信。
remote/* 相关模块在负责远程任务的执行与管理。
plugins、skills、MCP 构成了一个清晰的分层扩展体系。
main.tsx 在启动阶段就已经在预取远程托管配置和能力注册信息。
最关键的是,它并非将这些能力全部塞进一个臃肿的“大插件系统”。它的做法更像是精心设计的分层装配:
commands 层:解决用户的各种交互入口(如 slash commands)。
tools 层:解决原子能力的执行。
skills 层:解决可复用、组合性的高级工作流。
plugins 层:解决本地化、个性化的功能扩展。
MCP 层:解决标准化、外部能力的无缝接入。
这套分层架构带来了两个直接好处:
- 用户入口清晰:不同性质的能力不会混为一谈,降低认知负担。
- 安全策略分化:不同类型的能力可以走不同的安全审查与权限策略,兼顾灵活与安全。
这正是为什么我认为 Claude Code 不仅仅在做一个“更强的聊天机器人”,而是在扎实地构建一个软件代理(Software Agent)的基础设施。对于想深入理解现代 智能系统 设计思想的开发者,这类项目是极佳的学习素材。
实践指南:构建自己的Agent,应优先借鉴哪些设计?
看完源码,我认为最有现实指导意义的部分在此。大多数团队并不需要(也没必要)一次性复刻 Claude Code 的全部能力,但下面这四个基础设施层面的设计,绝对值得优先“抄作业”。

1. 分离运行时与交互层
第一优先级不是增加更多花哨的工具,而是将会话生命周期管理、工具调用引擎、消息状态回写、权限判定逻辑、上下文治理策略等核心业务,从 UI 组件中彻底剥离出来,形成一个独立的运行时服务。
如果这一步不做,后续一旦需要增加 Headless 模式、自动化流水线或子代理能力,代码的复杂度将失控,技术债务会迅速堆积。
2. 为工具赋予“运行时语义”
许多团队在设计工具时,只定义名称、入参和出参的 Schema。然而,真正决定 Agent 在复杂任务中稳定性的,是工具的运行时语义。你需要明确声明:
- 该工具是否可并发执行(
isConcurrencySafe)?
- 执行是否会产生副作用(
side_effects)?
- 执行过程是否可被安全地中断(
interruptible)?
- 该工具执行失败后,是否应该取消与之关联的其他并行任务?
Claude Code 的强大之处正在于此:它不仅知道“如何调用一个工具”,更知道“应该如何以正确的策略来运行一组工具”。
3. 像管理资源一样管理上下文
不要再把上下文管理简单地理解为“写一个聪明的总结 Prompt”。更稳健的工程化做法是:
- 设立预算:计算可用的上下文窗口。
- 设置阈值:定义警告线、阻塞线。
- 制定策略:明确在达到不同阈值时,该采取何种压缩(compact)或修剪(trim)策略。
- 准备熔断:为连续失败的情况设计降级或中止逻辑,防止系统“卡死”。
这套资源治理思维能极大提升长对话任务的稳定性和可预测性。
4. 构建统一的运行时权限判定链
如果你的 Agent 未来需要支持子代理、远程执行或自动化 Worker,那么权限系统必须设计为一条在运行时贯穿始终的判定链,而不是一堆分散在各处、难以维护的 if 判断和 confirm 调用。
这件事越早做,未来架构演进的成本就越低,系统的安全性也越有保障。
总结与启示
源码中确实还能看到许多有趣的“隐藏功能”,比如 Undercover 模式、Buddy 宠物系统、KAIROS 自主代理模式、语音支持、远程托管以及大量的特性开关(feature flags)。这些都表明 Claude Code 的产品边界远比我们目前看到的更广阔。
然而,如果只把注意力放在这些“彩蛋”上,可能会错过它最核心的价值。Claude Code 的核心竞争力,不在于它隐藏了多少炫酷功能,而在于它已经把构建一个稳健 Agent 所需的基础设施做对了。
这些基础设施包括:清晰的运行时抽象、专业的工具调度系统、工程化的上下文治理、统一的权限判定链路,以及为多代理协作准备的基础。正是这些“看不见”的工程设计,决定了它为何能长期、稳定地工作。
如果你今天依然把 Agent 简单地理解为“一个更会聊天、更能写代码的模型外壳”,那可能还停留在认知的第一阶段。通过对 Claude Code 源码 的分析,我更加确信:下一代 AI 编程助手乃至通用 Agent 的竞争,比拼的将不再是“谁更会回答问题”,而是:
- 谁的架构更像一个健壮的运行时?
- 谁的设计更像一个可扩展的系统?
- 谁更能在真实世界复杂、多变的任务流中,保持稳定、可控与可靠?
Claude Code 之所以给人感觉更好用,不是因为它的模型更“能说会道”,而是因为它的底层系统更“会工作”。对于广大开发者而言,深入研究和讨论这类优秀项目的设计哲学,是提升自身系统架构能力的绝佳途径。
源码信息
注:本文内容基于公开的反编译代码进行分析,仅供学术研究与技术学习参考。使用者应自行遵守相关法律法规及软件服务条款。