Files
Agent-System-Documents/docs/guides/task-planning-and-execution.md
T
weichen 4ce8155161 Expand guides with worked examples for intents, runs, and squads
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。
2026-10-08 09:33:13 +00:00

20 KiB
Raw Blame History

Agent 的任务规划与执行:架构与调用链

基准:Agent-System-Dev 组合 218fc4b1ba00b0a03b5bb79f292b3eba6c987a58(R0,2026-10-08 锚点核验)。 行号为该提交下的函数入口位置(个别内部区段为约略范围),随代码演进漂移;文件与函数名是稳定锚点。 internal/ 指 modules/backend/internal/;core/ 指 modules/core/; nruntime/ 指 deps/agent-native/runtime/。


1. 一句话结论

系统有两套并存的规划机制:

  1. 默认主线 = LLM 自主规划(ReAct 循环):没有预置 DAG。普通消息由 backend LLMRunner 驱动,进入 deps/agent-native 自研内核的单轮循环 (组装上下文 → 调 LLM → 解析工具调用 → 执行工具 → 回填 → 直到模型不再调工具), 模型可用 update_plan / update_todos 工具自主维护任务列表(右栏 Plan/Todos 面板)。
  2. 可选结构化路径 = WorkflowDef(数据化步骤列表):可由意图绑定启动,也可由模型 调用 run_workflow goal=... 触发"规划子代理生成步骤 → 用户 HITL 确认 → 编译执行" (internal/runtime/workflow_compiled.go:91 planCompiledWorkflow)。工作流的 编译与步进执行在 internal/wfcompile 包,执行时装配到小队引擎上步进 (挂起 → HITL 卡 → Respond;执行态 → Resume),收口带 critic 终判。

执行主体分两层:backend 的 runmgr(Run 生命周期/事件/持久化/策略)+ internal/runtime(各 Runner);真正的智能体循环内核在 deps/agent-native/runtime/loop.go。


2. Run 生命周期与状态机

契约定义在 modules/core/model.go:

  • RunStatus(model.go:166): pending → running → (waiting_hitl ⇄ running) → completed | failed | cancelled | interrupted
  • RunPhase(model.go:178):thinking → acting → responding → finalizing → done
  • RunKind(model.go:158):conversation | subagent | tool; Run 结构体(model.go:188)含 ParentRunID(任务树)、Usage、Error。

状态迁移代码位置(均在 internal/runmgr/runmgr.go):

迁移 代码位置
创建(pending) :1023 startClaimedRun(建 Run + store.CreateRun,internal/store/messages.go:120)
运行 :1055 附近 execute(置 running/thinking)
HITL 挂起/恢复 :449 AskHITL 置 waiting_hitl;:1261 ResolveHITL 恢复 running
终态 :1087 finishRun → internal/store/recovery.go:125 SettleRun(条件 UPDATE + 同事务写权威助手消息树,防并发双终态)→ 发 run.completed/failed
取消 :1222 CancelRun(根 run ctx 取消,子 run 派生自父 ctx 天然级联;并唤醒 HITL 等待)
停机中断/重启对账 :1655 InterruptRunning、启动时 :1689 ReconcileInterrupted
会话并发控制 :980 ClaimConversation(一会话至多一个在途 run,忙返回 409,server.go 错误映射)

3. 端到端调用链(普通消息 → 结果落库)

