ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Agent工作流架构设计:增强型、链式与路由式三种基础形态解析

Agent工作流架构设计:增强型、链式与路由式三种基础形态解析

做了一段时间Agent应用,我最大的感受是:大多数人聊Agent都在聊模型能力,却很少聊工作流怎么搭。模型选多大、提示词怎么写,这些当然重要,但真正决定一个项目能不能从Demo变成稳定产品的,往往是那层看不见的架构——多个步骤怎么编排、工具怎么调用、任务怎么分发。今天想跟你系统聊一聊Agent工作流架构设计里的三种基础形态:增强型、链式、路由式。这三种结构覆盖了大部分真实业务场景,理解它们的原理和取舍,比追着模型版本跑实在得多。

这篇文章适合正打算做Agent应用、被多步骤流程编排劝退的开发者,也适合已经跑通原型但发现一上复杂度就失控的团队。我会把三种架构的适用边界、核心代码骨架、选型思路以及我踩过的坑一次讲透,尽量让你读完之后能直接对着自己的业务场景做判断。

1. 三种Agent工作流架构的核心思路

1.1 为什么架构层面的设计被长期低估

很多人刚开始做Agent时,习惯把全部逻辑塞进一个超长的System Prompt里,希望模型“一个脑袋搞定所有事”。这种做法在简单Demo里确实能跑通,但一旦业务开始要求调用外部工具、处理多步操作、应对不同方向的用户请求,单一Prompt的瓶颈会立刻暴露。模型要同时承担意图理解、流程控制、结果生成、异常处理,任何一个环节出问题,整条链路的行为都不可预测。这就是我后来转向工作流架构设计的原因:把“让模型自由发挥”变成“让模型在有限框架里高质量完成子任务”。

架构设计的本质,是给Agent划定活动的边界和路径。你不去设计路径,模型就会自己随机走一条路,而随机路径在工程上是不可接受的。增强型、链式、路由式这三种架构,对应的是三类最典型的协同需求:单体智能增强、流程确定性编排、任务按需分发。理解它们,等于拿到了搭建更复杂系统的三块基础积木。

1.2 三种架构的一句话定位

先给一个快速对照,方便你建立整体印象:

架构类型核心思想解决的核心问题典型形态
增强型给单Agent配工具、记忆、规划能力单模型能力不足,需要外部能力补全模型 + 工具调用 + 短期记忆
链式将多步骤按固定顺序串接复杂任务需要拆解成确定性流水线步骤A → 步骤B → 步骤C
路由式根据输入内容分发到不同子Agent请求类型多样,需要专业分工分类器 + 多个专用处理单元

这三个不是互斥选项。我自己的项目里经常是路由式在最外层接流量,内部某个分支再用链式拆步骤,链式的某个节点里再放一个增强型Agent去调用工具。架构是组合出来的,先单独理解,再谈组合。

2. 增强型架构:让模型真正用好手里的工具

2.1 增强型架构的原理与核心组成

增强型架构,简单说就是“单Agent + 外部能力增强”。模型本身是一个推理核心,但它不知道实时天气、查不了内部订单库、没法帮你发邮件,所以要在它外面挂一圈工具,让它按需调用。除此之外,增强型架构通常还包含两个关键部件:记忆模块和规划模块。

记忆模块解决的是“多轮上下文能不能带上”的问题。没有记忆,模型每轮都是“失忆”状态,用户说过的话转头就忘;有了短期记忆和长期记忆,Agent才能在连续对话中保持行为的一致性。规划模块解决的是“复杂目标怎么拆”的问题。模型拿到用户目标后,自主规划出执行步骤,然后一步一步调用工具完成。实际落地时,多数实现都依赖“函数调用”协议来实现工具调用,因为这比让模型输出一段JSON再自己去解析要可靠得多。

2.2 工具定义与函数调用实现示例

