多 Agent 调研助手实战:Supervisor-Worker 模式 + Tavily + FastAPI
用 LangChain 的 Supervisor-Worker 模式,构建一个能自动拆解问题、搜索、分析、生成报告的多 Agent 系统。
一、为什么做这个项目
面试 AI Agent 开发岗时,有 3 类高频问题:
- "多 Agent 怎么协作?" — 多个 Agent 之间怎么通信、分工、汇总
- "你做过真实 API 集成吗?" — 不只是模拟数据
- "你的项目有部署经验吗?" — 能通过 HTTP 调用吗
这个项目一次覆盖了这 3 个问题。
二、架构:Supervisor-Worker 模式
用户输入调研主题
│
▼
Supervisor(主管 Agent)
┌─────────────────────────┐
│ create_plan(topic) │ ← LLM 将主题拆成多个子问题
│ 输出: ResearchPlan │
└──────────┬──────────────┘
│
┌───────┼───────┐
▼ ▼ ▼
Worker 1 Worker 2 Worker 3 ...
(搜索) (搜索) (搜索)
│ │ │
▼ ▼ ▼
Analyzer Analyzer Analyzer
(分析) (分析) (分析)
│ │ │
└───────┼───────┘
▼
Writer(撰写 Agent)
│
▼
Markdown 调研报告
关键设计
每个 Worker 只做一件事:
| Agent | 职责 | 技术 |
|---|---|---|
| Supervisor | 拆解问题 | model.with_structured_output() → ResearchPlan |
| Searcher | 搜索资料 | Tavily Search API(真实数据) |
| Analyzer | 提炼关键信息 | LLM → Finding(结构化输出) |
| Writer | 生成报告 | LLM → Markdown |
三、结构化数据流
核心是用了 Pydantic 定义数据结构,让 LLM 的输出可预测、可验证:
class ResearchPlan(BaseModel):
topic: str
background: str
questions: List[ResearchQuestion]
class Finding(BaseModel):
question: str
summary: str
details: str
sources: List[str]
每个 Agent 的输入和输出都是结构化的 Pydantic 对象,而不是自由文本。这就避免了"LLM 乱说话"的问题——格式错了就会抛出 ValidationError,不会静默地生成垃圾数据。
四、Supervisor 是怎么拆问题的
核心代码只有几行:
def create_plan(topic: str) -> ResearchPlan:
prompt = f"针对「{topic}」拆解出 3-5 个子问题..."
response = model.invoke([HumanMessage(content=prompt)])
data = json.loads(clean_json(response.content))
return ResearchPlan(**data) # ← Pydantic 自动校验
难点在于 LLM 返回的 JSON 可能有格式问题(markdown 代码块、缺少外层括号等),需要做一层清理:
# 去掉 ```json 标记
if raw.startswith("```"):
raw = raw.split("\n", 1)[1]
if raw.endswith("```"):
raw = raw.rsplit("\n", 1)[0]
# 补全缺少的 {}
if not raw.startswith("{"):
raw = "{" + raw
if not raw.endswith("}"):
raw = raw + "}"
这就是生产环境的现实——LLM 输出永远不会完全规则,必须有一层防御性解析。
五、真实搜索:Tavily API
用 Tavily(专为 AI Agent 设计的搜索 API)代替模拟数据:
from tavily import TavilyClient
client = TavilyClient(api_key=os.environ["TAVILY_API_KEY"])
results = client.search(query=keyword, max_results=5)
为什么选 Tavily 而不是普通搜索 API?
- Tavily 返回的是已经处理过的内容(摘要、标题、URL),而不是原始 HTML
- 专为 LLM 消费设计,结构干净
- 免费额度 1000 次/月,够学习和演示
六、FastAPI 部署
用了 50 行代码加了一个 Web 接口:
@app.post("/research")
async def do_research(req: ResearchRequest) -> ResearchResponse:
plan = create_plan(req.topic)
findings = [analyze(q, search(q)) for q in plan.questions]
report = write_report(plan.topic, findings)
return ResearchResponse(report=report)
启动:
uvicorn app:app --reload --port 8000
调用:
curl -X POST http://localhost:8000/research \
-H "Content-Type: application/json" \
-d '{"topic": "AI Agent 开发工程师 广州 2025"}'
返回的就是一份完整的 Markdown 调研报告。
七、总结
这个项目的核心模式可以概括为:用结构化数据流驱动多 Agent 协作。每一步的输入输出都是 Pydantic 对象,create_plan 产出 ResearchPlan,Searcher 产出原始文本,Analyzer 产出 Finding,Writer 产出 Markdown。流程清晰、可追踪、容易 debug。
适用场景:
- 市场调研
- 竞品分析
- 技术方案调研
- 求职市场分析
可以改进的方向:
- 用 Tavily 的分页参数获取更多结果
- 给每个 Worker 加独立的状态跟踪(有没有搜完、有没有失败)
- 加缓存层,相同主题不重复请求 API
八、项目链接
GitHub: github.com/cuzz123/res…
配套项目:
- 客服 Agent(LangGraph + FastMCP + Chroma RAG):github.com/cuzz123/cus…
- MCP File Server(FastMCP 协议实现):github.com/cuzz123/mcp…
- MCP API Gateway(Tavily 工具集):github.com/cuzz123/mcp…
这是第三个实战项目。前两个覆盖了单 Agent + MCP,这个覆盖了多 Agent 协作 + 真实 API + 部署。三个项目组合起来覆盖了 Agent 开发的主要技术栈。接下来还会做第四个(MCP API Gateway),关注后续更新。