← 全部文章

Claude Code源码解读-命令执行全流程

本文系统性拆解了 Claude Code 的源码实现,完整还原了一个终端 AI Agent 从用户输入到模型推理再到工具执行与结果渲染的全链路流程。文章从架构层面出发,详细分析了 CLI 启动流程、React+Ink 终端 UI、上下文构建机制、Anthropic API 流式调用、消息与内容块分层体系、工具执行系统以及 Agentic Loop(自主循环执行机制)。

更新于 2026.06.25

本文目录 10 节
Claude Code源码解读-命令执行全流程封面

当用户在终端按下回车 — Claude Code 架构全链路深度解析

本文基于 Claude Code 开源代码的逆向分析,完整还原一条用户指令从终端输入到 API 调用、工具执行、响应渲染的全链路。Claude Code的实现堪称教科书级别,是我们学习Agent开发非常好的教材。


一、引言

Claude Code 是 Anthropic 推出的 AI 编程助手,运行在终端中。与简单的聊天机器人不同,它具备自主执行能力 — 读写文件、运行命令、搜索代码、调用外部工具 — 一切都在终端里完成。

当你在终端输入”帮我修复这个 bug”并按下回车,背后发生了什么?

本文将沿着代码路径,从 claude 命令的入口开始,一步一步还原整个处理链路。


二、启动流程

2.1 入口文件

Claude Code 的启动经历三个文件:

dev-entry.ts  →  cli.tsx  →  main.tsx  →  replLauncher.tsx

dev-entry.ts 是开发入口,处理 --version / --help 快速路径后,将控制权交给 cli.tsx。

cli.tsx (src/entrypoints/cli.tsx) 是真正的生产入口。main() 函数处理多种启动模式:

启动模式说明
--version打印版本号
--dump-system-prompt输出系统提示词(调试用)
--daemon-worker后台守护进程模式
MCP servers启动 MCP 服务器
Chrome native host浏览器扩展模式
正常交互模式进入 REPL

对于正常的交互模式,控制权交给 main.tsx。

main.tsx (src/main.tsx) 是 CLI 引导的核心,负责:

  1. Commander.js 命令行解析 — 解析所有 CLI 参数
  2. 认证初始化 — API Key / OAuth / AWS 凭证 / GCP 凭证
  3. 设置加载 — settings.json、项目级配置
  4. MCP 客户端初始化 — 连接外部 MCP 服务器
  5. GrowthBook 特性开关 — A/B 测试和功能开关
  6. 插件与技能系统 — 加载 skills 和 plugins
  7. 权限系统初始化 — 工具权限配置

最终调用 launchRepl()。

2.2 终端 UI 层

// src/replLauncher.tsx
renderAndRun(root, <App><REPL /></App>)

Claude Code 的终端 UI 基于 React + Ink 构建。没错,终端界面是用 React 渲染的。Ink 将 React 组件树映射为终端输出,使得复杂交互界面可以用声明式的方式构建。

REPL 组件(src/screens/REPL.tsx,数千行)是整个交互体验的心脏。它管理:

  • 用户输入区域(PromptInput 组件)
  • 消息渲染区域(Messages 组件)
  • 进度指示器
  • 权限请求弹窗
  • 上下文管理

三、用户输入

3.1 输入捕获

用户在 PromptInput 组件中输入文本并按下 Enter 后,onSubmit 回调被触发(REPL.tsx 约第 3174 行)。

这个回调首先进行一系列判断:

用户按下 Enter
  ├── 是 / 开头的斜杠命令? → 本地立即执行(如 /help、/compact、/model)
  ├── 是 exit/quit? → 退出进程
  ├── 当前有任务在运行? → 排队等待(enqueue)
  └── 正常文本 → 进入 handlePromptSubmit()

斜杠命令不需要调用 API,直接在本地执行。例如 /compact 压缩上下文,/model 切换模型。

3.2 消息处理

handlePromptSubmit()(src/utils/handlePromptSubmit.ts)是网关函数,它:

  1. 展开粘贴的文本引用和图片
  2. 处理斜杠命令
  3. 调用 processUserInput() 将原始文本转为结构化消息
  4. 将消息传递给 onQuery() 进入查询流程

processUserInput()(src/utils/processUserInput/processUserInput.ts)将用户输入转为 UserMessage 对象:

{
  type: 'user',
  message: {
    role: 'user',
    content: '用户输入的文本...'  // 或结构化的多模态内容数组
  }
}

至此,用户的原始文本已被转化为一个标准化的消息对象。下一步,Claude Code 需要为这次对话组装完整的上下文。



四、上下文组装

