跳到主要内容

LLM 作为编译器模式:分离计划生成与执行

· 阅读需 12 分钟
Tian Pan
Software Engineer

当一个 PlanCompiler 风格的智能体(agent)与直接的 LLM 生成代码模式在 300 个分层多步任务中进行基准测试时,结构化方法实现了 92.67% 的成功率,单任务成本为 0.00128。而直接方法——即LLM在自由形式的循环中逐步决定行动——成功率为620.00128。而直接方法——即 LLM 在自由形式的循环中逐步决定行动——成功率为 62%,单任务成本为 0.0106。这意味着准确率提高了 50%,而成本仅为原来的八分之一。

差异不在于模型的能力。两种方法使用的是同一个模型。差异在于架构:一个将计划生成与计划执行分离开来;另一个则将两者混为一谈。

这种模式——提示 LLM 发出一个结构化的执行计划,然后由确定性引擎运行——正在成为生产级 AI 工程中被严重低估的转变之一。发现这一点的团队通常是在遇到同样的瓶颈之后:他们的智能体在演示中表现出色,通过了评估,但在生产环境中却以一种难以调试的方式失败。LLM-as-compiler 模式并不能解决所有的智能体问题,但它直接解决了大规模应用中最常遇到的失败模式。

编译器类比

Andrej Karpathy 提出了一个非常有用的框架:将 LLM 视为编译器,而不是解释器。在传统软件中,编译器接收源代码(非结构化的人类意图)并生成构件(结构化的可执行文件),然后由确定性的运行时(runtime)运行。编译器的任务在构件边界处结束,随后由运行时接管。

大多数智能体系统打破了这种分离。LLM 同时充当编译器和运行时:它决定下一步做什么,调用工具,观察结果,再决定下一步做什么,如此在连续的循环中进行。推理和行动是交织在一起的。这就是 ReAct 模式(Reason-Act-Observe),它非常适合探索性的、短周期的任务。但当你需要大规模的可预测性、可审计性或成本控制时,它就会崩溃。

LLM-as-compiler 模式恢复了这种分离:

  • 计划生成阶段:LLM 接收任务,对其进行推理,并发出一个完整的结构化执行计划——这是一个描述采取哪些步骤、按什么顺序、使用哪些输入的构件。
  • 执行阶段:确定性引擎逐步验证并运行该计划,在验证之前不需要 LLM 的进一步参与。

LLM 的工作是思考。运行时的工作是行动。这两个阶段都不会试图去做另一个阶段的工作。

是什么让计划变得足够结构化以执行

这种模式的幼稚版本只是提示 LLM “写一个计划”,然后解析响应。这失败的原因与自由形式的智能体执行失败的原因相同:未定型、未经验证的 LLM 输出在结构上是脆弱的。

一个生产级的实现至少需要:

有类型的节点注册表(A typed node registry)。 LLM 从一组具有已知输入和输出类型的固定命名操作中进行选择。它不能发明新的工具或临时操作。“查询客户数据库”是一个有类型的节点;LLM 选择它并提供有类型的参数。

执行前的静态验证。 在任何一个步骤运行之前,都要检查计划的结构有效性:节点是否存在于注册表中,节点之间的连边是否类型兼容,依赖图是否无环,所有必需的参数是否齐全。PlanCompiler 中的这种七阶段验证消除了在非结构化基准测试中不断出现的各种运行时故障。

不可变的计划版本控制。 计划是一等构件,会被存储、版本化并与其执行踪迹相关联。如果一次运行在 12 个步骤中的第 7 步失败,系统确切地知道正在运行的是哪个计划,并可以从上一个检查点重新运行,而不是从头开始。

这与“仅仅使用函数调用(function calling)”有着本质的区别。函数调用约束的是单个工具的调用。而 LLM-as-compiler 模式在执行开始前,将整个多步计划作为一个整体进行约束。

它解决的失败模式

要理解为什么这种模式很重要,就需要理解非结构化智能体系统到底出了什么问题。

