Skip to content
预计 1 分钟右侧目录可快速定位

模型计划如何变成真实执行:ToolExecutor、Planner 与 GraphCompiler ​

前置:Context、Retrieval 和 Tool Catalog 怎样接起来
核心问题:Planner 给出计划后,为什么还需要 GraphCompiler,ToolExecutor 又怎样保证只执行已经验证和授权的动作?

模型返回 shell call,Executor 先 sandbox policy,再运行并保存 exit/log artifact。Planner 生成 nodes/deps,若 cycle validation fail则重新规划,而不是边执行边猜。

Tool Executor ​

最终 Harness 把 ToolExecutor 作为唯一副作用入口,并注入 Registry、PolicyEngine、ExecutionRecordStore 与具体 Runner。Planner/Model 只能产生 ToolCall intent,不能持有 Runner。

🔍 源码对照:内部 Tool Executor 不应依赖 MCP request 类型 ​

完整源码与通用分析见 06-04 Tool Search / Execution Pipeline。这里不重复代码;这里关注内部 contract:Planner / GraphCompiler 只产生内部 ToolCall,ToolExecutor 不应依赖 MCP request 类型。

源码说明

案例仓库展示了 Tool adapter、workflow、subagent runtime,但不一定按我们的 Planner → GraphCompiler → Scheduler 命名拆分。这反而是很好的验证:Shadow Harness 的 GraphCompiler 不是为了模仿某个框架,而是为了把概率性的 StructuredPlan 转成 deterministic graph,并在执行前做 dependency/cycle/capability validation。

工程边界

不能因为 Grok Bot 里找不到同名 GraphCompiler 就认为这个抽象多余;也不能把它的 workflow 文件直接翻译成我们的 DAG model。

Shadow Harness 对照

  • Planner 只产生 semantic intent/plan;GraphCompiler 产生可验证 ExecutableGraph。
  • ToolExecutor 不接受 Planner 任意函数对象,只接受已解析的 ToolBinding。

验证

让 Planner 输出循环依赖、未知 Tool、无权限 Tool 三类计划;必须在 graph compile/validation 阶段失败,不能调度后才发现。

Planner ​

Planner 通过 PlannerPort 接收 task + current observation snapshot,只返回版本化 StructuredPlan。测试环境可以替换成 ScriptedPlanner,而不改 Runtime。

Planner 不写 NodeState、不 claim worker、不执行 Tool;这些属于 Compiler/Scheduler/Executor。

Graph Compiler ​

GraphCompiler 是模型输出与 Runtime 之间的 deterministic seam:把 StructuredPlan 转成内部 ExecutableGraph,分配 stable node identity,并验证 dependency/cycle/capability binding。

compile 失败返回 plan/config error;未经 compile 的结构不能进入 Scheduler。

三个组件怎样接力,而不是互相越权 ​

Planner 收到当前 Context 后提出语义计划:

text
search auth → inspect token logic → patch → test

GraphCompiler 把它变成有稳定 node id 和 dependency 的 Graph,并在执行前做 validation。Scheduler 只消费这个已验证 Graph。运行到 patch 时,ToolExecutor 再负责 schema validation、permission、timeout、真实调用和 ToolResult normalization。

text
Planner          probabilistic intent
   ↓
GraphCompiler    deterministic structure
   ↓
Scheduler        deterministic readiness/admission
   ↓
ToolExecutor     controlled side effect

如果 Planner 直接调用 Python function,权限和 trace 会被绕过;如果 ToolExecutor 决定“下一步应该测试”,它又侵入了 Planner 的语义职责。Shadow Harness 的价值就在于把这些边界做成可以单独测试和替换的组件。

Failure Modes ​

Planner 输出与 Executor Contract 没有编译边界 ​

症状: Planner 直接生成可执行对象,GraphCompiler 只是透传。

为什么危险: 模型输出变化会直接改变执行语义,无法独立验证 DAG/invariant。

处理: Planner 只产 StructuredPlan;Compiler 生成内部 ExecutableGraph;Executor 只接受已验证 graph/node。

如何验证 ​

Case断言
Planner 输出与 Executor Contract 没有编译边界让 ScriptedPlanner 输出悬空依赖或未知 Tool,断言 GraphCompiler 拒绝且 ToolExecutor 调用数为 0。

关联源码 ​

自测 ​

  1. Planner 输出“修改文件后跑测试”,为什么必须经过 GraphCompiler 才能让 Scheduler 执行?
  2. ToolExecutor 应负责真实调用,Planner 应负责意图;如果 Planner 直接调用 Tool,会把哪些边界揉在一起?

Sources ​

AI Engineering · Agent · Harness · Backend Systems