# 步骤 位置
1 HTTP 入口 postMessage:附件经 ingest.Parse;/ 命令不启 run;意图识别 + route.Decide 三分支 internal/server/server.go:574;路由调用 :656
2 抢会话槽位 + 消息落库(幂等 requestId) server.go:679 → runmgr.go:980;server.go:686 附近 AppendMessageWithRequest
3 启动 run:工作流回合 StartClaimedWorkflowRun(定义深拷贝进 Launch,插件卸载不影响在跑副本);普通回合 StartClaimedConversationRun → startClaimedRun:建 Run 落库 → 注册 runHandle → selectConversationRunner → 附件原件落工作区 → go m.execute(rc, runner) server.go:725,727;runmgr.go:991, 996, 1023-1043;runner 选择 runmgr.go:918
4 LLMRunner.Execute(internal/runtime/llm.go:198)准备阶段:模型路由 ResolveChatModel(internal/runtime/model.go:54,settings models.chat.* + 画像 ModelRoute,密钥经 SecretLookup);@knowledge 显式引用触发 RAG(llm.go:216 附近);system 段 prompts.Service.ResolveSystem(internal/prompts/service.go:290);上下文组装 ctxasm.AssembleInput/FinishAssembly(internal/ctxasm/ctxasm.go:45、finish.go:97,产出 ContextObservation 随 run.completed 下发);工具声明(编排型内置 + 注册表过滤,llm.go:267-315;计划模式过滤 filterPlanDecls llm.go:332)
5 进入内核:l.runDirect(...)(internal/runtime/llm_direct.go:95)把声明包成内核工具注册进 agenttools.NewRegistry、打开转录 journal(<sandbox>/.agentx/transcript.jsonl)、接线 Stop 钩子(交付物门禁 + 验证器)、调 nruntime.Run(...)
6 内核 ReAct 单轮循环 nruntime.Run(deps/agent-native/runtime/loop.go:196,for turn < cfg.MaxTurns 默认 12):① ctx/预算检查 → ② prepareRequest(loop.go:787:转录投影 + 窗口清理 + 记忆注入 + reminders)→ ③ consume 流式消费 LLM 事件(loop.go:492)→ ④ 持久化 assistant → ⑤ 有工具调用:executeTools(loop.go:595,可并行),每个 runOne(loop.go:709)走完整性校验 → gateTool(hooks PreToolUse,ask 决策交宿主 PermissionAsk)→ commitToolIntent(崩溃恢复配对)→ cfg.Tools.Execute → AfterTool,结果按 Role=tool 回填 → continue 下一轮 → ⑥ 无工具调用:ContinueOnLength 续写(loop.go:399)+ follow-up drain + Stop 钩子决定续跑(stopDecision loop.go:645;宿主侧做交付物门禁与验证,最多 3 次续跑)→ settle 结束;轮数耗尽报 max turns exceeded(loop.go:447)
7 工具执行回落宿主:编排型工具在 runner 内消化——squad_orchestrate → squadadapter.Orchestrate(case 在 llm_direct.go:479)、delegate_task → rc 端口 SpawnBackground/SpawnAgent(llm_direct.go:493 起)、update_plan/update_todos → rc.UpdatePlan/UpdateTodos、run_workflow、submit_card/card_*(各 case 依次在 llm_direct.go:471 runTool 内);其余 → rc.ExecuteTool(runmgr.go:740):画像三清单 → policy.Decide(计划模式 deny / ask→HITL 确认卡)→ registry.Execute(internal/tools/registry.go:94)→ 结果截断转工件
8 子代理 run(任务树):spawnSubagent/startChild(runmgr.go:1348/1358,startChild 做深度检查)建 Kind=subagent 子 run(ParentRunID 指父)→ 发 agent.spawn(runmgr.go:1375)→ finishChild(runmgr.go:1401)跑 SubLLMRunner.Execute(internal/runtime/sub_loop.go:31,同样调 nruntime.Run)→ 子转录独立落盘 → 结果截断 32000 字(runmgr.go:1780 capSubagentResult)。后台子代理:spawnBackground(runmgr.go:1475,每会话上限 3);完成后 deliverNotices(runmgr.go:1560)在会话空闲时以 system-reminder 启动新父回合汇报(startNoticeRun,runmgr.go:1616)
9 终态收敛:finishRun(runmgr.go:1087)usage 汇总 → 终态消息树(tool_call/tool_result/thinking/card 部件)→ SettleRun 单事务落库 → submit_card 回填锚点 → 发 run.completed(含 ContextObservation)/run.failed。工件:runCtx.WriteArtifact → store.CreateArtifact → artifact.created 事件 → 文本进检索索引;工件作为 PartArtifactRef 挂进助手消息树

完成判定者 = 内核循环 + 宿主 Stop 钩子组合:模型不再调工具且无 follow-up → Stop 钩子 (交付物门禁说谎检测、可选验证器)决定续跑或放行 → 可选用主模型 composeFinal 重写 最终回复(nruntime/compose.go)→ finishRun 落终态。


