☰
多Agent系统架构设计与工程落地:从编排式到蜂群式的实践指南
2026/10/17 14:33:16 网站建设 项目流程

上一篇把评测与幻觉治理聊透了,这篇终于该说说多Agent系统。系列走到第五篇,站在我们前面的是一个更尴尬的处境:单Agent已经跑通了业务流程,但压不住复杂度,功能一多,提示词越长,上下文越臃肿,工具选择越慢。于是自然想到把任务拆开,让几个Agent各管一段。这个方向是对的,但大多数团队会在“拆开之后”迅速踩坑:消息乱飞没人收,状态散落到处改,A的幻觉被B当成事实拿去用,最后整个系统跑得像一个失控的部门。

今天我们就把这块彻底拆开:多Agent系统到底解决什么问题,编排式和蜂群式差在哪,通信与状态怎么管,Harness Engineering在体系里具体管什么。这篇不会停留在概念图,而是直接带你搭一个能跑的最小多Agent系统,再把生产中高频踩的坑列成排查表。

1. 为什么多Agent不是炫技而是架构需求

1.1 单Agent的痛苦清单

先说一个非常典型的场景。你在做一个智能客服数据分析系统,最初是一个Agent负责全部:读用户对话、提炼诉求、查订单、生成回复、判断是否需要人工介入。业务量小的时候还好,数据量一上来,几个问题会同时爆发。

第一是上下文膨胀。每次分析都要把用户对话、商品信息、历史订单塞进同一个上下文,prompt越长,模型注意力越分散,输出质量肉眼可见地下降。第二是工具选择的冲突。同一个Agent手里挂着查询订单、发送通知、修改工单、读取知识库等十几个工具,每一步推理都要在大候选集里挑一个,模型在工具选择上的耗时会显著增加,而且选错的概率同步上升。第三是单点失败。只要其中一个环节出错,比如订单查询超时,整个流程跟着断掉,重来就是全部重来,浪费的不只是时间,还有token预算。

还有一个更隐蔽的问题:职责边界不清。当“读对话”和“生成回复”绑在同一个Agent里,模型的风格约束和事实提取逻辑杂糅在一段prompt里,容易互相干扰。你希望它在提取诉求时严格客观,又希望它在生成回复时温和亲切,两套要求同时压在同一个上下文里,模型只能折中。

我一直认为,多Agent出现的根基其实不在“AI更聪明”,而在工程上的职责隔离。

1.2 多Agent真正解决的三个问题

多Agent系统最常见的价值认知是“并行处理”,但实践中它的核心收益其实是另外三件事。

第一是失败隔离。把一个长链路拆成多个独立Agent之后,日志分析子任务失败,只需要重跑它,报告生成子任务的结果可以保留在存储里。这在办理实时性较强的业务时是决定性的差异,单Agent是全局崩溃,多Agent是局部重试。

第二是工具集收敛。给每一个Agent只挂它真正会用到的两三个工具,工具选择空间大幅缩小,模型的判断压力也随之下降。实测下来,一个Agent挂超过八个工具时,选错工具的频率会明显上升,而拆开之后每个Agent只挂两三个工具,不仅更稳,单次调用的响应速度也会快不少。

第三是策略可按角色单独调整。每个Agent有自己的system prompt和温度参数,日志分析Agent可以把温度调到最低以求确定性,报告生成Agent可以适当调高让表达更自然,客服回复Agent可以单独配置敏感词拦截。这些策略在单Agent体系里搅在一起,根本没法独立优化。

1.3 判断是否需要多Agent的标准

并不是所有任务都需要多Agent。我见过有的团队把一句话能解决的事情拆成五个Agent,结果链路变长、成本翻倍、效果变差。要不要拆,用下面几条标准判断。

第一,任务是否天然分阶段,且不同阶段的输入输出形态差异大。比如采集、分析、生成、发送,这是天然分阶段的任务,适合拆。而“帮我写一封邮件”这种端到端创作,拆了反而破坏语感。

第二,子任务之间是否存在独立的工具和数据源。日志分析Agent只需要读日志库,指标Agent只需要读监控API,两者互不依赖,这种拆开能稳定获益。

