从零到上线:一个真实项目教你 多 Agent 协作与全栈开发
说实话,第一次接触多 Agent 协作这个概念时,我内心是有点抵触的。当时觉得这玩意儿不过是把几个 prompt 拼在一起,套上一个"智能体协作"的壳子,本质还是大模型 API 调用,能玩出什么花?直到我在一个真实项目里,用多 Agent 架构重新做了一整套全栈系统,从需求分析、任务编排、代码生成一路打到部署上线,我才意识到自己原来的认知有多浅。多 Agent 协作不是简单堆 Agent 数量,而是重新设计系统分工的逻辑;它解决的也不是"生成一段代码能不能跑"的问题,而是"一个复杂度稍微高一点的业务场景,怎么让 AI 稳定、可控、可维护地落地"的问题。
这篇文章就围绕这个真实项目来写。我完整走了一遍从零到上线的过程,里面包含了架构设计、技术选型、Agent 角色划分、全栈开发落地、部署调优,以及大量踩坑后的复盘。如果你正在纠结"单 Agent 到底够不够用"、"多 Agent 协作到底是不是炒作"、"AI 全栈开发的边界在哪",那这篇应该能给你一些实在的参考。
1. 为什么需要多 Agent:一个问题逼出来的架构决策
1.1 单 Agent 的崩盘现场
先说项目背景。我做的这个系统,是一个面向中小型电商团队的"竞品分析报告自动生成平台"。用户只需要输入一个行业关键词,比如"便携咖啡机",系统要自动完成:抓取主流电商平台上的竞品数据、清洗和聚合销量与评价数据、分析价格区间和卖点分布、生成一份带图表和结论的竞品分析报告,最后还要自动出 PPT 大纲。整个链条跨了数据采集、数据分析、文案生成、可视化呈现四块完全不同的能力。
最开始,我用的是单 Agent 方案,一个大 prompt 把任务全部包进去,让模型自己决定怎么拆解。初版跑起来其实挺惊艳的,输入关键词,等两三分钟,真的能看到一份像模像样的报告。但问题很快暴露出来,而且每一个都是致命的:
- 只要数据源里的某一个平台反爬策略变了,整个任务就失败,因为 Agent 把采集逻辑、清洗逻辑、报告生成逻辑全混在一套上下文里,任何一个环节出错都难以定位。
- 上下文长度根本不够用。抓回来的数据动辄几万条,塞进一个会话里,很快就把 token 窗口撑爆,到后期模型已经开始"遗忘"前面的数据。
- 无法并行。单 Agent 只能一条路走到黑,采集、分析、生成必须串行,效率低得很明显。
- 排查问题极痛苦。每次报错,你都不知道是工具调用出了错,还是模型推理出了错,还是数据格式传丢了。整个过程就是个黑盒。
这个阶段我得出一个结论:单 Agent 能做 Demo,但做不了系统。当一个任务涉及多个完全不同领域的工具和数据逻辑时,把所有能力塞进一个 Agent 里,不是"上下文管理的艺术问题",而是架构上的根本错误。
1.2 拆开的思路:一个人干不过的事,让一个团队来干
后来我换个角度看问题。如果这个系统不是 AI 系统,而是由一个人类团队来做,我会怎么排兵布阵?我大概会安排四类角色:一个跟客户确认需求的项目经理,一个负责写爬虫的采集工程师,一个做数据分析的分析师,一个出报告和 PPT 的文案设计。每个人只管自己那块,交付之后交给下一个人。
多 Agent 协作的本质就是这样,把一个大而全的智能体,拆成一组各司其职、又能够互相传递任务的智能体团队。每个 Agent 拥有独立的大模型实例、独立的提示词体系、独立的记忆空间和工具集。它们之间通过某种通信机制协作,上游 Agent 的输出就是下游 Agent 的输入。
这样做的好处很直观:每个 Agent 的上下文都很短,只装跟它职责相关的数据和指令;某个 Agent 出错了,单独修那个 Agent 就行,其他模块不受影响;可以把某个 Agent 替换成更合适的模型或工具,而不需要重写整条链路。但我当时没有意识到的是,这个方案的复杂度从前端转移到了编排层。Agent 之间的数据怎么传递、任务怎么交接、失败怎么处理、状态怎么同步,这些问题比单个 Agent 内部的 prompt 工程要难得多。
1.3 该不该用多 Agent:我的判断标准
我也认真考虑过"是不是杀鸡用牛刀"。如果你只是做一个"翻译助手"或者"单轮问答机器人",纯单 Agent 完全够。但如果你遇到这么几种情况,多 Agent 协作几乎是必然的选择:
- 任务链路跨越多个领域,比如采集、分析、生成,每一步需要完全不同的工具和模型能力。
- 单个任务的数据量和上下文需求会超过模型的稳定处理范围。
- 系统需要持续的稳定性和可运维性,不能每次跑任务都像开盲盒。
- 你希望系统的某一部分可以被独立替换和升级,而不是牵一发动全身。
我的经验是:如果任务链路超过三个环节,且每个环节涉及不同的工具和数据形态,直接上多 Agent。如果是一个简单的单环节任务,千万别为了追概念硬拆,那是给自己找麻烦。
2. 多 Agent 架构设计与全栈技术选型
2.1 系统的整体架构分层
项目启动时我先画了一张整体架构图,核心思路是"前端 + 后端服务 + Agent 编排层 + 工具层"四层分离。
第一层是前端 Web 应用,用户在这里输入关键词、配置生成参数、查看历史报告。第二层是后端 API 服务,负责任务接收、状态管理、数据持久化。第三层是 Agent 编排层,这是整个系统的核心中枢,四个 Agent 在这里注册、调度、通信。第四层是工具层,每个 Agent 可以调用的外部能力,比如电商数据采集引擎、数据处理脚本、图表生成服务、PPT 导出服务。
这种分层的好处是每一层都可以独立扩展。比如说,我后来把 Agent 编排层单独拆成了一个常驻服务,与后端 API 分离部署,就是因为发现 Agent 任务耗时太长,不能阻塞 Web 请求的正常响应。这算是我在这次项目里比较早的一个架构决策,也直接避免了后来很多性能问题。
2.2 Agent 框架怎么选:从 LangGraph 到自研轻量编排
在最开始的方案选型阶段,我对比了市面上常见的几类多 Agent 编排框架。像 Autogen 和 CrewAI,当时我用下来的感受是:它们把 Agent 之间的协作方式已经做成了定义好的模式,比如 CrewAI 里的"流程"概念,Role 配合 Task,确实很容易上手。但问题是,一旦你的业务链路里有大量自定义逻辑、个性化工具调用、自定义状态流转,这些框架的抽象反而会变成束缚,为了适配框架本身的设计而扭曲业务逻辑。
我当时调研了 LangGraph,它给我留下的印象最深。LangGraph 不像其他框架那样预设了太多 Agent 协作的固定模式,而是把整个过程建模成一张图,节点是你定义的功能模块,边是模块之间的流转条件。这种设计极其适合复杂的业务链路,因为你可以非常精细地控制每一步的执行条件、分支、回退,以及状态如何在节点之间传递。
最终我的技术方案是:用 LangGraph 作为 Agent 编排内核,但把它封装在一个自研的调度服务里。这个调度服务负责管理 Agent 的注册信息、任务队列、回调通知和运行日志。这个组合等于把框架的灵活性和业务的定制需求做了个平衡,后面实际开发时确实省了不少事。
2.3 前后端技术栈:一切以交付速度和可维护性为准
前端我选了 React + TypeScript,原因很朴素:生态最稳,社区方案最多,遇到任何问题都能找到答案。UI 组件库用了 Ant Design,不是因为设计多好看,而是它的中后台组件覆盖度非常高,表格、表单、步骤条这些都是我需要的,可以少写很多重复代码。状态管理用了 Zustand,这个选择在当时被几个朋友吐槽过"为什么不选 Redux"。
我的理由很简单:Redux 的模式比较重,样板代码多,Zustand 写起来轻量,API 直接,而且 TS 类型支持极其友好。后端用了 Python 的 FastAPI,因为 Agent 编排层是 Python 生态,后端和编排层用同一种语言,可以省掉一层跨语言通信的工作。FastAPI 的异步支持和 Pydantic 数据校验在处理长任务状态轮询这件事上非常顺手。
数据库用了 PostgreSQL 加 Redis。PostgreSQL 存用户、任务记录、报告内容和元数据,Redis 负责缓存任务运行状态和热点数据。文件存储这块,生成的 PPT、图表和完整报告导出文件,存在了本地的 MinIO 对象存储服务里,后续如果上云也可以无痛切换。技术栈整体没有特别激进的部分,全是经过验证的成熟组合,因为我当时给自己的底线是:项目要能顺利上线,不搞技术炫技。
3. 核心实现:四个 Agent 如何协作完成一条任务链路
3.1 Agent 的角色定义与领域边界
多 Agent 系统里最忌讳的事情是职责重叠,两个 Agent 都能干同一件事,它们在任务交接时就会出现"没人管"或"抢着管"的混乱局面。我最后将整条任务链路划分为四个角色,彼此边界非常清楚。
采集 Agent 负责对接电商平台的公开数据接口和网页抓取逻辑,接收一个行业关键词,输出结构化的原始数据集合,包括商品标题、价格、月销量、累计评价数、店铺名称、上下架时间等。我对它有一个硬性要求:所有数据必须经过标准化处理,统一单位、统一字段名,这个规定让后一个环节省了非常多的事。
分析 Agent 的任务是解读结构化数据,做一些预处理和聚合计算,比如价格分布区间、销量集中度、品牌集中度、关键词词频,输出一份数据分析摘要。这个 Agent 不是我让模型去算复杂统计,而是让它调用我自己写的 Python 分析模块来算,它负责的是解读计算结果,判断哪些数据值得重点关注。
文案 Agent 根据分析摘要生成完整的竞品分析报告,包括摘要、市场趋势、竞品对比、风险提示、策略建议这些章节。这里我要求它必须具备稳定输出结构化 Markdown 的能力,方便后续的渲染环节直接转换格式。
最后是呈现 Agent,它是整个系统里最"孤独"的一个角色,因为它做的事情跟 Big Model 几乎没有关系。它接收结构化 Markdown 报告,调用脚本转换为 PPT 大纲和图表数据,通过 python-pptx 生成可下载的 PPT 文件。之所以也把它设计成一个 Agent,是为了保持任务链路的统一性和就算出了问题也能在日志里定位到具体角色。
3.2 基于 LangGraph 的任务编排流程
在这套架构里,LangGraph 负责控制所有 Agent 的流转顺序。我把流程定义成了一条串行链路,先生成采集任务、再触发分析任务、再生成文案、最后生成 PPT。每一步完成之后,调度服务都会把产出物写入 PostgreSQL 的任务表中,同时更新任务状态,由 Web 后端通过 WebSocket 向前端推送进度信息。
除了主流程,我设置了几个条件节点:如果采集的数据量为零或者清洗后可用数据量过低,就触发"数据不足"分支,直接终止任务并向用户返回提示,不让后续的 Agent 接一个空数据集。如果某个 Agent 调用失败了,则进入局部重试逻辑,最多重试三次,三次仍失败才彻底终止。重试逻辑的粒度是单个 Agent,不是整个任务链,这样能避免"一个环节出错全部从头再来"的尴尬。
这里我必须说一个当时踩过的坑。LangGraph 里的节点函数会共享同一个状态字典,如果你的 Agent 在状态里传了体积很大的数据,比如埋了个几十 MB 的 DataFrame,后面每一步都会被这个巨大的状态拖累,因为它们会持续占用模型上下文或内存。后来我在状态字典里只放数据的引用 ID,比如数据表主键或者 MinIO 文件路径,真正的数据放外部存储,Agent 需要时再自行加载。这个改动让系统内存占用直接降了 60% 以上。
3.3 Agent 之间通信:数据契约的重要性
多 Agent 系统最容易忽略的是 Agent 之间传递的数据格式问题。每个 Agent 都由大模型驱动,大模型的输出天然带有不确定性。如果 Agent A 输出一个 JSON 对象,而 Agent B 期望收到另一个字段结构的 JSON,轻则解析失败,重则 B 拿到错误数据生成一份完全错误的报告。
为了解决这个问题,我引入了"数据契约"机制。每一个 Agent 的输出和输入,都必须遵循预先定义的 Pydantic 模型。分析 Agent 给文案 Agent 的数据不是自由文本,而是必须符合 AnalysisResult 模型的实例,里面定义了 price_summary、keyword_top_10、distribution_analysis 这些字段以及它们的类型。所有 Agent 的工具调用结果也走同样的校验逻辑,一旦输出不符合协议,触发重试或者纠错提示,绝对不让脏数据流到下游。
我当时写了一套简易的"协议校验器",本质是个 Pydantic 校验函数,插入到 LangGraph 的每个节点后面。从这以后,Agent 之间通信的稳定性提高了一个档次。你会发现,真正让多 Agent 系统稳定运转的,与其说是 Agent 的聪明程度,不如说是边界是否有清晰契约。
4. 全栈开发中的关键细节:前端、后端、数据与服务的咬合
4.1 后端 API:把长任务从请求周期里剥离出来
这是我从第一版设计就坚持的原则:Agent 任务一定不能阻塞 HTTP 请求。用户提交一个任务后,后端先创建一条任务记录,返回一个 task_id,然后立即把任务推送到后台队列。前端拿到 task_id 之后,通过 WebSocket 或前端轮询来跟踪进度,等到任务完成后再去获取报告内容。这套模式现在说起来简单,但当时真的有同事提议"任务反正要等几分钟,直接做成同步请求算了",我坚决否了。同步请求一旦网络超时或者用户中途关闭页面,整个任务就变成一个半死不活的状态,排查起来想哭。
后端 API 实际实现了这么几个核心接口:创建任务接口,接收关键词和配置项并生成 task_id;需要预置一份任务状态表,包含 pending、running、success、failed、timeout 五个状态;查询任务状态接口,提供当前进度进度描述;获取报告接口,根据 task_id 查询报告内容和附件下载链接;历史报告列表接口,支持分页和按关键词筛选取。
为了实现这些功能,我顺带把 FastAPI 的后台任务能力研究透了,最终是 Redis 队列加独立 worker 进程来消费任务。Worker 进程作为常驻服务运行,启动后订阅 Redis 队列,从队列里拉取任务后调用 Agent 编排服务,这个过程完全独立于 Web 服务。
4.2 前端交互设计:用"进度条 + 日志流"安抚用户情绪
因为 Agent 任务的耗时通常在 30 秒到 5 分钟之间,前端的交互设计如果只做一个转圈 loading,用户大概率会怀疑系统是不是挂了。我做了两个东西:任务进度条和实时日志流。
进度条背后对应的是一个阶段状态机:数据采集中、数据分析中、报告生成中、PPT 组装中、任务完成。为了让进度条更真实,我在后端记录了每个阶段的耗时占比,当前端拿到进度状态后,按比例展示进度。这不是精确逻辑,但用户感知上好很多。
实时日志流是最受好评的功能,前端通过 WebSocket 订阅任务日志,后端将 Agent 运行过程中的关键信息实时推送,比如"正在采集第 3/8 个数据源"、"价格区间分析完成"、"报告生成耗时 12.3 秒"。这些日志不仅给用户看了安心,我自己调试时也拿它当排查线索,多 Agent 系统跑起来之后,你极度需要可视化的过程证据。
4.3 数据持久化与文件管理
这条项目的文件类型稍微复杂,有用户配置数据、任务记录数据、Agent 中间产物、最终报告文件、PPT 文件。我的数据库设计里,用户配置数据存 JSONB 原始配置,方便扩展字段而不需要频繁变更数据库表结构;任务记录表加关键索引,用 task_id 查询表单数据;状态字段要用枚举字符串而不是随便填单词,避免脏数据。
Agent 中间产物主要存在 MinIO 中,PostgreSQL 只存文件路径名和文件大小的元信息。为什么不用本地磁盘?因为生成的文件多、体积大,本地磁盘既不好扩容,也不方便迁移,MinIO 提供了 S3 兼容接口,将来如果上阿里云 OSS 或者 AWS S3,直接改配置就能切过去。我在这个项目里养成了最开始就搭好对象存储的习惯,确实后续省事。
5. 上线部署与稳定性优化:从能跑到能扛住
5.1 容器化部署方案
项目部署用的是 Docker Compose,整套系统由前端容器、后端 API 容器、Agent 编排容器、Worker 容器、PostgreSQL、Redis、MinIO 七个服务组成。每个服务都写了独立的 Dockerfile,并通过 Compose 文件统一编排。
这里有一个重要的部署经验:Agent 编排服务和后端 API 必须拆开跑,因为 Agent 任务长期占用 CPU 和网络资源,如果和 API 混在一起部署,Node 进程会被大任务拖垮,直接影响前端页面的响应速度。拆开后,只需给 Agent 编排服务单独设置资源上限,就能保证 Web 服务稳定性。
另外谷歌等外部模型 API 的调用网络超时问题也部署时被重点关注,我用 Python 的重试库给所有外部 API 调用配置了指数退避加最大重试次数的策略。部署在通用云服务器环境中要尽量减少对外部依赖重试消耗,这个选择在实际运行里减少了很大比例的任务失败。
5.2 监控与日志体系
上线前我搭建了一套轻量日志方案,所有 Agent 的输入输出摘要、耗时、调用链信息都写成结构化日志。日志不记录完整的 prompt 和原始数据,因为那可能包含敏感信息,也占用太多磁盘空间。只记录关键元信息,例如任务 ID、Agent 名称、步骤名称、耗时状态、错误信息摘要。
遇到任务卡死、报错的情况,我先查结构化日志找到出问题的 Agent 和步骤,再根据 trace_id 搜出整条链路的相关日志。多 Agent 系统在没有 tracing 的情况下排错简直就是灾难,因为一个任务可能跨 4 个 Agent、6 次工具调用、3 次状态变更,没有统一的 trace_id 根本拼不回去。
稳定性调优方面,我还做了三个关键指标看板:任务成功率、平均耗时、各 Agent 调用失败次数。其中各 Agent 失败的统计尤其是重点,如果分析 Agent 经常失败,通常不是模型问题而是数据格式问题。通过监控,我肉眼可见地把任务成功率从初期的 72% 提升到了 95% 以上。
6. 踩坑实录与问题排查技巧
6.1 高频问题的根因和解决速查表
我把整个开发和试运行时期遇到的高频问题整理成了清单,每一类其实都可以从架构层或工具层找到应对办法。
| 问题现象 | 根因 | 解决办法 |
|---|---|---|
| Agent 大模型输出频繁格式错误 | 上下文过长导致指令遵循能力下降 | 强制要求模型工具输出 JSON,在协议层做解析,失败时自动重试 |
| 任务链偶发停滞不动 | 某个 Agent 被外部 API 限流卡住 | 配置全局超时时间,超时触发局部重试逻辑 |
| 数据库连接数爆满 | 多个 Agent 同时读写 PostgreSQL 连接没释放 | 引入连接池复用,限制 Worker 并发数 |
| 前端内存持续增长 | 长时间 WebSocket 反复推送且未释放旧日志 | 前端限制日志区最大行数,超出则丢弃最早的日志 |
| PPT 生成报格式错误 | 文案 Agent 输出了不合法的 Markdown 结构 | 在呈现 Agent 前增加 Markdown 语法校验节点 |
当新问题出现时,我形成了一条自己的排查路径:先看是哪一个 Agent 阶段失败,再去看这个 Agent 的输入数据协议是否被满足,然后看模型的输出日志是否存在异常,最后才怀疑模型本身能力不够。这个顺序覆盖了我遇到的绝大部分问题。
6.2 多 Agent 调试的三个黄金参数
多 Agent 系统调试会涉及到三个核心参数:温度 temperature、触发阈值 threshold、上下文记忆长度 max_tokens。温度我固定设为 0.2,因为在任务链路中,稳定性远比创造性和多样性更重要。阈值用得最多的是 Agent 内部置信值,如果模型输出结果感觉不够可靠,宁可触发重试,也不往下游传递不确定的结果,保证"宁可不做,也不做错"。
上下文记忆长度这块,我只让 Agent 保留跟当前步骤相关的数据摘要,不把历史步骤的原始数据全部带入。通过这三个参数的组合调优,系统从"有时候趁手,有时候拉胯"变成了"稳定输出的工具",这个变化是整个项目让我最有成就感的部分。
6.3 关于全栈开发和 AI 协作的最终心得
这个项目做下来,我对"AI 全栈开发"有了新的理解。AI 不是你手里的万能锤子,它在某些环节是得力助手,但在某些环节你需要自己动手去补全工具的准确性。真正靠谱的开发方式是"把 AI 当成极具天赋但不守规矩的核心员工",你必须有流程、规范、验证和兜底。
那个数据契约机制、那个全局 Trace ID、那一整套状态机设计,都不是为了炫技,而是为了让 AI 的不确定性被约束在可控范围内。全栈开发的难度从来不在某一项技术本身,而在如何让系统所有环节严密咬合。
如果让我重新做这个项目,我会把 Agent 的可观测性做得更早、更重,因为运行多 Agent 系统的成败很大程度上不取决于模型聪明与否,而取决于你能不能第一时间看到每个 Agent 到底在做什么、做成了什么、为什么失败。这套认知,是我在这个真实项目中最值钱的一笔收获。