ARTICLE DETAIL

资讯详情

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

多Agent系统构建实战:从流程拆解到生产部署

多Agent系统构建实战:从流程拆解到生产部署 1. 构建思路先拆流程再谈Agent1.1 为什么多Agent不等于“多个模型实例”OpenAI Agents SDK构建指南系列写到第五篇我默认你已经把一个能跑的Agent项目攥在手上了。如果还没有建议先回头补齐前四篇的内容。这一篇要解决的不是“怎么调用工具”这种基础问题而是“如何把一个demo级别的Agent重构成一套能协作、能扩展、能上生产的多Agent系统”。我自己最近接的一个实际项目特别能说明这件事。客户要做一个制度条例学习助手需求听起来不大员工提问它回答制度条款。但真正拆开之后考验的是“意图判断、语义检索、溯源引用、权限过滤、多轮追问”这五层能力的协作。任何一个环节交给同一个Agent去处理Prompt都会膨胀到失控实测效果就是回答像“和稀泥”——什么都能说一点什么都不够精准而且无法定位错误出在哪个环节。多Agent不等于开多个会话任务。很多人误以为“我并行调五个模型让它们各干各的最后合并结果”就叫多Agent。这是把负载均衡和多智能体协作搞混了。真正的多Agent系统核心是职责划分和上下文隔离每个Agent是独立进程有自己的提示词、工具集、记忆范围和触发条件。它们之间的通信是结构化交接而不是把所有信息都塞进一个共享上下文里。我在重构那个学习助手时用的类比是“餐厅后厨”。一个人既收银又掌勺还传菜客流小的时候没问题客流一大必然崩。Agent也一样一个Agent同时承担意图识别、信息检索、报表计算、权限校验大模型会变“贪心”倾向于用最省事的方式回答问题而不是按照你设想的逻辑链路去执行。拆成前厅对话管理、后厨制度检索、传菜口生成回复三个Agent之后每个环节的上下文都变得轻量、纯粹出了问题一眼就能看到是哪个环节翻的车。SDK里承接Agent之间分工协作的东西是Handoff交接机制它不单纯是“调用另一个Agent”而是把当前会话状态、消息历史、意图上下文切换给目标Agent。实践中有个常被忽视的细节Handoff时需要显式声明交接理由和转移目标否则模型在边界模糊时会频繁来回踢皮球陷入两个Agent互相“让贤”的死循环。1.2 三种协作模式的选择逻辑根据我拆项目的经验多Agent协作逃不开三种基础模式顺序流水线、路由分发、嵌套层级。每种模式都不是万能的选错模式后面再调参都救不回来。顺序流水线适合流程固定的业务比如工单自动处理第一步分类工单第二步提取关键信息第三步匹配解决方案第四步生成回复。每一步的输入是上一步的输出Agent之间像工厂传送带上的工位。优势是流程可预测、调试简单劣势是“一条路走到黑”——如果中间某一步的判断出现了偏差后面所有步骤都会跟着错而且没有回头机制。路由分发是另一种常见的用法前面有一个轻量的Router Agent负责意图分诊把请求派给相应的垂直Agent。制度条例学习助手用的就是这种模式。员工问“年会报销上限是多少”Router直接判定为“报销制度”转给报销Agent如果追问“为什么去年能报销两次今年不行”Router判定为“政策对比需求”转给差异分析Agent。两个Agent各守一摊Prompt各自维护互不干扰。嵌套层级则更复杂一些适用于研究型或规划型任务父Agent负责总体目标拆解子Agent负责执行子任务子Agent还可以继续下派孙Agent形成树形结构。这种模式最强大的地方是可以实现“计划-执行-反馈-修正”的闭环。不同模式选型的判断条件我一般看两个维度。第一看“分支数量”整个业务流程里明确的意图分支是否超过三个超过就适合用路由分发。第二看“容错需求”单步结果不可逆的还是可回退的可回退用流水线就能解决问题需要兜底重试的考虑嵌套层级。决策时可以用下面这张表快速匹配业务特征推荐模式典型场景流程固定、步骤清晰顺序流水线工单分类、数据清洗分支多、意图差异大路由分发智能客服、学习助手任务复杂、需要逐步推演嵌套层级研究报告、方案生成这里要说一个容易犯的错嵌套层级不是“越深越好”。子Agent嵌套超过三层消息传递耗时会指数级上升而且大模型在长链路中的记忆衰减非常明显。我自己踩过的坑是四层Agent链路上最内层Agent几乎完全忽略父Agent给定的约束回答风格跑偏到无法直视。最后的解决办法很简单压缩到两层加上每层的结构化总结回传效果反而稳了不少。2. SDK核心组件进阶工具、记忆、上下文的实战定型2.1 工具进阶写法让Agent“会正确使用”而不是“疯狂乱调用”工具是多Agent系统的“手脚”。SDK的工具注册机制很灵活但灵活不代表你随便写个函数标注一下就能用得好。我见过太多人把工具参数设计成嵌套JSON对象结果模型生成参数时频繁漏字段各种报错。这里有一条硬性经验参数能平铺绝不嵌套能用简单类型绝不搞复合结构。举个对比。采购系统里有个“生成采购申请单”工具参数设计成“requester_info嵌套对象姓名、部门、员工号”模型有时候只填姓名不填员工号然后报参数缺失错误。改成三个平铺参数request_name、request_dept、request_empid之后错误率直接下降一半。模型的JSON生成能力没有你想的那么稳平面结构永远比嵌套结构更容易被准确生成。工具描述同样值得打磨。模型不是通过函数名理解工具而是通过description理解工具的。description写得含糊模型就会在边界场景里自作主张。我的写法模板是“在什么情况下使用这个工具、执行后会做什么、会返回什么、如果无法满足条件应该怎样”。句式和长度都有讲究太短模型无法理解边界太长又占上下文窗口。两到三句话是我实测性价比最高的长度。还有一个很多人忽视的地方工具内部不要抛裸异常。Agent SDK遇到工具抛异常时会把异常信息回传给模型模型会尝试自行修正或换一种调用方式。这本来是好设计但如果异常信息格式混乱比如直接打印traceback堆栈模型根本不知道下一步该做什么只会反复重试同一个失败调用。正确的做法是在工具内部捕获所有异常然后返回结构化错误对象包含code、message和suggestion三个字段。顺手给一个简化版示范基于Pythondef query_inventory(product_id: str) - dict: try: data inventory_api.send(product_id) if data is None: return {code: 404, message: 商品不存在, suggestion: 请检查商品ID后重试} return {code: 200, message: 查询成功, data: data} except TimeoutError: return {code: 503, message: 库存服务超时, suggestion: 请稍后重试} except Exception as exc: return {code: 500, message: f内部错误: {exc}, suggestion: 联系管理员排查}这样模型拿到返回值就知道是换个ID重试还是等待一会儿再查而不是对着一个traceback干瞪眼。2.2 记忆策略让Agent“记得住”又不会“记太杂”长任务场景里记忆是维持多轮对话流畅性的关键。但记忆不是“把用户说过的话全部原样存起来”那么简单。所有对话历史都攒着上下文窗口迟早爆更麻烦的是模型会被大量无关的历史噪声干扰注意力分散到错误的地方。我的做法是把记忆分三层。第一层是短期记忆也就是当前会话窗口里的完整对话不用特殊处理跟着消息历史走第二层是摘要记忆当消息历史超过阈值时触发一次摘要Agent把前面的对话压缩成结构化结论用户目标、已解决事项、待办事项、关键偏好第三层是长期记忆把跨会话的关键事实写入向量库或KV存储在会话启动时主动检索注入。实现摘要记忆有个关键的触发时机问题。我曾经困惑“到底多少轮对话才该触发摘要”最后实测的经验是当原始消息文本累计超过6000个token时触发比较合适。低于这个值摘要反而会丢失上下文细节高于这个值上下文窗口的压力已经开始拖慢生成速度了。同时摘要本身要有轻微的信息冗余宁可多保留细节也不要为了精简而丢掉后续推理需要的关键事实。用SDK搭建摘要记忆可以在运行时动态拼装系统提示词。每个Agent启动时先读取长期记忆里的用户档案拼进系统提示词消息历史超过阈值时调用摘要Agent对旧对话重写。提示摘要Agent本身也是一个Agent它的输出结构最好用JSON格式固定下来字段包括goal、resolved、pending、preferences这样下游解析成本极低也方便后续代码调试。2.3 上下文管理省钱和保质的平衡点一个被严重低估的成本黑洞是上下文冗余。同一个大段参考文档如果传给三个子Agent各一份token消耗就是三倍。而且多Agent并行执行时每个Agent都会读取同一个基础资料费用成倍增长。我在项目里是这么控制成本的基础资料统一读一次由Router负责摘要提取然后只把摘要部分传给下游。原始文档只在需要深度检索时按需提取。比如制度条例学习助手法律条文原始文本有几十万token不可能全量塞给Agent。我的做法是启动时先做一次向量化普通问答走检索增强生成RAG路径只把最相关的几段文本拼进提示词。只有在用户明确要求对比多个制度差异时才动用全局读取功能。另外值得关注的是工具返回值的token管理。当你调用一个返回大数据集的工具工具返回结果会完整留在上下文里。如果这个结果只被中间过程使用一次后面根本不需要再引用它了它就变成纯成本。早期的API版本对工具结果没有做自动截断后面需要手动的做法是工具返回值里如果数据量大在返回前先做预处理只保留模型推理真正需要的字段而不是把整个数据库表结构原样返回。这个“裁剪返回值”的思维特别重要。一个外部接口返回200个字段Agent做一次判断可能只需要5个剩余195个全是噪声。裁剪过后既省token又减少模型在无关字段上产生幻觉的概率。属于一举两得的优化。3. 知识库与业务系统Agent正式接上企业“地气”3.1 知识库构建不只是“把文档扔进向量库”Agent要回答公司制度、产品手册、故障排查手册背后一定得有一个知识库撑腰。但“知识库构建”四个字门槛全在细节里。我自己帮客户搭过农业知识库、故障数据库、制度条例库结构不同但有三条共通的实践心得。第一数据清洗比向量化更重要。原始文档里常见的格式混乱、表格分页、页眉页脚干扰如果不清洗直接分块检索质量会惨不忍睹。我见过一个故障库同一个故障处理方案因为故障描述换行方式不同被拆成了十几个碎片检索出来总是残缺版本的答案。清洗的标准动作包括统一换行符、去除页眉页脚、表格转纯文本时用分隔符保留结构、繁体简体统一。第二分块策略按文档类型差异化设计。制度条例适合按条款分块每条制度一个块故障排查手册适合按“现象-原因-解决方案”三元组分块产品手册适合按“功能模块-参数说明-操作步骤”分块。统一的固定字数切块是最偷懒也最容易劣化检索效果的做法。切块的时候还要保留元数据字段至少要记录来源文档、章节编号、更新日期这样回答时才能做溯源引用。第三检索优化比“加更多向量”更重要。如果Top K检索出的结果不够精准提高K值只会引入更多无关文本。我的优化路线是先用向量检索召回候选再用重排序模型精排最后设置相关性阈值滤掉低分内容。这个“向量召回重排阈值过滤”三件套基本上把RAG检索质量拉高了一个层级。没有重排模型时可以先用关键词过滤做一次粗排效果也能接受。顺带说一个制度条例场景里的特殊细节权限隔离。不同岗位的员工能看的制度范围不同这个过滤必须在检索时完成而不是检索后靠Prompt约束模型“不要泄露不应看到的内容”。后者完全不可靠模型没那么听话。在检索阶段就根据用户级别过滤掉无权访问的知识块才是工程上可信的方案。3.2 业务系统接入让Agent调用API而不是直连数据库Agent要落地到企业场景必然要和企业内部系统“握手”。这里我有一条很坚决的原则Agent永远不要直连生产数据库。理由很简单Agent的查询语料是自然语言生成SQL的出一次错误的DELETE或者不限定WHERE条件的SELECT代价是你担不起的。正确的姿势是“工具层适配”把业务操作封装成工具函数Agent只负责决定“调哪个工具、传什么参数”真正执行SQL的还是那些经过review的代码。权限控制也落在工具层工具函数内部检查当前请求者的身份和权限位没有权限直接返回错误码压根不给Agent触碰数据的空间。集成外部系统的过程里超时和连接池管理是两个隐藏雷区。Agent调用工具可能触发外部系统API而大模型的思考时间加上多次工具调用会让同一条链路上对上游系统的请求压力远超日常。我的做法是给每个工具调用设一个硬超时比如5秒超过就返回失败并在工具内做连接复用。如果上游系统响应本身比较慢比如报表服务建议做成异步任务Agent先创建任务返回任务ID之后轮询任务状态而不是死等同步结果。还有一点需要特别警示不要把内部API的完整Swagger文档一股脑丢给模型。模型只会被大量无关接口搞晕还可能自行拼出你没打算开放的接口调用路径。正确做法是只挑选Agent真正需要使用的5到10个接口编写精简版描述注册为工具。接口越多模型的选择成本越高选错的概率越大。4. 生产部署与稳定性能演示和能上线是两回事4.1 部署形态与容量评估本地跑通的Agent和线上扛住真实流量的Agent中间隔着一整条工程化的沟。部署的第一步是把Agent服务无状态化所有会话状态、记忆数据落到外部存储Redis或数据库服务实例本身不保存任何运行状态。这样扩容变成“多复制几个实例”那么简单。无状态化做完了才能谈容量评估。我用的估算口径是“单次完整任务的token总消耗”。别只看Prompt里的系统提示词长度要把多轮交互、工具返回值、模型生成内容全算进去。按我的经验一个普通的企业客服Agent单次简单问答消耗800到1500 token一次复杂的研究型问答可能破5000 token。拿这个数字乘上预估并发量就能粗略估算每分钟token峰值消耗从而决定模型规格和预算。并发连接数的评估也不难。SDK支持异步并发但下游模型API限流通常是瓶颈。一个稳妥的处理是引入请求队列和速率限制注意别让Agent的tool call火焰风暴把上游系统打崩。部署时的连接清理同样关键。长时运行的服务数据库连接池、Redis连接、外部API的连接复用都需要定期检查。我遇到过一次线上事故就是因为一个工具函数每次都新建HTTP客户端跑了两周以后连接数全部积压在那里内存直接爆掉。工具函数里必须复用连接对象这是个教训。4.2 可观测性日志、追踪、告警三板斧多Agent系统的排错难度远超单体程序。你看到的只是用户输入和最终输出中间经过Router、各个子Agent、多次工具调用任何一层出错都会导致最终结果变质。没有观测手段排查就变成了盲人摸象。可观测性的基础是结构化日志。所有Agent的输入输出、工具调用的入参出参、每一步的耗时和token消耗都按JSON格式落日志。日志还要带request_id链路追踪字段这样从用户请求进来到多个Agent协作完成全程时序可以串起来看。线上查问题的时候request_id就是定海神针。告警规则也有必要提前埋好。我常用的规则有这几种单次任务耗时超过某阈值比如30秒同一个工具连续失败超过3次token消耗异常激增Agent回调整跌到某个比例以下。回调整跌这个指标很容易被忽视但它其实是观察Agent行为质量的关键指标——本来应该调用工具的环节没有调或者调了错误工具这种偏差最终会体现在回复质量上。我还建议建立“语义回归测试集”。Agent系统改一次Prompt或升级一次模型效果可能就变了。维护一套固定的测试用例集定期跑一遍对比输出结果是否满足预期成本虽高但在企业落地场景里几乎不可省略。我见过太多项目升级一个模型版本之后线上效果断崖式下跌团队却过了一个星期才发现。5. 踩坑实录与高频问题排查速查5.1 五个高频故障及排查方法多Agent项目跑久了难免碰到以下问题我这里按“现象-原因-方案”格式化整理方便你直接当工具表查。故障现象常见原因排查与解决方案工具反复被调用但参数总是错工具参数嵌套过深或描述边界模糊改成平面参数结构补全描述中的适用场景和边界条件上下文越长回复质量越差历史消息冗余、摘要记忆没触发设置消息历史阈值引入摘要压缩裁剪工具返回值两个Agent互相“让贤”Handoff触发条件宽泛显式定义交接理由收紧交接触发条件设置最大交接轮数用户问常识性问题也触发知识库检索路由策略没有识别“不需要工具”的场景在Router的提示词里显式声明“不触发工具”的判定条件升级模型后回答风格突变没有语义回归测试建立固定用例集改版后先灰度对比线上效果再全量切换5.2 我自己摸出来的几条调试心得最后说几条常规文档里不会写的东西。第一给工具描述做A/B测试。我原以为工具排错只在逻辑层后来发现工具描述写着“计算员工报销额度”和“根据公司报销制度计算员工当年可报销剩余额度”模型触发工具的准确率差异非常明显。描述里带上“边界条件”和“预期返回结构”会让模型的理解准确度上一个台阶。建议每次改动工具描述后都拿固定用例集跑一遍对比效果。第二用小样本集做快速回归。不用建几千条用例的大测试集几十条覆盖典型场景的用例就够日常回归了。每次调完Prompt或工具本地先跑一遍这小几十条能拦住大部分劣化。第三成本算总账别只看单次调用价格。多Agent架构下一次用户请求可能产生5到10次模型调用。把全链路都算进去之后有些看起来“单次很便宜”的小模型选择实际总成本反而更高因为它的推理能力不足导致需要更多轮重试和修正。综合考量后选择一个中等规格模型往往比“省钱用小模型”更划算。结尾写到这里正好是系列第五篇的收尾位置。按系列规划下一篇会聊更进阶的微调与对齐话题这里预告一句也不算剧透。回到今天讲的内容。从单Agent到多Agent系统表面上改写的是代码结构实际上是变换了思考方式。你得先能拆解业务才谈得上构建Agent你得先承认模型不是万能的才愿意给它配工具、配记忆、配知识库你得先接受线上和本地不一样才肯花力气做无状态化、做监控、做回归测试。这些都不是SDK直接教给你的能力但恰恰是Agent项目能不能活下来的关键。我在实际项目中最大的体会是构建Agent的时间分配应该是一分在写提示词和调工具九分在搭观测体系和做回归测试。理由很简单提示词和工具是“开发”而观测体系是“保障”。没有保障体系的开发上线即裸奔。每次踩坑后回头看能让你快速定位“是哪个环节变了”的从来不是直觉而是日志和trace。最后分享一个小技巧作为本期结尾在Agent系统上线前先故意做一次“故障演练”——手动断开知识库接口、模拟模型服务超时、把某个工具返回值改成异常格式然后观察Agent的行为响应是否符合预期。经历过这轮演练的系统上线后的稳定性会让你省很多事。
返回列表