实战收官:从 0 到 1 构建并部署一个多智能体应用
- 收官项目一句话:给定主题 → 多路检索 → 精读 → 产出带引用的报告——「个人研究助理」,多智能体的最小完整形态。
- 架构没有新东西:编排者-工作者(第 8 篇)+ ReAct 循环(第 3 篇)+ 工具调用(第 5 篇)+ 记忆(第 7 篇)+ 上下文预算(第 4 篇)——收官就是确认每块拼图都来自哪一篇。
- 评测不编数字:本系列博客的生产线自身就是这套架构的实证——十篇文章、评审轮次与得分全程留痕,「评测驱动迭代」跑给你看。
- 部署三条铁律:基础镜像固定版本且运行态最小化;密钥只走环境变量(12-factor);healthcheck 门控依赖,启动期给足宽限。
上篇回顾:上一篇立好了考勤制度——评测与护栏。至此,九篇零件全部到齐。收官篇只做一件事:把它们拧成一台真的能交付价值的多智能体应用,装进容器,部署上线,然后复盘。
一、需求与架构:先说清楚要做什么
收官项目的需求一句话就能说清:用户给定一个研究主题,系统多路检索资料、精读筛选,产出一份带引用的研究报告。这个「个人研究助理」是多智能体的最小完整形态——小到两篇文章能讲完,大到足以复用前九篇的每一块零件。为什么是它,而不是更炫的浏览器操作或客服机器人?回到第 1 篇的判据:「验证反馈越清晰的任务,Agent 越可靠」——这一判据与 Anthropic 强调的「成功标准清晰、结果可验证」一脉相承 [4]——研究报告的验证信号天然清晰:引用可逐条核对、事实可交叉验证、报告可读性用户可以直接反馈。收官选它,是选了一条每一步都能被检验的路。选它还有个私心:LangChain 官方的开源项目 open_deep_research 与它完全同构,学完可以对照一个生产级仓库继续深挖 [3]。
架构在第 8 篇已经画过:一个编排者(Orchestrator)把主题拆成多个检索角度,派出并行的工作者(Worker)各自搜索与精读,结果蒸馏回传,最后由写作角色汇总成带引用的报告,评审角色按第 9 篇的质量清单把关。落实第 9 篇的 BDD 精神,动手前先写三条验收标准:「给定任一主题,报告须包含至少 5 条可核验的引用」「每条引用的 URL 必须真实可达」「报告须注明检索完成日期」。写不出验收标准的需求,就是还没想清楚的需求——这条纪律对收官项目同样生效。落实到模块,每一块都有出处:
| 模块 | 职责 | 来自哪一篇 |
|---|---|---|
| 任务循环 | 思考-行动-观察、停止条件、错误恢复 | 第 3 篇 ReAct |
| 工具层 | search、read(研究场景)+ write_report(沿用第 5 篇)+ 确认门控 | 第 5 篇工具调用 |
| 上下文预算 | 裁剪旧工具结果、摘要压缩 | 第 4 篇上下文工程 |
| 记忆 | 跨会话记住用户偏好与研究历史 | 第 7 篇记忆系统 |
| 编排 | 拆解、并行委派、汇总 | 第 8 篇多智能体协作 |
| 评测与护栏 | 数据集回放、轨迹断言、三层防线 | 第 9 篇评测与护栏 |
这张表就是收官的底气:收官篇不引入任何新概念。Anthropic 在自己的多智能体研究系统里也是这么做的——编排、并行子 Agent、引用痕迹、质量评审,全是已知模式的生产级组合 [5]。真正的工程发生在「把它们正确地拼起来」。
二、总装:主程序骨架
项目结构保持朴素——五个文件,每个对应前文一份实现:
research-assistant/
├── agent_loop.py # 第 3 篇:react() 循环 + 停止条件 + 错误回填
├── tools.py # 第 5 篇:search/read/write_report 工具 + schema + 确认门控
├── memory.py # 第 7 篇:MemoryStore(JSON + 关键词检索)
├── orchestrator.py # 第 8 篇:plan() + 并行 worker + 汇总
├── main.py # 本篇:入口——组装、注入记忆、落盘报告
└── evals/cases.jsonl # 第 9 篇:评测集(从真实失败案例长出来)
main.py 负责把零件拧在一起(前文模块以 import 引入,函数签名与各篇一致):
from agent_loop import react_step
from memory import MemoryStore
memory = MemoryStore(f"memory/{__import__('os').environ['USER_ID']}.json") # 跨用户隔离:一人一文件
def research(topic: str, max_steps: int = 12) -> str:
"""入口:检索编排交给 orchestrator 的思路,单 Agent 版先用 react 走通全链路。"""
hits = memory.search(topic) # 记忆注入:开场先看「以前研究过什么」
known = "\n".join(f"- {i['content']}" for i in hits) or "(无相关历史)"
messages = [
{"role": "system", "content":
"你是研究助理。流程:先用 search 工具多角度检索,read 工具精读,"
"最后 write_report 产出带引用的报告。每次先说一句当前判断再行动;"
"证据不足就继续检索,不要编造引用。" + f"\n\n[历史研究]\n{known}"},
{"role": "user", "content": f"研究主题:{topic}"},
]
for _ in range(max_steps): # 循环:第 3 篇的心脏,原样复用
result = react_step(messages) # react 的单步封装(见 agent_loop.py)
if result is not None: # 无工具调用 = 任务完成,返回最终答复
return result
return "已达步数上限,任务未完成。"
# 多智能体版:把 research() 换成第 8 篇的 orchestrate(),
# worker 的 system 换成上面的研究提示——其余一行不改。
if __name__ == "__main__":
import sys
topic = sys.argv[1] if len(sys.argv) > 1 else "AI Agent 评测方法 2026"
print(research(topic))
注意总装的两个原则。第一,单 Agent 版先跑通,再换多智能体版——第 8 篇说「默认答案是别拆」,收官项目也一样:单 Agent 版能产出合格报告,就先上线它;撞到三瓶颈,把 research() 换成 orchestrate(),一行切换。第二,记忆注入保持稳定——「历史研究」段放在 system 尾部、内容按条目时间排序,别让 KV-cache 频繁失效(第 4 篇的账,部署后每天都要付)。另外两条目录纪律也值得写进 README:依赖用 requirements.txt 锁版本,保证容器里跑的就是你测过的组合;memory/ 与 output/ 在部署时挂载为数据卷——容器可以随时销毁重建,用户的记忆与研究产出不能跟着陪葬(第 7 篇的租约条款,在部署层兑现)。部署形态上,上线前补一个十行的 app.py:用 FastAPI 把 research() 包成 HTTP 服务,并提供 /health 探针——下一节 Dockerfile 的启动命令与探测,都指向它。
三、评测与迭代:用真实数据说话
收官项目的评测,直接套第 9 篇的三件套:数据集回放 + 轨迹断言 + 评审循环。而它「评测驱动迭代」的最好实证,恰恰是本系列博客的生产线自己——你正在读的这十篇文章,就是一套多智能体流水线(调研、写作、评审、排版各司其职)按同样纪律生产出来的。看它的真实台账:
- 十篇文章全部经过「写作 → 评审 → 修订」循环,首轮评审得分 13~15/16 常见,修订后终轮全部 ≥15;评审抓出的典型问题包括:元信息失实(字数标注虚高)、引用错置(把 A 文的话挂到 B 来源)、代码演示不可解(工具集缺枚举能力)、跨篇回指错标——每一类都对应第 9 篇清单里的一项检查;
- 每一轮评审意见都作为「错误回填」喂给写作者修订,与第 3 篇的循环同构;三轮上限 + 通过线(≥14 且无 0 分)就是停止条件与熔断器;
- 全部过程留痕在项目仓库的台账与日志里——第 9 篇说「trace 先于评测」,这里连评审意见本身都是可追溯的。
这套对照不是修辞:你能读到十篇完整、可追溯、带评审得分的文章,本身就是「评测驱动迭代」有效的证据。把它搬到你的项目里:评测集先攒十个真实 bad case,跑第一轮回放,修到全绿,再谈上线。还有第二层值得记:每篇的 R1 失分类型(字数失实、引用错置、演示不可解)本身就是一份现成的改进清单——评测数据不应只修「这一篇」,还应修「生产线」:把它们合并进评审清单与作业手册,是这条流水线 v2 的第一件事。
四、部署:三条铁律与一个 Dockerfile
部署 Agent 应用没有黑魔法,但有三条铁律。铁律一:基础镜像固定版本,运行态最小化——基础镜像用官方 slim 变体并锁死版本(生产建议按 digest 锁定),运行态保持最小;Docker 官方 Python 指南还给了两条直接可抄的实践:「构建、运行两阶段,运行态只拷依赖与源码」,以及把 .env 挡在构建上下文之外 [1]。铁律二:密钥只走环境变量——12-factor 的配置原则:配置与代码严格分离,「代码库随时可以开源而不泄露凭据」[2]。铁律三:healthcheck 门控依赖——Agent 应用启动要加载配置、建连接,给足 start_period;slim 镜像没有 curl,探测命令用 Python 一行替代:
# Dockerfile —— 多阶段:构建态装依赖,运行态只拷走 venv 与源码
# 生产建议按 digest 锁定版本
FROM python:3.12-slim AS build
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir --prefix=/install -r requirements.txt
FROM python:3.12-slim
WORKDIR /app
COPY --from=build /install /usr/local
COPY . .
EXPOSE 8000
HEALTHCHECK --interval=30s --timeout=5s --retries=3 --start_period=20s \
CMD python -c "import urllib.request;urllib.request.urlopen('http://localhost:8000/health')"
CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8000"]
# docker-compose.yml(节选)—— 密钥运行时注入,绝不烧进镜像层
# services:
# research-assistant:
# build: .
# environment:
# OPENAI_API_KEY: ${OPENAI_API_KEY} # 来自宿主机 .env,12-factor Factor III
# USER_ID: demo
# ports: ["8000:8000"]
部署后的第一件事,不是庆祝,是跑一遍第 9 篇的八条上线 checklist——冒烟集、回归集、门控、注入检测、输出审查、trace、人工抽检、成本预算,一条一条打勾。上线后第一周,盯三个数:失败率(按会话统计)、单次研究成本(token/会话)、长任务超时率——三个数各配一个「回退阈值」,触线即回滚到上一个镜像 tag。回滚预案在上线当天就要演练一次,等到出事才第一次执行回滚,你练手的那个时机,往往是最糟的时机。
五、踩坑复盘与系列总结
收官的复盘,还是用生产线自己的真实台账。十篇生产中评审抓出频率最高的问题,恰好是 Agent 工程的通用教训:
- 元信息也会失实(两篇文章字数标注虚高)——元数据要像功能一样断言,不能靠自觉;
- 引用会错置、链接会死亡(出处张冠李戴、文档迁移后 404)——引用必须程序化核验,关键论断要能逐字溯源;
- 演示会「看起来可运行」(工具集缺枚举能力、变量未导入)——演示代码必须真跑一遍,注释与代码要同屏 review;
- 评审循环真能兜底(首轮 13~15 分,终轮全部 ≥15)——回路不是仪式,是质量的本体。
最后,把十篇地图留给你:
| # | 篇目 | 带走的一件事 |
|---|---|---|
| 01 | 从 Chatbot 到 Agent | 三问定身份:目标、工具、循环 |
| 02 | 解剖一个 Agent | 四大件按需加装,每件都有税 |
| 03 | ReAct 与循环工程 | 完成是目标,预算是底线,熔断是保险丝 |
| 04 | 上下文工程 | 上下文是工资单:先分配、再消费 |
| 05 | 工具调用实战 | 模型点菜,你的代码下厨;危险操作过人 |
| 06 | MCP 入门 | M×N 变 M+N;第三方 server 是不可信输入 |
| 07 | 记忆系统实战 | 宁可少记不可错记;遗忘是特性 |
| 08 | 多智能体协作 | 默认别拆;拆了就要把制度写进 prompt |
| 09 | 评测与护栏 | 评测集从真实失败案例长出来,回放当 CI 跑 |
| 10 | 实战收官(本篇) | 先单 Agent 跑通,再一行切换多智能体 |
延伸阅读分两层。想继续追生产级实现,只推一个:LangChain 官方的 open_deep_research 仓库 [3](已于 2026-08 归档为只读,仍值得精读)——与本篇同构,读完十篇的你已经完全有能力读懂它,然后超越它。想常备案头的四站官方文档也值得收藏:modelcontextprotocol.io(工具生态)、OpenAI 与 Anthropic 的 SDK 文档(两家官方能力边界)、docs.langchain.com(编排与记忆)——本系列的全部关键论断,最终都溯源到这四个域名的某一页。
系列结语
十篇之前,我们问「AI Agent 到底是什么」;十篇之后,你手里有循环、工具、记忆、上下文预算、编排、评测与护栏,以及把它们拧成一台真机器的完整过程。这个系列本身也是一条 proof:十篇文章由多智能体流水线按「调研 → 写作 → 评审 → 修订」的回路自动生产,全程留痕、可追溯——你刚读完的,既是一套教程,也是一次 loop engineering 的完整实验记录。
系列到这里完结,但 Agent 的故事才刚开始。最好的下一步,不是读第十一篇——是开一个空目录,写下你的第一行 run_agent()。遇到问题,回到对应的那一篇;做出来了,欢迎回来在评论区告诉我。
参考来源
- Containerize a Python application, Docker Docs, 2026,docs.docker.com
- The Twelve-Factor App · III. Config, 2011-2026,12factor.net
- Open Deep Research, LangChain, 2025,github.com
- Building Effective Agents, Anthropic, 2024-2025,anthropic.com
- How we built our multi-agent research system, Anthropic, 2025,anthropic.com