跳转到内容

Single Agent 模型

Claude Code 的 agent 系统从一个简单的抽象出发:single agent 是一个自包含的单元,拥有自己的 system prompt、tool 集合、模型偏好和行为约束。每个 sub-agent——无论是内置的还是用户自定义的——都是这一模型的实例。

所有 agent 共享一个定义在 src/tools/AgentTool/loadAgentsDir.ts 中的基类型:

// src/tools/AgentTool/loadAgentsDir.ts — BaseAgentDefinition
export type BaseAgentDefinition = {
agentType: string // 唯一标识符(如 "general-purpose"、"Explore")
whenToUse: string // 供父 agent 决定何时派生的描述
tools?: string[] // 允许的 tool(undefined = 全部,['*'] = 全部)
disallowedTools?: string[] // 明确禁用的 tool
skills?: string[] // 预加载的 skill 名称
mcpServers?: AgentMcpServerSpec[]
hooks?: HooksSettings
color?: AgentColorName
model?: string // "inherit" = 继承父级模型,或指定模型 ID
effort?: EffortValue
permissionMode?: PermissionMode
maxTurns?: number
memory?: AgentMemoryScope // 'user' | 'project' | 'local'
isolation?: 'worktree' | 'remote'
background?: boolean
omitClaudeMd?: boolean // 跳过 CLAUDE.md 注入(为只读 agent 节省 token)
// ...
}

三种具体类型继承自此基类型:

classDiagram
    class BaseAgentDefinition {
        +agentType: string
        +whenToUse: string
        +tools?: string[]
        +model?: string
        +memory?: AgentMemoryScope
        +isolation?: string
    }
    class BuiltInAgentDefinition {
        +source: "built-in"
        +getSystemPrompt(params): string
    }
    class CustomAgentDefinition {
        +source: SettingSource
        +getSystemPrompt(): string
        +filename?: string
    }
    class PluginAgentDefinition {
        +source: "plugin"
        +getSystemPrompt(): string
        +plugin: string
    }
    BaseAgentDefinition <|-- BuiltInAgentDefinition
    BaseAgentDefinition <|-- CustomAgentDefinition
    BaseAgentDefinition <|-- PluginAgentDefinition

内置 agent 注册在 src/tools/AgentTool/builtInAgents.ts

src/tools/AgentTool/builtInAgents.ts
export function getBuiltInAgents(): AgentDefinition[] {
if (
isEnvTruthy(process.env.CLAUDE_AGENT_SDK_DISABLE_BUILTIN_AGENTS) &&
getIsNonInteractiveSession()
) {
return [] // SDK 用户可以从空白状态开始
}
if (feature('COORDINATOR_MODE')) {
if (isEnvTruthy(process.env.CLAUDE_CODE_COORDINATOR_MODE)) {
const { getCoordinatorAgents } = require('../../coordinator/workerAgent.js')
return getCoordinatorAgents() // 完全不同的 agent 集合
}
}
const agents: AgentDefinition[] = [
GENERAL_PURPOSE_AGENT,
STATUSLINE_SETUP_AGENT,
]
// 条件性添加...
if (areExplorePlanAgentsEnabled()) {
agents.push(EXPLORE_AGENT, PLAN_AGENT)
}
// ...
return agents
}

六个内置 agent 各司其职:

Agent模型Tool核心特性
General Purpose默认 sub-agent['*'](全部)多步骤任务的主力
Explorehaiku(外部)/ inherit(内部)只读(无 Edit/Write/Agent)快速代码库搜索,omitClaudeMd: true
Planinherit只读(同 Explore)架构规划,omitClaudeMd: true
Verificationinherit只读 + Bash + WebFetch对抗性测试,background: true
Claude Code GuidehaikuGlob/Grep/Read/WebFetch/WebSearch文档查询,permissionMode: 'dontAsk'
Statusline Setupsonnet仅 Read/Edit状态栏配置,color: 'orange'

只读强制执行。 Explore 和 Plan agent 均通过 disallowedTools 实现只读模式,而非通过特殊的”只读”标志:

src/tools/AgentTool/built-in/exploreAgent.ts
export const EXPLORE_AGENT: BuiltInAgentDefinition = {
agentType: 'Explore',
disallowedTools: [
AGENT_TOOL_NAME, // 禁止派生 sub-agent
EXIT_PLAN_MODE_TOOL_NAME,
FILE_EDIT_TOOL_NAME, // 禁止编辑
FILE_WRITE_TOOL_NAME, // 禁止写入
NOTEBOOK_EDIT_TOOL_NAME,
],
omitClaudeMd: true, // 在 3400 万次以上 Explore 派生中节省约 5-15 Gtok/周
// ...
}

