Why: 补充实例让导览可对照实操:意图打分/填槽/多意图裁决给出 intentctl explain 实测轨迹(含样例意图、歧义、优先级 tie-break、 能力目录),任务执行给出工具清单与典型回合走查(含 ClaimGate 三类拦截),小队给出 agent-squad demo 全流程实测与真实工作区 目录树/TASK.md 实拍;并修正事实:默认意图目录为空、插件 overlay 与 registry loader 两种文件形态不同。 Evidence: intentctl explain/catalog 与 agent-squad demo 为 2026-10-08 本地实测输出(命令见各节);锚点仍为 Dev R0 218fc4b1;git diff --check 通过;五篇互链全部可解析。SRC=SELF。 Impact: 仅文档增补(02/03/04/05 四篇),无代码影响。 Refs: Dev 任务分支 feature/architecture-guides。
8.6 KiB
何时启动小队或子 Agent:触发条件与调用链
基准:Agent-System-Dev 组合
218fc4b1ba00b0a03b5bb79f292b3eba6c987a58(R0,2026-10-08 锚点核验)。 行号为该提交下的函数入口位置(个别内部区段为约略范围),随代码演进漂移;文件与函数名是稳定锚点。internal/指modules/backend/internal/。
1. 一句话结论
系统有两条"委派"线,都发生在普通 run 的执行过程中(小队不是独立的一层):
- 子代理(sub-agent):模型在回合中调用
delegate_task工具 → runmgr 派生Kind=subagent的子 run(任务树)。 - 小队(squad):三条触发路径 —— ① 设置
runtime.entry=squad让对话本身 走 SquadRunner;② 模型调用squad_orchestrate工具;③ 演示消息含#squad。 三者最终都汇入deps/agent-squad引擎。成员执行统一走 agent-native 内核 (legacy 的 agent-system 子 run 压缩路径已退役,internal/squadadapter/adapter.go:289-292注释明示;后端缺席时 fail-closed,不静默降级)。
另有第三种"规划委派":run_workflow 触发的规划子代理(workflowPlannerID),
见任务规划与执行第 7 节。
2. 子代理:delegate_task 触发链
触发条件
主对话模型判断某段工作适合独立完成(如长调研、批量整理)时,在 ReAct 循环里发出
delegate_task 工具调用(工具名常量 internal/runtime/llm.go:58)。工具声明与门禁在
internal/runtime/llm.go:267-315(编排型工具随上下文声明;子代理 spec 由 prompts 包提供
tools/model/maxTurns 约束,禁止子代理再持有派发类工具,internal/prompts/service.go)。
调用链
| # | 步骤 | 位置 |
|---|---|---|
| 1 | 内核循环解析出 delegate_task 调用 → runTool 分派 |
internal/runtime/llm_direct.go:471 runTool,case 在 :493 起 |
| 2 | 后台模式:经 rc 端口断言调 SpawnBackground;前台:SpawnAgent |
llm_direct.go:502, 516 附近 |
| 3 | runmgr 派生子 run | internal/runmgr/runmgr.go:1348 spawnSubagent → :1358 startChild(深度检查在此,注释 :1356) |
| 4 | 建 Kind=subagent 子 run,ParentRunID 指向父 run(任务树) |
runmgr.go startChild 内;契约 modules/core/model.go:188 |
| 5 | 发 agent.spawn 事件(前端 AgentTracker 可见) |
runmgr.go:1375 |
| 6 | 独立 ctx 执行(后台模式 detach) | runmgr.go startChild 内 |
| 7 | 子代理执行器 = SubLLMRunner.Execute —— 同样进入 nruntime.Run 内核循环(独立转录、按子代理 spec 收窄工具) |
internal/runtime/sub_loop.go:31 |
| 8 | 完成回填 AgentResultPayload;结果截断 32000 字 |
runmgr.go:1401 finishChild;runmgr.go:1780 capSubagentResult |
后台子代理
delegate_task可请求后台模式 →spawnBackground(runmgr.go:1475), 每会话上限 3 个(runmgr.go常量)。- 后台子代理完成后不直接打扰当前回合,而是进通知队列:
deliverNotices(runmgr.go:1560)在会话空闲时以 system-reminder 消息启动一个新父回合汇报结果 (startNoticeRun,runmgr.go:1616)。 - 取消级联:子 run 的 ctx 派生自父 run,
CancelRun(runmgr.go:1222)取消根 run 即级联取消全部子 run。
3. 小队:三条触发路径
路径 A:squad_orchestrate 工具调用(工具路径)
| # | 步骤 | 位置 |
|---|---|---|
| A1 | 模型在回合中调用 squad_orchestrate goal=... |
工具名常量 internal/runtime/llm.go:62;声明 llm.go:268 附近 |
| A2 | 声明门禁:settings runtime.squad(默认 true)开启才声明;entry 已是 squad 时不再提供,避免套娃 |
internal/runtime/llm.go:467 squadToolEnabled;:266 注释 |
| A3 | runTool 分派 → squadadapter.Orchestrate(rc, dataDir, goalText) |
internal/runtime/llm_direct.go:479 → internal/squadadapter/adapter.go:47 Orchestrate |
| A4 | 之后进入 agent-squad 引擎(规划→调度→质检) | 见小队工作机制 |
路径 B:对话入口模式(entry=squad)
| # | 步骤 | 位置 |
|---|---|---|
| B1 | 灰度开关 runtime.entry=squad(默认 direct) |
internal/settings/settings.go:90 |
| B2 | runmgr 选 Runner:selectConversationRunner 检查 runtime.entry=="squad" → 返回 SquadRunner |
internal/runmgr/runmgr.go:918(注入点 :908 SetSquadRunner,装配 internal/app/app.go:306) |
| B3 | SquadRunner.Execute(internal/runtime/squad_runner.go:26)先做 LLM 分诊:modelRouter.Route(:146,轻量模型输出 JSON `direct |
plan,parseRoute :167)—— direct = 单步 assistant 直通(deps/agent-squad/squad/router.go:55 directAssistantPlan);plan = 进 Leader 委派(router.go:29 applyRoute设metadata["mode"]="leader"`) |
| B4 | plan 模式 → squadadapter.RunEntry → 引擎 leader 模式 |
internal/squadadapter/entry.go:42 RunEntry;deps/agent-squad/squad/engine.go(RunOptions.Mode="leader",Options 注释 engine.go:99-105) |
路径 C:演示/脚本
用户消息含 #squad → MockRunner 走同样 Orchestrate(internal/runtime/mock.go)。
一条"不可达"的路径(设计预留)
意图识别绑定 blueprint 动作可路由到 KindSquad(internal/route/route.go:96-97),
但当前双重不可达:server.go:664 明确注释 SquadReady 保持 false(per-run entry
覆盖未就位);且系统默认意图目录为空(见意图识别 4.5 节),
不装插件就没有意图可命中 blueprint。小队的实际启动走上面 A/B/C 三条路径;意图目录
对小队的现实作用是注入规划者/Leader 提示词的能力目录(deps/agent-squad/adapters/intent/catalog.go)。
4. 装配(启动期)
| 内容 | 位置 |
|---|---|
runmgr 注入三个 runner(LLMRunner / SubLLMRunner / MockRunner),SquadRunner 经 SetSquadRunner |
internal/app/app.go:287-306 |
角色指令来源接提示词库(agent.squad.<kind>) |
app.go:176 → squadadapter.RoleInstructions(adapter.go:303) |
| agent-native 内核选项:模型路由、Tavily 搜索、解释器、MCP、技能根、Subagent 桥接、PermissionAsk、检查点 | app.go:196 squadadapter.AgentNativeOptions |
小队后端解析器:只注册 "agent-native" 内核工厂(legacy "agent-system" SpawnSubagent 压缩路径已退役删除;工厂缺席解析 fail-closed) |
internal/squadadapter/adapter.go:292 BuildBackends(退役注释 :289-291);entry.go:103 DefaultBackend="agent-native" |
| 内核工厂注册 | deps/agent-squad/adapters/native/register.go:61 RegisterFull |
5. 两条线的对比小结
| 子代理 delegate_task | 小队 squad | |
|---|---|---|
| 触发者 | 主对话模型 | 设置开关 / 主对话模型 / 演示脚本 |
| 执行单位 | 一个子 run(Kind=subagent) |
一组角色化步骤(每步一个 agent-native 内核 agent) |
| 编排者 | 主对话(单层委派,子代理不可再委派) | agent-squad 引擎(DAG 调度 / Leader 循环) |
| 并发 | 后台最多 3/会话 | 无写集冲突的步骤可并行 |
| 深度 | 1 层(startChild 深度检查,runmgr.go:1356-1358;子代理 spec 禁派发工具) |
成员内核里的 delegate_task 经 SubagentFactory(adapter.go:234)桥回产品 SpawnSubagent,深度恒为 1,子 run 不再嵌套小队 |
| 汇总 | AgentResultPayload 回父 run |
交付物聚合 output.md → 主 run 工件(见小队工作机制) |
6. 关键文件清单
| 职责 | 文件 |
|---|---|
| delegate_task 分派 | internal/runtime/llm_direct.go:493 起 |
| 子 run 派生与任务树 | internal/runmgr/runmgr.go:1348-1475、1560-1616 |
| 子代理执行器 | internal/runtime/sub_loop.go |
| 工具声明与门禁 | internal/runtime/llm.go:267-315, 466-467 |
| squad_orchestrate 分派 | internal/runtime/llm_direct.go:479 |
| 小队适配器(工具路径 + 后端组装 + Subagent 桥接) | internal/squadadapter/adapter.go(Orchestrate :47、SubagentFactory :234、BuildBackends :292、builtinRoles :306) |
| 小队适配器(入口路径) | internal/squadadapter/entry.go(RunEntry :42、kernelRoles :177) |
| 对话入口 Runner + LLM 分诊 | internal/runtime/squad_runner.go(Execute :26、Route :146) |
| Runner 选择 | internal/runmgr/runmgr.go:918 |
| 灰度开关 | internal/settings/settings.go:90 |
| 装配 | internal/app/app.go:176, 196, 287-306 |