写在前面
为什么写这份黄皮书
Claude Code 是 Anthropic 推出的 AI 编程助手,它不仅仅是一个"能写代码的聊天机器人"——它是一个完整的 AI Agent 系统。理解它的工作原理,对于想进入 AI Agent 领域的开发者来说,是一个极好的起点。
这份黄皮书不会教你如何"使用"Claude Code,而是带你深入它的源码,一步步拆解它是如何工作的。
你需要准备什么
- 基本的编程概念(不需要精通特定语言)
- 对"AI 是什么"有模糊的认知即可
- 好奇心 —— 这是最重要的
这份文档的阅读方式
每个章节都以一个"生活化的比喻"开头,然后逐步深入到技术细节。建议按顺序阅读,因为后一章的内容会建立在前一章的理解之上。
课程地图
整体学习路线
这份黄皮书共分为 10 个阶段,外加导论和总复习,构成了一个完整的学习闭环:
- 第一阶段:认识 Claude Code 的全貌
- 第二阶段:理解程序的入口 ——
main.tsx - 第三阶段:深入对话引擎 —— QueryEngine
- 第四阶段:核心运行循环 ——
while(true) - 第五阶段:工具调用机制 —— 从意图到执行
- 第六阶段:安全机制 —— Agent 的护栏
- 第七阶段:四层工具生态
- 第八阶段:服务层架构
- 第九阶段:隐藏功能揭秘
- 第十阶段:基础设施全景
第一阶·遇见Claude Code
Claude Code 是什么?
Claude Code 是 Anthropic 官方推出的命令行 AI 编程工具。你可以把它想象成一个住在终端里的"编程搭档"——你用自然语言告诉它要做什么,它帮你写代码、改 Bug、重构项目。
它的与众不同之处
和普通的 ChatGPT 对话不同,Claude Code 是一个 Agentic 系统:
- 它可以自主决定使用什么工具(读文件、写文件、执行命令…)
- 它能多轮循环执行任务,直到任务完成
- 它有安全边界,不会随意执行危险操作
项目源码结构
Claude Code 的源码是用 TypeScript 编写的,核心结构大致如下:
claude-code/ ├── src/ │ ├── main.tsx # 程序入口 │ ├── query-engine/ # 对话引擎 │ ├── tools/ # 工具系统 │ ├── services/ # 服务层 │ └── safety/ # 安全模块 ├── package.json └── ...
接下来的每一章,我们都会深入其中的一个模块。
第二阶·你醒啦cc - main.tsx 和那扇门
程序的起点:main.tsx
每个程序都有一个入口。对于 Claude Code 来说,main.tsx 就是那扇"门"——程序从这里启动,初始化各种组件,然后进入主循环。
你可以把它想象成一家餐厅的"开门营业"流程:
- 先打开灯、启动厨房设备(初始化配置)
- 检查今天的菜单和库存(加载模型参数和工具)
- 然后坐等客人上门(等待用户输入)
关键代码片段
main.tsx 的核心职责是:
- 解析命令行参数
- 初始化 LLM 客户端
- 设置工具注册表
- 启动对话循环
main.tsx 不做具体的事,它是一个"调度者"——把各个模块组装在一起,然后启动整个系统。
初始化流程
// 简化的初始化流程 1. 解析 CLI 参数(模型选择、工作目录等) 2. 创建 LLM 客户端连接 3. 注册所有可用工具 4. 设置安全策略 5. 进入主循环 →
第三阶·发这么多消息不嫌烦吗 - QueryEngine: 多轮对话的管家
什么是 QueryEngine?
QueryEngine 是 Claude Code 的对话管理中枢。它负责处理你和 AI 之间的每一轮交互,管理对话历史,并确保上下文不会丢失。
想象你和一个非常聪明的助手对话:
- 它会记住你之前说过的每一句话
- 它知道当前的任务是什么
- 它决定什么时候该回复、什么时候该调用工具
多轮对话的本质
LLM 本身是"无状态"的——每次调用都是独立的。QueryEngine 的工作就是把对话历史拼装起来,让 LLM "看起来"有记忆:
[
{ role: "system", content: "你是一个编程助手..." },
{ role: "user", content: "帮我看看这个文件" },
{ role: "assistant", content: "好的,让我读取..." },
{ role: "tool", content: "[文件内容]" },
{ role: "assistant", content: "这个文件的问题是..." }
]
Token 管理
对话历史不可能无限增长(有 Token 限制)。QueryEngine 还需要负责:
- 判断何时需要裁剪历史
- 保留关键上下文
- 在 Token 限制内最大化信息量
第四阶·假期这么少,你怎么给我陪伴 - 永不停歇的 while(true)
Agent 的心跳:主循环
Claude Code 的核心是一个 while(true) 循环——它会不断运行,等待用户输入,处理请求,返回结果,然后再次等待。就像一个永不休息的值班员。
// 伪代码:Agent 主循环
while (true) {
// 1. 等待用户输入
const userInput = await getUserInput();
// 2. 发送给 LLM 处理
const response = await llm.chat(messages);
// 3. 如果 LLM 返回文本 → 直接显示
if (response.type === "text") {
display(response.content);
}
// 4. 如果 LLM 要调用工具 → 执行工具
if (response.type === "tool_use") {
const result = await executeTool(response.tool);
messages.push(result);
continue; // 回到循环顶部,继续处理
}
// 5. 如果 LLM 说"任务完成" → 等待下一个任务
if (response.type === "done") {
break;
}
}
循环的终止条件
一个负责任的 Agent 不会真的永远循环。它会在以下情况退出:
- LLM 判断任务已完成
- 达到最大循环次数限制
- 用户主动中断
- 发生不可恢复的错误
第五阶·什么叫给我花钱算是转移支付? - 从 LLM 说"用这个工具"到真正干活
工具调用的完整链路
当 Claude 说"我要读取这个文件"时,实际发生了一系列精密的操作:
- 意图识别:LLM 分析用户请求,决定需要使用工具
- 生成调用指令:LLM 输出结构化的工具调用请求(JSON 格式)
- 权限检查:系统验证这个调用是否在允许范围内
- 实际执行:运行对应的工具函数
- 结果返回:将工具执行结果送回 LLM
Tool Use 的数据格式
// LLM 输出的工具调用(简化)
{
"type": "tool_use",
"name": "read_file",
"input": {
"path": "/home/user/project/main.tsx"
}
}
// 系统执行后的返回
{
"type": "tool_result",
"content": "文件内容..."
}
为什么 LLM 不能直接执行代码?
这是一个重要的安全设计:LLM 只负责"决策",工具系统负责"执行"。这样可以在中间加一道安全检查,防止 LLM 执行危险操作。
第六阶·不可以,要做好安全措施 — Agent的"安全带"
为什么 Agent 需要安全机制?
一个能读写文件、执行命令的 Agent,如果没有安全限制,就像一辆没有刹车的跑车——跑得快,但极其危险。
Claude Code 的安全架构
- 权限分级:读取文件 vs 写入文件 vs 执行命令,权限等级不同
- 沙箱机制:工具执行在受限环境中,不能随意访问系统资源
- 用户确认:危险操作需要用户手动确认
- 路径限制:只能在工作目录范围内操作
审批流程
// 安全检查流程
Tool Request
↓
权限检查 → 有权限? → Yes → 执行
↓ No
用户确认 → 同意? → Yes → 执行
↓ No
拒绝执行,返回错误
常见安全场景
- 读取用户主目录外的文件 → 需要确认
- 执行
rm -rf等危险命令 → 拒绝或强确认 - 网络请求到未知服务器 → 需要确认
第七阶·我喜欢有能力的 — 四层工具的完整生态
Claude Code 的工具分层
Claude Code 的工具系统分为四层,每一层解决不同层次的问题:
- 第一层:基础文件操作 — 读文件、写文件、列目录
- 第二层:代码智能 — 搜索代码、分析语法树、理解项目结构
- 第三层:执行环境 — 运行 shell 命令、执行脚本
- 第四层:外部集成 — Git 操作、网络请求、API 调用
工具注册机制
所有工具在启动时统一注册到工具注册表中。LLM 通过查阅注册表来知道"有哪些工具可用":
// 工具注册表示例
{
"read_file": {
"description": "读取指定路径的文件内容",
"parameters": { "path": "string" },
"permission": "read"
},
"write_file": {
"description": "将内容写入指定路径",
"parameters": { "path": "string", "content": "string" },
"permission": "write"
},
"execute_command": {
"description": "执行 shell 命令",
"parameters": { "command": "string" },
"permission": "execute"
}
}
工具选择的智能
LLM 会根据用户的意图,从注册表中选择最合适的工具。这个过程完全是自动的——你不需要告诉它该用什么工具。
第八阶·我们的关系有点上不了台面了 — 服务层
隐藏在幕后:服务层
除了直接面对用户的工具层,Claude Code 还有一个庞大的服务层——它处理各种"不太光彩"但不可或缺的工作:
- 认证服务:管理 API Key、用户身份验证
- 日志服务:记录每一次操作,便于调试和审计
- 配置服务:管理全局配置、项目级配置
- 缓存服务:缓存 LLM 响应、文件内容,减少重复请求
- 通知服务:长任务完成时提醒用户
服务层的协作模式
用户请求 → Agent 主循环
↓
┌─────┼─────┐
↓ ↓ ↓
工具层 服务层 安全层
↓ ↓ ↓
└─────┼─────┘
↓
统一响应
第九阶·你还瞒着我什么? — 官方隐藏的功能
你可能不知道的功能
Claude Code 有很多功能在官方文档中并不显眼,但它们对于高级用户来说非常有价值:
- 自定义系统提示词:可以通过配置文件注入额外的指令
- 扩展点(Hooks):在工具执行前后插入自定义逻辑
- MCP 协议支持:可以连接外部的 MCP 服务器来扩展能力
- Worktree 模式:在独立的工作树中运行,不影响主分支
配置文件的秘密
# .claude/settings.json
{
"customInstructions": "在所有操作中优先使用中文...",
"allowedTools": ["read", "write", "execute"],
"mcpServers": {
"my-server": {
"command": "node",
"args": ["my-mcp-server.js"]
}
}
}
调试模式
通过环境变量可以开启详细的调试输出,查看 LLM 的每次请求和响应,以及工具的执行过程。
第十阶·看透你了——一个简单循环 + 几十倍的基础设施
最终的全景图
回顾整个黄皮书,你会发现一个有趣的事实:
但为了支撑这个"简单"的核心,需要几十倍复杂度的基础设施——安全机制、服务层、工具生态、配置系统、日志审计……
从简单到复杂的映射
| 核心概念 | 支撑设施 |
| 对话循环 | QueryEngine + Token管理 + 上下文裁剪 |
| LLM 调用 | API 客户端 + 重试机制 + 流式响应 + 缓存 |
| 工具系统 | 四层工具 + 权限控制 + 沙箱 + MCP |
| 安全机制 | 权限分级 + 审批流程 + 路径限制 + 审计日志 |
工程的启示
这给我们的启示是:一个优秀的 Agent 系统,核心算法可能并不复杂,但工程化的能力才是真正的壁垒。安全性、可靠性、可扩展性——这些才是区分玩具和产品的关键。
总复习·我们的故事线
回顾整个旅程
让我们沿着故事线,重新梳理一遍:
- 遇见 → Claude Code 不只是聊天,它是一个 Agent
- 入门 →
main.tsx是起点,初始化一切 - 对话 → QueryEngine 管理多轮对话和上下文
- 循环 →
while(true)是 Agent 的心脏 - 工具 → LLM 发指令,工具系统执行
- 安全 → 权限分级 + 审批 = 可信赖的 Agent
- 生态 → 四层工具系统覆盖各种场景
- 服务 → 幕后英雄支撑整个系统
- 隐藏 → MCP、Hooks、配置文件扩展能力
- 全景 → 简单核心 + 复杂基础设施 = 优秀产品
下一步行动
- Clone Claude Code 源码,亲自阅读和调试
- 尝试自己实现一个简化版的 Agent
- 关注 Anthropic 的更新,持续跟进架构变化
- 加入社区,和其他学习者交流心得