24年3月斯坦福大学、CMU和伯克利分校的论文“ALTO: An Efficient Network Orchestrator for Compound AI Systems”。
ALTO,一种网络编排器,用于高效地服务复合 AI 系统,例如语言模型流水线。 ALTO 通过利用特定于生成语言模型的优化机会(流式中间输出)来实现高吞吐量和低延迟。 当语言模型逐token生成输出时,ALTO 在可能的情况下提供跨阶段传输中间输出的机会。
跨分布式流水线阶段实例的中间数据传输,有两个新挑战:正确性和负载平衡。 为应对这些挑战,提出一个聚合-觉察路由接口和分布式提示-觉察调度的需求。
复合AI系统前端
许多框架和特定域的编程语言提供了使用高级抽象表达复合AI系统的接口[5,13,18,42]。 给定一些中间转换层,ALTO 可以有效地服务于这些更高级别抽象中表达的流水线。
LM 服务系统
LM 服务系统通过跨请求有效管理 LM 计算使用的内存来优化 LM 推理吞吐量 [12,15,42]。 这些引擎和许多商业 LM API 端点也公开了流式tokens的接口。 与 ALTO 不同,这些系统不处理分布式部署,也不处理流式传输部分输出时出现的相关正确性和负载平衡挑战。 此外,这些系统专门优化语言模型,而不是语言模型与其他工具的组合。
并行化复合 AI 系统
之前的工作已经尝试自动并行化 LM 调用图 [14,22,29]。 虽然 ALTO 也可以同时执行逻辑并行阶段,但这些方法不利用部分输出流或任何正确性和负载平衡问题。
流处理
流查询引擎已在数据库和系统社区中得到了广泛的探索[1,3,4,21,40]。 这些系统执行长时间运行的查询,持续输出结果,同时进行流水线计算并可靠地维护长期状态。 与这些系统一样,ALTO 在节点之间传输部分结果,但它的目标是最大限度地减少相对较短的 AI 流水线计算的端到端延迟。 查询的不同资源消耗(例如,更长或更短的 LM 输出)还需要在 ALTO 中进行细粒度的动态流水线-觉察调度,以保持工作节点的有效利用。
微服务服务系统
许多分布式系统框架能够将逻辑上独立计算阶段的流水线部署为微服务,并使用队列在这些阶段之间通信数据[20, 36]。 有些甚至特别针对机器学习工作负载进行优化[8]。 与 ALTO 相比,这些系统不利用 LM 的自回归生成特性来促进部分输出流。
生成语言模型(LM)通常链接在一起并与其他组件组合成复合AI系统[41]。 复合AI系统应用包括检索增强生成(RAG)[10,11,16,26],结构化提示[2,35,38],聊天机器人验证[6,7,9,32],多步问答[ 13, 39],智体 [19, 24, 28, 37],以及 SQL 查询生成 [17, 33]。
如图显示受 FacTool [7](“FacTool: Factuality Detection in Generative AI – A Tool Augmented Framework for Multi-Task and Multi-Domain Scenarios”)启发的流水线示例,FacTool [7] 是一种复合AI系统,通过检索相关文档作为事实的佐证对聊天机器人进行事实检查。 当用户提出问题时(第 1 阶段),从响应中提取声明(第 2 阶段),并为每个声明生成搜索查询(第 3 阶段)。 检索相关文档的搜索查询来自使用 BM25(第 4 阶段)的知识语料库,并由 ColBERT 重新排序(第 5 阶段和第 6 阶段)。这里阶段 2 中提取的每个声明一旦可用就可以流式传输到阶段 3,而不是等待所有声明发出。 第 3 阶段生成的每个搜索查询都可以类似地流式传输到第 4 阶段和第 5 阶段。
如图是上图中FacTool 启发的流水线提供服务的可视化跟踪。每个阶段的方块代表单个输出单元; 在这些跟踪中,为每个全局请求提取两个声明,并为每个声明生成两个搜索查询。 在左侧,等待所有输出产生,然后再将中间数据发送到下游阶段,而在右侧,一旦可用就在阶段之间传输部分输出。这样在单个请求中跨阶段重叠计算可以减少延迟。
ALTO 通过聚合-觉察路由解决了正确性的挑战,聚合-觉察路由是一个接口,用于表达部分输出必须在哪儿进行聚合。 设计的可能扩展将实现更动态的负载-觉察任务放置,同时仍然满足聚合的硬要求。这是一个分布式提示-觉察调度的设计,在动态分配的提示之间实现负载平衡,无需引入长时排队延误。
聚合-觉察路由。 ALTO 引入一种新接口,可通过聚合-觉察路由在多个输出粒度级别上实现细粒度的路由规范。 通过此接口,ALTO 能够在逻辑上独立部分输出之间实现完全负载平衡,同时仍然强制执行任何指定的聚合规则。
分布式提示-觉察调度。 分布式提示-觉察调度的目标是在一组异构提示之间动态地进行负载平衡,每个提示以不同的频率产生不同数量的部分输出。
首先演示如何在流水线跨阶段部分输出的流式传输,从而显着提高复合AI系统在吞吐量和延迟方面的服务性能。 特别是,用 ALTO 原型评估FacTool 启发的流水线中流式性能。
用round-robin调度在实例之间对运行数据进行负载平衡; 用简单的基于哈希的方法来选择下一个实例来转发传输数据。
根据不同 𝜆 的泊松分布将负载注入系统,测量端到端吞吐量(实现的负载)和延迟(中位数和 P99)。 这里实现的负载是在一个时间间隔(例子中12 分钟)内发送的请求总数/完成所有请求所花费的wall-clock时间。
采用 SQuAD [25] 查询输入数据。用 vLLM [15] 0.26版 进行生成 LM 服务。 对于检索,用检索-和-重新排序流水线 [23],该流水线使用自定义 BM25 [27] 实现作为第一阶段检索器,然后使用 ColBERT [30, 31] 作为重新排序器; BM25 是专门为流式处理而设计的,因为它公开了一个接口来逐token计算文档相关性分数,然后对所有查询tokens进行求和。 在一个具有 8 个 80 GB A100-SXM GPU 和 256 个 AMD EPYC 7763 CPU 的NVIDIA HGX 节点上进行评估。
ALTO 由两部分组成:(1) 用于各个流水线阶段的推理接口,阶段之间有队列,(2) 在这些阶段之间转发数据的中央运行。
ALTO 有三个设计目标:
- 确保任何状态流水线阶段的部分状态正确聚合。 当某些流水线阶段必须聚合时,ALTO 必须确保需要聚合的部分输出发送到该阶段的同一实例。
- 在副本之间均匀地平衡尽可能多的工作。 在尊重聚合约束的同时,ALTO 应尽可能均匀地负载平衡到达中央调度器的工作。
- 在聚合约束允许的情况下,ALTO 应尽可能最大化查询的并行性。 用于指定聚合约束和提示信息的轻量级接口。用于指定聚合约束和提示信息的接口应该是轻量级的,位于队列接口的顶端。
为了实现这些目标,ALTO 以微服务为模型,但在两个方面偏离了现有的微服务编程模型。 ALTO 提供API 来指定聚合约束和提示信息,而不是 RPC。 调度算法使用此信息来确保正确性并改善负载平衡。
如图是ALTO系统图。 ALTO 包括异步排队接口和集中式运行,可在流水线阶段之间数据自动路由。
运行在 ALTO 之上的应用程序通过从输入队列接收数据并通过输出队列发送中间数据来与集中式运行进行通信。
队列。 ALTO 使用队列在流水线阶段之间异步转发数据。 每个队列都是两个可靠的 UNIX 域sockets的包装,尽管可以通过一个网络socket包装扩展到多节点设置。 一个socket从源阶段到中央运行(输出队列),而第二个socket从中央运行到下一个阶段(输入队列)。 每个队列都有一个关联的用户定义Protobuf 来描述数据类型(例如,Token 或 Claim)。 去序列化仅发生在应用程序中; 传输中的数据不会被去序列化,因为它是通过运行转发的。
集中运行。 ALTO 运行接受两个配置文件作为输入:第一个指定各个流水线阶段及其资源需求以及输入和输出队列名称,而第二个指定为每个流水线阶段生成多少个实例。 运行会自动将全局请求 ID 添加到每个请求对应的数据头中。 运行还负责强制执行聚合约束并调度运行中的数据。运行是用 ∼7000 行 Rust语言 实现的。
应用。 在原型实现中,ALTO 阶段是用 Python 编写的。 ALTO运行在启动时将输入和输出队列名称传递给每个阶段,然后开发人员调用ALTO库函数来初始化应用程序端sockets。 应用程序端队列使用 async-io 进行异步执行。 ALTO 支持任意 LM 服务引擎,只要它们可以与 async-io 接口并异步流增量输出。 其与 vLLM [15] 和 SGLang Runtime [42] 集成。