我用一段伪代码来演示增强型架构的骨架。真实项目里你可以用任何主流Agent编排SDK,但核心结构基本一致。

import os from some_agent_sdk import Agent, Tool # 示意:某个Agent编排SDK def get_weather(city: str, date: str = "today") -> str: """查询指定城市某天的天气情况""" # 这里接入第三方天气服务或内部数据服务 data = weather_service.query(city=city, date=date) if data is None: return f"抱歉,未能查询到{city}在{date}的天气数据" return data.summary_text weather_tool = Tool( name="get_weather", description="查询某个城市指定日期的天气状况,入参为城市名和日期", parameters={ "type": "object", "properties": { "city": {"type": "string", "description": "城市名称,例如华东某市"}, "date": {"type": "string", "description": "日期,格式为YYYY-MM-DD,默认当天"} }, "required": ["city"] }, func=get_weather ) agent = Agent( model="your_model_name", tools=[weather_tool], system_prompt="你是一个生活助手,用户问天气时主动查询并友好回复。" ) resp = agent.run("明天那边冷不冷?")

这个例子里有几个细节值得注意。工具描述一定要写清楚参数的含义和默认行为,因为模型是靠描述来理解工具的。参数类型和必填项要严格标注,否则模型可能传错格式。工具函数本身要处理异常,返回结构化错误信息,比如“查不到数据”和“服务超时”要分开表达,否则模型会把错误当成正常结果继续推理。

2.3 适用场景与落地注意事项

增强型架构最适合的场景有三类:一是问答类应用,需要结合实时数据或私有知识库作答;二是操作类应用,比如让Agent帮忙订会议室、发消息、改文档;三是需要多轮交互的助手型产品,用户在对话中逐步提出需求,Agent边理解边执行。

但增强型架构的局限也很明显:所有流程控制都依赖模型的自主判断,一旦任务步骤过多、分支过深,模型就容易“迷路”。我实测下来,当一次任务需要连续调用超过四五个工具并且结果之间有依赖关系时,增强型架构的错误率会明显上升。另外,任何一次工具调用的失败都可能被模型“将错就错”地编造出一个看似合理的结果,这是最让人头疼的。所以我的建议是:工具调用的每一个返回都必须包含成功/失败的明确标记,Agent的系统提示词里要专门加一条“工具调用失败时,必须如实告诉用户并停止后续操作”。

3. 链式架构:把长流程拆成可控的流水线

3.1 链式架构的工作方式与设计逻辑

链式架构的核心思想非常朴素:一个复杂的任务,拆成多个串行的子步骤,每个子步骤由一个独立模块完成,前一个步骤的输出作为后一个步骤的输入。这就像工厂里的流水线,每个工位只负责一道工序,工序之间顺序固定、接口清晰,哪一步出了问题就直接在哪一步返工。

为什么要这样设计?因为很多业务任务虽然有复杂性,但流程本身是确定的。比如“生成一份销售周报”,固定的路径就是:拉取数据 → 清洗加工 → 生成分析文案 → 排版输出。这种任务如果交给一个增强型Agent自由发挥,它可能在“清洗加工”阶段就开始自由创作,或者在“生成文案”时把数据弄丢。而链式架构通过代码层把顺序锁死,模型只负责其中某个环节,自由度被限制在可控范围内,整体输出的稳定性会显著提升。

3.2 链式架构的代码骨架示例

链式架构的实现重点在于定义清楚每个步骤的输入输出协议。下面是一个高度简化但结构完整的示例:

