图引擎在智能体开发场景的应用实践
导读
随着 AGI 理论的不断突破,智能体已经成为 LLM 在企业落地的最重要的形式之一。一个完备的智能体必须能实现:感知、推理、计划、执行等一套完整的功能,从工程的角度来看 workflow 特别适合这种复杂任务的分析、拆解、重组、执行, 再结合 CoT 技术, 实现 LLM 和业务功能完美契合的智能体应用。本文尝试用成熟的图引擎技术驱动 workflow 探索更多样性的拓展 agent 能力的方法,以更好应对各类业务场景。
01 简介
1.1 什么是智能体
以大模型(LLM)为核心, 具备以下特性的智能化系统:
交互性: 通过文字,语音,图像等多种交互方式来理解用户的持续性需求 (感知);
适应性: 感知环境的变化持续进化,以更好地完成任务和适应复杂环境 (记忆);
自主性: 能够自主学习,主动思考和决策 (推理);


1.2 业务形态、流程
一个智能体生态平台,用户可以在上面体验功能各异的智能体 app,同时也能让用户将自己的优秀想法以极低的成本(通过快速组装已有的插件、workflow、知识库、记忆) 快速实现成新的 agent。



系统特色:
流程编排能力:支持可视化的数据流加工,通过编辑各个处理节点将原始 input 加工成 output;
功能复用能力:众多的 agent 库、插件库都可直接复用到自己的智能体里, 可插拔、替换;
低代码能力:无需大量写代码,直接通过拖拽元素就能拼装出想要的功能。


1.3 业务场景的需求难点
1.3.1 能自由组装流程实现人机无缝衔接、数据解耦
能将人的需求表达和 agent 思考结果的进行完美串联融合,发挥各自优点;
除 context 外更多样性的数据传递方式,更好满足 workflow、cot 等流程编排的场景;
细粒度控制数据传递、适配方式,满足特定场景的灵活性和性能的平衡需求。
1.3.2 能更精细规划路径、简化流程设计
支持多种路径控制能力,满足多样性的静态化任务编排;
支持在 workflow 内部动态编排新的子 flow, 满足动态化的场景。
1.3.3 能对流程进行统一的控制、干预
流程运行过程中当出现超时、异常等非预期情况需要框架能提供快速干预、退出机制;
摆脱对 executor(执行器的依赖),更低成本支持大量功能异构的流程。
1.3.4 能进行简单的功能注入
支持在模型前后、工具调用前后等地方注入策略逻辑和观测代码,避免对大量节点进行浸入式改造;
支持流程编排时给节点初始化赋值,降低数据传递的成本;
支持任意节点信息的流式输出能力,满足长流程中阶段性结果的 sse 输出需求。
1.3.5 能支持缺少代码能力的使用场景
将用户生或者 LLM 产生的 cot 转化成具体流程配置;
将流程配置转换成可运行的代码。
1.4 为什么自研图引擎
1.4.1 常用智能体开发框架简介
LangChain 框架:一个开发智能体的框架,定义了 prompts, index, memory, agents, tools, outputParser 等一系列功能抽象,通过 chains 将各个功能串联成应用。
开发模式:
Chains: 规划静态任务, 很多抽象都实现了 chains 的接口,规划好路径就能让各功能有序执行
AgentExecutor: 执行动态任务,某些场景无法预知执行路径,需要不同的输入走不同的分支,因此引入代理人(AgentExecutor), 通过多轮循环推理产生最终结果
总结:多轮学习和推理是自主 ai 系统的基本的能力, Chains 不具备循环”能力, AgentExecutor 多轮调度是一个不透明度黑盒。


LangGraph:基于 LangChain 基础上演化的框架,引入条件边,赋予用户对循环的控制能力。
开发模式:用透明化的有向状态图打破 LangChain 动态任务的循环黑盒 (AgentExecutor)


已有框架比较注重系统的自主性,对业务执行路径的编排能力较弱。
1.4.2 业务需求的挑战
强化的路径控制能力:既能满足 llm 的多轮循环特性, 又能结合 cot 模式的功能编排;
传统功能的结合能力:模型存在知识能力边界,业务需要结合之前传统功能来满足多样性、个性化的需求, 在数据的校验、传递、并发、同步,流程控制等这些贯穿整个业务随处可见的基建功能都需要支持。
这些都不是已有智能体开发框架本身所擅长的,从下层视角看需要提供一个更通用、更精细化控制能力的流程驱动框架增强以下特性来满足业务需求。
02 用 seda 图引擎驱动 workflow 的模式开发智能体
对于以上共性需求我们引入图引擎驱动 workflow 的开发模式:将任务拆解成独立的功能节点,不仅可以包含 LLM, prompts, memory, tools, 等智能体(ai)元素还融入了 分支、循环、条件、多路复用、数据传递等传统应用所擅长的路径编排、数据转发、超时控制、错误处理等方面的功能,为智能体应用提供一个更强大、稳定、便于解耦且可黏合性强的基座环境。


