做企业级智能体平台这件事,我从最早的单个Agent问答机器人做起,到后来接手一个要支撑多条业务线的Agent Platform,中间踩过的坑比想象中多得多。很多人以为把几个Agent接上大模型接口,再套一个管理后台就是企业级了,实际上真正的企业级Agent Platform要解决的是多Agent协同、工具接入、状态记忆、权限审计、稳定性治理和成本控制这一整串问题。我以某跨平台系统的设计过程为背景,讲讲怎么从架构层面把这些事情落地。如果你正打算从写Demo走向做平台,或者已经在做Agent落地但被各种工程问题缠住,这篇内容应该能给你一个完整的设计坐标系。
1. 项目背景:为什么企业需要自建 Agent Platform
1.1 从单个Agent到多Agent协作的瓶颈
我最初做智能体时,需求特别简单:用户提问,模型调用订单查询接口,返回结果。整体链路固定、参数固定,代码里写死就行。但需求一旦多起来,单一Agent根本撑不住。
举个例子,某客户申请退款,客服Agent要先判断意图,然后去订单系统查信息,接着调用售后策略Agent判断是否符合退款条件,如果符合,还需要给审批Agent生成一个审核工单。整个过程涉及四五个Agent,每个Agent都有不同的系统调用、不同的上下文需求。如果还在一个代码文件里按if else写,开发和迭代会很痛苦。多Agent协作的复杂度不是线性的,而是组合爆炸的。
这时候就需要平台层:把Agent的任务编排、工具调用、上下文记忆、权限控制、日志追踪都收拢到统一架构里。这就是Agent Platform存在的意义。
市面上的编排框架确实能解决一部分问题,但企业环境有强约束,比如安全审计要可追溯、要对接自研权限体系、要支持人工审批节点,这些硬性要求迫使平台核心链路必须掌握在自己手里。所以很多团队最终都走向了自建平台的道路,我也不例外。
1.2 企业级平台的核心职责
站在企业视角,Agent Platform不只是一个技术底座,它更像一个“操作系统”,给上层业务提供一致的Agent运行环境。我把核心职责拆成五块:任务编排、工具接入、状态管理、安全审计和稳定性治理。这五块在单体脚本阶段和平台化之后,完全是两种做法。
| 职责 | 单体脚本阶段 | 平台化之后 |
|---|---|---|
| 任务编排 | 写死调用链 | 声明式DAG + 人工审批节点 |
| 工具接入 | 每个业务单独联调 | 统一注册中心 + 统一鉴权 |
| 状态管理 | 上下文扔在代码变量里 | 会话记忆 + 工作流状态分离 |
| 安全审计 | 基本靠记录日志 | 全链路Trace + 操作审计 |
| 稳定性 | 宕机靠重启 | 限流熔断 + 可观测告警 |
这五条听起来都像常识,但真正落地时,每一条背后都有不少细节。
另外,自建平台之前先做两个判断:团队是否有长期投入智能体的计划,是否有多条业务线可以复用同一个底座。如果只是做一个短期项目,那真没必要自建平台,直接在一个框架里写死就够。只有当你看到“Agent能力会被多个业务方反复使用”这个信号时,平台化才值得投入。
2. 架构设计的三个关键层
2.1 协同调度层:让多个Agent并行干活不乱套
协同调度层是整个平台的骨架。我最初用的编排方式是Pipeline,也就是一个Agent干完传给下一个。简单场景没问题,但是遇到分支和并行就绕不过去了。比如用户查订单时,既要查物流,又要查优惠券,还可能要查库存,这几个查询互相独立,完全可以并行。Pipeline就只能串行,白白增加响应时间。
后来我换成了基于DAG的任务编排。每个任务是一个节点,节点之间通过依赖关系连接。调度器只负责按拓扑顺序执行节点,能做并行的节点自动并行。这个模式不是新东西,但放在大模型场景下特别合适,因为很多任务天然是“先理解,再并行查询,再汇总”的结构。
当时我设计了一个最小可用的编排描述格式,类似下面这样:
{ "workflow": "after_sale_refund", "nodes": [ {"id": "intent", "type": "llm", "params": {}}, {"id": "order_query", "type": "tool", "service": "trade.order.get", "depends_on": ["intent"]}, {"id": "coupon_query", "type": "tool", "service": "trade.coupon.get", "depends_on": ["intent"]}, {"id": "policy_check", "type": "llm", "depends_on": ["order_query", "coupon_query"]}, {"id": "approval_create", "type": "tool", "service": "oa.workflow.create", "depends_on": ["policy_check"]} ] }这段配置表达的意思:先识别意图,然后并行查询订单和优惠券,再做策略判断,最后创建审批工单。调度器拿到图之后,先做环检测,再按依赖执行。这里我踩了个坑:节点执行完不能只认“成功”,要分“成功”“失败”“需要人工介入”三种状态。因为模型生成的流程不是每次都能顺利跑完,有些情况必须停下来等审批。
编排引擎的选型上,我的经验是不要一上来就追求最复杂的方案。如果你的团队人数不多,先自研一个支持DAG、嵌套子流程、人工审批节点的轻量引擎,比引一个庞然大物再二次开发更容易掌控。但如果团队已经有成熟的流程编排中间件,直接复用它的执行底座,再把LLM节点和工具节点接进去,会更稳。
也有一部分架构师倾向于让模型自己做规划,也就是Plan-and-Execute,让Agent自己生成执行计划。这种做法在技术Demo里很漂亮,但在企业环境里,模型生成的计划不稳定,涉及资金操作时尤其可怕。我认为更稳妥的做法是:业务流程由平台和产品定义成模板,模型在模板边界内做参数填充和分支判断。我的设计原则是:让模型做决策,但不要让它定义流程。
2.2 工具接入层:把企业内部系统变成Agent的手脚
企业级Agent Platform最难的不是模型层,而是工具接入层。内部系统非常多,不同系统的接口风格、鉴权方式、返回结构都不一样。如果不做统一抽象,每个Agent直接对接系统,最终会疯掉。
我采用的方式是做统一工具注册中心。每个工具对外暴露一份描述文件,包含工具的名称、用途描述、入参JSON Schema、出参结构、调用方式、超时时间、权限码等。模型层通过Function Calling机制来选工具,但真正的调用逻辑统一由平台执行。这个设计的价值在于:模型不需要关心工具的内部实现,只需要读懂描述文件并生成结构化参数。
举个实际例子:订单查询工具的描述文件里写清楚“根据订单号或用户ID查询订单基础信息,返回订单状态、金额、商品列表”。模型根据用户语义生成参数,平台再校验参数是否合法、用户是否有权限,最后才真正调接口。
这里要给出一个非常重要的建议:工具描述要写得像给新人看的接口文档,不能只写一句“查询订单”。模型选工具的准确率很大程度取决于描述质量。我当时带着团队把所有高频工具的描述重写了三轮,每次都是根据线上选错工具的Case去修正描述里的边界词。
安全方面,工具分为查询型和写操作型两类。查询型工具可以允许Agent自动调用,写操作型工具必须增加审批节点。有些团队贪图流程顺畅,让Agent直接执行退款、改价一类的操作,风险很大。我见过一个Case,模型把促销活动的折扣率理解错,险些对整个价格体系造成影响。所以平台必须做强管控。
注意:所有敏感工具的调用都要走审批,审批动作本身也要入审计日志。这是企业级平台和Demo之间最大的分水岭。
2.3 记忆与状态层:让Agent记得住、续得上
Agent Platform第三个关键层是记忆与状态。很多人在做单Agent时都忽略这个,直接用messages列表把所有历史塞给模型。到了平台级,这个问题会变成三个子问题:会话内短期记忆、跨会话长期记忆、流程状态记忆。
短期记忆我直接用Redis存最近的N轮消息。N一般取6到10轮,超过这个窗口就丢给摘要Agent压缩成历史摘要,和最近几轮一起拼进Prompt。这里注意,不要把整个会话无脑塞给模型,一个是Token浪费,另一个是噪音太多导致注意力被稀释。用户之前提到过的一个关键订单号,是可以被少量关键信息覆盖的,没必要把全部聊天记录都保留。
实操心得:不要把所有历史都塞给模型。6-10轮短期消息 + 历史摘要 + 结构化业务上下文,是性价比最高的组合。
跨会话长期记忆我用的是向量库加关系库的组合。向量库存用户长期偏好和业务实体,关系库存结构化数据比如“用户上次咨询的时间”“未完成的工单编号”。在每次会话开始时,平台会先做一个记忆召回,把当前用户相关的实体和偏好注入上下文。这一步做好之后,Agent看起来就“记得你”。
流程状态记忆最容易在设计时被漏掉。企业场景里一个流程可能要跑十几分钟甚至几小时,中间如果有一步失败,不能推倒重来。我设计了基于状态机的流程持久化,每个节点执行前后都把状态写进数据库。这样如果某个Agent实例重启,可以从最近一个快照恢复。节点状态分Pending、Running、Succeeded、Failed、Blocked、NeedApproval。有了这个状态,也可以在管理后台直观看到整个流程走到哪了。
3. 核心模块实现与踩坑实录
3.1 任务编排引擎的选型与二次改造
核心模块第一块就是编排引擎。前面提到我选择了基于DAG的轻量自研方案,具体落到实现上,有几个关键点。
第一个关键是节点抽象。节点类型至少要有四种:LLM节点、工具节点、条件判断节点、人工审批节点。LLM节点负责调用模型,工具节点负责执行已注册的企业服务,条件判断节点用模型或规则决定走哪个分支,审批节点把流程暂停等待人工处理。节点之间通过上下文对象传递数据,这个上下文对象就是平台里流动的“工作记忆”。
第二个关键是循环检测和深度限制。模型在编排中生成分支时,可能会出现A依赖B、B依赖A的非法情况。我实现了一个基于DFS的环检测,每当流程定义变更或动态生成时,先校验一遍。同时在运行时加最大深度限制,比如超过20层直接终止并告警。这个深度限制非常重要,后面我会单独讲一个真实死锁事故。
第三个关键是热更新。企业业务经常要调整流程,不可能每次改一个节点都发版。我把流程定义做成配置化,存到数据库里,管理后台可以修改节点参数、调整依赖关系。平台支持灰度发布:先切一小部分流量到新流程,对比成功率再全量。这一步做下来,业务方对平台的满意度提升非常明显。
3.2 上下文管理与长期记忆的存储方案
这里详细讲讲上下文怎么做。我最初跟所有人一样,把messages当字符串拼一拼就发给模型。后来发现两个问题:一是长期会话把上下文窗口直接跑满,二是多Agent之间传参依赖自然语言,容易产生歧义。
我的做法是把上下文分成三层:内存层、缓冲层、持久层。内存层就是当前Prompt里实际看到的内容,一般包括系统提示、工作流摘要、最近几轮对话、当前业务上下文。缓冲层是最近N轮的完整消息,存Redis,用来生成摘要和补充细节。持久层就是上面说的向量库加关系库,存长期记忆和流程快照。
多Agent传参方面,我强烈建议不要用自然语言段落做接口。比如客服Agent把“用户想退款,订单号是ABC123”传给工单Agent,看起来没问题,但一旦句子长了,后一个Agent提取关键信息很容易出错。后来我们改成结构化传参:每个节点输出都尽量输出稳定字段,比如{intent: "refund", order_id: "ABC123"}。LLM节点在Prompt里明确要求返回JSON结构,平台再做一次schema校验。表面上看多了一个校验步骤,实际上大大降低了幻觉沿链路放大的概率。
长期记忆的更新策略也值得说。不是所有用户说过的话都值得存,我设定了一套规则:只有涉及具体业务实体、用户明确表达偏好、或者被策略判断为“重要事件”的内容,才写入长期记忆。否则都把记忆库塞满垃圾,召回时反而干扰判断。
3.3 权限隔离与安全审计的落地细节
企业级平台的权限隔离不能靠模型自觉,必须在平台层做硬隔离。我当时设计了一套三级模型:用户身份、Agent身份、工具权限码。
用户身份从统一登录系统接入,包含部门和角色。Agent身份指的是每个Agent在平台上注册时的服务账号。工具权限码用于标识某个工具需要的权限级别,比如订单查询需要read:order,创建退款单需要write:refund。当用户发起请求时,平台会组装一个三元组:用户身份加Agent身份加目标工具权限码,然后到权限中心校验。只有用户本身有这个权限且Agent被授权调用这个工具,调用才会放行。这个逻辑听起来复杂,但实现成一套中间件后对业务透明。
安全审计方面,我给每次Agent调用生成全局Trace ID,从用户请求进入开始,到模型响应、工具参数、工具结果、最终回复,全部记录成结构化日志。日志里包含每个节点的输入输出摘要、模型名、Token数、耗时、状态码。这些日志进入统一的日志平台,保留至少90天。做这个事最大的价值不是事后追责,而是当你需要复现一个坏Case时,能够把完整链路拉出来看,定位是模型问题、提示词问题还是工具数据问题。
还有一个容易被忽略的点:审计日志里不能只记成功请求,失败的、超时的、被拦截的请求更要记录。很多时候线上隐患就藏在一批被权限系统拦掉的异常调用里,这些调用恰恰反映了某个Agent正在尝试越权操作。
4. 性能优化与稳定性治理
4.1 高并发下的限流与熔断设计
平台一旦接入多条业务线,流量就不是单个Agent时那种量级了。我见过最夸张的情况是某个运营活动上线,一下把模型API配额打满,紧接着下游服务被拖垮。从那次之后,限流和熔断就成了平台的第一优先级。
限流要分三层:第一层是用户维度的限流,防止单个用户刷接口;第二层是Agent维度的限流,防止某个Agent把资源耗尽;第三层是模型API维度的限流,保护上游模型服务的配额。每一层都用了独立的令牌桶,配额写在配置中心,支持业务高峰期临时调整。
熔断的触发条件要精细设计。最简单的方案是连续N次调用超时或返回错误就打开熔断器,但不同模型服务的表现差异很大。我的做法是维护一个滑动窗口,统计最近一分钟的错误率和P95时延。错误率超过10%或P95超过设定阈值时,触发半开状态,放少量请求探测;恢复后再关闭熔断。对于Agent场景,熔断后的兜底方案不能只是一个报错页面,而是让平台返回一条“当前服务繁忙,请稍后再试”的答案。业务方对这个兜底逻辑接受度很高。
这里还要提一个并发细节:DAG中并行节点会放大对模型API的压力。比如一个流程里有5个节点可以并行,那么这一瞬间就会同时发出5个模型请求,如果全平台同时有很多请求进来,压力会非常猛。所以在调度器里我做了一个“并发令牌”控制,每个流程同一时间最多只允许N个模型请求在途,超出部分排队等待。这比单纯靠上游限流更直接,也避免了瞬时尖峰打爆调用配额。
4.2 可观测性:追踪一次Agent决策的完整链路
普通后端接口的Trace是一条线,Agent调用则是一张图。一个用户请求可能触发多个LLM节点和多个工具节点,每个节点之间还有依赖关系。所以我们把Trace设计成了Span树:根Span是用户请求,子Span是每个节点执行。每个Span都记录自己的开始时间、结束时间、输入摘要、输出摘要、模型名、Token消耗、状态。
这套追踪系统上线后,定位问题的效率提高了很多。以前要凭日志猜,现在直接在看板上看节点耗时,一眼就能发现哪一步模型调用太慢,哪一步工具报错。我给团队的硬性要求是:线上所有Agent运行记录必须可以回放。也就是说,通过Trace ID能把当时的输入输出重新展示出来。这不仅是排查工具,也是优化提示词的第一手数据。
如果要再进阶,还可以把每个节点的输出做一次一致性校验。比如工具节点返回的订单状态是“已关闭”,但最终回复却告诉用户“退款成功”,这就是明显不一致。后来我在平台加了一个简单规则:关键业务输出必须与工具结果一致,不一致的回复会被拦截并告警。这个规则救了很多次。
可观测性的另一个层次是业务指标监控。除了技术指标,还要统计每个流程的完成率、转人工率、平均节点数、平均Token消耗。这些指标能反映Agent平台真正的业务价值。比如某个流程完成率一直在降,可能不是模型坏了,而是工具接口返回的数据结构变了,模型解析不了。这类问题如果没有业务指标,很难被及时发现。
4.3 成本控制:Token用量与响应时延的平衡
跑企业级Agent Platform,最大的持续成本几乎都是模型API费用。我做过一次统计,一个中等复杂度流程平均要消耗一万多Token,如果日均十万次调用,费用相当夸张。所以成本控制必须作为一个架构模块来做,而不是事后看账单。
我用了三个手段。第一是缓存。对高频且答案稳定的问题,比如常见业务政策、操作指南,做语义缓存。用户提问先经过一个向量检索,如果相似度超过阈值,直接返回缓存答案,不再调用模型。这个功能上线后,模型调用量直接下降了接近四成。
第二是模型路由。不同任务用不同规格的模型:意图分类、实体抽取这类简单任务用便宜的小模型,生成回复、策略判断这类复杂任务用大模型。平台侧维护一张路由表,根据业务规则和输入复杂度决定调用哪个模型。这个过程要一直监控质量,不能只看价格。
第三是流式输出与业务解耦。不是所有场景都需要等完整回复才能展示,平台层支持SSE流式返回。但也有些后端逻辑必须在拿到完整结果后才能执行下一步,这时候就关掉流式,避免额外复杂度。我这里的建议是:流式是体验优化,不是性能优化,不要为了炫技把它用在流程编排里。
成本上还有一个小技巧:对LLM节点生成的中间结果做复用。比如同一个请求里,两个节点如果用到相同的策略判断,可以共享一次模型调用的输出,而不是让两个节点各调一次。这个在流程设计阶段就要注意,避免出现重复计算。
5. 上线后遇到的真实问题和排查记录
5.1 循环调用与死锁的识别与处理
上线之后遇到最离谱的问题是两个Agent互相调用,形成无限循环。事情是这样的:风控Agent需要调用人工客服Agent确认用户资质,而人工客服Agent又会在拿不到用户信息时调用风控Agent获取风险等级。某个用户请求恰好触发双方互相等待,最后消息直接螺旋上升,把底层服务搞到响应超时。
排查方式是通过Trace发现两个Agent的Span ID交替出现,且深度一直在涨。我赶紧加了平台级保护:所有Agent之间的调用必须记录调用链,如果深度超过预设值就直接终止。随后又加了循环检测,当一个Agent准备调用另一个Agent时,先检查这个目标是否在自己当前的调用链上游,如果是,就拦截并提示走人工处理。
这个Case让我认识到,企业级Agent平台必须像对待线程死锁一样对待Agent死锁。你可以不完美解决,但一定要能自动识别和熔断,把影响控制在一个请求内。
还有一个相关问题是超时设置。如果某个工具节点一直不返回,LLM节点会一直等待,导致整个流程悬挂。我后来给每个节点都设置了独立的超时时间,并且超时后不是直接失败,而是进入“降级分支”。比如查询物流超时,可以先用订单状态给用户一个近似回答,而不是让用户干等。
5.2 多Agent协作时的幻觉放大问题
另一个高频问题是幻觉沿着Agent链路被放大。单Agent偶尔产生幻觉,影响范围还小;多Agent接力的时候,一个Agent的错误输出会成为下一个Agent的输入,错误会被二次加工,变得更自然、更可信。
我遇到过一个退款审核场景:客服Agent把订单号识别错,工单Agent用这个错误的订单号查询,查不到信息,但它没有停,而是根据“用户想退款”这个意图,自动假设了一堆订单详情,生成了一个看似完整的退款方案。最终要不是审批人看过一眼,这笔业务就要出问题。
解决思路是三层夹击。第一层:关键实体必须从工具结果中获得,禁止LLM凭空生成。第二层:每次工具调用后,都要有一个校验节点,把工具返回结果和LLM声称的事实做一致性比对。第三层:对高风险操作,要求模型输出置信度,低于阈值就转人工。这套机制加上去之后,类似问题基本被挡住了。
在实际执行中,校验节点不一定每次都要调用模型做复杂判断。很多是简单规则,比如订单号是否为纯数字、长度是否合法、订单状态是否在枚举值内。先做规则校验,再做模型校验,成本会低很多。
5.3 模型切换时的兼容性坑
企业平台不会永远只用一家模型服务。随着业务升级,难免要换模型或者同时用多个模型。这时候就会发现,不同模型在Function Calling、JSON格式遵循、上下文长度上的表现差异很大。最坑的一次是切新模型后,工具参数频繁漏传,导致订单查询一直失败。
后面我把模型接入做成了适配器模式。每个模型是一个适配器,统一暴露四种能力:文本生成、工具调用、结构化输出、向量化。平台核心只依赖适配器接口,不直接依赖某家模型。切换模型时只需要调整适配器实现,而业务流程完全不用改。
还有一个很关键的经验:任何新模型上线前,必须跑一遍录制的回放测试。也就是把过去一周线上真实请求的输入输出录下来,用新模型重放一遍,对比关键字段的准确率和格式正确率。对比通过后,再用灰度流量逐步放量。千万不要图省事直接全量切换。我见过直接切换导致线上持续故障半个小时的案例。
模型切换还会暴露一个隐藏问题:不同模型对系统提示词的敏感度不一样。同一个Prompt在旧模型上表现很好,新模型上可能废话连篇或者频繁拒绝回答。所以回放测试里不仅要比准确率,还要比输出长度、拒绝率、格式遵循率,这些指标在灰度阶段都要盯紧。
5.4 复盘:几个反常识的设计决定
最后复盘几个当时觉得反常识但事后证明正确的决定。
第一个:不要把所有Agent都做成“自由发挥”型。平台定义好流程边界,模型只做参数填充。一开始团队觉得这样太死板,但实际运行后发现,越自由越容易失控,越有边界越好用。
第二个:不要迷信最便宜的小模型。成本控制里模型路由确实能省钱,但省钱的底线是质量。有些简单任务用小模型看似可以,上线后却发现识别错误率升高,反而导致下游更多校验和重跑,总成本更高。我后来把质量监控和成本报表放在同一个看板里,每次省成本都要看准确率曲线。
第三个:管理后台不只是一个配置界面,它本身也是平台的一部分。早期我把后台放在很靠后的优先级,后来发现业务方最需要的不是炫酷的模型能力,而是能看见流程走到哪、为什么卡住、怎么干预。后台的审批和干预能力做得好,平台才能在企业里真正被信任。
第四个:日志记录要从第一天就做,千万别等到出了事故再补。很多问题发生后,如果没有完整链路日志,连复盘都无从谈起。Agent平台的决策链路比普通接口复杂得多,没有日志就等于在黑暗里开车。
这几个决定看起来都不复杂,但在项目过程中每一步都顶着“快速上线”的压力。企业级Agent Platform没有捷径,所有“看起来麻烦”的设计,最后都会在故障和事故里把成本捞回来。