薄编排器:我们如何让 AI 智能体更可靠——通过给路由器更少的工作

  • 有时,向人工智能代理一次性提供其所需的所有知识并非正确做法。
  • 在 Meta,我们发现,通过将数据流水线中各代理的编排层设计得相对“轻量”——仅负责任务路由和可靠性检查,而由专门的代理承担领域推理——能够显著提升效率与准确性。
  • 我们分享了自身的流程与经验,并说明任何团队如何将其应用于生产环境中的 AI 代理。

我们构建了一个约 1,300 行的编排器,用于将 20 多个工作流分派给 14 个专业化的 AI 代理。它本身不执行任何领域相关的工作。这正是我们的设计初衷。

当我们首次部署 AI 代理以自动化 Meta 推荐系统中的数据列接入流程时——该流程横跨三个代码仓库、三种编程语言,且最多包含六个必须保持同步的流水线阶段——我们像大多数团队一样:构建了一个无所不知的“全能型”代理。

在演示环境中,它运行良好。但在生产环境中,却开始出现“幻觉”现象。

问题的根源并不在于提示词优化或更大的上下文窗口,而在于让核心代理承担更少的工作。我们称这种模式为“轻量编排器模式”:即由一个路由器负责任务的排序与可靠性检查,而将所有领域决策交由专业代理处理。

问题:上下文越多,效果越差

我们的流水线采用“配置即代码”的模式:Python 配置驱动 C++ 代码生成,生成的代码又供给数据处理服务,最终将数据写入分析系统。

接入单个数据列需要协调地修改配置注册表、后端服务以及数据流水线,且每列数据在到达目标之前需经过多达六个阶段。

我们的第一种方案是构建一个单一的 AI 代理,使其内置所有领域知识、配置模式、代码生成规则、流水线路由逻辑、验证要求以及十余种数据源的数据填充模式。

这个代理似乎拥有了所需的一切。而这恰恰是问题所在。

当上下文超过某一阈值后,额外的知识不仅未能提升性能,反而导致性能下降。该代理会混淆不同领域的概念,例如将某个子系统的字段命名规范误用于另一个子系统,或者在从不同数据源填充数据时错误地套用本应适用于另一数据源的代码生成模式。

西奈山医院温德赖希人工智能与人类健康系的一篇预印本指出,对于 80 项任务的批量处理,编排式多代理系统的准确率为 65.3%,而单个代理的准确率则降至 16.6%,同时令牌使用量可减少至原来的 1/65。

作者认为,这一现象源于该设计对任务的严格隔离,从而避免了上下文干扰。而我们遇到的情况则相反:单一代理被自身庞大的知识体系所淹没。

我们也评估过另一种单一代理的方案。在针对每项任务进行手动提示工程的情况下,其成功率可达 70%–80%;若无这种人工干预,成功率则骤降至 10%–20%。

这并非提示工程的问题,而是架构层面的问题。

解决方案:轻量级路由器搭配专业代理

我们将系统拆分为两层:

  1. 一个确定性的编排器,不承担任何领域相关工作。它负责意图分类、收集必要字段、执行可靠性检查,并将任务委派给合适的专业代理。它从不涉及代码层面的推理,从不生成配置,也从不接触代码库。它只是一个路由器。
  2. 十四名专业子代理,每位都是具备独立上下文的完整领域专家。例如,模式管理代理熟悉配置注册表,数据填充代理掌握为十种数据源生成代码的方法,验证代理了解构建系统与质量检查流程。没有一个代理能看清全局。这正是我们的设计亮点,而非缺陷。

编排器对每个请求均遵循固定的七步流程:

  1. 读取相应子代理的指令文件。
  2. 检查目标是否已存在(防止重复)。
  3. 向用户收集必要字段。
  4. 自动推断可获取的信息(如代码仓库类型、现有配置)。
  5. 执行可靠性检查,确认是否存在未解决的警告或待审核事项。
  6. 在完整的领域上下文中将任务委派给相应的子代理。
  7. 处理结果并上报错误,确认任务成功。

其中,步骤 1–5 和步骤 7 均为确定性操作,只有步骤 6 涉及大语言模型(LLM)的推理,且该推理发生在拥有独立领域知识的子代理内部。

我们的实现:工作流模板,而非新代理

一个重要的架构洞见是将“需要做什么”与“如何做”分离。编排器通过工作流模板定义各阶段的顺序——这些模板本质上是确定性状态机,用于约束 LLM 的决策空间:

  • 数据列接入:模式 → 验证 → 数据填充 → 测试
  • 事件接入:模式 → 数据填充 → 验证 → 测试 → 事件处理
  • 流水线迁移:评估 → 规划 → 数据填充 → 验证 → 监控

每个工作流模板均以不同的顺序复用那 14 个子代理。当我们需要支持全新的用例——流水线迁移时,并未新建代理,而是编写了一套新的工作流模板,以不同顺序调度已有代理。

无需新增一行代理代码,即可实现完整的生产级功能。

