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

当用户在终端按下回车 — 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 引导的核心,负责:
- Commander.js 命令行解析 — 解析所有 CLI 参数
- 认证初始化 — API Key / OAuth / AWS 凭证 / GCP 凭证
- 设置加载 —
settings.json、项目级配置 - MCP 客户端初始化 — 连接外部 MCP 服务器
- GrowthBook 特性开关 — A/B 测试和功能开关
- 插件与技能系统 — 加载 skills 和 plugins
- 权限系统初始化 — 工具权限配置
最终调用 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)是网关函数,它:
- 展开粘贴的文本引用和图片
- 处理斜杠命令
- 调用
processUserInput()将原始文本转为结构化消息 - 将消息传递给
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 API | API Key | ANTHROPIC_API_KEY |
| AWS Bedrock | AWS SigV4 | AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY |
| Google Vertex AI | GCP OAuth | GCP Application Default Credentials |
| Azure Foundry | API Key / OAuth | ANTHROPIC_FOUNDRY_RESOURCE |
| Claude.ai | 用户 OAuth | OAuth Token |
5.2 构建请求
queryModel()(src/services/api/claude.ts 约第 1017 行)构建完整的 API 请求:
- 消息归一化 —
normalizeMessagesForAPI()确保消息格式符合 API 规范 - 工具 Schema 构建 —
toolToAPISchema()将每个工具转为 JSON Schema - 系统提示词切分 —
buildSystemPromptBlocks()切分为可缓存块 - Thinking 配置 — 根据模型能力配置 extended thinking
- Effort 设置 — 设置推理强度(low / medium / high)
- 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_result | MCP 工具的执行结果 |
web_search_tool_result | Web 搜索结果 |
web_fetch_tool_result | Web 页面抓取结果 |
code_execution_tool_result | 代码执行结果 |
advisor_tool_result | Advisor 工具结果 |
其他:
| 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 | 抓取网页内容 |
WebSearchTool | Web 搜索 |
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 | 可选 | 就地压缩工具结果 |
| Autocompact | token 超过阈值 | 用 Haiku 模型对全文进行智能压缩 |
| Hard Limit | token 超过硬限制 | 强制终止并报错 |
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 的代码质量相当高,值得一读。
评论
无需登录,审核通过后公开。只有博主可以回复。
正在加载…
已公开的评论