4. LLM 调用与流式

  • 不用第三方 SDK,自研 HTTP 客户端 deps/agent-native/runtime/llm/client.go: 默认 OpenAI 兼容 POST {base}/chat/completions + stream:true; Protocol=anthropic 走原生 Messages(anthropic.go,带 cache_control 断点与签名思考块)。
  • Provider 预设:llm/providers.go(anthropic/openai/google/deepseek/minimax/ openrouter/groq/azure)+ models.json 自定义;ParseModelRef 支持 provider/model:thinking。
  • 流式解析:llm/sse.go ParseSSE → emitParsed 产出统一事件 (text_delta / reasoning_delta / tool_call_delta / message_end)。
  • 模型配置链:settings 覆盖链(defaults→system→user→project)+ 画像 ModelRoute (internal/runtime/model.go:30-62);轻量档回落主档(model.go:84); models.chat.fallbacks 故障切换(llm/fallback.go,在 runDirect 内接线); 重试(内核 WithRetry)。
  • 事件到前端:内核事件 → directRun.onEvent(llm_direct.go:278)转 rc.Emit(...) → runmgr.emit(runmgr.go:1217)→ 事件缓冲合并(150ms/64 条,internal/runmgr/events.go:42-43,83) → store.AppendEvents(事务内分配会话内单调 seq,internal/store/messages.go:243) → bus.Publish → SSE GET /api/events(server.go:275,Last-Event-ID 重放,15s 心跳); PG 多实例经 internal/pgbus NOTIFY/LISTEN 扇出。

5. 工具 / 技能 / 提示词体系

工具系统

  • 契约:modules/core/tools.go:16 ToolDesc(JSON Schema 参数、ReadOnly/Edits/Risk 权限声明)、 tools.go:33 HTTPToolSpec 无代码声明式 HTTP 工具。
  • 注册:internal/tools/registry.go:50 Register(后注册覆盖)、:112 RegisterBuiltin (time_now、knowledge_search、write_artifact、quality_review、跨会话 peers、ask_user 等); 另有 fs / exec / search / 声明式 HTTP / run_tool_script(需开关)各文件。
  • 执行策略在 runmgr:ExecuteTool(runmgr.go:740)deny→错误、计划模式 deny、 confirm/ask→HITL 确认卡、执行后超长截断转工件。
  • 结果回填:内核侧作为 Role=tool 消息进转录;UI 侧由 onEvent 聚成 PartToolCall+ PartToolResult 终态落库;下一轮由 ctxasm renderAssistantTurns(internal/ctxasm/ctxasm.go:174 附近) 还原成 provider 原生配对消息。