模型的回复质量取决于它能看到什么信息。Claude Code 在每次 API 调用前,会并行组装三部分上下文:

// src/screens/REPL.tsx — onQueryImpl()
const [,, defaultSystemPrompt, baseUserContext, systemContext] = await Promise.all([
  checkAndDisableBypassPermissionsIfNeeded(...),
  checkAndDisableAutoModeIfNeeded(...),
  getSystemPrompt(freshTools, mainLoopModelParam, ..., freshMcpClients),
  getUserContext(),
  getSystemContext()
])

4.1 系统提示词(System Prompt)

getSystemPrompt()(src/constants/prompts.ts)构建系统提示词,包含以下区块:

区块内容
角色定义“You are Claude Code, Anthropic’s official CLI for Claude”
工具使用指令如何调用 Bash、文件操作、搜索等工具
安全规则禁止生成有害内容、安全测试授权等
输出风格配置输出格式偏好
MCP 指令外部 MCP 服务器的工具说明
环境信息操作系统、shell、Node 版本等

这些区块通过 buildSystemPromptBlocks()(src/utils/systemPrompt.ts)组合,并被切分为可缓存的块,利用 Anthropic API 的 prompt caching 机制减少重复传输。

4.2 用户上下文(User Context)

getUserContext()(src/context.ts)返回当前日期时间。这就是为什么 Claude Code 知道”今天是 2025 年 6 月 25日”。

4.3 系统上下文(System Context)

getSystemContext()(src/context.ts)收集项目环境信息:

  • Git 状态 — 当前分支、最近提交、工作区变更
  • 操作系统环境 — 平台、shell 类型
  • CLAUDE.md 内容 — 项目级指令文件(类似于 .cursorrules)

这些信息让模型能理解”我在哪个项目、当前代码状态是什么”。

4.4 动态附加内容

除了上述三部分,还有一些在对话过程中动态附加的内容:

  • Memory 文件 — 持久化的用户偏好、项目记忆
  • Skill 定义 — 可用的技能列表(如 deep-research、test-driven-development)
  • Agent 定义 — 可用的子代理类型(如 Explore、code-reviewer)
  • Hook 结果 — 用户配置的钩子输出

组装上下文后,Claude Code 还需要确定:用哪个模型来处理这次请求?


五、API 流式调用

5.1 Anthropic SDK

Claude Code 使用 Anthropic 官方 TypeScript SDK:

// src/services/api/client.ts
import Anthropic, { type ClientOptions } from '@anthropic-ai/sdk';

通过 new Anthropic(ARGS) 创建客户端实例,支持 5 种后端:

后端认证方式环境变量
Direct APIAPI KeyANTHROPIC_API_KEY
AWS BedrockAWS SigV4AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY
Google Vertex AIGCP OAuthGCP Application Default Credentials
Azure FoundryAPI Key / OAuthANTHROPIC_FOUNDRY_RESOURCE
Claude.ai用户 OAuthOAuth Token

5.2 构建请求

queryModel()(src/services/api/claude.ts 约第 1017 行)构建完整的 API 请求:

  1. 消息归一化 — normalizeMessagesForAPI() 确保消息格式符合 API 规范
  2. 工具 Schema 构建 — toolToAPISchema() 将每个工具转为 JSON Schema
  3. 系统提示词切分 — buildSystemPromptBlocks() 切分为可缓存块
  4. Thinking 配置 — 根据模型能力配置 extended thinking
  5. Effort 设置 — 设置推理强度(low / medium / high)
  6. Cache 配置 — 设置 prompt caching 断点

5.3 流式传输

实际的 API 调用通过 Anthropic SDK 的流式接口:

const stream = client.beta.messages.stream({
  model: 'claude-opus-4-6',
  max_tokens: 16384,
  system: systemPromptBlocks,
  messages: normalizedMessages,
  tools: toolSchemas,
  // ...
});

这是一个 SSE(Server-Sent Events)流,模型的回复以增量方式逐步到达,而非等待完整响应。Claude Code 使用 queryModelWithStreaming() 包装此调用,并在流式失败时自动降级为非流式请求。

模型开始流式输出了。但流回来的数据有好几种类型,Claude Code 如何区分和处理它们?


六、消息类型体系

Claude Code 的消息系统分为三个层次,从底层 API 到上层应用逐层抽象。

6.1 第一层:API 流式事件

API 通过 SSE 流式返回的原始事件类型:

事件类型作用
message_start一条新消息开始,携带初始 token 用量
content_block_start一个内容块开始(text / tool_use / thinking 等)
content_block_delta内容块的增量数据(逐 token 到达)
content_block_stop一个内容块完成
message_delta消息级别的最终信息(stop_reason、总用量)
message_stop消息结束