第三,是否有局部失败后可以降级处理的场景。如果一个环节失败会导致整个业务无法继续,拆与不拆区别不大;只要存在“失败了能用兜底结果继续往前走”的空间,多Agent就值得考虑。

如果这些条件都不满足,老老实实用单Agent,反而更省钱、更省心。

2. 多Agent的设计范式:编排、蜂群,以及两者之间

2.1 编排式架构的任务分解与派发

编排式架构,也就是Orchestrator-Worker模式,是最容易上手、也是生产中应用最广的一种。一个主控Agent负责任务的接收、理解、分解、派发和汇总,若干个Worker Agent各司其职,执行具体子任务。

这个模式我习惯把它类比成项目经理制。主控是项目经理,他并不亲手写代码,而是拆活、派活、验收、汇总。Worker是执行者,只关心自己手里的这一块,做完回传结果。

编排式的优点非常明确。首先是可观测性好,每一条任务链路都清晰可查:谁派的任务、谁执行的、结果怎么样、卡在哪个环节。其次是可控性强,我可以在主控里对同一类任务定义标准处理流程,凡是走到分支的就按分支逻辑走,不容易乱。再次是责任链路清晰,出问题能直接定位是哪个环节的责任。

缺点也明显:主控是单点瓶颈。如果主控对任务的理解出现偏差,整个分解方向就会跑偏,下面的Worker再怎么稳定也无济于事。另外,主控的上下文也有容量上限,如果我让它把每个Worker的完整结果都拿回来再汇总,这个上下文会很快爆炸。所以在编排式里,主控尤其要克制,它只读摘要,不读全量。

2.2 蜂群式架构的去中心化协作

Agent蜂群借鉴的是生物蜂群的行为模式。它不设全局主导者,而是由多个Agent在共享环境中自由交互:每个Agent带自己的目标和行为约束,通过一组公共通信语义向其他Agent发布信息、响应消息、发起协作。整体行为从局部交互中涌现出来。

蜂群式的优点在于对动态任务适应性强。我可以在不重写主控逻辑的情况下,临时增加一个负责某种特殊信号分析的Agent,其他Agent通过识别它发布的消息类型自动开始协作。这在应对“长尾场景”时很有价值——比如业务里频繁出现未预定义的新异常类型,编排式的固定流程根本处理不了,蜂群可以临时组织一次非正式讨论来收敛结论。

但蜂群式的代价也非常棘手。首先是行为不可预测性强,多个Agent互相响应,可能出现无意义的对话循环,也可能出现没有Agent愿意接手的真空地带。其次是状态一致性难保证,每个Agent只掌握局部信息,难以形成全局视角,当多个Agent同时修改同一个共享存储区,很容易发生相互覆盖。再次是调试困难,一次任务的最终结果很难回溯是哪几个Agent之间交互产生的。

所以我的建议是:生产环境不要轻易上纯蜂群,纯蜂群更适合研究原型或低风险辅助任务。

2.3 折中式:编排主脑加临时蜂群

在实际项目中我落地最多的是第三种模式:以编排为主干,在特定分支上拉起临时蜂群。

主控Agent依然负责主流程的任务分解和派发。但当它遇到一个无法归入已知流程的异常分支时,不再强行按照规则处理,而是临时创建一个协作小组。这个小组由少数几个相关Agent组成,它们共享一个临时存储区,各自把自己掌握的信息写入,互相阅读并回应,进行最多两轮的自由讨论。最后由主控Agent综合小组的讨论结论做最终裁决。

我在一个运维告警场景里用过这个模式。常见告警有固定分类,能走标准流程;但偶尔会出现一种没有历史先例的复合告警,既涉及网络指标又涉及日志异常。主控会让网络指标Agent、日志分析Agent、用户影响Agent临时组成一个小组,三方在共享区里互相补充信息,两轮讨论之后给出一个“可能是磁盘满导致级联故障”的结论,再由主控决定升级路径。这个机制上线后,未分类告警的误判率明显下降了,而且没有牺牲主流程的稳定性。

折中模式的好处在于,它既保住了编排式的稳定主干,又能通过局部蜂群覆盖动态长尾,是工程上投入产出比最高的方案。

3. 通信、状态与上下文:让Agent合得来的底层机制