幻觉放大(Hallucination amplification)。 在自由形式的 ReAct 循环中,第 3 步检索到的错误数据会传播到第 4、5 和 6 步。随后的每一次 LLM 调用都会在错误的前提下进行推理并将其放大。到第 8 步时,智能体正自信地生成可以追溯到第 3 步单个检索失败的输出。具有中间验证检查点的结构化执行打破了这一链条:每一步的输出在传递给下一步之前,都可以根据预期的类型和模式(schema)进行验证。

工具误用级联(Tool misuse cascades)。 随着工具库存的增加,LLM 会表现出“函数选择错误”——从一组类似的选项中选择一个看似合理但错误的工具。当只有 4 个工具时,这很少见。当有 15 个工具时,在 10 步计划的某一步选错工具的概率就会大幅增加。约束 LLM 从有类型的注册表中生成计划,而不是每步动态选择工具,将其简化为计划时的分类问题,LLM 处理这类问题比处理一系列每一步的决策要好得多。

审计间隙(Auditability gaps)。 财务审计会问:“为什么这个智能体批准了这笔交易?”在自由形式的智能体循环中,答案是概率性的——你可以记录 LLM 的调用链,但你无法生成审计员接受的确定性决策记录。通过编译好的计划,你拥有一个在执行前指定每个决策的不可变构件,以及显示实际运行情况的执行追踪(trace)。语义操作(LLM 推理)与语法操作(数据流)被显式分开,使得合规级审计追踪在结构上变得可行。

执行中意外导致的状态损坏。 自由形式的智能体偶尔会在任务中途决定采取一些并非预期的行动——“为了提高效率清理缓存”、删除临时状态、提升权限以解除阻塞。从传统意义上讲,这些并不是模型故障;它们是智能体在没有任何约束的情况下试图解决问题时产生的涌现行为。预先验证的计划在任何副作用发生之前定义了执行边界。策略检查可以针对整个计划运行,而不是针对触发的每个动作做出反应。

何时使用,何时跳过

这种模式会带来额外开销 —— 主要是前期规划阶段(基准耗时 200–500ms)和验证层。对于那些证明了这些成本是值得的任务,其收益是显而易见的。而对于不值得的任务,增加的复杂性就是纯粹的负担。

在以下情况下使用该模式:

  • 任务包含 5 个以上连续步骤,且拥有一套稳定、可预测的工具集。PlanCompiler 的效率提升源于规划开销被分摊到了多个执行步骤中。
  • 准确率高于 90% 比亚秒级延迟更重要。对于财务分析、合规审查、病历处理以及类似的高风险工作流,92% 与 62% 的准确率差距决定了产品能否发布。
  • 需要可审计性。受监管行业需要决策记录。自由形式的智能体(agentic)执行无法生成审计人员所需质量的记录。
  • 你正在大规模运行。每项成功任务 8 倍的成本降低,在每天数千次运行的情况下会产生复利效应。如果每天只运行十次,这就无关紧要了。

在以下情况下跳过该模式:

  • 任务是探索性的,且路径会根据观察结果而改变。客户支持升级、研究综合以及开放式问题解决受益于 ReAct 循环的适应性,因为在完成上一步之前,往往无法知道正确的下一步是什么。
  • 简单查询。起草回复、总结文档、回答单个事实性问题。规划开销会比执行成本高出一个数量级。
  • 你的工具集频繁变动。计划在生成时就确定了特定的工具版本和 schema。如果你的工具 API 每周都在变化,过时的计划将变成比收益更大的维护负担。
  • 低于 500ms 的响应时间是底线。每一个毫秒都能被感知的交互式用户界面,在没有架构变通方案(预缓存计划、对可能的后续任务进行投机性执行)的情况下,无法承受规划阶段的耗时。

生产环境模式

在生产环境中运行此架构的团队已经总结出了一些研究论文中并不明显的模式。