每个事件都有明确的生命周期:一个 message_start 开始,中间穿插多个 content_block_start → delta → stop 三元组,最后以 message_delta → message_stop 结束。

6.2 第二层:Content Block

每个内容块都有独立的 type,代表不同的语义:

模型生成类:

Block Type含义
text普通文本回复
thinking模型的推理/思考过程(extended thinking)
redacted_thinking被加密的思考内容

工具调用类:

Block Type含义
tool_use调用本地工具(Bash、Read、Edit 等)
server_tool_use调用服务端工具(web_search 等)
mcp_tool_use调用 MCP 服务器的工具
mcp_tool_resultMCP 工具的执行结果
web_search_tool_resultWeb 搜索结果
web_fetch_tool_resultWeb 页面抓取结果
code_execution_tool_result代码执行结果
advisor_tool_resultAdvisor 工具结果

其他:

Block Type含义
citations引用信息
container_upload容器上传
connector_text连接器文本(feature-gated)

每种 Block Type 对应一种增量(Delta)类型,用于流式累积:

Delta Type累积目标
text_delta→ 追加到 text 块
input_json_delta→ 追加到 tool_use 的 JSON 输入
thinking_delta→ 追加到 thinking 块
signature_delta→ 设置 thinking 的签名
citations_delta→ 引用增量(目前是 no-op)

6.3 第三层:内部 Message 类型(9 种)

在应用层,Claude Code 定义了统一的 Message 联合类型(src/types/message.ts):

type Message =
  | UserMessage // 'user'           — 用户输入
  | AssistantMessage // 'assistant'      — 模型回复
  | ProgressMessage // 'progress'       — 进度信息
  | SystemMessage // 'system'         — 系统消息
  | AttachmentMessage // 'attachment'      — 附件/文件变更
  | HookResultMessage // 'hook_result'    — 钩子执行结果
  | ToolUseSummaryMessage // 'tool_use_summary' — 工具调用摘要
  | TombstoneMessage // 'tombstone'      — 占位符(标记已删除的消息)
  | GroupedToolUseMessage; // 'grouped_tool_use' — 分组的工具调用

其中 SystemMessage 最为丰富,拥有 20+ 种子类型:

local_command | compact_boundary | microcompact_boundary | api_error |
informational | thinking | memory_saved | stop_hook_summary |
permission_retry | scheduled_task_fire | away_summary | agents_killed |
api_metrics | file_snapshot | bridge_status | turn_duration | ...

6.4 三层关系

用户看到的 ← UI 渲染层
    ↑
9 种内部 Message(User / Assistant / System / Progress / ...)
    ↑
14+ 种 Content Block(text / thinking / tool_use / mcp_* / web_* / ...)
    ↑
6 种流式事件(message_start → content_block_start → delta → stop → ...)
    ↑
Anthropic API (SSE)

设计思想:流式事件是传输协议,Content Block 是语义单元,Message 是应用层抽象。模型的一次响应可能包含多个 Content Block(比如先 thinking 再 text 再 tool_use),每个 Block 通过流式事件逐步到达,最终组装为一个 AssistantMessage。


七、工具执行

Claude Code 的核心能力不仅仅是”聊天”,而是能实际操作你的代码库。这通过工具系统实现。

7.1 工具列表

src/tools.ts 的 getTools() 组装完整的工具列表:

工具功能
BashTool执行 shell 命令
FileReadTool读取文件
FileEditTool编辑文件(精确字符串替换)
FileWriteTool写入新文件
GlobTool按模式匹配搜索文件
GrepTool按内容搜索文件(基于 ripgrep)
AgentTool启动子代理
SkillTool调用技能
WebFetchTool抓取网页内容
WebSearchToolWeb 搜索
TodoWriteTool任务列表管理
NotebookEditTool编辑 Jupyter Notebook
TaskStopTool停止后台任务
LSPTool语言服务器协议操作
MCP 工具外部 MCP 服务器提供的工具

7.2 流式工具执行

这是 Claude Code 最巧妙的设计之一:工具在流式响应到达时即开始执行,不等流结束。

StreamingToolExecutor(src/services/tools/StreamingToolExecutor.ts)实现了这一点:

API 流式返回:
  [text block] → 显示文本
  [tool_use block 开始] → StreamingToolExecutor 立即开始执行
  [tool_use block 增量] → 累积 JSON 输入
  [tool_use block 完成] → 工具可能已经执行完了!
  [下一个 tool_use block] → 同时开始执行(如果是只读工具)