3.1 设计一套最小可靠的消息协议

多Agent系统里最容易被低估的部分就是通信协议。很多团队一上来让Agent之间互相直接调用,A直接调B的接口,B直接调C的接口,代码写得飞快,上线之后一片混乱:消息依赖隐式耦合、失败后不知道消息去哪了、想重试又找不到幂等标识。

我建议每个团队都定义一套最小的消息协议。下面是一份我在项目中普遍使用的消息负载示例。

{ "message_id": "msg_202502131234_001", "trace_id": "trace_8f4e2a1c", "sender": "log_analyzer", "receiver": "report_writer", "msg_type": "task_result", "task_id": "task_0187", "timestamp": "2025-02-13T12:34:56Z", "payload": { "status": "SUCCESS", "summary": "检测到3个P2级异常事件,均与订单服务超时相关", "refer": "storage://result/task_0187/full.json" }, "schema_version": "1.0" }

这套消息里有几个字段是我坚持保留的:message_id用于消息幂等,trace_id贯穿全链路追踪,task_id关联具体任务,msg_type区分消息类型,payload里尽量只放摘要和引用,不放全量数据。大对象写到对象存储,消息里放个引用地址,否则一张几MB的分析结果在Agent之间传递,会拖慢整个链路并烧掉大量token。

3.2 服务注册与发现机制

多Agent系统必须解决一个基本问题:怎么知道当前有哪些Agent在线、各自负责什么、处于什么状态。我在工程里会为每个Agent保存一份注册信息,Agent启动时自动注册,关闭时自动注销。

注册信息至少包含:Agent名称、角色描述、可用工具列表、当前状态(空闲/忙碌/熔断/下线)、支持的请求类型。主控Agent在分配任务时先去注册表里查找具备对应能力的Worker,而不是写死调用某个Agent的地址。这样新增一个Agent不需要改主控代码,只要注册表里多一条记录,主控在派活时就会把它纳入候选。

一套简单的注册表示例用结构化数据表示大致是这样:

agent_registry = { "log_analyzer": { "capabilities": ["log_parse", "event_extract"], "status": "idle", "endpoint": "agent://log_analyzer", "tools": ["parse_log", "query_event_db"] }, "metric_analyzer": { "capabilities": ["metric_anomaly", "trend_check"], "status": "busy", "endpoint": "agent://metric_analyzer", "tools": ["query_metric", "threshold_check"] } }

注册表用磁盘存储而不是内存,因为进程重启后Agent需要能从注册表恢复拓扑。这是很容易被忽略的细节:一旦主控重启而注册表信息丢失,所有Worker的调用关系就全断了。

3.3 任务状态与生命周期管理

多Agent的任务状态不能放在内存里。我见过有人用Python字典存任务状态,开发时跑得很欢,上线一重启全没了,所有进行中的任务变成孤儿。

正确的做法是任务状态持久化,并定义清晰的生命周期。一个任务通常经历这些状态:pending(等待分配)、running(执行中)、succeeded(成功)、failed(失败)、retrying(重试中)、timeout(超时)、canceled(取消)。

用一个简单的状态机表来记录:

状态触发条件下一步动作
pending任务创建主控分配Agent
runningWorker领取任务等待执行结果
succeeded返回成功进入汇总或下一步派发
failed返回失败判断是否重试
retrying失败且重试次数未达上限重新进入pending
timeout超过时限未返回走兜底逻辑并局部重试
canceled主动取消或熔断释放依赖资源

状态存储我建议用数据库表,并带上updated_at时间戳。这样即使某个节点崩溃,也能通过扫描超时状态把这个任务捞回来重新派发。数据库里的每一条记录都相当于系统的一个“心跳”,多Agent系统能不能稳健运行,很大程度取决于状态管理是否扎实。

3.4 上下文隔离与信息摘要

上下文隔离是我认为多Agent系统里最核心、也最容易做错的一个点。很多团队把全部内容塞在一个公共上下文里让所有Agent共享,这等于把多Agent硬生生做回单Agent,上下文污染必然发生。

