Claude Code 是什么?
想象一下,你有一个超级聪明的程序员朋友,他能听懂你的话, 帮你写代码、查文件、修bug,甚至能解释整个项目是怎么运作的。
Claude Code 就是这样的朋友——一个运行在终端里的 AI 编程助手。
就像和朋友聊天一样简单
当你输入命令时发生了什么?
让我们追踪一个完整的请求流程
1. 你发送请求
"帮我把所有的 console.log 改成 logger"
2. 理解你的意图
Claude 分析你的需求,理解要做什么
3. 规划行动步骤
搜索文件 → 找到 console.log → 替换成 logger
4. 执行工具调用
使用 Grep 搜索、Edit 修改文件
5. 返回结果
"已完成!修改了 12 个文件"
核心引擎:query 函数
在 Claude Code 的源码中,query 函数是整个系统的核心引擎。
让我们来看看它的一部分代码:
export async function* query(
params: QueryParams,
): AsyncGenerator<
| StreamEvent
| RequestStartEvent
| Message,
Terminal
> {
const consumedCommandUuids: string[] = []
const terminal = yield* queryLoop(params, consumedCommandUuids)
return terminal
}
export async function* query
↓ 导出一个异步生成器函数,名为 "query"(查询)
params: QueryParams
↓ 接收参数:包含系统提示、用户消息、可用工具等信息
AsyncGenerator<...>
↓ 返回一个异步生成器,可以持续产生事件流
yield* queryLoop(...)
↓ 委托给主循环,开始处理请求
生活类比
普通函数 = 点外卖
你点餐 → 等待 → 收到外卖(一次性完成)
生成器函数 = 现场做饭
备菜 → 炒菜 → 调味 → 装盘(你可以看到每一步)
Claude Code 的"手":工具系统
AI 不只是聊天,它能真正操作你的电脑
Bash
执行命令行操作
ls -la
npm install
Read
读取文件内容
读取 package.json
查看配置文件
Edit
修改文件
替换变量名
更新函数逻辑
Grep
搜索代码
查找函数定义
搜索关键字
Write
创建新文件
生成新组件
写入配置
Glob
查找文件
找到所有 .ts 文件
匹配文件模式
内部的"群聊":组件如何协作
当一个请求进来时,各个组件之间在"聊什么"
核心概念总结
恭喜你完成了第一模块!
一个能真正操作代码的 AI 编程助手,不只是聊天机器人
用户请求 → 理解意图 → 规划步骤 → 执行工具 → 返回结果
像流水线一样持续产出结果,让你看到思考过程
给 AI 装上"手"和"眼睛",能真正执行操作
📚 词汇表
使用人工智能技术帮助开发者编写、理解和改进代码的工具
一种可以逐步产生多个值的函数,像流水线一样持续产出结果
一套预定义的操作接口,让 AI 能够执行具体的编程任务
Claude Code 的核心处理逻辑,负责协调所有组件完成用户请求
在处理过程中持续产生的状态更新,让用户实时看到进度
🎯 模块 1 测验
检验你的理解程度!
1. Claude Code 和普通聊天机器人有什么区别?
✅ 正确!工具系统让 Claude Code 能执行实际操作,而不只是提供建议。
❌ 不太对。再想想看,是什么让 Claude Code 能够真正修改文件?
2. query 函数为什么要用生成器(Generator)?
✅ 完全正确!生成器像流水线一样持续产出事件,让你能实时看到 Claude 的思考过程。
❌ 不完全是。生成器的关键优势是什么?提示:想想"流"这个概念。
3. 当你发送"帮我查看项目结构"时,哪个工具会被使用?
✅ 对!Bash 工具可以执行命令行操作,比如 ls 来查看文件结构。
❌ 不太对。想想看,查看文件结构通常需要执行什么操作?
4. "工具系统"在 Claude Code 中扮演什么角色?
✅ 完全正确!工具系统让 AI 能真正操作文件、执行命令,而不只是聊天。
❌ 不太准确。工具的核心作用是什么?想想"手"和"眼睛"的比喻。
测验结果
模块 2:核心组件介绍
认识 Claude Code 的三大支柱:查询引擎、工具系统与状态管理
🏗️ 架构全景图
查询引擎 (QueryEngine)
协调整个对话流程
工具系统 (Tools)
执行具体操作
状态管理 (AppState)
维护应用状态
Claude Code 采用分层架构:查询引擎负责编排,工具系统负责执行,状态管理负责持久化。三者协同工作,形成完整的 AI 代码助手系统。
⚙️ 查询引擎 (QueryEngine)
查询引擎是 Claude Code 的核心协调器,负责管理整个对话生命周期。
export class QueryEngine {
private config: QueryEngineConfig
private mutableMessages: Message[]
private abortController: AbortController
private permissionDenials: SDKPermissionDenial[]
private totalUsage: NonNullableUsage
constructor(config: QueryEngineConfig) {
this.config = config
this.mutableMessages = config.initialMessages ?? []
this.abortController = config.abortController ?? createAbortController()
this.permissionDenials = []
this.totalUsage = EMPTY_USAGE
}
async *submitMessage(
prompt: string | ContentBlockParam[],
options?: { uuid?: string; isMeta?: boolean },
): AsyncGenerator {
// 实现消息提交逻辑
}
}
// 1. 初始化阶段
- 加载系统提示词
- 准备工具列表
- 设置权限上下文
// 2. 处理输入阶段
- 解析用户消息
- 处理斜杠命令
- 附加文件内容
// 3. API 调用阶段
- 调用 Claude API
- 流式接收响应
- 处理工具调用请求
// 4. 工具执行阶段
- 验证工具权限
- 执行工具操作
- 收集工具结果
// 5. 结果返回阶段
- 格式化响应消息
- 更新使用统计
- 返回结果给用户
// 创建查询引擎实例
const engine = new QueryEngine({
cwd: process.cwd(),
tools: availableTools,
commands: allCommands,
mcpClients: mcpConnections,
agents: agentDefinitions,
canUseTool: checkToolPermissions,
getAppState: () => store.getState(),
setAppState: (fn) => store.setState(fn()),
readFileCache: new FileStateCache(),
})
// 提交消息并获取响应
for await (const message of engine.submitMessage(userInput)) {
if (message.type === 'assistant') {
console.log('Assistant:', message.message)
} else if (message.type === 'result') {
console.log('Result:', message.result)
}
}
每个 QueryEngine 实例对应一个对话会话。多次调用 submitMessage() 会在同一会话中继续对话,状态(消息历史、文件缓存、使用统计等)会在多次调用之间持久化。
🔧 工具系统 (Tools)
工具系统定义了 Claude 可以执行的所有操作,从文件读写到 Bash 命令执行。
🎮 交互式工具探索
点击不同类别查看工具类型:
文件操作工具
// Read 工具定义
const ReadTool: Tool = {
name: 'Read',
description: '读取文件内容',
inputSchema: z.object({
file_path: z.string(),
offset: z.number().optional(),
limit: z.number().optional(),
}),
call: async (input, context) => {
const content = await fs.readFile(input.file_path, 'utf-8')
return { data: content }
},
isReadOnly: () => true, // 只读操作
isEnabled: () => true,
}
搜索工具
// Grep 工具定义
const GrepTool: Tool = {
name: 'Grep',
description: '在文件中搜索模式',
inputSchema: z.object({
pattern: z.string(),
path: z.string().optional(),
glob: z.string().optional(),
}),
call: async (input, context) => {
const results = await searchFiles(input.pattern, input.path)
return { data: results }
},
isReadOnly: () => true,
isSearchOrReadCommand: () => ({ isSearch: true, isRead: false }),
}
Bash 工具
// Bash 工具定义
const BashTool: Tool = {
name: 'Bash',
description: '执行 Shell 命令',
inputSchema: z.object({
command: z.string(),
}),
call: async (input, context) => {
const result = await execCommand(input.command)
return { data: result.stdout }
},
isReadOnly: (input) => isReadOnlyCommand(input.command),
isDestructive: (input) => isDestructiveCommand(input.command),
}
MCP 工具
// MCP 工具示例(来自外部服务器)
const MCPTool: Tool = {
name: 'mcp__server__tool_name',
description: 'MCP 服务器提供的工具',
mcpInfo: {
serverName: 'server',
toolName: 'tool_name'
},
isMcp: true,
call: async (input, context) => {
// 通过 MCP 协议调用远程工具
const result = await callMCPTool(
context.mcpClients,
'server',
'tool_name',
input
)
return { data: result }
},
}
📋 工具接口核心方法
| 方法 | 职责 | 返回值 |
|---|---|---|
call() |
执行工具逻辑 | Promise<ToolResult> |
description() |
生成工具描述 | Promise<string> |
checkPermissions() |
验证权限 | Promise<PermissionResult> |
isReadOnly() |
判断是否只读 | boolean |
isDestructive() |
判断是否破坏性 | boolean |
💾 状态管理 (AppState)
AppState 使用 React Context 和自定义 Store 管理全局应用状态。
export type AppState = {
// 对话状态
messages: Message[]
promptSuggestion: CompletionBoundary | null
// 工具权限
toolPermissionContext: ToolPermissionContext
// 模型配置
mainLoopModel: string
customSystemPrompt?: string
appendSystemPrompt?: string
// UI 状态
verbose: boolean
fastMode: FastModeState
theme: ThemeName
// 文件历史
fileHistory: FileHistoryState
attribution: AttributionState
// 推测状态(预测用户输入)
speculation: SpeculationState
}
// 读取状态
function MyComponent() {
const messages = useAppState(s => s.messages)
const verbose = useAppState(s => s.verbose)
const model = useAppState(s => s.mainLoopModel)
return {/* 使用状态 */}
}
// 更新状态
function AnotherComponent() {
const setAppState = useSetAppState()
const handleClick = () => {
setAppState(prev => ({
...prev,
verbose: !prev.verbose,
// 只更新需要的字段
}))
}
return
}
// ✅ 推荐:使用函数式更新
setAppState(prev => ({
...prev,
messages: [...prev.messages, newMessage],
}))
// ✅ 推荐:只更新需要的字段
setAppState(prev => {
const updated = { ...prev, verbose: true }
return updated
})
// ❌ 避免:直接修改状态
setAppState(prev => {
prev.messages.push(newMessage) // 不要这样做!
return prev
})
// ✅ 推荐:使用不可变更新
setAppState(prev => ({
...prev,
messages: [...prev.messages, newMessage],
}))
useAppState() 使用选择器模式,只有当选择的值真正改变时才会重新渲染。对于多个独立字段,多次调用 hook 比返回新对象更高效。
🤝 组件协作流程
让我们看看三大组件如何协同工作来处理一个用户请求:
用户输入
用户发送消息:"帮我找到所有 TypeScript 文件中的 TODO 注释"
QueryEngine 接收
submitMessage() 被调用,创建新的对话轮次
调用 Claude API
将消息历史和系统提示词发送给 API
API 返回工具调用
返回:Grep(pattern="TODO", glob="*.ts")
权限检查
canUseTool() 验证是否允许执行 Grep 工具
执行工具
Grep.call() 执行搜索,返回结果
更新状态
通过 setAppState() 添加新消息到历史
返回结果
将搜索结果返回给用户,完成对话轮次
📖 核心词汇表
📝 知识检测
问题 1:QueryEngine 的主要职责是什么?
问题 2:Tool 接口中哪个方法是必须实现的?
问题 3:以下哪种方式更新 AppState 是正确的?
// A
setAppState(prev => {
prev.messages.push(newMessage)
return prev
})
// B
setAppState(prev => ({
...prev,
messages: [...prev.messages, newMessage],
}))
问题 4:QueryEngine 每次调用 submitMessage() 会如何处理状态?
💻 实战练习
练习:创建自定义工具
中等基于你学到的 Tool 接口知识,创建一个简单的自定义工具。这个工具应该能够统计指定目录下的文件数量。
- 定义工具的 name 和 description
- 使用 z.object() 定义 inputSchema
- 实现 call() 方法,使用 fs.readdir() 读取目录
- 实现 isReadOnly() 返回 true
- 使用 buildTool() 创建最终工具
查看参考答案
import { buildTool } from './Tool.js'
import { z } from 'zod'
import { readdir } from 'fs/promises'
import { join } from 'path'
export const CountFilesTool = buildTool({
name: 'CountFiles',
description: '统计指定目录下的文件数量',
inputSchema: z.object({
directory: z.string().describe('要统计的目录路径'),
pattern: z.string().optional().describe('可选的文件匹配模式'),
}),
async call(input, context) {
try {
const fullPath = join(context.options.cwd, input.directory)
const files = await readdir(fullPath)
let filteredFiles = files
if (input.pattern) {
const regex = new RegExp(input.pattern)
filteredFiles = files.filter(f => regex.test(f))
}
return {
data: {
total: filteredFiles.length,
directory: input.directory,
files: filteredFiles,
},
}
} catch (error) {
return {
data: {
error: error.message,
total: 0,
},
}
}
},
isReadOnly: () => true,
isEnabled: () => true,
})
🎯 模块总结
- QueryEngine 是对话的核心协调器,管理整个查询生命周期
- Tools 定义了 Claude 可以执行的所有操作,通过统一接口实现
- AppState 使用不可变数据结构和 React Context 管理全局状态
- 三者通过清晰的接口协作:QueryEngine 调用 Tools,Tools 更新 AppState
- 理解组件协作流程对于调试和扩展功能至关重要
模块 3:工具系统如何工作
🎯 学习目标
- 理解 40+ 工具如何注册、发现和执行
- 掌握权限系统的保护机制
- 追踪工具调用的完整生命周期
- 理解 MCP 工具的集成方式
🍽️ 比喻:高级餐厅的点菜系统
Claude Code 的工具系统就像一个高级餐厅:
- 菜单(tools.ts):列出所有可用的"菜品"(工具)
- 点菜(Claude):AI 根据需求选择合适的工具
- 权限检查(门卫):确保操作安全,保护你的系统
- 厨房执行(工具实现):实际执行操作的代码
- 上菜(返回结果):将执行结果返回给 Claude
📦 核心概念 1:工具注册表(tools.ts)
src/tools.ts 是整个工具系统的"中央菜单",它管理着所有 40+ 内置工具的注册和发现。
// 工具注册:每个工具都被导入并注册
import { BashTool } from './tools/BashTool/BashTool.js'
import { FileReadTool } from './tools/FileReadTool/FileReadTool.js'
import { GrepTool } from './tools/GrepTool/GrepTool.js'
// ... 40+ 更多工具
/**
* 获取所有基础工具(这是单一真实来源)
* 注意:这个列表必须与 Statsig 配置保持同步
* 以便系统提示可以被缓存
*/
export function getAllBaseTools(): Tools {
return [
AgentTool,
TaskOutputTool,
BashTool,
GlobTool,
GrepTool,
FileReadTool,
FileEditTool,
FileWriteTool,
// ... 更多工具
]
}
🔍 代码解读
- 集中注册:所有工具在
getAllBaseTools()中注册,这是工具的"单一真实来源" - 条件加载:某些工具只在特定环境下加载(如
USER_TYPE === 'ant') - 缓存同步:工具列表必须与远程配置同步,以优化性能
- 类型安全:使用 TypeScript 的
Tools类型确保所有工具符合接口
为什么集中注册很重要?
集中注册让系统可以:
- 统一管理:在一个地方看到所有可用工具
- 权限控制:在工具暴露给 AI 之前进行过滤
- 性能优化:通过缓存工具列表减少 token 消耗
- 动态加载:根据环境和配置动态启用/禁用工具
🔧 核心概念 2:工具接口(Tool Interface)
每个工具都实现一个标准化的 Tool 接口,定义在 src/Tool.ts 中。这就像每个"菜品"都有标准的菜谱格式。
export type Tool<Input, Output, Progress> = {
// 基本信息
readonly name: string // 工具名称
aliases?: string[] // 别名(向后兼容)
searchHint?: string // 搜索提示(3-10词)
// Schema 定义
readonly inputSchema: Input // 输入参数的 Zod schema
readonly inputJSONSchema?: ToolInputJSONSchema // JSON Schema 格式
outputSchema?: z.ZodType<unknown> // 输出 schema
// 核心方法
call(
args: z.infer<Input>,
context: ToolUseContext,
canUseTool: CanUseToolFn,
parentMessage: AssistantMessage,
onProgress?: ToolCallProgress<Progress>,
): Promise<ToolResult<Output>> // 执行工具
// 描述和权限
description(input: z.infer<Input>, options: ...): Promise<string>
checkPermissions(input: z.infer<Input>, context: ...): Promise<PermissionResult>
// 安全和并发
isEnabled(): boolean // 是否启用
isReadOnly(input: z.infer<Input>): boolean // 是否只读
isDestructive?(input: z.infer<Input>): boolean // 是否破坏性
isConcurrencySafe(input: z.infer<Input>): boolean // 是否并发安全
// UI 渲染
renderToolUseMessage(input: ..., options: ...): React.ReactNode
renderToolResultMessage?(content: ..., options: ...): React.ReactNode
// 元数据
maxResultSizeChars: number // 结果大小限制(字符数)
isMcp?: boolean // 是否 MCP 工具
}
🔍 关键方法解析
| 方法 | 作用 | 比喻 |
|---|---|---|
call() |
执行工具的核心逻辑 | 厨师做菜 |
description() |
生成工具的 AI 描述 | 菜单上的菜品说明 |
checkPermissions() |
检查权限 | 门卫检查订单 |
renderToolUseMessage() |
渲染工具调用 UI | 厨房显示屏显示订单 |
🎬 交互演示:工具调用的生命周期
点击下方按钮,观察 Claude 如何调用工具的完整流程:
🔄 工具调用生命周期
🔒 核心概念 3:权限系统
权限系统是 Claude Code 的安全网,确保 AI 不会执行危险操作。它就像餐厅的门卫,检查每个订单是否安全。
权限模式
Claude Code 支持三种权限模式:
- default:正常权限检查,需要用户确认
- auto:AI 自动决策,适合信任环境
- bypass:跳过权限检查(仅限特殊情况)
🔌 核心概念 4:MCP 工具集成
MCP (Model Context Protocol) 工具是动态加载的外部工具,可以扩展 Claude Code 的能力。就像餐厅可以临时聘请"特邀厨师"。
🔄 MCP 工具加载流程
发现 MCP 服务器
从配置文件(.claude/mcp.json)读取 MCP 服务器列表
连接服务器
为每个 MCP 服务器建立连接,获取工具列表
转换工具格式
将 MCP 工具转换为 Claude Code 的 Tool 接口
合并到工具池
使用 assembleToolPool() 合并内置和 MCP 工具
💻 MCP 工具合并代码
/**
* 组合完整的工具池(内置 + MCP)
* 这是内置工具和 MCP 工具合并的单一真实来源
*/
export function assembleToolPool(
permissionContext: ToolPermissionContext,
mcpTools: Tools,
): Tools {
// 1. 获取内置工具(已根据权限过滤)
const builtInTools = getTools(permissionContext)
// 2. 过滤被拒绝的 MCP 工具
const allowedMcpTools = filterToolsByDenyRules(
mcpTools,
permissionContext
)
// 3. 按名称排序(内置工具在前,MCP 工具在后)
// 这样可以保持缓存稳定性
const byName = (a: Tool, b: Tool) =>
a.name.localeCompare(b.name)
// 4. 去重(内置工具优先)
return uniqBy(
[...builtInTools].sort(byName)
.concat(allowedMcpTools.sort(byName)),
'name'
)
}
MCP 工具的优势
- 动态扩展:无需修改核心代码即可添加新工具
- 权限继承:MCP 工具遵循相同的权限系统
- 类型安全:自动转换为 TypeScript 类型
- 缓存优化:支持工具延迟加载(defer_loading)
🔨 实际例子:Read 工具的完整实现
让我们看看一个真实工具的完整实现:
import { z } from 'zod/v4'
import { buildTool, type ToolDef } from '../../Tool.js'
// 1. 定义输入 Schema
const inputSchema = lazySchema(() =>
z.strictObject({
file_path: z.string().describe('要读取的文件的绝对路径'),
offset: z.number().optional().describe('开始读取的行号'),
limit: z.number().optional().describe('读取的最大行数'),
})
)
// 2. 实现工具
export const FileReadTool: ToolDef<typeof inputSchema, string> = {
name: 'Read',
description: 'Read a file from the local filesystem',
inputSchema,
outputSchema: z.string(),
// 3. 实现核心调用逻辑
async call(args, context, canUseTool) {
const { file_path, offset, limit } = args
// 3.1 权限检查
const permission = await checkReadPermissionForTool(
file_path,
context
)
if (permission.behavior === 'deny') {
return permission
}
// 3.2 读取文件
const content = await readFileInRange(
file_path,
offset || 0,
limit || 2000
)
// 3.3 返回结果
return {
data: content,
newMessages: []
}
},
// 4. 实现权限检查
async checkPermissions(args, context) {
return await checkReadPermissionForTool(
args.file_path,
context
)
},
// 5. 安全属性
isReadOnly: () => true, // 只读操作
isDestructive: () => false, // 非破坏性
isConcurrencySafe: () => true, // 并发安全
// 6. UI 渲染
renderToolUseMessage(input, options) {
return <ReadToolUseMessage input={input} />
},
// 7. 元数据
maxResultSizeChars: Infinity, // 结果大小限制
getActivityDescription(input) {
return `Reading ${input.file_path}`
}
}
// 8. 使用 buildTool 填充默认值
export default buildTool(FileReadTool)
🔍 实现解析
Schema 定义
使用 Zod 定义输入参数,提供类型安全和自动验证
工具定义对象
实现 ToolDef 接口,包含所有必需和可选方法
核心调用逻辑
call() 方法执行实际操作:权限检查 → 读取文件 → 返回结果
权限检查
checkPermissions() 实现工具特定的权限逻辑
安全属性
声明操作特性:只读、非破坏性、并发安全
UI 渲染
提供 React 组件渲染工具调用和结果的 UI
元数据
配置工具行为:结果大小限制、活动描述等
构建工具
使用 buildTool() 填充默认值,生成完整的 Tool 对象
📚 关键术语
Tool 接口的对象,包含 call()、description() 等方法
readonly Tool[]
buildTool() 会填充默认值
behavior(allow/deny/ask)和 updatedInput
data、newMessages 等字段
📝 模块测验
测试你对工具系统的理解:
src/tools.ts 是工具注册表,管理所有 40+ 内置工具。
call() 方法执行工具的核心逻辑,就像厨师实际做菜。
assembleToolPool() 负责合并内置工具和 MCP 工具,并进行去重和排序。
buildTool() 函数的主要作用是什么?
buildTool() 填充工具定义中的默认值(如 isEnabled、isReadOnly 等),生成完整的 Tool 对象。
🎓 模块总结
在本模块中,我们学习了:
- 工具注册:
src/tools.ts是所有工具的中央注册表 - 工具接口:
Tool接口定义了工具的标准结构 - 权限系统:四层保护确保操作安全
- MCP 集成:动态加载外部工具,扩展系统能力
- 工具生命周期:从用户请求到最终响应的完整流程