通过 omitClaudeMd 优化 token。 只读 agent 不需要 CLAUDE.md 中的提交/PR/lint 规范。omitClaudeMd 标志会将这些内容从 agent 的 userContext 中剥离,在规模化场景下节省可观的开销。

对抗性 prompt。 Verification agent 拥有最复杂的 system prompt(约 130 行),专门用于对抗 LLM 倾向于草草确认结果的问题:

src/tools/AgentTool/built-in/verificationAgent.ts
const VERIFICATION_SYSTEM_PROMPT = `You are a verification specialist.
Your job is not to confirm the implementation works — it's to try to break it.
You have two documented failure patterns. First, verification avoidance:
when faced with a check, you find reasons not to run it...`

自定义 agent 从带有 frontmatter 的 markdown 文件或 JSON 定义中加载。getAgentDefinitionsWithOverrides() 中的加载流水线:

flowchart LR
    A[loadMarkdownFilesForSubdir 'agents'] --> B[parseAgentFromMarkdown]
    C[loadPluginAgents] --> D[Plugin agents]
    E[getBuiltInAgents] --> F[Built-in agents]
    B --> G[All agents list]
    D --> G
    F --> G
    G --> H[getActiveAgentsFromList]
    H --> I[Active agents<br/>deduplicated by priority]

当多个 agent 共享相同的 agentType 时,优先级链决定哪个生效:

// src/tools/AgentTool/loadAgentsDir.ts — getActiveAgentsFromList
const agentGroups = [
builtInAgents, // 最低优先级
pluginAgents,
userAgents, // ~/.claude/agents/
projectAgents, // 仓库中的 .claude/agents/
flagAgents, // feature flag 管理
managedAgents, // 策略/企业管理(最高优先级)
]
const agentMap = new Map<string, AgentDefinition>()
for (const agents of agentGroups) {
for (const agent of agents) {
agentMap.set(agent.agentType, agent) // 后面的组覆盖前面的
}
}

这意味着项目级 agent 定义可以覆盖内置 agent,而 managed/policy agent 可以覆盖一切。

.claude/agents/code-reviewer.md 中的自定义 agent:

---
name: code-reviewer
description: "Reviews code changes for quality and correctness"
tools:
- Read
- Glob
- Grep
- Bash
model: inherit
permissionMode: bypassPermissions
maxTurns: 50
memory: project
---
You are a code review specialist. Review the provided code changes...

frontmatter 经过 Zod 验证(AgentJsonSchema),markdown 正文成为 system prompt。当设置了 memory 时,system prompt 会动态追加 agent 特定的 memory 内容:

getSystemPrompt: () => {
if (isAutoMemoryEnabled() && memory) {
return systemPrompt + '\n\n' + loadAgentMemoryPrompt(agentType, memory)
}
return systemPrompt
}

Agent 可以声明自己的 MCP server 需求:

// MCP server spec 的两种形式
export type AgentMcpServerSpec =
| string // 按名称引用:"slack"
| { [name: string]: McpServerConfig } // 内联:{ "my-server": { command: "..." } }

声明了 requiredMcpServers 的 agent,在对应 server 不可用时会被过滤掉:

export function hasRequiredMcpServers(
agent: AgentDefinition,
availableServers: string[],
): boolean {
return agent.requiredMcpServers.every(pattern =>
availableServers.some(server =>
server.toLowerCase().includes(pattern.toLowerCase()),
),
)
}

Agent tool(src/tools/AgentTool/)是主 agent 派生 sub-agent 的方式。当主 Claude 实例决定使用 sub-agent 时,它会调用 Agent tool,并传入与某个活跃 agent 定义匹配的 subagent_type 参数。该 tool 随后:

  1. activeAgents 中解析 agent 定义
  2. 通过 getSystemPrompt() 构造 system prompt
  3. 选择模型(继承、指定 ID 或默认 sub-agent 模型)
  4. 使用 agent 的 tool 集合和 prompt fork 一个新对话
  5. 将 agent 的最终响应返回给父级

这创建了清晰的父→子关系:每个 agent 在自己的 context 中以自己的约束条件运行,而父级保留对派发和结果解释的完全控制权。