from dataclasses import dataclass from typing import Any @dataclass class StepResult: success: bool data: Any error_msg: str = "" def step_extract_requirement(user_input: str) -> StepResult: # 调用模型抽取意图与关键实体 try: parsed = model_extract(user_input, output_schema=REQUIREMENT_SCHEMA) return StepResult(success=True, data=parsed) except Exception as e: return StepResult(success=False, data=None, error_msg=str(e)) def step_generate_plan(requirement: dict) -> StepResult: # 根据抽取出的意图生成执行计划 plan = model_plan(requirement) if plan_quality_check(plan) is False: return StepResult(success=False, data=None, error_msg="计划生成质量不合格") return StepResult(success=True, data=plan) def step_execute_plan(plan: dict) -> StepResult: # 按计划执行具体操作 output = execute_plan_steps(plan) return StepResult(success=True, data=output) def chain_process(user_input: str) -> str: r1 = step_extract_requirement(user_input) if not r1.success: return f"需求理解失败:{r1.error_msg}" r2 = step_generate_plan(r1.data) if not r2.success: return f"计划生成失败:{r2.error_msg}" r3 = step_execute_plan(r2.data) if not r3.success: return f"执行失败:{r3.error_msg}" return final_report(r3.data)

每一步返回StepResult结构体,把成功/失败状态和业务数据分开,外层代码就能轻松做分支处理。这一步非常关键,它保证了链路中任何一环出错都能被马上捕获,而不是把错误静默传下去。

3.3 参数传递与错误处理的细节

链式架构的成败往往隐藏在两个细节里:数据Schema和错误恢复。每个步骤之间的数据传递必须提前定义好固定的Schema,比如步骤A输出的JSON结构,步骤B必须严格按照相同结构去读。我见过太多项目在链路上用“自由格式文本”传递中间结果,结果步骤B的模型读到的是步骤A模型重新组织过的措辞,字段对不上,整个链路就崩了。解决方法是强制每个步骤输出结构化数据,并且对关键字段做非空校验和类型校验。

错误恢复策略也要提前想清楚。我常用的策略有三种:终止、降级、重试。对于不可恢复的错误,比如依赖的外部服务挂了,直接终止并返回明确错误;对于可以降级的场景,比如推荐引擎超时,返回通用推荐结果先顶上;对于延迟类错误,比如模型接口一次超时,做两次有限重试。实际项目里这些策略应该配置化,不要写死在代码逻辑里,否则后期调整成本非常高。

另外,链式架构还有一个容易忽视的优势:可观测性。每一步的输入、输出、耗时、token消耗都能被记录下来,定位问题时非常直观。这一点是增强型架构很难提供的,在实际排障时价值极大。

4. 路由式架构:让最合适的Agent接单

4.1 路由式架构的核心机制

路由式架构的设计思路,是系统里有多个Agent或处理流程,每个只负责某一类任务,入口处有一个路由判定模块,根据当前请求的特征把任务分发给最合适的处理单元。这跟客服中心非常像:电话打进来,先由语音导航判断用户是想办业务、报故障还是投诉,再转给对应专员,而不是让一个全能客服处理所有事情。

路由式架构解决的,是“一个Agent包打天下导致专业性不足”的问题。如果你的业务请求类型差异很大,比如既有政策咨询又有技术问题还有售后投诉,把它们塞进同一个Agent,模型会被相互冲突的指令搞糊涂。分开之后,每个子Agent都能用高度定制的提示词、工具集和回答策略,质量和可控性都会上一个台阶。

4.2 路由实现的两种常见方案

路由判定模块有两种常见实现:规则路由和语义路由。

规则路由适合结构化特征明显的请求。比如根据接口参数里的业务类型字段、包含的特定关键词、用户选择的下拉选项来直接决定走哪个分支,速度快、零成本、完全可控。缺点是无法覆盖表达灵活的自然语言请求。

语义路由则是把请求文本经过一个模型进行分类,输出目标分支。实现上通常有两种做法:一是直接调用一个轻量模型做“意图分类”,输出结果是预定义的路由标签;二是用向量化召回,将用户问题与各分支的代表性样本做相似度匹配,最相似者获胜。分类路线更适合类别之间的边界相对清晰的场景,向量路线更适合类别多、判断维度模糊的场景。我在自己的项目里常用“规则优先 + 语义兜底”的组合:先看有没有命中规则的条件,没有再看语义分类,两层都拿不准就落到默认分支。