每个子代理都遵循标准化的结构:

  • 知识来源:运行时需加载哪些领域文件(通常每个文件约数千 tokens)。
  • 前置收集清单:编排器在委派任务前必须收集哪些信息。
  • 分步工作流程:特定领域的执行计划。
  • 发现模式:如何在单体代码库中查找相关的代码模式。
  • 故障排除:常见故障及其对应解决方法的映射关系。

这种统一性意味着,添加一个新的子代理只是模板化的工作,而不是从零开始的工程开发。第15个子代理在结构上与第一个完全相同。

知识文件是在子代理执行时按需加载的,并未嵌入到编排器中。我们维护着25份以上按工作流领域组织的知识文件。当某份知识文件被更新时,下一次会话会自动使用最新版本——无需对编排器进行任何改动。

同样的知识文件服务于我们代理的多个平台实现。

结果

过去,为一列数据准备配置需要人工花费三到四天时间,而使用我们早期的配置驱动系统则大约需要一天。采用轻量级编排器的系统只需不到一小时即可完成。

更宏观的背景是:系统约三分之二的变更无需进行显著的人工编辑。之所以能做到这一点,是因为我们在通用性与深度领域知识之间做出了权衡,这是一项经过深思熟虑的架构选择。

编排器是通用的;子代理则是专业化的。

为何这种方法有效(以及为何重量级编排器行不通)

传统做法是让编排器成为最“聪明”的组件——赋予它所有上下文信息,由它来推理该做什么以及如何去做。这种方法在一定条件下奏效,但一旦超出其能力范围就会失效,尤其是在规模扩大、涉及复杂多步骤工作流以及跨异构子系统的场景下,往往在最需要它的时候反而失灵。

轻量级编排器之所以有效,是因为它将架构边界与计算边界相匹配:

  • 确定性决策保持确定性。“哪个子代理负责处理这个?”是一个路由决策,而非推理任务。不要为此使用大语言模型。
  • 上下文隔离避免交叉污染。用于数据源A的人口代理永远不会看到数据源B的模式,因此不会“幻觉”出错误的结果。
  • 故障被有效遏制。如果某个子代理失败,编排器会重试或升级处理;该失败不会破坏编排器的状态,也不会影响其他子代理的上下文。
  • 系统各层可独立改进。一个更好的模型能同时提升全部14个子代理的性能;知识文件的更新会立即生效;新的工作流模板无需修改代理即可解锁新功能。没有单一组件承担全部负担。

如何将其应用于您的AI代理

这一模式并不局限于数据管道。任何构建生产级AI代理的团队都能从中受益:

  1. 将路由与推理分离。如果您的编排器在做领域决策,说明它承担了过多职责。路由应是确定性的:关键词匹配、意图分类、字段收集。将所有领域推理下沉到独立的子代理中。
  2. 设计结构统一的专业子代理。每个子代理都应具有相同的结构:知识来源、所需输入、执行步骤、错误处理。这样,新增功能就变成了模板化的工作,而非架构变更。
  3. 通过工作流模板而非新建代理来扩展规模。当需要支持新用例时,首先问自己:是否可以通过不同顺序组合现有代理来实现?如果无法在不同工作流间复用代理,说明这些代理与特定用例耦合过紧。
  4. 在运行时加载知识,而非在构建时嵌入。若将知识嵌入编排器,每次更新都必须重新部署;按需加载则更新可立即生效,且适用于所有平台。
  5. 明确划定确定性与概率性的边界。对于每个组件,都要判断:这是路由决策(确定性)还是推理任务(概率性)?编排器应位于一侧,子代理位于另一侧,二者不应混用。

支持轻量级编排器的最强论据来自其替代方案的失效模式。当重量级编排器发生“幻觉”时,错误会蔓延至下游的所有环节:它可能路由到错误的代理、收集错误的字段,或跳过可靠性检查。

而轻量级编排器几乎不存在“幻觉”的空间,因为它的路由和可靠性步骤不依赖大语言模型的推理,而是遵循固定的协议。真正的创造性发生在下游,在那些领域限定、风险最小化且故障可被有效遏制的环境中。

下一步计划

我们正在扩展这套架构,以应对新管道领域中数据列数量的增长。根据我们的组合式理念,这一扩展应当顺利,因为规模化只需增加工作流模板和知识文件,而无需重建代理。

我们也在探索如何利用生产环境中的持续反馈,通过自动化闭环识别故障模式,并针对子代理的知识提出有针对性的改进方案,所有变更均需经人工审核后方可实施。

一个反直觉的启示是:在我们的AI代理系统中,最重要的组件往往是那个承担最少工作的部分。让编排器保持轻量化,让子代理更加专业化,整个系统就会变得更加可靠。

致谢

这项工作是团队协作的成果。参与此项工作的其他人员包括:Mani Bhushan、Rahul Maliakkal、Jae Ha、Chakrapani Kumar、Vivek Tiwari和Amanda Yin。

本文首发于Meta工程博客。

添加评论
点赞收藏
点踩分享查看原文
评论
?
参与讨论