十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

智能体工作流下LLM服务优化:从数据系统视角看查询优化与架构演进

智能体工作流下LLM服务优化:从数据系统视角看查询优化与架构演进 1. 从“单次问答”到“工作流”为什么Agentic Workflows对LLM服务提出了新挑战最近和几个做AI应用落地的朋友聊天大家普遍有个感觉去年还在卷大模型的单次问答效果今年风向已经彻底变了。现在大家讨论的核心不再是“怎么让模型回答得更准一点”而是“怎么让模型能像员工一样自主完成一个包含多步骤、多工具调用的复杂任务”。这就是所谓的“智能体工作流”Agentic Workflows。比如一个数据分析Agent它可能需要先理解你的自然语言指令然后去数据库查询数据接着调用Python脚本进行清洗和计算最后生成一份图文并茂的报告。这整个过程模型不再是终点而是串联起整个数据流和控制流的“大脑”。这种转变直接把压力给到了底层的大模型服务LLM Serving层。传统的LLM服务无论是开源的vLLM、TGI还是云厂商的托管服务其设计核心都是优化“单次、独立”的文本生成请求。它们的评价指标很明确高吞吐量Tokens per Second、低延迟Time to First Token。为了实现这个目标大家使出了浑身解数连续批处理Continuous Batching来动态合并请求、PagedAttention来优化KV Cache内存管理、量化压缩来减少模型体积。这套组合拳在应对聊天、翻译、摘要这类场景时确实效果拔群。但Agentic Workflows一来这套“高并发、低延迟”的单一优化目标就有点不够看了。我最近在尝试将一个简单的数据分析工作流上线就遇到了几个典型问题请求的“长尾依赖”与“状态保持”一个工作流中的多次LLM调用不是独立的。前一步的输出比如“用户想要分析上季度华北区的销售数据”是后一步的输入和上下文。这意味着服务端需要有能力关联起同一个工作流内的多次请求并维护必要的会话状态。而传统服务架构默认每次请求都是无状态的状态管理完全甩给了上游的应用层这导致了大量的序列化/反序列化开销和网络往返。计算模式的异构性工作流中LLM的调用模式非常多样。有时是“规划”Planning需要模型进行长链条的推理生成一个步骤列表这属于计算密集型。有时是“工具调用”Tool Calling模型只需要判断该调用哪个工具并生成参数这属于短平快的决策型。有时是“反思”Reflection需要模型对之前的执行结果进行评估这又可能涉及对历史上下文的深度检索。传统服务用同一套批处理策略和调度优先级去处理所有请求就像用一把锤子去应对螺丝、钉子和木板效率自然低下。与外部数据系统的“高频握手”这是最容易被忽视但恰恰是“Data Systems Perspective”这个视角的核心。Agent工作流本质是一个数据流水线用户指令是输入经过LLM的“加工”理解、规划、决策触发对外部工具数据库、API、文件系统的“数据操作”再将结果返回给LLM进行“二次加工”最终产出。这个过程中LLM服务与数据库、向量库、对象存储等数据系统之间存在大量、细粒度的交互。每一次交互都可能带来网络I/O、数据序列化、权限验证的开销。如果LLM服务和数据系统是两套完全独立的、通过远程网络调用的体系那么整个工作流的延迟将有相当一部分消耗在“握手”上而不是实际的计算上。所以当我们谈论“Efficient LLM Serving for Agentic Workflows”时我们讨论的已经不仅仅是如何更快地生成下一个token。我们讨论的是一个系统性问题如何设计一个服务架构使其能高效地支持具有状态性、异构性且深度依赖外部数据系统的复杂工作流这需要我们将LLM服务不再视为一个孤立的文本生成黑盒而是将其重新定位为整个智能数据流水线的核心协调与执行引擎。接下来我们就从数据系统的角度拆解这里面的核心优化思路。2. 核心瓶颈拆解Agentic Workflows中的“数据墙”与“调度墙”要优化先得找到瓶颈。在Agentic Workflows的上下文中效率瓶颈往往不在模型本身的浮点运算速度上而在于数据移动和任务调度的开销上。我们可以形象地称之为“数据墙”和“调度墙”。2.1 “数据墙”工作流内外的数据搬运成本“数据墙”指的是在LLM服务内部、以及LLM服务与外部数据系统之间频繁数据交换所带来的巨大开销。这主要包括三个层面第一层上下文数据的序列化与反序列化。在一个多步工作流中上一步的产出可能是结构化数据、文本或代码需要作为下一步LLM调用的输入上下文。在典型的微服务架构下这个上下文数据会在工作流引擎、LLM服务、以及可能存在的“上下文管理服务”之间来回传递。每一次传递都涉及JSON或Protobuf的序列化/反序列化。当上下文很长例如包含大量历史对话或检索到的文档时这个开销会变得非常可观。更糟糕的是同一个上下文可能会被反复发送给LLM服务例如在规划、执行、反思多个步骤中造成冗余的数据传输。第二层工具调用时的数据格式转换与I/O等待。当LLM决定调用一个工具比如查询数据库时会发生以下操作LLM服务生成一个结构化的工具调用请求如{“action”: “query_db”, “sql”: “SELECT * FROM sales WHERE region‘north’“}。工作流引擎或专门的“工具执行器”接收到这个请求。执行器需要解析请求建立数据库连接执行SQL。数据库返回结果集可能是JSON、表格数据等。执行器需要将结果集“翻译”成LLM能理解的、连贯的自然语言描述再塞回给LLM进行下一步处理。步骤3和4涉及网络I/O和数据库查询延迟这个等待时间是不可避免的。但步骤1、2、5中存在的多次数据格式转换和网络跳转则是可以优化的“浪费”。特别是步骤5如何将结构化的查询结果高效、无损地转换成高质量的文本提示本身就是一个有开销的操作。第三层向量检索与模型推理之间的数据穿梭。对于需要知识检索的Agent如客服、问答工作流中通常包含一个“检索-增强生成”RAG环节。常见的做法是用户问题 - 向量化 - 向量数据库查询 - 取回Top K相关文档 - 将文档拼接成提示词 - 发送给LLM。这里从向量数据库取回的大量文本数据需要通过网络从向量数据库服务传输到LLM服务。如果这两个服务部署在不同的机器甚至不同的可用区网络延迟和带宽就会成为瓶颈。2.2 “调度墙”异构任务在统一计算资源下的争抢“调度墙”指的是传统LLM服务统一的调度策略无法适应工作流中异构的计算任务导致资源利用不均衡和尾部延迟增高。假设你的LLM服务集群有10张A100 GPU采用一个统一的调度队列和连续批处理策略。现在同时来了三种请求A类规划任务来自一个刚启动的复杂数据分析Agent需要生成一个长达10步的详细计划。输入提示词很长要求输出也长思考深度要求高高temperature多采样单次请求预计耗时5秒。B类工具调用决策来自一个正在执行中的网页自动化Agent它刚刚获取到一个页面的HTML需要判断点击哪个按钮。输入输出都短要求极低延迟100ms内响应以便快速完成动作链。C类反思任务来自一个代码生成Agent它上一步生成的代码执行报错了需要分析错误日志并给出修正建议。需要加载较长的历史上下文之前的对话和代码进行中等长度的推理。在传统的公平队列或FIFO先进先出调度下B类请求很可能被卡在A类长任务后面即使它的计算量很小也必须等待前面的长任务完成批处理推理。这对于追求流畅交互体验的Agent来说是致命的。虽然连续批处理允许提前释放已生成完毕的序列但对于这些超短任务来说等待入批、等待调度本身的时间占比就太高了。更本质的问题是这些异构任务对GPU资源的需求特征是不同的。规划任务A类是计算密集型持续占用算力。工具决策B类是访存密集型因为输入输出短KV Cache小但需要快速加载模型权重进行计算。反思任务C类则可能对显存带宽压力较大因为要加载很长的KV Cache。用同一套调度策略去管理它们就像让短跑运动员、马拉松选手和铅球运动员在同一条赛道上按同一规则比赛显然无法让每种“运动员”都发挥出最佳水平。因此高效的LLM Serving for Agentic Workflows必须考虑对不同类型的任务进行差异化调度和资源隔离。这引出了下一个核心思路查询优化。3. 借鉴数据库思想将“查询优化”引入LLM服务调度标题中的“Data Systems Perspective”和“Query Optimization”这两个关键词给了我极大的启发。这不就是在暗示我们可以向成熟的数据系统尤其是数据库取经吗数据库几十年来核心解决的就是如何高效地执行声明式的查询Query。而Agent工作流中LLM的每一次调用无论是规划、工具调用还是反思都可以被抽象为一种对“知识”或“能力”的“查询”。那么数据库领域的“查询优化”思想就能被巧妙地迁移过来。3.1 将LLM请求视为“查询计划”在数据库中一条SQL语句会被解析器转换成一颗“语法树”然后查询优化器会根据数据统计信息如索引、表大小和成本模型生成一个或多个高效的“物理执行计划”比如是先做Join还是先做Filter用哪个索引。类比到LLM服务一个进入系统的Agent工作流请求可能是一个复杂的用户指令也可以被看作一个“高级查询”。这个查询的“执行计划”就是由LLM自身或一个上层Orchestrator如LangChain, LlamaIndex动态生成的一系列LLM调用步骤。传统的做法是Orchestrator生成这个计划后就简单地按顺序向LLM服务发送HTTP请求等待上一个的响应后再发下一个。这相当于数据库的“嵌套循环”执行效率最低。而引入“查询优化”视角后LLM服务层可以尝试做更多计划预览与重组如果服务层能提前知晓或预测一个工作流的完整步骤比如通过一个轻量级的“规划预览”模型或者从Orchestrator那里拿到一个预估的执行图它就可以像数据库优化器一样考虑是否要重组执行顺序。例如一个工作流中如果有多个独立的工具调用决策B类任务是否可以将它们批量发送给LLM这类似于数据库的“批处理操作”。谓词下推这是一个非常经典的数据库优化技术。把过滤条件谓词尽可能推到靠近数据源的地方执行以减少后续处理的数据量。在Agent场景中“数据源”可以是外部工具。例如一个查询是“帮我找出上个月销售额超过100万且客户满意度低于平均值的订单并分析原因”。一个低效的计划可能是先让LLM生成SQL取出所有上个月订单 - 在应用层过滤 - 再把结果给LLM分析。而一个优化的、“谓词下推”后的计划是让LLM直接生成带过滤条件的SQLWHERE amount 1000000 AND satisfaction (SELECT avg(satisfaction)...) - 数据库直接返回精准的结果集 - LLM分析。这样大幅减少了不必要的数据搬运。这就要求LLM服务或Orchestrator有能力进行这种“下推”的推理。公共子表达式消除在工作流中同样的上下文或中间结果可能被多个步骤使用。优化器可以识别出这些“公共子表达式”只计算一次并将其结果缓存起来供后续步骤复用。例如在RAG流程中对同一个用户问题进行的向量检索其结果可以在规划、生成、润色等多个步骤中共用无需重复检索。3.2 基于代价的调度与资源预留数据库的查询优化器依赖于“代价模型”来选择最优计划。这个代价包括CPU时间、I/O次数、内存使用等。同样LLM服务调度器也可以建立一个简单的代价模型计算代价基于请求的输入长度、预设的输出最大长度、模型参数量、量化精度估算所需的GPU FLOPs。内存代价估算KV Cache的大小与输入长度和生成长度有关。I/O代价估算需要从外部系统获取的数据量。有了代价估算调度器就可以做出更智能的决策对于B类短平快任务识别其低计算、低内存代价的特性将其放入一个高优先级、小批次的快速通道队列。甚至可以为了极致延迟在GPU上常驻一个专门处理此类请求的、轻量化的模型副本比如更小的模型或LoRA适配器实现资源的物理隔离。对于A类长任务任务识别其高计算代价将其放入一个低优先级、大批量的批处理队列。可以利用其容忍较高延迟的特性等待凑够一批类似任务后一起计算最大化GPU利用率吞吐量。动态资源预留对于已知的、多步骤的工作流调度器可以尝试为其预留一部分“专用”资源或者至少保证其不同步骤间的上下文切换开销最小例如尽量让同一个工作流的多个步骤由同一个GPU实例处理避免跨节点传输巨大的KV Cache状态。这听起来很复杂但其实有一些开源系统已经在朝这个方向探索。例如Ray和Flyte这类工作流编排系统其底层的任务调度器就具备基于资源需求的异构调度能力。将LLM服务与这类系统深度集成是构建高效Agent服务栈的一个可行路径。4. 系统架构演进从“服务”到“执行引擎”基于以上的分析一个面向Agentic Workflows优化的LLM服务架构可能不再是我们熟悉的那个独立的、提供/v1/completions接口的HTTP服务器。它会演变成一个更贴近数据系统的、深度集成的执行引擎。我想分享几个可能的设计方向。4.1 模式一LLM服务与工作流引擎的“紧耦合”在这种架构下LLM服务模块不再是独立的而是作为工作流引擎如 Temporal、Airflow、或自定义的Orchestrator的一个原生插件或内置运行时。工作流引擎直接管理LLM调用的生命周期、状态维护和调度。优势状态本地化工作流的上下文状态由引擎统一管理LLM模块可以通过高效的内存共享或进程间通信直接访问彻底消除了序列化和网络传输开销。统一调度引擎可以全局统筹LLM任务、工具调用任务、数据查询任务实现真正的异构工作负载调度。例如它可以在等待数据库查询结果的同时让GPU去处理另一个工作流的LLM任务实现计算和I/O的重叠。细粒度优化引擎可以基于对工作流DAG有向无环图的全局视图实施我们前面提到的“查询优化”如批量处理、操作重排序等。挑战复杂性高需要将LLM服务通常是用Python/C写的深度嵌入到工作流引擎可能是用Go/Java写的中。失去了LLM服务作为独立组件的通用性和可替换性。4.2 模式二智能“数据代理”与LLM服务的协同这是另一种思路不改变LLM服务本身而是在它和外部数据系统之间插入一个智能的“数据代理”层。这个代理负责处理所有与数据相关的繁重工作。它的核心职责包括连接池与协议优化为数据库、API等外部系统维护高效的连接池并可能使用更高效的二进制协议如gRPC替代HTTP。数据格式的智能转换当LLM调用工具时代理接收结构化的调用请求。它不仅能执行调用还能智能地将返回的结构化数据如JSON、表格转换成对LLM最友好的提示文本格式。这个转换逻辑可以预先定义或由一个小模型驱动目标是最大化信息密度、减少无关噪音。结果缓存与复用代理可以缓存频繁查询的数据结果例如针对“上个月销售额”的查询结果在短时间内可以被同一个工作流内的多个步骤复用甚至在不同工作流间共享。谓词下推的执行者代理可以解析LLM生成的不完整或低效的“数据操作指令”如一段有瑕疵的SQL利用自身对数据源的了解将其优化并执行返回精准结果。在这种架构下LLM服务本身仍然专注于它最擅长的“思考”和“生成”而所有“数据搬运工”的脏活累活都由这个专门的代理层高效处理。这很像数据库中的“联邦查询”或“数据虚拟化”层。4.3 对“Helium”的猜想一个潜在的参考方向你提供的热词中出现了“Helium”。经过搜索这很可能指的是一个名为Helium的研究项目或概念浏览器它强调将数据查询与计算更紧密地结合。虽然具体细节不详但这个名字给我的启发是未来的LLM服务引擎或许会像一个“浏览器”对待JavaScript一样对待工作流。浏览器加载一个网页其中的JavaScript代码可以本地、高效地操作DOM文档对象模型。类比过来一个“Helium-like”的LLM执行引擎可以加载一个工作流“脚本”这个脚本中的LLM调用、工具调用都能在一个沙箱化但高性能的运行时环境中直接执行对“数据DOM”即工作流上下文和连接的外部数据源句柄进行低开销的操作。它可能具备以下特征工作流编译将高级的工作流描述如Python DSL编译成一种高效的中间表示进行静态的优化如常量折叠、死代码消除、操作融合。统一内存空间工作流上下文、模型参数、工具返回的数据尽可能存在于一个统一的内存地址空间或高速共享内存中避免拷贝。流式执行与懒加载数据不必等全部准备好才推给LLM可以以流的方式逐步提供LLM的生成也可以流式地触发下游工具调用实现流水线并行。5. 实操建议与当前可落地的优化策略聊了这么多架构设想可能有些遥远。那么对于今天就要部署Agentic Workflows的团队有哪些切实可行的优化策略呢我结合自己的实践总结了几点5.1 策略一实施分层提示词与上下文管理这是对抗“数据墙”最直接有效的手段。不要将整个工作流历史都无脑地塞进每一次LLM调用的上下文。设立“工作内存”与“长期记忆”将上下文分为两层。“工作内存”只保留当前步骤直接相关的、精简的信息如上一步的输出、当前工具调用的参数。“长期记忆”则存储完整的历史但通常不直接输入模型而是通过一个检索动作按需将最相关的片段提取到“工作内存”中。这大大减少了每次请求的令牌数。结构化摘要对于复杂的中间结果如一个大JSON或数据表格在传递给下一步之前先让一个小模型或规则系统生成一个关键信息摘要。例如数据库返回了100行数据不要全塞进去而是先总结出“总计销售额500万最大单笔订单来自客户A金额80万”这样的要点。这本质上是一种“数据压缩”。使用LLM-native的上下文窗口管理工具如果你使用vLLM或TGI充分利用它们对滚动窗口Sliding Window、注意力下沉Attention Sink等技术的支持这些技术能在有限的上下文窗口内更智能地保留关键信息。5.2 策略二构建面向Agent的模型服务网关在现有的LLM服务如vLLM集群前面部署一个自研的智能网关。这个网关负责请求分类与路由根据请求的元数据如来自哪个工作流、预设的max_tokens大小、是否有tool_choice参数等将其分类为“长任务”、“短决策”、“反思”等并打上标签。多队列调度网关后方对接多个LLM服务实例或队列。例如队列A高优队列连接着专门服务max_tokens 100请求的、加载了4-bit量化小模型的vLLM实例。用于工具调用决策。队列B批处理队列连接着用于长文本生成的、开启连续批处理的vLLM实例。用于规划和报告生成。队列C专用队列为某些对延迟敏感的核心业务工作流预留的专用实例。请求批处理与上下文缓存网关可以主动将短时间内收到的、多个独立工作流中的同类短请求如工具决策批量合并成一个大的批处理请求发送给后端提升吞吐。同时它可以维护一个短期的上下文缓存如使用Redis如果同一个工作流的连续请求携带了相同的长上下文网关可以只发送一个上下文ID后端LLM服务从缓存中读取避免重复传输。5.3 策略三工具执行的“本地化”与“批量化”优化与外部数据系统的交互。本地化尽可能将数据密集型工具如向量数据库、关系型数据库与LLM服务部署在同一个物理节点、同一个可用区甚至同一个Pod内K8s环境下。使用Unix Domain Socket或共享内存进行通信彻底消除网络延迟。对于读取频繁的参考数据考虑将其加载到LLM服务进程的内存缓存中。批量化对于工作流中可能并行的、独立的工具调用例如一个分析任务需要同时查询销售额、用户活跃度、库存三个指标不要串行执行。在工作流设计层面就支持并行工具调用。让Orchestrator同时发起三个查询然后等待所有结果返回后再统一交给LLM。这能显著降低整体延迟。工具结果预处理在工具返回原始数据后、交给LLM之前插入一个轻量级的“结果适配器”。这个适配器可以是一组规则模板也可以是一个微调的小模型专门负责将数据库结果、API响应等转换成精炼、格式良好的自然语言描述。这个步骤离线化、批量化处理不占用主LLM推理的等待时间。5.4 策略四监控与可观测性建设没有度量就没有优化。你需要建立针对Agentic Workflows的专门监控体系关键指标工作流端到端延迟从用户发出指令到收到最终结果的耗时。这是最重要的用户体验指标。LLM服务分步延迟拆解看时间主要花在了“规划”、“工具决策”、“生成”哪个环节工具调用延迟每个外部工具DB、API的响应时间。上下文令牌数分布统计每次LLM调用输入上下文长度的分布找到那些异常长的“尾巴”。GPU利用率与队列深度观察不同任务队列的积压情况。链路追踪使用OpenTelemetry等工具为每个工作流请求生成一个唯一的Trace ID贯穿LLM服务、工具调用、数据库查询等所有环节。这样当某个工作流变慢时你能一眼看出瓶颈是在“等数据库”还是“卡在GPU队列里”。从我实际部署的经验来看仅仅实施策略一和策略三就能将一些典型工作流的端到端延迟降低30%-50%。优化之路是永无止境的但核心思想始终不变将LLM服务从孤立的文本生成器重新定义为整个智能数据流水线的核心协调组件用数据系统的思维去设计它的通信、调度和执行模型。这不仅是技术的演进更是我们对“服务”这个概念认知的深化。
返回列表