下面是一个语义路由的简化示意:

ROUTES = { "weather": weather_agent, "finance": finance_agent, "tech": tech_agent, } DEFAULT_AGENT = general_agent def route_request(user_input: str) -> Agent: # 第一步:规则命中 for keyword, route_name in KEYWORD_RULES.items(): if keyword in user_input: return ROUTES[route_name] # 第二步:语义分类 route_name = classify_intent(user_input, candidates=list(ROUTES.keys())) return ROUTES.get(route_name, DEFAULT_AGENT) def main(): user_input = receive_request() agent = route_request(user_input) reply = agent.run(user_input) return reply

4.3 路由判定的质量保障

路由判定虽然看起来只是一个分类模块,但它的质量直接决定整个系统的上限。路由错了,后面子Agent再专业也白搭。这里有几个我反复强调的保障手段。

路由标签的设计一定要互相排斥、穷尽无遗。每个类别之间尽量少重叠,同时必须要有“其他”类兜底,否则模型在不确定时就会硬选一个。每个分支的说明文字要写清楚该类目负责什么、不负责什么,这对分类模型的理解准确性影响非常大。我建议专门为路由层准备一份评估集,收集几百条各类型真实用户请求,每调整一次模型或提示词,先跑一遍评估集看分类准确率有没有变化。很多项目不重视路由评估,直到线上用户反复被转错才开始查,那时候成本已经很高了。

另外一个容易被忽略的问题是:路由层往往要承受比子Agent更大的流量,所以它的延迟和成本要控制好。能用小的模型尽量用小的,不要一上来就上最大参数模型做分类。速度上来之后,整体体验才会真正“路由”起来。

5. 架构选型:从需求倒推最优解

5.1 三类典型需求的选型对照

很多朋友问我:“这三种架构到底怎么选?”我的回答一直是:别从架构出发,从需求出发。你手上的任务是什么类型,就直接决定该用哪种架构。为了方便你对照判断,我整理了一个选型速查表:

需求特征推荐架构原因
开放域问答、需要实时信息、需要调用工具增强型灵活度高,适合不可枚举的多样化请求
固定流程、多步骤、步骤间有依赖关系、要确保稳定输出链式确定性高,流程可锁死,便于定位问题
请求类型差异大、不同类别需要不同专业策略路由式专业分工,每个子任务用最匹配的能力解决
先分大类,每类内部再走固定步骤路由 + 链式外层分派,内层流程保证,兼顾分工与稳定
复杂开放任务,流程本身不确定,但要求边界可控路由 + 增强型分方向后分别调用不同工具集

选型最大的忌讳是“为架构而架构”。如果项目只有一两个固定流程,非要去搭一套复杂路由,纯属给自己挖坑。同样的,如果业务场景本来就是天马行空的开放问答,非要强行拆成固定链条,反而会扼杀掉模型本身的泛化优势。

5.2 复梳理:组合式架构的可能

真实项目里,三种架构的组合是常态。我的一个实际项目就是一个典型的三层结构:最外层是路由式架构,负责把用户请求分到“信息查询”“流程办理”“问题建议”三个方向;每个方向上再用链式架构,把查询拆成“生成参数 → 调接口 → 汇总结果”,把流程办理拆成“确认资格 → 执行操作 → 输出回执”;而每个链式步骤里再嵌入增强型能力,让模型在参数生成环节调用工具去校验数据格式。

这种组合的好处是每一层的复杂度都被控制在可理解范围内。路由层不需要关心内部怎么实现,链式层不需要关心输入从哪里来,增强型节点只要把自己的子任务做好就行。整个系统的调试体验也非常好:先看路由分对了没有,再看链路哪一步断了,最后看模型调用工具的参数对不对。层与层之间的职责边界一旦清晰,协作效率会远超一个大而全的单体Agent。