正确的做法是每个Agent只有自己职责范围内的上下文窗口。子Agent执行完任务后,向外部只暴露摘要和结构化结果,不暴露推理过程。主控Agent看到的不是“日志Agent读了哪些日志、做了哪些过滤、中间经历了什么思考”,而是“日志Agent产出的事件列表、置信度、完整结果引用地址”。这些摘要信息才是Agent之间传递的“通货”。

这里有一个很实用的技巧:对每个Agent定义“输出模板”。比如日志分析Agent的输出固定为:异常事件列表、事件级别、涉及服务、置信度、完整报告引用地址。强制执行这个模板之后,Agent之间的信息流会变得非常规律,后续无论是主控汇总还是报告生成,都能稳定消费这些结构化输出,不会因为某个Agent多写了一段无关文字而污染下游。

3.5 全链路追踪与日志规范

多Agent系统的排查难度会随着Agent数量翻倍增长,所以可观测性必须从第一天就建立起来。

最朴素有效的方法是给每次请求生成一个trace_id,并让它渗透到所有子任务的日志里。加一条规定:所有Agent的每条日志输出都必须包含trace_id、agent_name、task_id、timestamp。这四个字段缺一不可。

日志打的时机也要定好:收到消息时打一条“received”,开始执行时打一条“start”,执行结束时打一条“succeeded/failed”,发往下一个Agent时打一条“sent”。这样在排查一条挤压了很久的任务时,我可以直接按时间线把整个链路里的日志全部捞出来,看到它每一步经历了什么。我在早期项目里就是因为日志只打结论不打过程,排一个通信问题排了两天,最后才发现是消息根本没发出去。

4. 实操:搭一个跨部门协作的多Agent运维值班系统

4.1 场景与Agent角色设计

下面用一个真实场景把前面所有机制串起来。假设我们要为一个中等规模的在线服务搭一个“智能值班助手”,它能接收告警事件,自动分析原因,生成处理建议,必要时升级到人工。

按职责拆分成四个Agent:

  • 值班主控(ShiftLeader):接收输入,负责任务分解、派发、汇总和最终决策判断。
  • 日志分析Agent(LogAnalyzer):读取告警时段的相关日志,提取异常事件和错误码。
  • 指标异常Agent(MetricAnalyzer):读取服务监控指标,判断延迟、错误率、饱和度等变化趋势。
  • 报告Agent(ReportWriter):基于前两个Agent的结构化结果,生成给运维人员看的总结报告和SOP建议。
  • 升级Agent(Escalator):当主控判断告警级别高或派发失败时,将信息写入人工工单系统。

角色拆分的核心原则是:职责互斥、工具隔离、依赖单向。主控不碰具体日志和指标数据,只做调度和决策;日志Agent不负责写最终报告;报告Agent不访问原始日志,只消费结构化结果。

4.2 基础设施与通信层搭建

通信层我直接用消息总线实现,不采用Agent之间的直接RPC调用。总线的核心价值是解耦:发送方不需要知道消息会被谁消费,接收方也不需要知道消息来自谁,只需要按msg_type和receiver匹配。

在代码层面,一个最小的消息总线原型可以长这样:

class MessageBus: def __init__(self): self.queues = {} def publish(self, msg): receiver = msg.get("receiver") if receiver: self.queues.setdefault(receiver, []).append(msg) else: # broadcast to all agents with matching msg_type for agent_name in self.queues: if msg["msg_type"] in self.subscriptions.get(agent_name, []): self.queues[agent_name].append(msg) def consume(self, agent_name): if agent_name in self.queues: return self.queues[agent_name].pop(0) return None

实际生产里我当然不建议用内存队列,这个原型只是为了说清楚机制。工程上可以用合适的消息中间件,每个Agent消费自己的独立队列,保证一个Agent崩溃不会影响其他已有消息的投递。

4.3 主控Agent的执行逻辑

主控Agent干活的方式不是自己闷头处理,而是生成任务计划、派发给下游、收集结果、做决策。它的执行逻辑大致是:

收到新告警事件 -> 读取告警级别与类型 -> 根据类型生成派发计划(发给LogAnalyzer和MetricAnalyzer并行执行) -> 等待两个Worker返回结构化结果(带超时30秒) -> 读取摘要与置信度 -> 如果明确且置信度高,进入汇总阶段 -> 如果存在不明确分支,拉起临时蜂群小组协商 -> 汇总后把摘要交给ReportWriter生成报告 -> 根据严重级别决定是否触发Escalator -> 输出值班决策