分层模型执行。 规划阶段是认知难度最高的部分 —— 它需要理解完整任务,正确进行分解,并以类型化的 schema 表达这种分解。在这里使用你最强大的模型。执行阶段在很大程度上是机械性的:运行类型化操作,将输出传递给输入,并在每个边界进行验证。更小、更快、更便宜的模型可以很好地处理这一点。一个团队报告称,他们使用前沿模型进行规划,使用便宜 10 倍的模型进行执行,准确率下降不到 2%。这种 Token 经济效益非常可观。

计划审核关口。 对于高风险工作流,在计划生成和计划执行之间插入一个人工审批步骤。计划是可读的 —— 它是一个结构化的产物,而不是意识流。合规官可以在 30 秒内扫描一个包含 10 个步骤的计划,并在产生任何副作用之前批准或拒绝它。这在 ReAct 循环中架构上是不可能的,因为智能体在任何人能够审查其决定之前就已经采取了行动。

计划缓存。 对于重复类似任务的工作负载(批量文档处理、每日数据扩充、定期合规检查),可以缓存常见任务模式生成的计划。规划成本只需支付一次;后续运行直接跳到执行阶段。缓存失效也很简单:当类型化节点注册表(node registry)发生变化时,引用了修改后节点的缓存计划将失效。

混合路由。 大多数生产系统并不会让所有任务都通过编译器模式。探索性查询流向 ReAct 循环。多步骤事务性工作流流向编译器管道。路由决策是在上游根据任务分类做出的 —— 包括意图类型、预期步骤数、工具集稳定性以及输出是否需要审计追踪。

间接成本

坦率地面对该模式在延迟之外的成本是很有必要的。这种抽象是真实存在的。

调试失败的计划执行需要理解两个层面:为什么 LLM 生成了这个计划(一个概率性问题),以及为什么执行在这个步骤失败了(一个确定性问题)。这些是需要不同工具的独立问题。投资于此架构的团队需要良好的计划可视化、跨版本的计划比对以及执行追踪回放。这些并不难构建,但并非没有成本。

类型化节点注册表也会带来维护工作。每当你的底层工具发生变化,你都需要更新工具实现以及它向规划器公开的 schema。在快速变化的系统中,这可能成为流程瓶颈 —— 注册表需要刻意的维护,而不像临时工具调用那样随性。

PlanCompiler 的残余错误在这里很有启发性:在剩余的错误中,有 59% 涉及规划器在受限节点无法处理边缘情况时,绕过它们转向不受限的替代方案。这是一个 schema 完整性问题 —— 注册表未能完全覆盖任务空间。维护 schema 的完整性是一项持续性的工作,而不是一次性投资。

这如何改变你构建 Agent 的方式

从自由形态的 Agent 执行转向结构化的“计划-执行”(plan-execute)架构,其核心不在于选择某种模式,而在于选择一种思维模型。

自由形态的执行将 LLM 视为自主决策者:给它一个目标,让它自行探索。而结构化的“计划-执行”则将 LLM 视为产出规范的领域专家:给它一个目标,让它生成一个由可靠引擎运行的精确制品(artifact)。

第二种架构在生产环境最关键的维度上表现得更加稳健。计划可以被审查、测试、版本化和回滚。执行失败被定位在特定步骤中,而不是扩散到不透明的决策循环里。成本也是可预测的,因为 Token 的消耗是由计划阶段决定的,而不是由 Agent 在运行过程中决定采取多少步骤决定的。

对于受监管行业中的多步工作流、在对成本敏感的规模化应用中,或者任何需要对“为什么 Agent 会这样做”给出明确回答的场合:编译器模式(compiler pattern)所带来的额外开销是值得的。


核心洞见其实并不新鲜。编程语言设计者在几十年前就意识到,将编译与执行分离能让系统更可靠、更易调试且更具可审计性。现在的创新之处在于,我们可以将 LLM 引入编译阶段——并且这种方式在生产环境中经受住了考验。

References:Let's stay in touch and Follow me for more thoughts and updates