skills 包 = 内置技能文件:go:embed recipes/**(internal/skills/skills.go:23 附近), 启动 Seed(skills.go:53)落 <data>/skills/,带 manifest 哈希做升级/drift 保护; 供内核的 SKILL.md 加载器与 load_skill 渐进披露工具消费 (deps/agent-native/runtime/skills/skills.go)。

prompts 包 = 提示词模块库:embed library/*.md + DB 用户覆盖链。 ResolveSystem(internal/prompts/service.go:290):base/env 层按画像引用 → task 层全员触发匹配(command/intent/attachment 三类触发)→ 正文点名的 method.* 辅助模块跟随注入 → 占位符填充({{date}}/{{model}}/{{skillsDir}})。 另提供子代理 spec(tools/model/maxTurns,service.go:81 附近;禁止子代理持有派发类工具)、 AgentPrompt、工具描述覆盖。

ctxasm 包 = 上下文组装:AssembleInput(internal/ctxasm/ctxasm.go:45)= sys 段 → 历史窗口(默认 40 条,超出注入抽取式摘要)→ 卡片/工件正文回填 (防"下一轮失忆")→ 当前轮文本 + 附件解析全文(默认 48000 字符截断)+ knowledge 块; FinishAssembly(finish.go:97)追加条件注入;产出 Report(token 估算、裁剪记录、 prefixHash)作为可观测 ContextObservation。记忆注入在内核按请求完成(loop.go prepareRequest 段)。


5.5 主对话模型手上有哪些工具

模型每轮请求能看到的工具分三类(全部在 LLMRunner.Execute 声明阶段组装,llm.go:267-315):

类别 工具名(实测常量/注册名) 来源
编排型(在 runner 内消化,不走通用执行器) update_plan / update_todos(维护右栏计划/待办)、delegate_task(派子代理)、squad_orchestrate(发起小队)、run_workflow(发起工作流)、review_findings、submit_card、card_begin/card_append/card_commit(流式产卡三段式) internal/runtime/llm.go:56-70 常量
内置产品工具 time_now、knowledge_search(项目/插件知识全文检索)、write_artifact(写工件)、quality_review(交付物打分)、ask_user(主动提问=HITL)、跨会话 peers 系列 internal/tools/registry.go:112 RegisterBuiltin
内核工作区工具(经 hostbridge 注入内核) read_file / write_file / edit_file / multi_edit / list_dir / grep / glob / load_skill / run_python / run_command / web_search / tavily_search / fetch_url / delegate_task internal/runtime/hostbridge.go:15-21 kernelToolNames;web_search/tavily_search 仅在配置了搜索密钥时注册

实际可见集 = 以上与画像三清单(allow/deny/confirm,core/profile.go)过滤后的交集; 计划模式下 filterPlanDecls(llm.go:332)会再收窄。


5.6 实例:一个典型回合的机制走查

走查基于上文全部代码锚点;模型输出为示意,机制、工具名与顺序均为代码实测。

用户输入:"把我会话里刚上传的季度数据整理成一份摘要文档,并告诉我三个关键结论。"

  1. 进入回合:postMessage → 意图 fallback(没有装匹配意图)→ route.Decide 判 KindTurn → 抢会话槽位 → startClaimedRun 建 Run{pending} → 选 LLMRunner → go execute()(runmgr.go:1023, 918)。
  2. 上下文组装:ctxasm.AssembleInput(ctxasm.go:45)——system 段(base/env/task 提示词 模块,prompts.ResolveSystem)→ 历史窗口(默认 40 条)→ 当前轮文本 + 附件解析全文 (ingest 已把 xlsx/csv 解成 ParsedDocument,默认 48000 字符截断)→ knowledge 块。
  3. 第 1 轮 LLM:模型看到数据后先调 update_todos(拆 3 个待办)+ read_file(读附件 解析物)。两个工具经内核 runTool 回落宿主执行,结果以 Role=tool 消息回填转录 (loop.go executeTools 段),UI 侧聚成工具过程部件。
  4. 第 2 轮 LLM:模型调 write_artifact(把摘要写成工件)。宿主执行 → artifact.created 事件 → 工件登记进会话。
  5. 第 3 轮 LLM:模型输出三个结论的纯文本(无工具调用)→ 内核判定无工具调用 → follow-up drain → Stop 钩子:宿主做交付物门禁(deps/agent-native/runtime/gates/gates.go:52 ClaimGate)——它抓三类"说谎":① 回复正文出现工具调用标记但本轮没有真实调用; ② 引用了不存在的工件 ID;③ 声称"已生成/已登记文件"但这轮没有产出对应工件。 本例模型确实产出了工件,门禁放行;若模型只写了结论却声称"文件已生成", 门禁拒绝结算并附原因让模型续跑(最多 3 次续跑,loop.go stopDecision + 宿主接线)。
  6. 收口:可选用主模型 composeFinal 重写最终回复 → finishRun(runmgr.go:1087)→ SettleRun 单事务落 run 终态与助手消息树 → 发 run.completed(带 ContextObservation)。

子代理变体:若第 2 轮模型改调 delegate_task {agent:"researcher", task:"分析季度数据"}, 则走 llm_direct.go:493 → runmgr.go:1348 派生 Kind=subagent 子 run(任务树 + agent.spawn 事件)→ SubLLMRunner 用同一内核循环独立跑完 → 结果回填父轮。


6. HITL(人工介入)

  • 契约:modules/core/hitl.go:33-36 四种卡(choice/input/confirm/form)。
  • 挂起:runCtx.AskHITL(runmgr.go:449)存卡 → run 置 waiting_hitl → 发 hitl.request → 收件箱投影 → waitHITL 阻塞等恢复(支持超时)。
  • 恢复:POST /api/hitl/{id}/resolve → runmgr.ResolveHITL(runmgr.go:1261) 三分支:选项回填恢复;自由输入命中其他意图 → 取消挂起 run 并转轨;否则作澄清回答回填。
  • 触发时机:a) 工具确认(画像 confirm 清单 / policy ask,runmgr.go:757 附近与内核 PermissionAsk 端口);b) 工作流缺槽位提问(internal/wfcompile/run.go 槽位补齐段)、 显式 hitl 步骤(internal/wfcompile/host.go:138 doHitl)、动态计划执行前确认 (RunOptions.RequireConfirm,internal/wfcompile/run.go:34);c) ask_user 工具。

7. workflow 体系与"规划器"

  • internal/workflow/registry.go:工作流定义注册表(只依赖 core)。 Registry.Set 整体替换快照、ByIntent 按意图查定义、Launch 产启动副本。
  • 编译执行器在 internal/wfcompile/(Q3 WP1):
    • run.go:39 RunCompiled:缺槽位逐个 HITL input 卡收齐 → compiler.go:76 Compile 编译 WorkflowDef → 装配到小队引擎(squad)步进执行(挂起 → HITL 卡片 → Respond; 执行态 → Resume)→ critic 终判 → outcome 汇总(run.go 文件头注释即此流程)。
    • RunOptions(run.go:27):DynamicLimits(模型生成上限:≤8 步、禁 script)、 RequireConfirm(模型生成工作流执行前强制 HITL 确认;注册的声明式工作流免确认)、 ModelScript(脚本步为模型提供,执行前单独确认)。
  • "先规划任务列表再执行"的 planner 真实存在:internal/runtime/workflow_compiled.go:91 planCompiledWorkflow —— rc.SpawnAgent(workflowPlannerID, "规划", …) 派规划子代理 输出 WorkflowDef JSON("只输出 JSON,不要完成目标本身")→ wfcompile.ParseWorkflowDef 解析校验 → runLaunch 以 DynamicLimits:true, RequireConfirm:true 执行(用户 HITL 确认计划后步进)。另有 registeredWorkflowLaunch(:117,注册定义 + 快照脚本正文)、 modelScriptLaunch(:138,模型脚本,单独确认)。入口 Runner 是 CompiledWorkflowRunner(workflow_compiled.go:30,Execute :39)。

8. deps/agent-native 内核的其他部件

  • runtime/ 是进程内自研内核(不派子进程):loop.go 循环、llm/ 客户端、 tools/ 内核注册表(deferred 延迟暴露 + tool_search)、session/(JSONL 转录树, 可 fork/clone)、session_agent.go(headless AgentSession:steer/follow_up/abort/换模型)、 hooks/、memory/、skills/、promptx/、mcp/、checkpoint/、subagent/、 gates/(验收+守卫)、codeorch/(Python 依序调工具的代码编排)、policy/。
  • rpc/ 是本地 JSONL RPC(一行一命令,双向 pipe),把内核暴露给子进程/外部宿主; 产品后端主路径不走 rpc,直接进程内调 nruntime.Run。
  • adapters/native/backend.go 把内核包成 exec.Backend(exec/backend.go 接口), 供小队成员执行使用(见小队与子 Agent 启动、 小队工作机制);adapters/pitransport/ 是远程 pi runner 的 HTTP/NDJSON 传输适配(产品未用为主)。

9. 关键文件清单

职责 文件
Run/消息/计划/工件契约 modules/core/model.go、events.go、hitl.go、tools.go
Run 生命周期枢纽 modules/backend/internal/runmgr/runmgr.go
事件缓冲与 seq modules/backend/internal/runmgr/events.go
Runner 端口与四实现 internal/runtime/runner.go、llm.go、sub_loop.go、workflow_compiled.go、squad_runner.go
内核桥接(工具/事件/Stop 钩子) internal/runtime/llm_direct.go(runDirect :95、onEvent :278、runTool :471)
模型路由 internal/runtime/model.go
工作流编译执行 internal/wfcompile/run.go(RunCompiled :39)、compiler.go(Compile :76)、host.go(doHitl :138)
工作流入口与 planner internal/runtime/workflow_compiled.go(CompiledWorkflowRunner :30、planCompiledWorkflow :91)
工作流定义注册表 internal/workflow/registry.go
内核 ReAct 循环 deps/agent-native/runtime/loop.go
LLM 客户端/协议/预设 deps/agent-native/runtime/llm/client.go、providers.go、sse.go、anthropic.go
上下文组装 internal/ctxasm/ctxasm.go、finish.go
提示词库 internal/prompts/service.go
技能种子 internal/skills/skills.go
工具注册表 internal/tools/registry.go
run/事件/工件落库 internal/store/messages.go、recovery.go
HTTP 入口与 SSE internal/server/server.go