主循环(所有会话/子 agent 共用)
restored-src/src/query.ts
query() / 内部的 queryLoop:一轮轮调模型、解析 tool use、执行工具、把结果写回消息、直到结束。 这是整个产品里 “agent 行为”的公共引擎。* 代码文件核心就是定义了一个:queryLoop
子Agent类型:
子 agent 类型分三块:内置(代码写死)、自定义(你自己加)、以及不能当subagent_type选的隐式 fork。
按能力划分:
只读型:Explore、Plan、verification
全能力:general-purpose、worker、自定义(默认)
专用型:statusline-setup、claude-code-guide
特殊:fork(隐式)
explore 子agent:
Explore 没有单独的「Explore 引擎」,核心是一份类型定义 + 若干针对Explore的特殊优化,实际执行走通用的 Subagent 管线。
执行流程:
主 agent: Agent({ subagent_type: "Explore", prompt })
↓
AgentTool.tsx → 查找 EXPLORE_AGENT 定义
↓
runAgent.ts → 组装 prompt/工具/上下文 → query() 循环
↓
Glob / Grep / Read / Bash → 通用工具执行搜索
↓
AgentTool.tsx → 返回报告(one-shot,无 resume 提示)
对话流程:
用户输入
↓
主 agent(query 循环)
↓
主 agent 自己决定:
├── 直接用 Read / Grep / Bash … 处理
└── 调用 Agent({ subagent_type: "Explore", prompt: "..." }) → 这时才创建子 agent
没有「用户一说话就后台 spawn Explore」这类机制。子 agent 的创建是一次 tool call,和调用Read一样,由模型在当轮推理里决定是否发起。对话框里的需求先进主 agent;子 agent 是主 agent 认为需要委派时,通过Agent工具显式创建的,不是用户发消息就自动触发。
何时委派:
用户消息
↓
query 主循环(src/query.ts)
↓
模型读 system prompt + Agent 工具描述
↓
模型决定:直接 Read/Grep,还是 tool_call → Agent(...)
↓
若调了 Agent → AgentTool.tsx → runAgent.ts 才真正创建子 agent
决策点 = 模型的 tool choice,不在某段 TypeScript 的if/else里。
AgentTool.tsx的call()只做:权限校验、类型解析、spawn 执行,不负责「该不该委派」。
总结:
Explore 的业务逻辑主要在exploreAgent.ts(prompt + 工具/模型配置);执行在runAgent.ts的通用子 agent 循环里;runAgent.ts和agentToolUtils.ts里有少量 Explore/Plan 专属的上下文与工具过滤优化。若要改 Explore 行为,通常从exploreAgent.ts的getExploreSystemPrompt()和disallowedTools入手。
子Agent与Tool的区别
执行模型区别:
| 普通 Tool | 子 Agent(Agent工具) | |
|---|---|---|
本质 | 单次能力调用 | 派生一个会自己多轮推理、多工具协作的小 agent |
例子 |
|
|
普通 Tool:
主 agent → tool_call(Read) → 读文件 → 返回结果 → 结束
子 Agent:
主 agent → tool_call(Agent) → runAgent() → query() 循环
→ 子 agent 自己调 Read/Grep/Bash…(多轮)
→ 汇总报告 → 返回主 agent
-----------------------------------------------------------------------------------------
普通 tool:一次输入、一次输出。
子 agent:独立 mini 对话,内部可反复调很多 tool。
是否有自己的「大脑」
| 普通 Tool | 子 Agent | |
|---|---|---|
LLM 推理 | 无(纯代码执行) | 有(完整 |
System prompt | 无 | 有(如 Explore 的只读 specialist prompt) |
自主决策 | 无 | 自己决定下一步用哪个 tool |
Read不会「思考」;Explore 会先 Glob 再 Grep 再 Read,路径由子 agent 自己定。
上下文:
| 普通 Tool | 子 Agent | |
|---|---|---|
对话历史 | 不参与 | 有独立消息链(fork 除外会继承主上下文) |
可见用户对话 | 仅本次参数 | 默认看不到(需在 |
上下文成本 | 一次 tool result | 子 agent 多轮 tool 输出;主 agent 通常只收最终摘要 |
工具集:
| 普通 Tool | 子 Agent | |
|---|---|---|
能力 | 固定单一能力 | 可调多种 tool |
限制 | 无 | 按类型限制(如 Explore 禁 Write/Edit) |
子 agent 是「带工具包的 agent」,不是单一能力点
类型与配置:
| 普通 Tool | 子 Agent | |
|---|---|---|
定义位置 |
|
|
可配置性 | 固定 |
|
实例 | 无状态 | 每次 spawn 新 |
调用方式(对主 agent)
两者对主 agent 都是 tool call,但语义不同:
// 普通 tool — 原子操作 Read({ file_path: "src/foo.ts" }) // 子 agent — 委派任务 Agent({ subagent_type: "Explore", description: "搜认证模块", prompt: "在 src/auth/ 找 session 处理逻辑,报告文件路径和调用链" })耗时与并行:
| 普通 Tool | 子 Agent | |
|---|---|---|
延迟 | 通常毫秒~秒级 | 常需多轮 API,秒~分钟 |
并行 | 可多个 tool 并行 | 可一次 spawn 多个子 agent 并行 |
后台 | 一般同步完成 | 支持 |
权限与身份
| 普通 Tool | 子 Agent | |
|---|---|---|
身份追踪 | 无 |
|
权限 | 主 agent 权限上下文 | 可单独 |
续跑 | 不支持 | 异步子 agent 可用 |
何时用哪个?(与代码 prompt 一致)
| 场景 | 更合适 |
|---|---|
已知文件路径,读一下 |
|
搜一个 class/函数名 |
|
2–3 个文件内查找 |
|
大范围探索、多轮搜索 | 子 agent |
复杂多步研究/实现 | 子 agent |
改一行代码 |
|
改完要独立验证 | 子 agent |
架构关系图
主 Agent (query 循环)
├── 普通 Tools(原子)
│ ├── Read / Write / Edit
│ ├── Grep / Glob / Bash
│ └── AskUserQuestion / ...
│
└── Agent Tool(元工具 → 子 agent)
└── runAgent() → 新的 query 循环
└── 子 agent 再调普通 Tools
总结:普通 tool 是主 agent 的「手脚」(单次动作);子 agent 是主 agent 雇的「临时工」(有自己的判断和多轮工具使用),通过Agent这个元工具接入,结果以 tool result 形式回到主 agent。
三层 Prompt 对比
| 类型 | 给谁看 | 作用 | 普通 Tool | 子 Agent |
|---|---|---|---|---|
① 主 agent System prompt | 主 agent | 定义主会话身份、规范 | 共享同一份 | 共享同一份(fork 可继承) |
② Tool description | 主 agent | 教主 agent 如何调用这个工具 | ✅ 有 | ✅ |
③ 子 agent 专属 System prompt | 子 agent 自己的 query 循环 | 定义子 agent 身份、行为、约束 | ❌ 没有 | ✅ 有 |
FileEditTool/prompt.ts、FileReadTool/prompt.ts属于 ② Tool description,不是 ③ 子 agent System prompt。