工具调用不一定要串行
很多 Agent 系统的工具调用是 ReAct 式的:模型决定一个动作,工具返回 observation,模型再决定下一步。这个模式灵活,但延迟高、token 多,也容易循环。
LLMCompiler 的问题意识很清楚:很多函数调用其实可以并行。只要知道任务之间的依赖关系,就没必要等一条链走完再执行下一条。
这个想法借用了经典编译器里的优化:识别哪些指令能并行,哪些必须等待前序结果。
三个组件
LLMCompiler 的核心由三个部分组成:
- Function Calling Planner;
- Task Fetching Unit;
- Executor。
Planner 负责把用户问题翻译成任务序列和依赖关系,本质上是一个 DAG。某个任务如果依赖前序结果,就用占位变量表示。
Task Fetching Unit 像指令获取单元:哪个任务依赖满足了,就尽快发给 Executor。它不需要额外 LLM,主要做队列管理和变量替换。
Executor 并行执行工具。执行结果回来后,如果还有下游依赖,就继续触发;如果规划不够,就把中间结果交给 Planner 动态重规划。
它解决 ReWOO 的一个痛点
ReWOO 也是先规划再执行,但它更偏静态蓝图。LLMCompiler 允许动态重规划,所以能处理一些执行图不能一开始完全确定的任务。
这点很重要。真实工具任务往往有两类:一类是“可以提前并行查完”的,比如查多个电影、多个网页、多个商品;另一类是“必须看中间结果再决定”的,比如 Game of 24、交互式购物、排障流程。
LLMCompiler 试图同时覆盖这两类:能静态并行就静态并行,需要重规划就重规划。
工程里的启发
我觉得 LLMCompiler 最大的启发不是具体 benchmark 提升,而是提醒我们:工具调用层应该有调度器。
如果把所有工具调用都交给模型一步步发,系统会很慢,也很难控制成本。更好的方式是让模型负责生成依赖图,让程序负责执行和并行化。
这也更容易做观测:每个任务节点有输入、输出、依赖、耗时、错误。出问题时可以定位是规划错、工具错、变量替换错,还是最终汇总错。
不要忽略 Planner 质量
当然,依赖图错了也会出问题。Planner 如果漏掉依赖,把本该串行的任务并行了,就会拿到错误结果。Planner 如果把无关任务加进图里,也会浪费成本。
所以实现时需要格式约束、示例、验证器,甚至可以对 DAG 做静态检查。比如变量是否已定义,任务是否引用未来结果,工具参数是否符合 schema。
小结
LLMCompiler 把 Agent 工具调用从“模型反应式循环”推进到“计划图 + 调度执行”。
它适合那些有多个工具调用、可并行部分明显、延迟成本敏感的任务。对我来说,这篇论文的核心提醒是:Agent 的智能不全在模型里,也在运行时调度里。