Streamlit版本视频链接:【行业分析多智能体系统】https://www.bilibili.com/video/BV1SHGL64Ezz?vd_source=d6133bb57af968b84453e903bc33dc44
最近在学习大模型应用开发时,也是摸爬滚打,从低代码智能客服"写个聊天机器人"这个层面,再是尝试做了一个更接近真实业务流程的小项目:行业分析多智能体系统。
这个系统的目标很明确:给定一个研究主题,系统自动去搜索资料、整理信息、生成一份结构化行业分析报告,然后再经过 AI 审稿和人工主编审核,最后才进入发布环节。
整个项目虽然还只是一个原型,但已经把多智能体协作、工作流编排、人工介入审核、FastAPI 接口化这几块串起来了。更有意思的是,我在调试过程中还遇到了一个非常典型的工作流 bug:
明明人工审核时我选择了"打回重写",系统却还是直接发布了。
这篇文章就来完整复盘一下这个项目
一、项目目标
这个项目本质上是一个"自动化行业研究助手",核心流程包括:
- 输入一个行业研究主题
- 自动搜索公开资料
- 汇总内容并生成结构化 Markdown 报告
- 让 AI 审稿,决定是否需要修改
- 在关键节点暂停,等待人工主编审核
- 审核通过后再发布最终报告
相比单轮问答,这种任务更适合用 工作流 + 多角色分工 的方式来实现,而不是把所有逻辑塞进一个 Prompt 里一次性完成。
二、项目技术栈
这个项目目前使用的主要技术如下:
- Python
- LangGraph:负责多智能体工作流编排
- FastAPI:对外暴露 API
- SQLite:保存工作流状态
- Anthropic/Kimi 兼容模型调用
- DuckDuckGo Search(ddgs):做网页搜索
- Jina AI Reader:抓取网页正文
- Chroma + Embeddings:预留本地知识库检索能力
从项目定位来看,它不是一个完整产品,而是一个比较典型的 AI Agent 工程化原型。
三、系统整体架构
我把这个系统拆成了 5 个角色节点:
Researcher:负责搜索资料、抓取网页内容Analyst:负责生成或修改行业分析报告Reviewer:负责从 AI 角度审稿Human_Review:人工主编审核节点Publisher:负责美化排版并输出最终报告
整个流程大致如下:
的设计思路、实现方式,以及我踩到的关键坑。
Start
↓
Researcher
↓
Analyst
↓
Reviewer
├─ 审核通过 / 达到重试上限 → Human_Review
└─ 审核不通过 → Analyst
Human_Review
├─ approve → Publisher
└─ reject → 应该打回重写(这里后面会讲到一个坑)
Publisher
↓
End
这套结构的好处在于:每个节点职责明确,后续你想替换某个角色的能力会非常方便,比如替换搜索引擎、替换审稿规则、增加导出方式等。
四、为什么选择 LangGraph
一开始我也想过,能不能直接写一个大 Prompt,让模型自己完成"搜索、总结、审稿、修改、发布"这一整套流程。
但很快我发现,这种方式不太适合真实项目,主要有几个问题:
-
流程不可控
你很难精确规定"什么时候暂停""什么时候人工介入""什么时候回退重写"。
-
状态不好管理
报告初稿、审稿意见、人工反馈、最终成稿,这些都需要在多个步骤之间传递和保存。
-
可调试性差
如果最后结果不对,你很难快速定位是搜索阶段有问题,还是审稿阶段逻辑有问题。
LangGraph 的优势就在这里:它不是只让你"调模型",而是允许你把整个任务拆成一个真正的状态机或工作流图。
这也是我觉得它特别适合做多智能体项目的原因。
五、核心状态设计
为了让多个节点之间共享信息,我定义了一个统一状态 ResearchState,里面包含了整个流程需要传递的关键字段:
topic:研究主题target_url:目标网页raw_data:搜索和抓取后的原始资料local_doc_path:本地知识库文件路径draft_report:当前草稿feedback:人工审核反馈final_report:最终报告review_comments:AI 审稿意见revision_count:修改轮次
这个状态对象非常关键。
因为在 Agent 工作流里,很多问题本质上都不是 Prompt 问题,而是 状态流转问题。
比如:
- 当前报告是第几版?
- 是 AI 审稿打回的,还是人工主编打回的?
- 现在处于暂停状态,还是已经结束?
- 最终发布的是草稿,还是修订后的版本?
这些都必须明确记录在状态里。
六、多智能体节点是怎么分工的
1. Researcher:资料搜集员
Researcher 节点的主要职责有两个:
- 调用搜索引擎查找相关结果
- 抓取网页正文,整理成后续可供分析的资料
如果提供了本地文档路径,它还会尝试走一遍简单的 RAG 流程,从本地资料里检索相关内容,再与公开网页资料合并。
这个设计比较贴近真实业务:
行业研究很少只依赖模型自己的参数知识,通常需要结合外部检索结果一起生成。
2. Analyst:行业分析师
Analyst 节点负责生成报告。
这里我做了两种模式:
- 如果没有审稿意见,就根据资料直接写初稿
- 如果已经有
review_comments,就按修改意见重写
这样就能形成一个"写初稿 -> AI 审稿 -> 打回修改 -> 再生成"的闭环,而不是每次都从头开始。
3. Reviewer:AI 审稿员
这个节点相当于一个内部质检员。
它会检查当前报告是否合格,并输出两种可能结果:
DECISION: PASSDECISION: REJECT+ 修改建议
如果通过,就进入人工审核;如果不通过,就把修改意见交回给 Analyst。
这里我还设置了 revision_count,避免无限重写。
4. Human_Review:人工主编审核
这是我觉得整个项目里最有工程味的一部分。
现实业务里,很多内容即使经过 AI 审稿,也仍然需要人工把关,尤其是面向外部发布的内容。
所以我在图里专门预留了一个 Human_Review 节点,用来做:
- 人工确认是否发布
- 人工打回重写
- 保证关键流程由人兜底
这也是整个系统区别于"纯自动生成"的关键点。
5. Publisher:发布员
Publisher 节点负责最后一步,把中文报告进一步翻译和排版成更适合展示的 Markdown 成品,并保存到 outputs/report.md。
这个阶段我还加了一些格式美化逻辑,比如标题、分隔线和 Emoji 排版,让最终结果更像一篇可读性较好的文档。
七、FastAPI 如何把工作流封装成服务
虽然这个项目目前还没有独立前端,但已经通过 FastAPI 把整个流程封装成了几个 API。
1. 启动研究任务
POST /api/research/start
作用:
- 接收研究主题
- 创建初始状态
- 启动 LangGraph 工作流
- 返回当前草稿和下一个节点
2. 流式启动任务
POST /api/research/stream
作用:
- 用流式方式返回节点运行状态
- 更适合后续前端做实时展示
这意味着后面如果我要补前端页面,其实后端接口已经准备得差不多了。
3. 人工审核接口
POST /api/research/review
作用:
- 由人工提交
approve或reject - 更新当前状态
- 让 Agent 从中断点继续执行
这部分是人机协同的关键。
4. 状态查询接口
GET /api/research/status/{thread_id}
作用:
- 查询指定任务当前走到哪一步
- 查看完整状态值
这对于调试多步流程非常有帮助,因为你可以随时知道工作流内部到底保存了什么。
八、LangGraph 里的"暂停与恢复"真的很好用
这个项目里,我最喜欢的一个点就是 中断机制。
在编译图时,可以指定:
- 在
Human_Review节点之前中断 - 等待人工输入
- 再从当前状态恢复执行
这种机制很适合做:
- 人工审核
- 人工确认执行高风险操作
- 人工补充信息
- 审批流
比起"把所有逻辑一次性跑完",这种方式更符合实际业务流程。
换句话说,LangGraph 更像是在搭一个"AI 工作流系统",而不只是调一个模型接口。
九、项目运行效果
当前这个项目虽然没有独立前端页面,但已经可以通过 Swagger UI 完成完整调试:
- 输入
thread_id - 输入研究主题
topic - 启动研究任务
- 查看系统返回的草稿
- 提交人工审核结果
- 查看最终状态和生成报告
终端里也会输出完整的执行日志,比如:
- 搜索资料
- 抓取网页
- 分析生成
- AI 审稿
- 人工审核暂停
- 发布成稿
这种日志对于理解工作流很有帮助,也方便排查问题。
十、这次项目里我踩到的一个关键坑
这部分我想重点记录一下,因为它非常典型。
问题现象
我在人工审核阶段明明输入的是"打回重写",按理说系统应该回到修改环节重新生成报告。
但实际运行时,终端里却出现了这样的现象:
- 先打印:
审核不通过,打回重写 - 紧接着又进入了:
Publisher - 最终还是把报告发布了
也就是说,日志文案看起来像打回了,但实际控制流并没有真的回退。
一开始我以为是哪里没接好
最初我怀疑的是:
- 是不是
/review接口没把参数传进去? - 是不是状态没更新成功?
- 是不是模型把 reject 理解错了?
但后面看代码和日志才发现,真正的问题不是 API,也不是模型,而是 工作流边的定义有问题。
根因分析
在 human_review_node 里,如果人工反馈不是 APPROVED,代码只是打印了一句"打回重写",然后返回了空结果。
但更关键的是,图定义里用了固定边:
Human_Review -> Publisher
这就意味着:
无论人工审核是 approve 还是 reject,只要
Human_Review节点执行完,下一步都会进入Publisher。
所以系统的真实行为其实是:
- 你说了 reject
- 节点也打印了 reject
- 但图里没有"回到 Analyst"的路径
- 最后只能继续发布
这个问题特别能说明一点:
在 LangGraph 这种工作流框架里,日志语义不等于控制流语义。
你打印"打回重写"不代表流程真的会回退,真正决定下一步去哪的是图上的边和路由函数。
这个坑给我的启发
我觉得这个问题很有代表性,因为它暴露了多智能体项目里最容易忽略的一点:
不是"模型说了什么"最重要,而是"状态和路由怎么设计"最重要。
做 Agent 项目时,很多人容易把注意力都放在 Prompt 上,但其实工程里真正决定系统行为的,往往是:
- 状态字段怎么定义
- 条件路由怎么写
- 中断点放在哪里
- 哪些节点是固定边,哪些节点要走条件判断
十一、当前项目还有哪些不足
这个项目目前能跑,但还远远谈不上完整,至少还有这些明显不足:
1. 没有独立前端
现在主要还是通过 Swagger UI 调试接口,缺少真正的可视化页面。
2. 人工审核 reject 的流程还需要完善
当前逻辑里,人工打回后的控制流设计还需要修正。
3. 本地知识库能力还比较初级
虽然预留了 local_doc_path,但还没有完整接入文件上传和更稳定的知识库流程。
4. 发布模块还比较简单
目前只是输出 Markdown,后面可以考虑支持 HTML、PDF 或网页展示。
5. Prompt 和报告质量还有优化空间
比如行业报告的结构、引用规范、事实校验等,都可以继续加强。
十二、后续优化方向
如果继续做下去,我准备从这几个方向迭代:
- 给项目补一个最小前端页面,替代 Swagger 交互
- 修复人工审核 reject 后的条件路由
- 增加任务列表和历史记录查询
- 支持上传 PDF/文本作为本地知识库
- 优化流式展示效果
- 增加报告导出能力
- 加入更细粒度的审稿规则和事实校验机制
这样项目就会从一个"学习型原型"逐步变成一个更完整的 AI 应用 Demo。
十三、总结
这次做这个行业分析多智能体系统,对我来说最大的收获不是"调通了一个模型",而是更清楚地理解了:
- 多智能体系统的核心不只是 Prompt
- 工作流编排比单轮调用更适合复杂任务
- 状态管理和路由设计决定了系统是否可靠
- 人工审核节点在真实业务里非常重要
- FastAPI 很适合把 Agent 工作流快速封装成服务
如果只是做一个"能回答问题"的 Agent,其实并不难。
真正有挑战的是:怎么让它按你设计的业务流程稳定运行,并且在关键节点允许人类接管。
而这也是我觉得 LangGraph 这类框架真正有价值的地方。
结尾
如果你也在学习 LangGraph、多智能体系统或者 FastAPI,欢迎交流。
后面如果我把这个项目补上前端页面,或者把人工审核流进一步完善,也会继续记录更新。