声明 :本文源码标注的文件路径均来自
src/src/目录,为 Claude Code v2.1.88 反编译后的 TypeScript 源码,供学习与研究参考。
一、引言:从一个工具到一整个 Agent 系统
Claude Code 是 Anthropic 官方的 CLI 编程助手,它不仅是一个增强版的 REPL(Read-Eval-Print Loop),更是一个完整的 Agent 系统------它能够自主规划、调用工具、记忆上下文,并在多轮交互中持续推进复杂任务。
理解 Claude Code 的 Agent 实现原理,本质上是理解以下几个核心子系统的设计哲学与工程实践:
- Agent 核心循环:消息如何驱动一轮又一轮的推理与执行
- Tool 系统:工具的定义、执行与并发控制
- 多 Agent 编排:子 Agent 与协调者模式的实现
- 记忆与上下文管理:如何在有限上下文窗口内维护长期知识
- 安全与权限体系:如何在开放能力的同时保障系统安全
- Hooks 扩展机制:如何让用户干预 Agent 的每一步行为
本文将逐一展开,结合源码文件路径,帮助你在阅读后能够自行深入对应模块继续研究。
二、整体架构:从入口到 Agent 核心循环
2.1 程序入口与初始化
Claude Code 的入口由 src/src/entrypoints/cli.tsx 统一分发,根据命令行参数路由到不同模式(普通对话、Agent SDK、后台任务等)。真正的全局初始化在 src/src/entrypoints/init.ts 中完成,依次完成配置加载、网络初始化、遥测注册与清理函数注册。
在 src/src/main.tsx 中,我们可以看到完整的启动流水线:
typescript
// src/src/main.tsx(约第 50-80 行,简化摘录)
loadGrowthBookFeatureFlags(); // 特性开关(实验性功能)
loadModels(); // 模型列表加载
loadPlugins(); // 插件系统初始化
loadSkills(); // 技能(Slash Commands)加载
loadAgents(); // 自定义 Agent 定义加载
startMcpServers(); // MCP(Model Context Protocol)服务器启动
renderREPL(); // 渲染主 REPL 界面
整个过程是同步串行的,每个步骤失败都会阻断后续流程,这与 Agent 系统对运行环境健壮性要求高的特点一致。
2.2 Agent 核心循环:query() 与 queryLoop()
源码文件 :src/src/query.ts
Agent 的核心是一个 while(true) 无限循环,由 query() 函数驱动。query() 是一个 AsyncGenerator,每次 yield 出一个流式事件(文本、思考过程、工具调用、工具结果等),直到遇到终止条件。
整个循环的状态机如下:
typescript
// src/src/query.ts - State 类型定义(简化)
type State = {
messages: Message[] // 消息历史
toolUseContext: ToolUseContext // 工具执行上下文
autoCompactTracking: AutoCompactTrackingState | undefined // 自动压缩追踪
maxOutputTokensRecoveryCount: number // max_tokens 恢复计数
turnCount: number // 当前轮次
transition: Continue | undefined // 继续指令
// ...
}
每轮迭代经过以下阶段:
vbnet
构建请求
└─ system prompt(静态缓存部分 + 动态部分)
└─ messages(带 cache breakpoints)
└─ tools(Schema 转换后)
调用 API(流式)
└─ message_start → content_block_start → content_block_delta → message_stop
处理响应块
├─ text 块 → 展示给用户
├─ thinking 块 → 展示推理过程
└─ tool_use 块 → 交给 StreamingToolExecutor 执行
后处理
├─ 自动压缩(auto-compact)当上下文接近窗口上限
├─ Token 预算检查
├─ Stop Hooks 执行
└─ 记忆预取(memory prefetch)
2.3 API 流式处理与容错
源码文件 :src/src/services/api/claude.ts
Claude Code 默认使用 SSE(Server-Sent Events)流式调用 Anthropic API,逐事件(event-by-event)处理,灵活性极高。核心处理流程为:
typescript
// src/src/query.ts - 流式事件分发(概念性伪代码)
for await (const event of stream) {
switch (event.type) {
case 'message_start':
// 初始化消息元数据
break
case 'content_block_start':
if (event.content_block.type === 'tool_use') {
// 新工具调用开始,推入 StreamingToolExecutor
streamingExecutor.addTool(event.content_block, assistantMessage)
}
break
case 'content_block_delta':
if (event.delta.type === 'thinking_block' || event.delta.type === 'text_delta') {
// 实时 yield 显示
yield event.delta
}
break
case 'message_stop':
// 消息接收完毕,处理所有工具结果
for await (const result of streamingExecutor.getRemainingResults()) {
yield result
}
break
}
}
当流式传输失败时,系统会降级为非流式调用 (最多一次),但代价是单次输出上限降至 64K tokens。如果遇到 max_output_tokens 错误,系统会依次尝试以下恢复策略:
collapse_drain_retry--- 尝试压缩上下文重试reactive_compact_retry--- 响应式压缩重试max_output_tokens_escalate--- 扩大 max_tokensmax_output_tokens_recovery--- 最多重试 3 次token_budget_continuation--- 在 token 预算内继续
typescript
// src/src/query.ts - 恢复链(Recovery Chain)
const recoveryChain = [
collapse_drain_retry,
reactive_compact_retry,
max_output_tokens_escalate,
max_output_tokens_recovery,
stop_hook_blocking,
token_budget_continuation
]
三、Tool 系统:Agent 的四肢
3.1 统一的 Tool 接口定义
源码文件 :src/src/Tool.ts
Claude Code 定义了一个严格的 Tool 接口,每个工具都通过 buildTool() 工厂函数构建。以下是核心接口结构:
typescript
// src/src/Tool.ts - Tool 接口核心字段
type Tool<Input, Output, P> = {
name: string // 唯一标识符
inputSchema: Input // Zod Schema,参数校验
call(
args: z.infer<Input>, // 解析后的参数
context: ToolUseContext, // 执行上下文(大量注入依赖)
canUseTool: CanUseToolFn, // 权限检查函数
parentMessage: AssistantMessage, // 父消息(用于推理链溯源)
onProgress?: ToolCallProgress<P> // 进度回调(支持长时间操作)
): Promise<ToolResult<Output>>
description(input?, options?): Promise<string> // 工具描述(给模型看)
prompt(options?): Promise<string> // 使用说明(给系统 prompt 用)
// 执行属性(影响并发调度)
isConcurrencySafe(input?): boolean // true = 可并行,false = 独占
isReadOnly(input?): boolean // 只读 = 不修改系统状态
isDestructive?(input?): boolean // 破坏性标记
// 权限
checkPermissions(input, context): Promise<PermissionResult>
// UI 渲染(React 组件,返回 Ink 兼容节点)
renderToolUseMessage?(input, options): React.ReactNode
renderToolResultMessage?(content, progressMessages, options): React.ReactNode
renderGroupedToolUse?(toolUses[], options): React.ReactNode | null
}
buildTool() 工厂函数使用 TOOL_DEFAULTS 填充所有可选字段:
typescript
// src/src/Tool.ts - 工厂默认值
const TOOL_DEFAULTS = {
isEnabled: () => true,
isConcurrencySafe: (_input?) => false, // 默认非并发安全
isReadOnly: (_input?) => false,
checkPermissions: () => Promise.resolve({ behavior: 'allow', updatedInput: input }),
// ...
}
export function buildTool<D extends AnyToolDef>(def: D): BuiltTool<D>
3.2 ToolUseContext:工具的"神经中枢"
源码文件 :src/src/Tool.ts(ToolUseContext 类型定义)
ToolUseContext 是一个约 150+ 字段的巨大对象,在每次工具调用时注入,为工具提供了 Agent 运行时的几乎所有上下文信息:
typescript
// src/src/Tool.ts - ToolUseContext 核心字段概览
type ToolUseContext = {
// 工具相关
options: {
tools: Tools // 可用工具池
commands: Command[] // 可用 Slash Commands
thinkingConfig: ThinkingConfig // 思考配置
mcpClients: McpClientMap // MCP 客户端
}
// 中断与取消
abortController: AbortController // 用户可随时取消
// 文件状态
readFileState: FileStateCache // 文件读取缓存(避免重复读)
// 状态管理
getAppState: () => AppState // Zustand 全局状态读取
setAppState: (updater) => void // 状态更新
// Agent 追踪
agentId?: string // 当前 Agent ID(多 Agent 时有用)
queryTracking?: QueryTracking // 当前查询追踪信息
// 上下文压缩状态
contentReplacementState: ContentReplacementState
// 权限上下文
permissionContext: PermissionContext
// ... 150+ 字段
}
这种设计使得工具无需自行获取这些信息------所有依赖都通过 context 注入,符合**依赖注入(DI)**的设计原则,极大提升了工具的可测试性和可组合性。
3.3 工具执行管道:权限 → Hooks → 调用 → 后处理
源码文件:
src/src/services/tools/toolExecution.tssrc/src/services/tools/toolHooks.ts
一次工具调用的完整管道如下:
scss
Zod 输入校验
→ tool.validateInput()
→ runPreToolUseHooks() // 执行 PreToolUse 钩子(可修改输入或阻断)
→ resolveHookPermissionDecision() // 合并 Hook 和权限系统决策
→ canUseTool() // 最终权限检查
→ tool.call() // 执行工具核心逻辑
→ runPostToolUseHooks() // 执行 PostToolUse 钩子(可触发后续行为)
→ (若出错) runPostToolUseFailureHooks()
typescript
// src/src/services/tools/toolExecution.ts - 工具执行管道核心
async function checkPermissionsAndCallTool(
tool, toolUseID, input, toolUseContext,
canUseTool, assistantMessage, messageId, requestId,
mcpServerType, mcpServerBaseUrl, onToolProgress
): Promise<MessageUpdateLazy[]> {
// Step 1: Zod 校验
const parseResult = tool.inputSchema.safeParse(input)
// Step 2: PreToolUse Hooks(可阻断)
const preHookResults = await runPreToolUseHooks(tool, input, toolUseContext)
// Step 3: 权限决策
const permissionResult = await resolveHookPermissionDecision(preHookResults, canUseTool)
// Step 4: 执行工具(支持长时间操作的进度回调)
const result = await tool.call(parseResult.data, context, canUseTool, ...)
// Step 5: PostToolUse Hooks
await runPostToolUseHooks(tool, result, toolUseContext)
return [{ message: toolResultMessage }]
}
⚠️ 关键设计 :工具的输入参数是在一个克隆的副本 上运行
tool.backfillObservableInput(),这样 Hooks 和权限检查不会意外修改原始参数,从而保护 Prompt Cache 的完整性。
3.4 并发控制:谁可以并行,谁必须串行
源码文件 :src/src/services/tools/StreamingToolExecutor.ts
这是整个工具系统中设计最精妙的部分之一。StreamingToolExecutor 维护了一个工具状态机:
typescript
// src/src/services/tools/StreamingToolExecutor.ts - 工具状态机
type TrackedTool = {
id: string
block: ToolUseBlock
status: 'queued' | 'executing' | 'completed' | 'yielded'
isConcurrencySafe: boolean
promise?: Promise<void>
results?: Message[]
pendingProgress: Message[] // 立即 yield 的进度消息
contextModifiers?: Array<(context: ToolUseContext) => ToolUseContext>
}
// 并发判断逻辑
canExecuteTool(isConcurrencySafe: boolean): boolean {
const executingTools = this.tools.filter(t => t.status === 'executing')
return executingTools.length === 0 ||
(isConcurrencySafe && executingTools.every(t => t.isConcurrencySafe))
// 即:队列空闲时任何工具可执行;或者执行中只有并发安全工具时,新的并发安全工具可加入
}
执行策略:
- 并发安全 的工具(如
Read、Glob、Grep):最多 N 个同时执行(N 默认 10,可通过CLAUDE_CODE_MAX_TOOL_USE_CONCURRENCY配置) - 非并发安全 的工具(如
Write、Bash):独占执行,形成"门锁" - 如果一个非并发安全工具启动,会等待所有当前执行中的工具完成后再开始
这种设计的好处是:模型可以一次性请求多个只读操作(如读取多个文件),它们会被并行高效地执行,而写操作和命令执行则保证串行以避免竞态条件。
四、工具注册与组装
源码文件 :src/src/tools.ts
Claude Code 有 43 个内置工具,分为多个类别:
| 类别 | 代表工具 | 源码文件 |
|---|---|---|
| 文件操作 | FileReadTool, FileEditTool, FileWriteTool | src/src/tools/FileReadTool/ 等 |
| 搜索 | GlobTool, GrepTool | src/src/tools/GlobTool/ 等 |
| 执行命令 | BashTool, PowerShellTool, REPLTool | src/src/tools/BashTool/ 等 |
| 网络 | WebFetchTool, WebSearchTool | src/src/tools/WebFetchTool/ 等 |
| 多 Agent | AgentTool, SendMessageTool | src/src/tools/AgentTool/ |
| 任务管理 | TaskCreateTool, TaskUpdateTool, ... | src/src/tools/TaskTool/ |
| 定时任务 | CronCreateTool, CronDeleteTool, CronListTool | src/src/tools/CronTool/ |
| 工作流 | EnterPlanModeTool, ExitPlanModeTool, EnterWorktreeTool | src/src/tools/PlanModeTool/ 等 |
| MCP | MCPTool, ListMcpResourcesTool | src/src/services/mcp/ |
工具组装的核心函数是 assembleToolPool(),它按以下顺序合并:
typescript
// src/src/tools.ts - 工具组装逻辑
export function assembleToolPool(permissionContext, mcpTools): Tools {
// 1. 获取所有内置工具(已按名称排序)
const builtins = getAllBaseTools()
// 2. MCP 工具排序
const sortedMcpTools = [...mcpTools].sort((a, b) => a.name.localeCompare(b.name))
// 3. 去重:内置工具优先
const merged = [...builtins, ...sortedMcpTools]
const deduplicated = uniqBy(merged, 'name')
// 4. 内置工具形成连续前缀(用于 Prompt Cache 稳定性)
return deduplicated
}
源码注 :
src/src/tools.ts中使用了feature('COORDINATOR_MODE')、feature('AGENT_TRIGGERS')等编译时特性开关,配合bun:bundle的feature()宏实现死代码消除(Tree Shaking),确保不相关特性的代码不会进入最终产物。
五、多 Agent 系统:子 Agent 与协调者模式
5.1 子 Agent(AgentTool):Agent 递归嵌套
源码文件:
src/src/tools/AgentTool/AgentTool.tsxsrc/src/tools/AgentTool/runAgent.tssrc/src/utils/forkedAgent.ts
Claude Code 的 AgentTool 允许一个 Agent 在运行时动态创建子 Agent,每个子 Agent 有独立的消息历史、工具池和系统提示。
子 Agent 的输入 Schema 定义了它的元信息:
typescript
// src/src/tools/AgentTool/AgentTool.tsx - 输入 Schema
const baseInputSchema = lazySchema(() => z.object({
description: z.string(), // 任务描述(显示用)
prompt: z.string(), // 子 Agent 的核心指令
subagent_type: z.string().optional(), // Agent 类型(general-purpose, explore 等)
model: z.enum(['sonnet', 'opus', 'haiku']).optional(), // 指定模型
run_in_background: z.boolean().optional() // 是否后台运行
}))
call() 方法中有四条 spawn 路径:
typescript
// src/src/tools/AgentTool/AgentTool.tsx - call() 方法逻辑框架
async call(input, context, canUseTool, parentMessage, onProgress) {
// 路径1: Teammate 模式(团队协作)
if (input.team_name && input.name) {
return spawnTeammate(input, context)
}
// 路径2: Fork 子 Agent(轻量级,共享父 prompt cache)
if (effectiveType === undefined && isForkSubagentEnabled()) {
return runForkedAgent(input, context, parentMessage)
}
// 路径3: 普通子 Agent(完全独立)
const agentDef = resolveAgentDefinition(input)
return runAgent(agentDef, input, context)
// 路径4: 远程隔离(git worktree 或远程会话)
if (input.isolation === 'remote') {
return runRemoteIsolationAgent(input, context)
}
}
异步 vs 同步执行 :如果 shouldRunAsync 为 true(后台运行、协调者模式、强制异步等),Agent 在后台线程中执行,主 Agent 不会等待结果:
typescript
// src/src/tools/AgentTool/AgentTool.tsx - 异步循环
while (true) {
const result = await Promise.race([
agentIterator.next(), // Agent 迭代器下一步
backgroundPromise // 超时自动后台化
])
if (result.done) {
finalizeAgentTool(agentMessages, agentId, metadata)
break
}
// 支持用户中断后自动后台化
if (userInterrupted) {
await agentIterator.return(undefined)
continueInBackground(agentIterator)
break
}
}
5.2 Fork 子 Agent:共享 Prompt Cache 的轻量方案
源码文件 :src/src/utils/forkedAgent.ts
Fork 子 Agent 是 Claude Code 的一个高阶优化 :普通子 Agent 会创建一个完全新的 API 会话,但 Fork Agent 通过 createSubagentContext() 确保父子 Agent 共享相同的缓存参数(如 cache_control 字段),使得 API 能够命中跨会话的 Prompt Cache,大幅降低 token 消耗和响应延迟。
typescript
// src/src/utils/forkedAgent.ts - 核心函数
export function createSubagentContext(
parentParams: AnthropicMessageParam[],
parentSystemPrompt: SystemPrompt,
childSystemPrompt: SystemPrompt
): SubagentContext {
// 确保 cache 的边界点(cache breakpoint)一致
return {
sharedCacheParams: extractCacheParams(parentParams),
childSystemPromptHash: hashSystemPrompt(childSystemPrompt)
}
}
5.3 协调者模式(Coordinator Mode):多 Agent 协作编排
源码文件 :src/src/coordinator/coordinatorMode.ts
协调者模式是 Claude Code 的多 Agent 生产级方案:主 Agent(协调者)负责任务分解、派发和结果综合,多个工作 Agent 并行执行子任务。
协调者模式的核心是继续 vs 派发决策矩阵:
| 场景 | 决策 | 原因 |
|---|---|---|
| 研究结果刚好是要编辑的文件 | 继续(SendMessageTool) | Worker 有文件上下文和清晰计划 |
| 研究广泛但实现范围窄 | 派发新 Agent(AgentTool) | 避免探索噪声 |
| 修正失败或扩展近期工作 | 继续(SendMessageTool) | Worker 有错误上下文 |
| 验证他人代码 | 派发新 Agent(AgentTool) | 全新视角,无实现偏见 |
| 完全无关的任务 | 派发新 Agent(AgentTool) | 无可复用上下文 |
协调者的系统提示约为 370 行(src/src/coordinator/coordinatorMode.ts),明确定义了 Research → Synthesis → Implementation → Verification 四个阶段的工作流程和工具使用规则。
六、记忆与上下文管理
6.1 记忆层次架构
Claude Code 实现了多层次的记忆系统:
scss
┌─────────────────────────────────────────┐
│ 长期记忆 (Long-term Memory) │
│ · CLAUDE.md 文件 (memdir 系统) │
│ · 自定义 Agent 定义 (.claude/agents/) │
│ · Team Memory (团队共享知识) │
├─────────────────────────────────────────┤
│ 会话记忆 (Session Memory) │
│ · SessionMemory 服务(后台子 Agent 维护) │
│ · 自动记录对话中的关键信息到 .md 文件 │
├─────────────────────────────────────────┤
│ 工作记忆 (Working Memory) │
│ · messages[] 数组(LLM 可见) │
│ · ToolUseContext 中的 readFileState 等 │
├─────────────────────────────────────────┤
│ 上下文压缩 (Context Compaction) │
│ · 自动压缩(auto-compact)触发时由子 Agent │
│ 生成摘要,替换旧消息段落 │
└─────────────────────────────────────────┘
源码文件:
src/src/memdir/memdir.ts--- 记忆目录管理src/src/memdir/findRelevantMemories.ts--- 上下文相关记忆检索src/src/services/SessionMemory/sessionMemory.ts--- 会话记忆(后台 Agent 维护)src/src/services/extractMemories/--- 记忆提取服务
6.2 自动上下文压缩(Auto-Compact)
源码文件 :src/src/query.ts(autoCompactTracking 相关逻辑)
当上下文接近模型窗口上限时,系统会触发自动压缩流程:
typescript
// src/src/query.ts - 压缩决策逻辑(概念性)
async function maybeCompact(state: State): Promise<State> {
const contextUsage = calculateContextUsage(state.messages, state.systemPrompt)
const windowLimit = getModelWindowLimit(state.model)
if (contextUsage / windowLimit > 0.85) { // 85% 阈值
// 创建一个压缩子 Agent,输入为即将被压缩的消息
// 子 Agent 输出一个摘要,然后替换原始消息范围
const summary = await runCompactAgent(state.messages, state.toolUseContext)
return {
...state,
messages: replaceWithSummary(state.messages, summary),
autoCompactTracking: { ... } // 记录压缩历史,避免重复压缩
}
}
return state
}
七、Hook 扩展机制
源码文件:
src/src/utils/hooks/execAgentHook.tssrc/src/utils/hooks/execPromptHook.tssrc/src/utils/hooks/execHttpHook.tssrc/src/services/tools/toolHooks.ts
Claude Code 提供了一个强大的 Hook 系统,允许用户在 Agent 运行的各个阶段拦截和干预行为。目前支持三种 Hook 类型:
| Hook 类型 | 执行时机 | 可干预内容 |
|---|---|---|
| PreToolUse | 工具执行前 | 修改输入参数、阻断执行 |
| PostToolUse | 工具执行后 | 记录日志、触发后续 Agent |
| Stop | Agent 轮次结束 | 发送通知、持久化数据 |
Hook 可以由多种机制触发:
typescript
// Hook 触发类型
type HookExecutionType =
| { type: 'command', command: string } // 执行 Shell 命令
| { type: 'agent', prompt: string } // 运行一个 Agent
| { type: 'prompt', template: string } // 渲染提示模板
| { type: 'http', url: string, method: string, body: object } // 发送 HTTP 请求
PreToolUse Hook 的返回值会与权限系统决策合并(resolveHookPermissionDecision),形成一个统一的允许/拒绝/需确认决策。
八、安全与权限体系
源码文件:
src/src/utils/permissions/permissions.ts--- 核心权限引擎src/src/utils/permissions/filesystem.ts--- 文件系统权限规则src/src/tools/BashTool/bashSecurity.ts--- Bash 危险命令检测src/src/utils/bash/bashParser.ts--- Bash AST 解析器(130KB)src/src/hooks/useCanUseTool.tsx--- 交互模式权限决策流程
Claude Code 实现了多层安全防御:
- 工具级权限 (
checkPermissions方法):每个工具自行定义敏感操作的条件 - Bash 命令 AST 分析 :将 Bash 命令解析为 AST,检测危险模式(如
rm -rf /、重定向到系统文件等) - 权限模式(Permission Modes) :
default:询问用户plan:需要明确批准bypass:允许所有auto:由 YOLO 分类器自动决策
- 沙箱执行 :
src/src/utils/sandbox/sandbox-adapter.ts支持在受限环境中执行危险操作
typescript
// src/src/hooks/useCanUseTool.tsx - 权限决策流程(简化)
async function useCanUseTool(toolName, input, context): Promise<PermissionResult> {
const tool = findToolByName(availableTools, toolName)
// 1. 工具自身权限检查
const toolPermission = await tool.checkPermissions(input, context)
if (toolPermission.behavior !== 'allow') return toolPermission
// 2. 全局权限规则检查(filesystem.ts 中的路径规则)
const globalPermission = await checkGlobalPermissionRules(toolName, input)
if (globalPermission.behavior !== 'allow') return globalPermission
// 3. Bash 特殊检测(若为 BashTool)
if (toolName === 'Bash') {
const bashAnalysis = parseBashCommand(input.command)
const dangerLevel = detectDangerousPatterns(bashAnalysis)
if (dangerLevel > context.permissionMode.threshold) {
return { behavior: 'block', reason: 'Dangerous pattern detected' }
}
}
return { behavior: 'allow' }
}
九、Build 系统与特性开关
源码文件:
src/src/tools.ts(feature()调用处)src/src/main.tsx(特性加载处)- 项目根目录
package.json
Claude Code 使用 Bun 作为构建工具,通过 bun:bundle 的 feature() 宏实现编译时特性开关:
typescript
// src/src/tools.ts - 编译时特性开关示例
if (feature('COORDINATOR_MODE')) {
// 只有开启协调者模式编译标志,才包含相关代码
const { CoordinatorMode } = require('./coordinator/coordinatorMode')
}
if (feature('AGENT_TRIGGERS')) {
// 定时任务和远程触发工具
const { CronTool, RemoteTriggerTool } = require('./tools/CronTool')
}
这种设计带来了显著的好处:
- 用户编译的产物只包含其开启的功能代码,体积最小化
- 不同部署环境(Ant 用户 vs 普通用户)可以有不同的功能子集
- 实验性功能(如
KAIROS、VOICE_MODE)可以在不重新编译的情况下通过配置切换
十、QueryEngine:面向 SDK 的高级抽象
源码文件 :src/src/QueryEngine.ts
QueryEngine 是 query() 函数的高级封装,专为 SDK/Headless 模式设计。它将 Agent 的核心能力以类形式暴露:
typescript
// src/src/QueryEngine.ts - 核心 API
export class QueryEngine {
constructor(config: QueryEngineConfig)
// 提交用户消息,返回流式结果
async *submitMessage(
prompt: string | ContentBlockParam[],
options?: { uuid?: string; isMeta?: boolean }
): AsyncGenerator<SDKMessage, void, unknown>
interrupt(): void // 中断当前 Agent
getMessages(): readonly Message[] // 获取消息历史
getReadFileState(): FileStateCache // 获取文件状态
getSessionId(): string // 会话 ID
setModel(model: string): void // 动态切换模型
}
在 SDK 模式下,Agent 的所有能力都可以通过 submitMessage() 调用,Agent 的循环、工具执行、权限处理对外部完全透明。Claude Code 的 /v1/agents 和 /v1/sessions API 底层正是基于 QueryEngine 实现。
十一、整体架构图
scss
┌──────────────────────────────────────────────────────────┐
│ main.tsx │
│ (GrowthBook → Models → Plugins → Skills → Agents → MCP) │
└──────────────────────────┬───────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────┐
│ QueryEngine / query() │
│ ┌──────────────────────────────┐ │
│ │ while(true) Agent Loop │ │
│ │ ① 构建请求 (System+Msgs+Tools) │ │
│ │ ② 调用 API (Streaming) │ │
│ │ ③ 分发事件 │ │
│ │ ├─ text → UI 展示 │ │
│ │ ├─ thinking → 推理展示 │ │
│ │ └─ tool_use → 工具执行器 │ │
│ │ ④ 工具执行管道 │ │
│ │ ├─ PreToolUse Hooks │ │
│ │ ├─ Permission Check │ │
│ │ ├─ tool.call() │ │
│ │ └─ PostToolUse Hooks │ │
│ │ ⑤ Auto-Compact / 后处理 │ │
│ └──────────────────────────────┘ │
└──────────────────────────┬───────────────────────────────┘
│
┌──────────────────┼──────────────────┐
▼ ▼ ▼
┌───────────────┐ ┌──────────────┐ ┌──────────────────┐
│ Tool Pool │ │ AgentTool │ │ CoordinatorMode │
│ (43 built-in │ │ (子Agent递归) │ │ (多Agent编排) │
│ + MCP tools) │ │ │ │ │
│ │ │ ├─ runAgent │ │ Coordinator │
│ Streaming │ │ ├─ ForkAgent │ │ ├─ Worker A │
│ Executor │ │ ├─ Teammate │ │ ├─ Worker B │
│ (并发/串行控制) │ │ └─ RemoteISO │ │ └─ Worker C │
└───────────────┘ └──────────────┘ └──────────────────┘
│ │ │
▼ ▼ ▼
┌──────────────────────────────────────────────────────────┐
│ ToolUseContext (150+ 字段依赖注入) │
│ tools | abortController | readFileState | permissions │
│ agentId | queryTracking | mcpClients | ... │
└──────────────────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────┐
│ Memory System │
│ CLAUDE.md (memdir) → SessionMemory → Auto-Compact │
│ Hooks: PreToolUse | PostToolUse | Stop │
└──────────────────────────────────────────────────────────┘
十二、总结:核心设计哲学
纵观 Claude Code 的 Agent 实现,有几条贯穿始终的设计哲学值得学习:
-
一切皆 Generator :核心循环
query()是AsyncGenerator,每个阶段的事件都可以被 yield 和实时处理,实现了真正的流式交互。 -
依赖注入替代全局状态 :
ToolUseContext统一注入所有上下文信息,工具不需要自行获取依赖,可测试性和可组合性极强。 -
并发安全分类 :通过
isConcurrencySafe标记,Agent 可以一次性请求大量只读操作并高效并行执行,而写操作则保证串行安全。 -
Prompt Cache 优先:无论是系统提示的静态部分缓存,还是工具池的连续前缀排序,还是 Fork Agent 的缓存参数共享,都在最大化利用 Anthropic 的 Prompt Cache 以降低成本和延迟。
-
可恢复的错误处理:Agent 循环永远不会因为一次错误就崩溃------它有一整套恢复链,从压缩重试到 token 上限扩容,确保长任务能够尽可能完成。
-
编译时 vs 运行时特性分离 :使用
feature()宏在编译时实现特性开关,用户产物体积最小化,同时保留了运行时的灵活性。
延伸阅读建议(源码文件路径,供深入研究):
- Agent 核心循环:
src/src/query.ts- 工具框架:
src/src/Tool.ts- 工具执行管道:
src/src/services/tools/toolExecution.ts、src/src/services/tools/toolOrchestration.ts- 并发执行器:
src/src/services/tools/StreamingToolExecutor.ts- 子 Agent 系统:
src/src/tools/AgentTool/AgentTool.tsx、src/src/utils/forkedAgent.ts- 协调者模式:
src/src/coordinator/coordinatorMode.ts- SDK 封装:
src/src/QueryEngine.ts- 权限系统:
src/src/utils/permissions/permissions.ts- Hook 机制:
src/src/services/tools/toolHooks.ts、src/src/utils/hooks/- 记忆系统:
src/src/memdir/、src/src/services/SessionMemory/- 工具注册:
src/src/tools.ts