6. 落地实践:常见坑位与排查方法

6.1 六个高频问题与应对策略

我把自己实际落地过程中反复遇到的坑梳理了一下,整理成了一张排障速查表:

现象可能原因解决办法
增强型Agent调用工具时参数频繁传错工具描述不清晰、参数示例缺失在描述里补充一到两个典型示例,强化参数边界说明
模型编造工具调用结果工具返回缺少成功/失败标记所有工具返回统一包装为结构化结果,强制带success字段
链式流程中下游步骤偶发输出乱码上游中间结果不是严格JSON步骤间强制用Schema校验,不合格直接抛错中止
链路超时问题难以定位缺少每步耗时的埋点给每一步加开始时间和结束时间,输出到日志
路由频繁分错方向路由标签语义重叠、边界模糊重写类目描述,减少重叠,增加“其他”兜底类
切换模型后整体行为大变提示词与模型能力不匹配为每个环节维护独立的评估集,切换后先回归测试

这六类问题基本覆盖了我所见的大多数翻车现场。它们的共同根源都是同一个:没有把可控和不可控的分清楚。工具调用和流程编排这些可控部分,要尽量用代码锁死;模型发挥部分,要给足边界条件和评估手段。

6.2 调试与评估的基础手段

最后聊一聊调试与评估。这部分经常被当成“上线后再说”的事情,但我的建议是:在架构设计阶段就要同步建立。至少要准备三样东西:一份典型请求集、一份全链路日志格式、一份关键指标看板。典型请求集覆盖各路由分支和各链路环节,每次调整后先跑一遍。全链路日志记录每一步的模型输入输出、工具调用序列、耗时和token消耗,出了线上问题能按请求ID一路追踪下去。关键指标至少要看三个:任务成功率、平均响应时长、无效调用占比。没有这些,你所谓的工作流架构就是开着一辆没有仪表盘的车,速度快慢全凭感觉。

评估集不需要一开始就很大,我通常从三四十条起步,后续每次遇到线上问题就往里加一条回归用例。三个月下来,这个评估集就是项目最宝贵的资产之一,比任何架构文档都管用。

7. 组合与演进:真实项目里的架构路径

7.1 从小原型到复杂系统,架构怎么跟着长

我见过不少团队的Agent项目演进路径,很有意思。一开始通常是一个增强型原型,一个模型加两三个工具,能回答不少问题,团队觉得“成了”。然后开始推给更多用户,问题就来了:请求五花八门,一个Agent疲于应付。于是团队加上路由,按主题分给不同Agent,问题缓解一阵。再后来,某个具体方向上的子Agent开始被要求做多步骤操作,发现单靠提示词控制不住,于是再把这一步拆成链式。最后形成混合架构,团队也慢慢理解了每种架构的边界和适用条件。

这个演进路径几乎无法跳过。你很难一开始就设计出一个完美的混合架构,因为对业务的理解是逐步深入的。更好的做法是:先清楚掌握三种基础架构的能力边界,当问题出现时,知道用哪块积木去补。

7.2 最后分享一个实践小技巧

我个人在实际操作中最受益的一个习惯是:给每一个Agent环节写一个“行为契约”。不管它是路由层、链式节点还是增强型Agent,都在代码旁边用一个简洁文档写清楚:这个环节的输入是什么、输出格式是什么、什么情况下算失败、失败后往哪返回。这份契约不需要很复杂,半页纸就够,但它逼着你想清楚每一个环节的边界。

踩过几次坑之后,我才真正明白,所谓Agent工作流架构设计,做的不是让模型变得更聪明,而是让模型在有限边界内更可靠。增强型、链式、路由式只是三种基础姿势,真正决定项目成色的,是你对业务任务拆解得是否足够清楚、对每一次模型行为的约束是否足够明确。希望这篇梳理能帮你少走一些弯路。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进