Claude Code 源码:Agent 工具 — 多 Agent 的路由与定义机制

Claude Code 源码:Agent 工具 --- 多 Agent 的路由与定义机制

导航

术语说明 :queryLoop 是 Claude Code 的核心执行循环,负责处理 LLM 的推理与工具调用闭环。详见 006-query-loop


目录

第一部分:为什么需要多 Agent

  • 核心问题
  • [子 Agent 的价值](#子 Agent 的价值 "#value-proposition")
  • [何时使用 Agent?如何触发?](#何时使用 Agent?如何触发? "#when-and-how-to-trigger")

第二部分:路由机制(核心)

第三部分:Agent 定义结构(核心)

第四部分:实现机制(核心)

第五部分:加载机制

  • [Built-in Agents](#Built-in Agents "#builtin-agents")
  • [Custom Agents](#Custom Agents "#custom-agents")
  • 加载优先级

第六部分:派生流程

  • [派生 Agent 的基本流程](#派生 Agent 的基本流程 "#spawn-flow")
  • [queryTracking 调用链追踪](#queryTracking 调用链追踪 "#query-tracking")

为什么需要多 Agent?

极限场景

用户说"实现用户认证功能,包括前端登录页、后端 API、数据库迁移、单元测试"。

单 Agent 串行执行

makefile 复制代码
主 Agent 的串行流程:
① 实现后端 API(10 分钟)
② 实现前端页面(10 分钟)
③ 编写数据库迁移(5 分钟)
④ 编写单元测试(10 分钟)

总耗时: 35 分钟
上下文污染: 所有文件内容都在主 Agent 的上下文中

多 Agent 并行执行

makefile 复制代码
主 Agent 的并行编排:
① 派生 backend-agent(10 分钟)
② 派生 frontend-agent(10 分钟,同时进行)
③ 派生 test-agent(10 分钟,同时进行)

总耗时: 10 分钟(并行)
上下文隔离: 每个 Agent 只看到相关文件

子 Agent 的价值

问题 子 Agent 的解决方案
上下文限制 每个 Agent 有独立的上下文窗口
任务分治 按领域拆分(前端/后端/测试)
并行执行 多个 Agent 同时工作
专业化 不同 Agent 有不同的工具集和提示词

何时使用 Agent?如何触发?

触发机制:LLM 的工具选择

核心流程

复制代码
用户请求 → LLM 分析任务 → 选择工具 → 调用 AgentTool

LLM 如何知道要用 AgentTool?

核心机制 :LLM 的工具选择是声明式匹配,而非硬编码规则。

less 复制代码
工具描述(What) + 系统提示词(When) = LLM 自主决策

设计哲学

  • 不是"if 用户说探索 then 调用 Explore"(硬编码)
  • 而是"给 LLM 工具说明书,让它自己判断"(声明式)

通过两个关键信息:

1. 工具描述(告诉 LLM 这个工具是干什么的)
typescript 复制代码
AgentTool.description = `
Launch a new agent to handle complex, multi-step tasks.

Agent types:
- Explore: Fast codebase exploration (read-only)
- Plan: Design implementation plans
- general-purpose: Full capabilities

Use for:
- Open-ended questions spanning the codebase
- Tasks requiring specialized expertise
- Parallel work (launch multiple agents concurrently)
`
2. 系统提示词(告诉 LLM 何时应该用)
markdown 复制代码
## When to Use the Agent Tool

✅ Use Agent when:
- Exploring unfamiliar code → Agent (Explore)
- Planning implementation → Agent (Plan)
- Parallel tasks (frontend + backend) → Agent × 2

❌ Don't use Agent when:
- Reading a single file → Use Read
- Simple search → Use Grep
- Direct code edit → Use Edit

何时触发 Agent?

场景 LLM 决策 原因
"读取 auth.ts" 使用 Read 单一文件,不需要 Agent
"探索认证系统实现" 使用 Agent (Explore) 多文件探索,系统提示词明确指导
"设计新功能方案" 使用 Agent (Plan) 规划任务,需要专业 Agent
"实现前后端功能" 使用 Agent × 2(并行) 可并行,系统提示词建议并行
"搜索 'login' 关键词" 使用 Grep 简单搜索,不需要 Agent

触发示例

css 复制代码
用户: "探索这个项目的认证系统"

LLM 分析:
1. 关键词: "探索" → 不是单一文件读取
2. 范围: "认证系统" → 涉及多个文件
3. 匹配工具描述: "Explore agent for codebase exploration"
4. 匹配系统提示词: "Exploring code → Use Agent (Explore)"

LLM 返回:
{
  "name": "Agent",
  "input": {
    "subagent_type": "Explore",
    "prompt": "探索认证系统的实现,找出相关文件和架构"
  }
}

关键设计点

核心问题:如何让 LLM 知道何时使用 AgentTool?

三种可能的实现方案

方案 A:在主 Agent 提示词中硬编码规则

markdown 复制代码
系统提示词:
"当用户说'探索'时,调用 Agent 工具,subagent_type='Explore'
当用户说'设计'时,调用 Agent 工具,subagent_type='Plan'
当用户说'实现前后端'时,并行调用两个 Agent 工具"

问题

  • ❌ 规则固定,无法适应语义变化("了解代码" ≈ "探索",但规则匹配不到)
  • ❌ 添加新 Agent 类型需要修改主提示词
  • ❌ 规则越来越多,提示词膨胀
  • ❌ 无法处理复杂场景("探索并修改" → 应该用哪个 Agent?)

方案 B:工具描述 + 系统提示词指导(Claude Code 采用)

typescript 复制代码
// 工具描述(声明能力)
AgentTool.description = `
Launch agent for complex tasks.
- Explore: codebase exploration (read-only)
- Plan: design implementation plans
Use for: open-ended questions, parallel work
`

// 系统提示词(使用指导)
"Use Agent (Explore) when exploring unfamiliar code
Use Agent (Plan) when planning implementation
Launch multiple agents for parallel tasks"

优势

  • ✅ LLM 理解语义,灵活匹配("了解代码" → 自动识别为探索场景)
  • ✅ 添加新 Agent 只需更新工具描述,主提示词不变
  • ✅ 描述简洁,不会膨胀
  • ✅ LLM 可以根据上下文综合判断

方案 C:只有工具描述,没有系统提示词指导

typescript 复制代码
// 只提供工具描述
AgentTool.description = `Launch a new agent to handle tasks`

问题

  • ❌ 描述太模糊,LLM 不知道何时应该用
  • ❌ LLM 可能过度使用或不使用 Agent
  • ❌ 缺少场景指导,决策不稳定

Claude Code 为什么选择方案 B?
维度 方案 A(硬编码规则) 方案 B(描述+指导)⭐ 方案 C(只有描述)
语义理解 ❌ 只能匹配关键词 ✅ 理解任务意图 ⚠️ 理解但缺少指导
扩展性 ❌ 修改主提示词 ✅ 只更新工具描述 ✅ 只更新工具描述
决策稳定性 ✅ 规则明确 ✅ 指导明确 ❌ 决策不稳定
维护成本 ❌ 规则膨胀 ✅ 描述简洁 ✅ 描述简洁
灵活性 ❌ 固定规则 ✅ 上下文判断 ⚠️ 过于灵活

方案 B 的核心优势

makefile 复制代码
工具描述(What): 告诉 LLM 这个工具能做什么
    +
系统提示词(When): 告诉 LLM 什么场景下应该用
    ↓
平衡了灵活性和稳定性
工具描述 = LLM 的"使用手册"
typescript 复制代码
// ✅ 好的描述(明确用途和场景)
description: `Launch agent for complex tasks. 
Use for codebase exploration, planning, parallel work.`

// ❌ 不好的描述(太模糊)
description: `Agent tool`
系统提示词 = LLM 的"决策指南"
markdown 复制代码
## ✅ 明确的指导
"Codebase exploration → Use Agent (Explore)"
"Parallel tasks → Launch multiple agents"

## ❌ 模糊的指导
"You can use agents if needed"

完整触发流程

markdown 复制代码
① 用户发送请求
   "探索认证系统"

② queryLoop 调用 LLM
   - 传入系统提示词(包含 Agent 使用指导)
   - 传入工具列表(包含 AgentTool 描述)

③ LLM 分析任务
   - 任务类型: 代码探索
   - 复杂度: 多文件
   - 匹配工具: Agent (Explore)

④ LLM 返回工具调用
   { "name": "Agent", "input": {...} }

⑤ queryLoop 执行 AgentTool
   - 路由到 spawnBuiltInAgent('Explore')
   - 过滤工具集(只读工具)
   - 启动子 queryLoop

⑥ 子 Agent 完成任务
   - 返回探索结果

⑦ 主 Agent 继续执行
   - 根据结果决定下一步

小结

触发机制的本质

复制代码
声明式工具选择 = 工具描述(能力声明) + 系统提示词(使用指导) + LLM 推理

三层决策模型

diff 复制代码
第一层:能力匹配
- LLM 读取工具描述
- 判断工具能否完成任务

第二层:场景匹配
- LLM 读取系统提示词
- 判断当前场景是否适合使用

第三层:成本评估
- 单一工具 vs 派生 Agent
- 串行执行 vs 并行执行

何时用 Agent?

  • 多文件探索 → Explore Agent
  • 实现规划 → Plan Agent
  • 并行任务 → 多个 Agent
  • 复杂任务 → general-purpose Agent

如何触发?

  • LLM 根据工具描述系统提示词自动选择
  • 不需要用户显式指定(LLM 自动决策)

不用 Agent 的情况?

  • 单文件操作 → Read/Write/Edit
  • 简单搜索 → Grep/Glob
  • 直接修改 → Edit

AgentTool 的路由机制

核心问题:AgentTool 如何根据参数选择不同的 Agent?

路由决策树

typescript 复制代码
// src/tools/AgentTool/AgentTool.ts(简化)
export const AgentTool = buildTool({
  name: 'Agent',
  
  async call(input, context) {
    const { subagent_type, team_name, prompt } = input
    
    // 💡 路由逻辑
    if (team_name) {
      // ① 团队成员 Agent(异步通信)
      return spawnTeammate(input, context)
    }
    
    if (subagent_type) {
      // ② 检查是否是 Built-in Agent
      const builtInAgent = BUILT_IN_AGENTS[subagent_type]
      if (builtInAgent) {
        return spawnBuiltInAgent(subagent_type, input, context)
      }
      
      // ③ 检查是否是 Custom Agent
      const customAgent = await loadCustomAgent(subagent_type, context)
      if (customAgent) {
        return spawnCustomAgent(customAgent, input, context)
      }
      
      // ④ 未找到指定的 Agent 类型
      throw new Error(`Unknown agent type: ${subagent_type}`)
    }
    
    // ⑤ 默认:派生 general-purpose Agent
    return spawnAgent(input, context)
  }
})

路由流程图

scss 复制代码
Agent 工具调用
    ↓
有 team_name?
    ├─ 是 → spawnTeammate()(团队成员 Agent)
    │
    └─ 否 → 有 subagent_type?
            ├─ 是 → 是 Built-in Agent?
            │       ├─ 是 → spawnBuiltInAgent()
            │       └─ 否 → 是 Custom Agent?
            │               ├─ 是 → spawnCustomAgent()
            │               └─ 否 → 抛出错误
            │
            └─ 否 → spawnAgent()(general-purpose)

参数组合矩阵

team_name subagent_type 路由结果
✅ 有 任意 spawnTeammate() --- 团队成员 Agent
❌ 无 "Explore" spawnBuiltInAgent() --- Built-in Explore Agent
❌ 无 "Plan" spawnBuiltInAgent() --- Built-in Plan Agent
❌ 无 "my-agent" spawnCustomAgent() --- Custom Agent(如果存在)
❌ 无 ❌ 无 spawnAgent() --- general-purpose Agent

关键点team_name 优先级最高,如果指定了团队,subagent_type 会被忽略。

路由函数的职责

函数 职责 同步/异步
spawnTeammate() 创建团队成员 Agent,立即返回 异步(不等待完成)
spawnBuiltInAgent() 启动 Built-in Agent,等待完成 同步(等待完成)
spawnCustomAgent() 启动 Custom Agent,等待完成 同步(等待完成)
spawnAgent() 启动 general-purpose Agent 同步(等待完成)

为什么 spawnTeammate 是异步的?

typescript 复制代码
// spawnTeammate 立即返回
const result = await spawnTeammate(input, context)
// result = { message: "Teammate has been spawned" }
// Agent 在后台运行,通过 SendMessage 通信

// 其他函数等待完成
const result = await spawnBuiltInAgent(type, input, context)
// result = Agent 的完整输出

异步错误处理 :如果子 Agent 报错退出,父 Agent 如何感知?这涉及团队通信机制,详见 010-team-collaboration


Agent 定义结构

核心问题:如何让同一个 queryLoop 表现出不同行为?

三个配置维度

维度 作用 实现方式
工具集 控制 Agent 能调用哪些工具 disallowedTools 过滤
提示词 控制 Agent 的行为和专业性 prompt 注入到系统消息
模型 控制 Agent 使用的 LLM model 参数覆盖

Agent 定义的完整结构

typescript 复制代码
// Agent 定义的类型
interface AgentDefinition {
  name: string              // Agent 名称
  description: string       // Agent 描述
  prompt: string            // 系统提示词
  disallowedTools?: string[] // 禁用的工具列表
  model?: string            // 使用的模型(可选)
}

// 示例:Explore Agent
const ExploreAgent: AgentDefinition = {
  name: 'Explore',
  description: '快速探索代码库的专用 Agent',
  
  // 维度 1:工具集
  disallowedTools: [
    'Agent',        // 不能派生子 Agent
    'Edit',         // 不能修改文件
    'Write',        // 不能创建文件
    'NotebookEdit', // 不能修改 Notebook
  ],
  
  // 维度 2:提示词
  prompt: `你是一个代码探索专家。你的任务是快速探索代码库,找出相关文件和架构模式。

使用 Grep 搜索关键词,使用 Read 理解代码结构,使用 Glob 查找文件。

重点关注:
- 文件组织结构
- 命名约定
- 架构模式
- 依赖关系

不要修改任何文件,只进行只读探索。`,
  
  // 维度 3:模型(可选,默认继承父 Agent)
  // model: 'claude-sonnet-4-6'
}

从定义到运行的流程

javascript 复制代码
① 用户调用 Agent 工具
   {
     "name": "Agent",
     "input": {
       "subagent_type": "Explore",
       "prompt": "探索认证系统"
     }
   }

② AgentTool 路由到 spawnBuiltInAgent()
   - 查找 BUILT_IN_AGENTS['Explore']
   - 获取 Agent 定义

③ 过滤工具列表
   availableTools = context.tools.filter(tool => {
     return !agentDef.disallowedTools.includes(tool.name)
   })
   // 结果:只有 Read, Grep, Glob, Bash 等只读工具

④ 构建消息序列
   messages = [
     { role: 'system', content: agentDef.prompt },  // 专业提示词
     { role: 'user', content: input.prompt }        // 用户任务
   ]

⑤ 选择模型
   model = agentDef.model ?? context.model

⑥ 启动 queryLoop
   context.deps.query({
     messages,
     tools: availableTools,  // 过滤后的工具
     model,                  // 选择的模型
     agentId: uuid(),        // 新的 agentId
   })

⑦ queryLoop 运行
   - LLM 收到系统提示词:"你是一个代码探索专家..."
   - LLM 只能看到 availableTools 中的工具
   - LLM 调用工具(只能调用 Read, Grep, Glob 等)
   - LLM 返回探索结果

⑧ 返回结果给父 Agent

实现机制

维度 1:工具集过滤

实现原理 :在启动 queryLoop 前,过滤掉 disallowedTools 中的工具。

typescript 复制代码
// src/tools/AgentTool/spawnBuiltInAgent.ts(简化)
export async function spawnBuiltInAgent(type, input, context) {
  const agentDef = BUILT_IN_AGENTS[type]
  
  // 💡 关键:过滤工具列表(LLM 视角的最终有效载荷)
  const availableTools = context.tools.filter(tool => {
    return !agentDef.disallowedTools?.includes(tool.name)
  })
  
  // 启动 queryLoop,传入过滤后的工具
  const result = await context.deps.query({
    messages: [...],
    tools: availableTools,  // ← LLM 只能看到和调用这些工具
  })
  
  return result
}

效果

typescript 复制代码
// Explore Agent 的定义
{
  disallowedTools: ['Agent', 'Edit', 'Write', 'NotebookEdit']
}

// 过滤后的工具列表(LLM 视角的最终有效载荷)
availableTools = [
  'Read',      // ✅ 可用
  'Grep',      // ✅ 可用
  'Glob',      // ✅ 可用
  'Bash',      // ✅ 可用
  // 'Edit',   // ❌ 被过滤
  // 'Write',  // ❌ 被过滤
  // 'Agent',  // ❌ 被过滤
]

LLM 的视角

diff 复制代码
当 Explore Agent 的 queryLoop 运行时:
- LLM 收到的工具列表中没有 Edit、Write
- LLM 无法调用这些工具(因为不在可用列表中)
- 即使 LLM 尝试调用,系统也会拒绝

维度 2:提示词注入

实现原理 :将 Agent 的 prompt 作为系统消息注入到 queryLoop。

typescript 复制代码
// src/tools/AgentTool/spawnBuiltInAgent.ts(简化)
export async function spawnBuiltInAgent(type, input, context) {
  const agentDef = BUILT_IN_AGENTS[type]
  
  // 💡 关键:构建系统提示词
  const systemPrompt = agentDef.prompt
  
  // 启动 queryLoop
  const result = await context.deps.query({
    messages: [
      { role: 'system', content: systemPrompt },  // ← Agent 的专业提示词
      { role: 'user', content: input.prompt }     // ← 用户的任务描述
    ],
  })
  
  return result
}

效果对比

typescript 复制代码
// Explore Agent 的提示词
prompt: `你是一个代码探索专家。你的任务是快速探索代码库...`

// LLM 收到的消息序列
[
  { role: 'system', content: '你是一个代码探索专家...' },  // ← 专业身份
  { role: 'user', content: '探索认证系统的实现' }          // ← 具体任务
]

// general-purpose Agent 的提示词
prompt: `你是一个通用的代码助手,可以执行各种任务。`

// LLM 收到的消息序列
[
  { role: 'system', content: '你是一个通用的代码助手...' },  // ← 通用身份
  { role: 'user', content: '探索认证系统的实现' }
]

为什么提示词很重要?

diff 复制代码
同样的任务"探索认证系统":

general-purpose Agent:
- 可能会尝试修改代码
- 可能会深入实现细节
- 可能会偏离探索目标

Explore Agent:
- 专注于只读探索
- 关注架构和模式
- 输出结构化的探索结果

维度 3:模型选择

实现原理:Agent 可以指定使用的模型,覆盖默认模型。

typescript 复制代码
// src/tools/AgentTool/spawnCustomAgent.ts(简化)
export async function spawnCustomAgent(agentDef, input, context) {
  // 💡 关键:使用 Agent 指定的模型(如果有)
  const model = agentDef.model ?? context.model
  
  // 启动 queryLoop
  const result = await context.deps.query({
    messages: [...],
    model,  // ← 使用指定的模型
  })
  
  return result
}

模型选择优先级

markdown 复制代码
1. Agent 定义中的 model 字段(最高优先级)
   ↓
2. 父 Agent 的 model
   ↓
3. 全局默认模型(最低优先级)

示例

typescript 复制代码
// Custom Agent 定义
{
  name: 'frontend-specialist',
  model: 'claude-opus-4-6',  // 💡 指定使用 Opus
}

// 主 Agent 使用 Sonnet
context.model = 'claude-sonnet-4-6'

// 派生 frontend-specialist Agent
{
  "name": "Agent",
  "input": {
    "subagent_type": "frontend-specialist",
    "prompt": "实现登录页面"
  }
}

// 结果:frontend-specialist 使用 Opus,而不是 Sonnet

加载机制

Built-in Agents

Claude Code 预定义了几种常用的 Agent 类型:

typescript 复制代码
// src/tools/AgentTool/builtInAgents.ts(简化)
export const BUILT_IN_AGENTS: Record<string, BuiltInAgentDefinition> = {
  'general-purpose': {
    name: 'general-purpose',
    description: '通用任务执行 Agent,拥有所有工具',
    disallowedTools: [],
    prompt: `你是一个通用的代码助手,可以执行各种任务。`
  },
  
  'Explore': {
    name: 'Explore',
    description: '快速探索代码库的专用 Agent',
    disallowedTools: ['Agent', 'Edit', 'Write', 'NotebookEdit'],
    prompt: `你是一个代码探索专家...`
  },
  
  'Plan': {
    name: 'Plan',
    description: '制定实现计划的专用 Agent',
    disallowedTools: ['Agent', 'Edit', 'Write', 'NotebookEdit'],
    prompt: `你是一个架构设计专家...`
  },
}

Built-in Agents 对比

Agent 类型 工具集 提示词重点 典型用途
general-purpose 所有工具 通用任务执行 默认 Agent
Explore Read, Grep, Glob 代码探索,理解架构 探索陌生代码库
Plan 只读工具 + Write(plan) 制定实现计划 复杂任务的规划

Custom Agents

用户可以在 .claude/agents/ 目录中定义自己的 Agent 类型。

文件格式

markdown 复制代码
<!-- .claude/agents/backend-specialist.md -->
---
name: backend-specialist
description: 专注于后端开发的 Agent
model: claude-sonnet-4-6
disallowedTools:
  - Agent
---

你是一个后端开发专家,专注于:
- API 设计和实现
- 数据库操作
- 性能优化

请遵循项目规范:
- 代码风格:参考 docs/coding-style.md
- API 设计:参考 docs/api-design.md

加载逻辑

typescript 复制代码
// src/tools/AgentTool/loadCustomAgent.ts(简化)
export async function loadCustomAgent(name: string, context) {
  // ① 构建文件路径
  const agentPath = join(getAgentsDirectory(), `${name}.md`)
  
  // ② 检查文件是否存在
  if (!fs.existsSync(agentPath)) {
    return null
  }
  
  // ③ 读取文件内容
  const fileContent = fs.readFileSync(agentPath, 'utf-8')
  
  // ④ 解析 frontmatter
  const { data: frontmatter, content } = matter(fileContent)
  
  // ⑤ 返回 Agent 定义
  return {
    name: frontmatter.name,
    description: frontmatter.description,
    model: frontmatter.model,
    disallowedTools: frontmatter.disallowedTools ?? [],
    content,  // 💡 Markdown 内容作为系统提示词
  }
}

加载优先级

vbnet 复制代码
① 检查 team_name(最高优先级)
   ↓
② 检查 Built-in Agents
   ↓
③ 检查 Custom Agents
   ↓
④ 默认 general-purpose Agent

为什么 Built-in 优先于 Custom?

diff 复制代码
防止用户意外覆盖系统 Agent:
- 如果用户创建了 .claude/agents/Explore.md
- 系统仍然使用 Built-in Explore Agent
- 避免破坏系统行为

派生 Agent 的基本流程

typescript 复制代码
// src/tools/AgentTool/spawnAgent.ts(简化)
export async function spawnAgent(input, context) {
  // ① 生成 agentId
  const agentId = context.deps.uuid()
  
  // ② 构建 queryTracking
  const queryTracking = context.queryTracking
    ? {
        chainId: context.queryTracking.chainId,
        depth: context.queryTracking.depth + 1,
      }
    : {
        chainId: context.deps.uuid(),
        depth: 0,
      }
  
  // ③ 启动 Agent(使用所有工具)
  const result = await context.deps.query({
    messages: [{ role: 'user', content: input.prompt }],
    agentId,
    queryTracking,
    tools: context.tools,  // 💡 所有工具
  })
  
  return result
}

queryTracking 调用链追踪

作用:追踪 Agent 的调用链和深度。

typescript 复制代码
interface QueryTracking {
  chainId: string  // 调用链 ID(同一链上的所有 Agent 共享)
  depth: number    // 调用深度(主 Agent = 0,子 Agent = 1,孙 Agent = 2)
}

示例

ini 复制代码
主 Agent (depth=0, chainId=abc)
  ├─ 子 Agent A (depth=1, chainId=abc)
  │   └─ 孙 Agent A1 (depth=2, chainId=abc)
  └─ 子 Agent B (depth=1, chainId=abc)

用途

  • 日志追踪:通过 chainId 关联同一任务的所有 Agent
  • 深度限制:防止无限递归(如限制 depth < 3
  • 性能监控:统计每个深度的 Agent 数量

深度限制与熔断 :如何防止 Agent 无限递归?Token 预算如何继承?详见 012-agent-lifecycle

并发冲突 :多个 Agent 同时修改同一文件时如何处理?文件锁、状态快照机制详见 011-concurrency


总结

核心要点

  1. 路由机制 :AgentTool 根据 team_namesubagent_type 参数路由到不同的函数
  2. 定义结构:Agent 通过三个维度配置:工具集、提示词、模型
  3. 实现机制
    • 工具集过滤:disallowedTools 过滤工具列表
    • 提示词注入:prompt 作为系统消息
    • 模型选择:model 覆盖默认模型
  4. 加载机制:Built-in Agents 优先于 Custom Agents

设计优势

  • 简单而强大:只需三个配置维度就能创建各种专业化的 Agent
  • 可组合:自由组合工具集、提示词、模型
  • 易于扩展:添加新 Agent 类型不需要修改 queryLoop 核心逻辑

高级应用模式

审计者模式 :如何用高级 Agent 审计低级 Agent 的输出?验证步骤、Schema 校验等高级模式详见 013-agent-patterns

本系列后续文章

  • 008-tool-explore:深入 Explore Agent 的实现细节
  • 009-tool-plan:深入 Plan Agent 的实现细节
  • 010-team-collaboration:团队协作和 SendMessage 机制
  • 011-concurrency:并发控制与状态一致性
  • 012-agent-lifecycle:Agent 生命周期管理
  • 013-agent-patterns:高级 Agent 应用模式

常见问题 FAQ

Q1: Agent 和 Tool 有什么区别?

A: Agent 是 queryLoop 的实例,Tool 是 Agent 可以调用的能力。

diff 复制代码
Tool(工具):
- Read, Write, Edit, Bash 等
- 执行具体操作
- 被 Agent 调用

Agent(代理):
- 运行 queryLoop 的实例
- 可以调用多个 Tool
- 有独立的上下文和工具集

Q2: 为什么 Command 不直接转换为 Tool?

A : 因为 Command 返回的是 prompt,不是操作结果。

diff 复制代码
Tool 的特点:
- 执行操作,返回结果
- 例如:Read 返回文件内容

Command 的特点:
- 返回 prompt 文本
- 例如:commit 返回 "Create a git commit following..."
- 需要 LLM 看到 prompt 后再决定如何执行

SkillTool 是桥梁,负责:

  1. 执行 Command(调用 getPromptForCommand
  2. 将 prompt 注入到对话(通过 newMessages
  3. LLM 看到 prompt 后自己决定调用哪些 Tool

Q3: 如何创建自定义 Agent?

A : 在 .claude/agents/ 目录创建 Markdown 文件:

markdown 复制代码
<!-- .claude/agents/my-agent.md -->
---
name: my-agent
description: 我的自定义 Agent
model: claude-sonnet-4-6
disallowedTools:
  - Agent
  - Edit
---

你是一个专门做代码审查的 Agent。

重点关注:
- 类型安全
- 错误处理
- 测试覆盖率

调用方式:

typescript 复制代码
{
  "name": "Agent",
  "input": {
    "subagent_type": "my-agent",
    "prompt": "审查这段代码"
  }
}

Q4: Built-in Agent 和 Custom Agent 的优先级?

A: Built-in 优先级更高。

diff 复制代码
加载顺序:
① 检查 Built-in Agents(Explore, Plan, general-purpose)
② 检查 Custom Agents(.claude/agents/*.md)

如果同名:
- Built-in 优先
- 防止用户意外覆盖系统 Agent

Q5: Agent 可以无限递归吗?

A: 理论上可以,但有保护机制:

typescript 复制代码
// queryTracking 追踪深度
{
  chainId: 'abc',
  depth: 2  // 当前深度
}

// 系统可以限制最大深度
if (queryTracking.depth >= MAX_DEPTH) {
  throw new Error('Max agent depth exceeded')
}

详细的深度限制和 Token 熔断机制见 012-agent-lifecycle

Q6: 如何调试 Agent 的工具过滤?

A: 在 Agent 定义中打印可用工具:

typescript 复制代码
// spawnBuiltInAgent.ts
const availableTools = context.tools.filter(tool => {
  return !agentDef.disallowedTools?.includes(tool.name)
})

console.log('Available tools:', availableTools.map(t => t.name))
// 输出: ['Read', 'Grep', 'Glob', 'Bash']

或者在 Custom Agent 的 prompt 中要求 LLM 报告:

markdown 复制代码
---
name: debug-agent
---

首先列出你可以使用的所有工具,然后执行任务。

Q7: Agent 之间可以通信吗?

A : 可以,通过 团队模式(Team):

typescript 复制代码
// 创建团队
{
  "name": "Agent",
  "input": {
    "team_name": "my-team",
    "name": "backend-agent",
    "prompt": "实现后端 API"
  }
}

// 另一个成员
{
  "name": "Agent",
  "input": {
    "team_name": "my-team",
    "name": "frontend-agent",
    "prompt": "实现前端页面"
  }
}

// 通过 SendMessage 通信
{
  "name": "SendMessage",
  "input": {
    "to": "frontend-agent",
    "message": "后端 API 已完成"
  }
}

详见 010-team-collaboration


相关文章

源码位置

  • src/tools/AgentTool/AgentTool.ts --- 路由逻辑
  • src/tools/AgentTool/builtInAgents.ts --- Built-in Agents 定义
  • src/tools/AgentTool/loadCustomAgent.ts --- Custom Agents 加载
相关推荐
江南月3 小时前
让智能体学会自我改进:从 0 理解 ReflectionAgent 的迭代优化
前端·人工智能
沸点小助手3 小时前
「 AI 整活大赛,正式开擂 & 最近一次面试被问麻了吗」沸点获奖名单公示|本周互动话题上新🎊
前端·人工智能·后端
网络工程小王3 小时前
【大模型基础部署】(学习笔记)
人工智能·深度学习·机器学习
亦暖筑序3 小时前
手写 Spring AI Agent:让大模型自主规划任务,ReAct 模式全流程拆解
java·人工智能·spring
万里鹏程转瞬至3 小时前
论文简读:Embarrassingly Simple Self-Distillation Improves Code Generation
人工智能·深度学习
空中湖3 小时前
大模型修炼秘籍
人工智能·agi
程序员鱼皮3 小时前
SBTI 爆火后,我做了个程序员版的 CBTI。。已开源 + 附开发过程
ai·程序员·开源·编程·ai编程
别或许3 小时前
4、高数----一元函数微分学的计算
人工智能·算法·机器学习
嵌入式老牛4 小时前
第4课 机器学习的三要素
人工智能·机器学习·优化·模型·学习准则