并发策略:

  • 只读工具并行执行 — FileReadTool、GlobTool、GrepTool 等可以同时运行
  • 写入工具串行执行 — FileEditTool、FileWriteTool、BashTool 必须排队
  • 错误传播 — Bash 错误会通过 siblingAbortController 中止同批其他工具,但不会杀死主循环

7.3 工具执行流程

runToolUse()(src/services/tools/toolExecution.ts)执行单个工具:

tool_use block 到达
  → findToolByName()          查找工具定义
  → runPreToolUseHooks()      执行用户配置的前置钩子
  → canUseTool()              权限检查(是否需要用户确认)
  → tool.call(input)          实际执行工具
  → runPostToolUseHooks()     执行后置钩子
  → 返回 tool_result 消息

权限系统是关键的安全机制。某些工具(如 Bash 执行命令、写入文件)需要用户明确授权。权限模式包括:

  • 自动允许 — 只读操作自动放行
  • 逐次确认 — 危险操作每次都要确认
  • 始终允许 — 用户可以配置特定工具自动放行

八、Agentic Loop

8.1 核心机制

query() 函数(src/query.ts)是一个 AsyncGenerator,运行 while(true) 循环。这是 Claude Code 实现”自主推理”的核心。

用户: "帮我修复 login 函数的 bug"

第 1 轮 API 调用:
  模型: "让我先看看 login 函数的代码" → [调用 GrepTool("login")]

  工具执行结果: "找到 src/auth.ts:42"

第 2 轮 API 调用:
  模型: "让我读一下这个文件" → [调用 FileReadTool("src/auth.ts")]

  工具执行结果: 文件内容...

第 3 轮 API 调用:
  模型: "找到 bug 了,第 52 行缺少 null 检查" → [调用 FileEditTool(...)]

  工具执行结果: 文件已修改

第 4 轮 API 调用:
  模型: "已修复。在 auth.ts 的 validateToken 函数中添加了 null 检查..."
  → [无工具调用,循环结束]

关键逻辑在 query.ts 约第 1384 行:

if (needsFollowUp) {
  continue; // 有工具调用,继续下一轮
} else {
  return; // 无工具调用,对话结束
}

8.2 上下文压缩策略

Agentic 循环的一个挑战是:每轮调用都会增加消息历史,token 数量快速增长。Claude Code 实现了四级压缩策略:

压缩级别触发条件实现方式
Tool Result Budget每次循环开始截断过长的工具结果
Snip Compaction可选删除旧的对话历史片段
Microcompact可选就地压缩工具结果
Autocompacttoken 超过阈值用 Haiku 模型对全文进行智能压缩
Hard Limittoken 超过硬限制强制终止并报错

Autocompact 是最有趣的一个:当对话历史过长时,Claude Code 会调用Haiku模型来压缩历史对话,保留关键信息的同时大幅减少用户花费。

9.3 并行的预取操作

在等待模型响应的同时,Claude Code 还会并行执行两个预取操作:

  • Memory Prefetch — startRelevantMemoryPrefetch() 预取可能相关的记忆文件
  • Skill Discovery — 发现可能需要的技能

这些预取结果在下一轮循环中可用,减少了不必要的延迟。

所有工具执行完毕,模型给出了最终回复。最后一步:把结果渲染到终端。


九、响应渲染

9.1 事件消费

回到 REPL 层,onQueryEvent()(src/screens/REPL.tsx 约第 2616 行)消费 query() generator 产出的每一个事件:

query() generator 产出的事件
  → stream_request_start   加载状态(显示 spinner)
  → assistant message      模型回复(追加到对话状态)
  → tool_use_summary       工具调用摘要
  → progress message       进度更新
  → system message         系统提示(错误、信息)

9.2 终端渲染

Messages 组件(src/components/Messages.tsx)使用 Ink 将所有消息渲染到终端。Ink 是一个将 React 组件映射为终端输出的库,使得 Claude Code 可以用声明式的方式构建复杂的终端 UI。

渲染内容包括:

  • 文本回复 — Markdown 格式化后的文本
  • 代码块 — 语法高亮的代码
  • 工具调用 — 显示工具名称和参数(如 Bash: npm test)
  • 工具结果 — 显示执行结果
  • 思考过程 — 折叠显示(如果启用了 extended thinking)
  • 进度指示器 — spinner 和进度条
  • 权限请求 — 弹出确认对话框

作者注:本文基于 Claude Code 泄露的代码的分析编写。代码路径和行号可能随版本更新而变化,但核心架构设计相对稳定。如果你对某个具体模块感兴趣,建议直接阅读源码 — Claude Code 的代码质量相当高,值得一读。

评论