2.1 实现更灵活的流程拆分组装、数据解耦
2.1.1 流程拆分
元素:
算子: 若干个函数的集合,组成一个业务逻辑上可简单描述的功能模块;
边: 联接 2 个算子,具有方向性,代表执行顺序,起始节点作为上游算子,指向节点作为下游算子;
联接:
串联: 一个上游算子联接一个下游算子,上下游顺序执行;
并联: 一个上游算子联接多个下游算子,上下游顺序执行,下游算子之间并行执行;
join: 多个上游算子联接一个下游算子,上游之间并行执行,下游等待所有上游执行完后再执行,实现汇聚、归并。
flow:
将复杂业务功能分解成若干个易实现、解耦、可复用的算子,根据业务执行顺序用边将算子串联起来,形成工作流。
用户请求从起始算子流入,通过 flow 的算子进行加工,最终从结束算子输出,完成整个业务流程。同时支持 dag 和 dcg(有环图)。

2.1.2 分层组装
子图(sub-flow):把一个 flow 也当成一个算子(sub-flow),直接挂到另一 flow 上,当数据推动到这个算子的时候就会触发这个(sub-flow)的内部逻辑,实现 flow 级别的抽象和复用;
分层脉络地图:功能复杂导致算子数量过多时可以按不同粒度划分层级,把相同抽象粒度的算子放到同一个层级,不同层级的算子通过子图实现串联。通过点击进入子图内部浏览功能细节,通过收拢子图回到上层抽象,以此实现功能导航地图,既方便浏览又方便解耦拆分到多人协作开发。

2.1.3 数据解耦
context 共享可以方便的在所有算子间传递数据,算子的插拔替换、顺序调整也无需考虑数据的匹配,但同时也带来了数据加工处理过程黑盒,以及为了尽量避免参数读、写范围放大而需要加强数据访问权限保护这 2 个问题。
为此我们提供了额外的方式,满足不同场景的需求。
链式推导 -- 更细粒度数据解耦
描述:上游 output 和下游 input 类型一致,就能串联并传递数据。
优势:output/intput 是数据传播的契约约束,数据加工流程清晰。相同 intput, output 定义的算子之间能串联且插拔替换;相互之间不匹配的算子能通过定义中间类型的"桥接"算子来实现串联。
短板:需要用户手工串联算子,而且算子间容易产生串联类型不匹配以及并发问题也需要用户自己解决。
自动推导 -- 自动优化使用和运行效率
描述:算子数量越多人工编排效率越低,在链式推导的方式上引入 Referential Transparency, Single Assignment 等规则约束来实现调用链自动推导。
优势:可以帮助用户自动管理大量算子的联接关系, 省时省力的同时还能在保证数据并发安全性的同时实现最大程度的并行化。
短板:关注的焦点从过程转移到数据,用户需要对流程做设计、优化时需要从数据入手做逆向推导流程(数据是在流程中慢慢产生和迭代的),违背了用户的使用习惯。而且对现有系统来说这种对数据读写的严格拆分、解耦往往需要全部推翻重来。

2.1.4 拷贝与引用
除了以上的数据传递方式外在不同的需求场景下我们同时还需要思考是传递数据的副本拷贝还是传递数据引用(本身)的问题
context 共享:出于性能考虑,基本都是采用传递引用的方式;
链式推导:可以手工指定,默认通过简单的判断下游算子的数量来自动决定:下游算子个数等于 1:传引用,大于 1: 第一个算子传引用,剩余算子传副本,尽可能在局部范围内降低用户心智负担;
自动推导:在 Referential Transparency, Single Assignment 双重数据访问规则保护下无需用户考虑并发安全性问题;
自定义:用户可以在联接 2 个算子之间的边(edge)上显示指定是副本拷贝还是传递数据引用(本身)来获取更大的灵活度。

2.1.5 类型适配
同一类功往往有多种实现,各自针对不同的使用场景有自己的优化,这些算子的 input/output 往往基本结构一致,但又稍稍有一些小差异,为了更方便让这些算子能快速插拔,提高功能复用度,降低复用成本,我们提供了一系列自动适配机制。
类型自动放大:内置多种数据类型及其变体自动转换逻辑:
A <---> *A, interface{}
A -> []A, []*A, []interface{}
特型自动匹配:上游算子的 output 类型是被下游算子 input 类型内部组合的子类型,相互能串联,并完成自动赋值。
自定义适配器:一个单独的适配器完成 2 个功能类同,但是 intput/output 参数形式差异较大的算子之间串联,适配器的 input 是上游算子的 output, 其 output 是下游算子的 input。
为什么不直接用过度算子实现:避免大量转换算子干扰业务流程;
为什么不把适配逻辑放算子内:避免侵入式改造和过度引用导致耦合。