这里有一段伪代码:

def handle_alert(alert): plan = create_plan(alert) # 返回["log_analyzer", "metric_analyzer"] send_to_bus(plan, trace_id) results = wait_results(plan, timeout=30) if results["log_analyzer"].status == "unclear" \ or results["metric_analyzer"].status == "unclear": results = run_swarm_brainstorm(results, trace_id) summary = digest(results) # 只取摘要,不取全量 report = request_report_writer(summary, trace_id) if alert.severity >= 3: request_escalation(report, trace_id) return report

主控的prompt我会写得非常克制:它的人物设定是“一个冷静、谨慎的值班班长,只做调度与决策,不代替专业Agent执行分析”。因为一旦它觉得可以自己分析,就会尝试读原始日志,要么上下文爆炸,要么和下游Agent的结论冲突。主控必须学会不干活。

4.4 子Agent的独立执行与结果回传

子Agent是被动的:它监听自己的队列,收到任务消息后开始执行,执行完按约定模板回传结果。它的核心保护在于,Agent进程自身不处理调度逻辑,只处理分内工作。

LogAnalyzer的执行逻辑:

收到task_request -> 按消息里的参数读取指定时间段日志 -> 过滤已知正常模式,提取异常事件 -> 每个异常事件给出级别和置信度 -> 把完整结果写入对象存储 -> 回传结构化摘要

回传的摘要控制在五条以内。如果异常事件数量很大,只把最重要的事件放进摘要,完整列表写在引用地址里。这样不仅能避免主控上下文膨胀,也能避免报告Agent在一次生成时被埋在几百条事件里。

MetricAnalyzer同样如此,它返回的是指标维度的判断:错误率是否突增、延迟是否劣化、异常起始时间点、相关性信息。两个Worker的结果是平行的,它们不直接通信,而是由主控在收到结果后做归并。

4.5 临时蜂群小组的建立与收敛

前面提到过,遇到未预定义的复合告警时,我会拉起一个临时蜂群。具体机制如下。

主控判断告警类型没有匹配到任何已知流程,于是创建一个临时协作会话:LogAnalyzer、MetricAnalyzer、以及一个可选的用户影响Agent被加入同一小组。它们在同一个共享公告区中写入自己的结论,并允许阅读其他人的结论。

规则控制非常重要:最多两轮自由回应。第一轮各自发布观点,第二轮阅读他人观点后做补充或修正;两轮结束后主控强制收敛,综合讨论内容做出裁决。这个限制是为了防止Agent之间没完没了地“对话”,把任务耗死在循环里。

在测试阶段,我发现如果不强制限制轮数,Agent们会在共享区里越聊越远,从技术问题聊到业务影响再聊到历史类似事件,这种发散并不是我们需要的。两轮足够让关键信息交汇,剩下的由主控做判断即可。

4.6 全局治理机制:权限、熔断、配额

如果说编排逻辑是多Agent系统的大脑,治理机制就是安全带。没有它,系统有多聪明就有多危险。

权限方面,每个Agent绑定自己的独立身份。主控能读取任务队列和注册表,但不能执行文件操作,也不能调用外部API;LogAnalyzer能读取日志库,但不能修改日志,更无权发送外部消息。所有对外API请求走统一网关,网关负责鉴权、限流和审计记录。

熔断方面,每个Agent配一个错误率监控。比如LogAnalyzer连续返回schema校验失败的次数超过5次,自动把它的注册状态置为“熔断”,不再分配新任务,同时通知值班人员介入。这里要有手动的恢复开关,等排查完再解除熔断。

配额方面,多Agent系统的成本控制比单Agent更紧迫,因为多个Agent并行起来,token消耗速度会让人措手不及。我的做法是双层预算:单Agent单任务预算(比如一次子任务最多消耗8000 token),以及全局小时预算(比如整个多Agent系统每小时不得超过10万token)。任一预算超限,主控直接拒绝新任务进入,已有任务允许执行到自然结束,但不接受新请求。

5. 稳定性增强的四个关键设计