2.2 实现精细化的路径规划
2.2.1 多功能边
if: 条件边 (单分支);
switch: 多条件边 (多分支);
multiplex: 多路复用边 (同时监听多个资源、信号);
optional edges: 可选边 (按需放弃对非强依赖上游的等待);
while: 循环边 (条件和循环次数组合实现 dcg);

2.2.2 动态规划
编译时构建一个基础的大致性的功能脉络(上层基础逻辑定义),具体实现逻辑由执行期根据代码运行情况及 LLM 返回结果动态规划做逻辑的实时增删、拼接、构建。

2.3 实现统一的驱动控制和干预
2.3.1 流程驱动
executor 执行器:
存算分离设计:执行器读取 flow 信息并驱动执行,提供路径控制、资源调配,flow 仅存储数据;
一次解析多次执行:对 flow 进行一次解析后可以得到该 flow 的一个 excutor, 后续相同的 flow 都可以通过该 executor 进行执行;
适用场景:系统里 flow 异构类型有限, 都需要大量重复的被执行, 能节省每次构建重复 flow 的开销。
flow 自驱动:
无需解析,直接执行:flow 被构建出来后,利用 flow 自驱动的功能直接运行, 无需构建执行器;
适用场景:系统里大量异构 flow,或者会动态产生出新构型的 flow,能节省复用度低的执行器构建的开销。

2.3.2 错误处理
退出流程
当算子返回值 <0 时表示发生错误,默认直接跳到最后一个算子执行(让系统能有一个给用户回包、打日志的机会) 后并退出当前流程,快速终止无效的执行逻辑,迅速释放资源。
逐层退出
当有多层(子图)时候,每一层有算子返回值 <0 都会直接跳转到本层子图的最后一个算子执行,随即返回回上一层。用户可以按需给上层指定返回值,当给上层的返回值 >=0 时候上游正常往后面算子执行,否则继续跳到本层的最后一个算子执行,以此类推直到整个 flow 结束。

2.3.3 超时控制
图超时
我们可以给整个 flow 指定一个执行的超时时间,触发后直接跳入到本层最后一个算子(让系统能有一个给用户回包、打日志的机会),这样快速终止无效的执行逻辑,迅速释放资源。
算子超时
一般没有特殊需求我们建议根据业务接口要求通过 flow 控制整体超时即可,由系统自行判断可以尽量避免一些超时设置不合理的问题,同时我们也保留单独指定算子超时的能力,算子发生超时但 flow 整体没有超时时会跳过超时算子继续往下执行;,尽可能保持必要的灵活性。

2.4 实现通用注入
2.4.1 事件监听
监听通用事件
提供以 aop 接口的形式统一支持算子 on_enter, on_leave, on_timeout, on_error 等关键事件的钩子机制,以全局函数或者算子成员函数的形式进行改写,以便用户能统一加入自定义的日志记录、监控、通知、错误处理等应对机制。
监听自定义事件
除了上面的通用事件,我们还提供统一的机制,提供用户在算子内部任意地方加入自定义事件的能力,帮用户简便地完成应用层框架监听机制的建设需求。

2.4.2 附加属性
除了 context 共享,链式推导的传递机制外我们还提供了额外第三种"附加属性"的方式来给算子传递数据,方便用户在编辑算子时就能给算子指定一些固定属性值,算子运行时能快速被读取,降低初始化成本。

2.4.3 流式输出
放置一个内置的流式输出的算子到 workflow 里,通过向这个算子的 channel 里写入数据即可实现在任意算子里流式输出信息来满足 sse 需求,同时将流式输出算子和最后一个算子相连,即可实现优雅退出。

2.5 实现低代码
提供可视化编辑器,让用户拖拽设计流程并产生对应的配置文件;
后端提供算子仓库作为用户功能实现的基础素材;
图引擎的 generate 负责将配置翻译成流程代码, builder 动态构建流程,driver 负责驱动流程运行并返回结果。