5.1 幂等与重试机制

多Agent系统不重试是不可能的,但不设计好重试就会产生重复副作用,比如一次告警的工单被创建三次。解决思路是:每个消息都带task_id,执行方在处理前先检查这个task_id是否已经处理过;如果处理过,直接返回上一次的结果,不再重新执行。

我把这个机制看作Agent版“消息去重”。尤其是在发送工单、发送邮件、修改数据库这类有副作用的动作上,必须做到幂等。否则一旦网络抖动引发重试,用户会收到三封一模一样的告警邮件。

5.2 超时与兜底降级

每个子Agent调用都要设置超时。我的默认值是30秒,分析类子任务可以放宽到60秒,但必须有上限。超时之后不能干等,而是启动兜底逻辑:先把该子任务的状态标记为unavailable,然后让下游Agent基于已有信息继续执行,同时触发一次异步重试。

兜底的另一个好处是,主控在汇总时会明确标识“某个来源的数据不可用”,报告Agent据此在生成报告时注明“日志分析结果缺失,指标分析结果正常”,而不是伪造一份看似完整的报告。这在值班场景里至关重要:给值班人看的报告必须诚实标注数据缺失范围,否则他误以为分析完整,就会做出错误决策。

5.3 输出边界与风险动作拦截

每个Agent的输出都要过一道校验层,通常做两件事:schema校验和风险动作识别。

schema校验保证Agent返回的消息结构符合约定,比如摘要字段必须是字符串、置信度必须是0到1之间的数字、状态字段只能在允许的集合内。不通过的输出直接丢弃并请求重试,不进入下游流程。

风险动作识别是另一道防线。比如把“删除”“重置”“拉黑”“转账”这类词放进动作风险表,一旦发现Agent的输出意图触发风险动作,强制进入人工确认流程。我绝不建议让Agent直接执行这类动作,无论它的置信度有多高。

5.4 成本预算与熔断联动

成本控制不只是事后看账单,而要前馈到调度决策。我习惯在系统里挂一个实时费用估算器,每完成一次大模型调用就把cost累加到全局计数器里,并且每5分钟巡检一次。若全局预算消耗超过当小时预算的80%,系统自动降低非关键Agent的调用降温,比如把日志分析的采样率从100%降为50%;若超过100%,直接熔断。

这套机制在早期项目里救过我一次。有一个Agent在异常场景下疯狂调用一个外部接口,几分钟内烧掉了相当于平时半天的预算,如果没有熔断,整个月的成本就绷不住了。

6. 常见故障库与排查方法

6.1 循环调用与对话死锁

现象:Agent A发消息给Agent B,B回应后又触发A,两者来回触发,任务永远不完结,token嗷嗷烧。

排查思路:先查消息里有没有hop跳数计数。我们为每条消息附加了一个跳数字段,每经过一次处理就加一;超过10次直接标记为死循环并终止。然后再看注册表和日志,找出是哪两个Agent之间存在双向依赖。修复方式通常是把其中一个调用方向改为单向,或者插一个主控节点做仲裁。

6.2 上下文污染

现象:报告Agent生成的内容里出现了日志Agent的分析细节,甚至出现了用户对话内容,但报告Agent本不该看到这些。

排查方式:检查消息负载。90%的情况是上游把全量上下文塞进了payload,而不是塞摘要。我的经验法则是:任何跨Agent传递的文本,超过500字就要警惕,超过2000字几乎必然引发污染。整改方法是强制输出模板,并限制摘要长度。

6.3 幻觉跨层传播

现象:第一个Agent产生了一个幻觉结论,它把这个结论当作事实传给了第二个Agent,第二个Agent在可信输入基础上又生成了更多推理,最终报告里赫然出现一个根本不存在的事件。

这是多Agent系统最可怕的问题。单Agent的幻觉还只是局部错误,多Agent的幻觉会层层放大。我的做法是两条原则:一是任何断言必须带置信度,置信度低于阈值时不得进入下游生成;二是对关键结论做“回查测试”,由独立的数据检查Agent去上游数据库核实这些结论是否存在事实支撑。

6.4 断链与孤儿任务

现象:某个Agent进程重启后,它正在处理的任务没有任何Agent接管,任务状态一直停留在running,成了孤儿。

原因通常是状态存储没做好持久化,或者重启后没有从数据库捞回pending任务。修复方法:Agent启动时先扫描数据库中所有属于自己但尚未完成的任务,按状态机重新接管。数据库表里每个任务都是“记录的延续”,进程重启是常态,不能把状态放在内存自嗨。

6.5 排查速查表

下面这张表是我自己一直在用的,直接贴出来供参考:

症状优先检查处置方法
任务卡住不结束消息全链路trace_id、Agent状态注册表确认是否循环依赖,按hop终止,检查超时设置
输出包含无关上下文payload大小、摘要模板限制跨Agent文本量,强制结构化输出模板
报告里出现明显错误事实上游置信度字段低置信度阻断传播,增加关键数据回查Agent
Agent重启后任务丢失数据库中任务状态记录启动时捞回未完成任务,状态机接管
预算快速消耗全局费用计数器检查Agent是否发散调用,触发配额熔断
多个Agent结果冲突主控汇总逻辑让主控基于置信度和时间戳做归并,必要时拉起临时蜂群讨论

6.6 一个典型的夜间故障复盘

有一次夜间告警量激增,值班助手开始频繁生成报告,但报告质量持续下降。我早上起来看日志,定位到根因:某个上游Agent返回的数据格式变了,导致下游Agent拿到的status字段一直是unknown,它为了“完成报告”,开始自动猜测unknown的含义,在报告里生成一堆看似合理但实际是编造的解释。

这个复盘的教训是:当Agent连续接收到它无法理解的结构化输入时,很多模型倾向于硬撑而不是承认失败。宁可让它明确标记“输入异常,无法分析”,也不要让它基于错误输入继续生成。所以后来我在所有Agent的system prompt里都加了一句:“遇到无法解析的输入时,必须返回错误状态,严禁猜测输入含义。”这句话在关键时刻省了很多事。

7. 踩坑记录与个人经验

7.1 最小拓朴起步,先跑通通信链路

做多Agent系统最容易犯的错,就是一上来就铺开七个Agent、十几种消息类型,结果连通信都没排通。我给的建议是:第一版只做一个主控加两个Worker的最小拓扑,把消息协议、注册表、状态机、日志追踪这几件基础设施跑稳。等这套链路稳定了,再加Agent、加蜂群、加复杂调度逻辑。

我自己的经历是,第一次搭多Agent系统时直接上了五个Agent,结果调试时发现在主控看来有Agent“消失”了。追了很长时间才发现是注册表配置写错,Agent注册名称和消费队列对不上,主控把消息发给了A,但A只订阅了B的队列。这种低级的通信问题恰恰是基础不牢的典型症状。

7.2 先验证通信,再调prompt

很多人遇到多Agent系统的怪问题,第一反应是调prompt,我的顺序刚好相反:先验证通信链路,再查状态流转,最后才怀疑prompt。因为在多Agent系统里,大多数“AI表现不好”的假象,本质是消息没送达、状态被覆盖、或者上下文被污染。这些都属于工程问题,不是模型问题。

我建议写一套最小链路自检:每次重启系统后,自动跑一个“心跳任务”从主控发到两个Worker,再回到主控,全程打印each消息的trace_id。链路通了再放心加任务,链路不通,所有Agent之间都是猜谜。

7.3 在Agent定义里写上“我不做什么”

最后一个我想强调的经验,也是这个系列里我想重点送给大家的:给每个Agent定义“我不做什么”,往往比定义“我能做什么”更重要。

日志Agent的prompt里明确写着“我不负责判断业务影响,我只负责日志事件提取”;主控的prompt里明确写着“我不亲自动手分析数据,我只负责调度和决策”;报告Agent的prompt里明确写着“我不提出维修建议,我只汇总已有结论”。这些负向约束让Agent之间不会越界抢活,也大幅减少了上下文污染和结论冲突。

好的多Agent系统里不是每个Agent都强大,而是每个Agent都识趣。它们知道自己的一亩三分地在哪里,不完美但边界清晰,组合起来反而能扛复杂任务。这是我在多Agent工程化上踩了无数坑之后,最想留给你的一个判断。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询