2.6 seda 相较其他图引擎实现的优势
2.6.1 图引擎实现方案一:多线程并发(thread-base-on-request)
本质:线程数和请求数 N:M 的模型,基于请求数量规划线程的设计, 由操作系统保证线程调度、资源分配的均衡。
优势:实现简单、数据局部性好,负载在系统处理能力阈值内性能及佳,适用于对耗时要求苛刻的场景。
短板:
流程黑盒:线程粒度太粗(请求粒度),不利于功能迭代、优化。
扩展性差:请求数受系统线程数制约, 负载超出系统处理能力阈值会使系统陷入“调度内耗” (上下文切换,锁竞争),处理能力指数级下降。

2.6.2 图引擎实现方案二:事件驱动并发(thread-base-on-resource)
本质:资源数和线程数 N:M 的模型, scheduler 根据系统资源初始化若干线程,将请求拆解成由若干个 non-blocking 节点组成的有限状态机(FSM),节点执行后将状态回传给 scheduler, 由其根据当时资源使用情况分配下一个节点的处理线程,直到整个有限状态机结束。
优势:
流程可视:通过有线状态机实现各个功能节点之间互相解耦;
扩展性佳:线程数不受请求数影响,能始终控制在系统资源可高效运行的阈值范围内;
吞吐量大:事件驱动极大程度避免了多线程之间的"资源内耗",能有效提升系统并发和吞图。
短板:
时延增大:一次请求处理过程跨多个线程执行增加了数据传递消耗的同时也降低了硬件缓存命中率导致请求延迟增大;
实现困难:中心化的 scheduler 调度器既要驱动业务状态流转又要管理资源调度往往会顾此失彼。

2.6.3 图引擎实现方案三:基于 seda 的图引擎驱动(thread-base-on-stage)
seda:staged event driven architecture
本质:将上面中心化的 scheduler 模块给拆分成多个子部件实现。
用多个事件队列将每个状态节点(stage), 组成一张数据流动网络 (Directed Graph);
每个 stage 都由事件队列(接收数据)、控制器(分配资源,驱动 stage 流转)、线程池(调节线程数)、事件处理器(业务处理 handler)组成;
优势:
资源按流程 stage 拆分,粒度适当 (按 request 粒度过小,容易陷入内耗;按 resource 粒度过大,容易浪费);
去除中心化模块,通过对事件队列的流速控制使得每个 stage 可以单独进行负载调节。
短板:
相比运行状态良好情况下的单线程处理一个请求的设计, 时延上会有增大 。

03 通用图引擎在智能体场景的实际应用
3.1 功能场景应用
3.1.1 根据大模型 COT 结果动态生成子 workflow
query:请预测下明年下周的天气情况
大模型将问题拆解成具备先后依赖关系的多个小步骤:
计算下一周对应的时间范围
查询本周天气情况
查询历史上前 n 年对应时间范围的的天气情况,
根据历史查询结合当前情况推测明年对应的时间范围的天气情况(结果保存到短期记忆)
如样本范围太小或结果单一则重复前面过程 3-4,直到给出预测结果的具体概率分布
大模型根据当前执行到的具体步骤将工作内容动态分解到子图并执行。

3.1.2 复杂场景的功能拆分解耦和精细化路径控制能力
用"多路复用"同时监听多值,支持任意数量路径分发,将 "路由和子功能调用" 算子进行拆分解耦;
用"可选边"将多处可能会触发到的公共逻辑"润色模型"模块拆分成独立算子;
用过"融合边"将各种不同类型的边融合汇聚到一个算子, 便于整体控制流程结束逻辑;
通过以上多种精细化路径控制功能,减少大量胶水代码的同时方便对流程图做快速修改,让用户专注于业务逻辑自身。

3.1.3 通用注入和循环增强
由侵入式改造转变成通用事件注入来统一控制算子内部的共性行为;
个性化功能增强也可以通过非侵入式方式注入算子内部;
在之前纯代码逻辑控制循环结束条件的同时增加了框架保护机制,避免响应不及时和资源长时间侵占。

3.2 小结
通过图引擎驱动 workflow 的开发模式提供了一个强大的基座,用户可以快速在其上通过插拔替换、顺序调整、串联汇聚、编辑出任意自己想要的流程,其强大的解耦和精细化路径控制能力从根本上解决传统 ai 开发模式带来的黑盒问题和相关不确定性问题,同时还能获得极佳的运行时效率(天然并发);其自带的低代码、分层导航等特性减少了大量胶水代码,还有助于多人同时入场并行开发,降低开发、维护成本。
目前系统已经接入 80w 开发者,15w 合作企业,超过 10w 个智能体。
————END————
推荐阅读
如何在百度百舸部署满血版DeepSeek-V3、DeepSeek-R1模型
首日调用客户破1.5万!DeepSeek-V3/R1上线背后的超低推理成本技术揭秘
评论