第20章:三层架构设计:Go、Rust 与 Python 的“三国演义”
单体架构(Monolith)是初创期的甜蜜陷阱。三层架构不是为了炫技,而是为了让每种语言做它最擅长的事——Go 负责指挥,Rust 负责安保,Python 负责外交。
你用 Python 写了一个 Agent Demo。 单进程,
asyncio 并发,工具直接在本地跑。 你在笔记本上跑得飞起,觉得“架构不过如此”。
直到你把它部署到生产环境,噩梦开始了:
- 性能瓶颈:10 个用户同时发请求,Python 的 GIL(全局解释器锁)就把 CPU 卡死了,响应像蜗牛。
- 安全漏洞:有个用户让 Agent 写一段代码“遍历服务器文件”,Agent 照做了,直接把你服务器的
/etc/passwd读了出来。 - 系统雪崩:一个工具调用吃光了 8GB 内存,导致主进程 OOM(内存溢出)被杀,其他正常的 99 个任务也跟着挂了。
这时候你才意识到:Python 是一个好的“胶水”,但不是一个好的“地基”。
我们要突破单体架构的天花板,就需要引入 多语言三层架构。这就像组建一支特种部队,不能全是拿枪的,还得有指挥官和拆弹专家。
01. 为什么要分层?(单体的极限)
在早期,我们通常使用 Python 单体架构:
graph TD
User -->|HTTP| PythonApp[Python 单体应用]
PythonApp -->|逻辑| Orchestration[编排逻辑]
PythonApp -->|执行| ToolExec[工具执行]
PythonApp -->|调用| LLM_API[模型接口]
它的三大硬伤:
- 安全边界模糊:工具代码和主进程共享内存。恶意代码可以轻松“越狱”。
- 并发能力弱:Python 在高并发调度上天生腿短(受限于 GIL)。
- 容错性差:一处崩溃,全盘皆输。
生产级的三层架构:
02. 第一层:Orchestrator(Go 语言)—— 指挥官
角色:系统的大脑。 职责:它不干具体的脏活累活,它只负责 发号施令。
- 接收用户请求。
- 决定调用哪个工作流(Planning)。
- 管理 Token 预算(Finance)。
- 记录审计日志。
为什么选 Go?
- 高并发:Go 的协程(Goroutine)是处理高并发请求的神器。几万个用户同时在线,Go 能轻松扛住,Python 早趴下了。
- 类型安全:编译型语言,能在代码运行前发现很多低级错误。
- Temporal 亲和性:我们后面要讲的 Temporal(工作流引擎),它的原生 SDK 是 Go 写的,最稳定。
比喻:Orchestrator 是 塔台指挥员。他不需要会开飞机,但他必须头脑清醒,能同时监控几百架飞机的起降。
03. 第二层:Agent Core(Rust 语言)—— 拆弹专家
角色:系统的保镖。 职责:它负责在 受控环境 中执行那些可能危险的操作。
- 运行用户生成的代码(Sandbox Execution)。
- 调用外部工具。
- 强制执行资源限制(CPU、内存、网络)。
为什么选 Rust?
- 极致安全:Rust 的内存安全机制,让你很难写出导致内存泄漏或崩溃的代码。
- 零成本抽象:性能接近 C++,但没有 C++ 的历史包袱。
- WASM 支持:Rust 对 WebAssembly(WASM)的支持极好。我们可以用 WASM 构建一个 “数字监狱” ,把不信任的代码扔进去跑,就算炸了也伤不到宿主机。
比喻:Agent Core 是 防爆盾。当 Agent 要执行“删除文件”或“运行脚本”这种危险动作时,必须在 Rust 构建的沙箱里进行。
04. 第三层:LLM Service(Python 语言)—— 外交官
角色:系统的嘴巴。 职责:它负责和各种 AI 模型打交道。
- 适配 OpenAI、Claude、Gemini 等各种 API。
- 处理 Embedding(向量化)。
- 管理 Prompt 模板。
为什么选 Python?
- 生态垄断:AI 界的库(LangChain, NumPy, PyTorch)全是 Python 的。
- 迭代极快:新的模型出来,Python SDK 永远是第一个更新的。
- 胶水能力:处理文本、拼接 Prompt,Python 最顺手。
比喻:LLM Service 是 翻译官。它不需要身体强壮(性能),也不需要全副武装(安全),它只需要长袖善舞,能跟各种 AI 大佬谈笑风生。
05. 层间通信:如何避免“语言不通”?
三种语言,三个服务,怎么协作? 我们使用 gRPC 和 HTTP。
请求流转示例:
- 用户 发请求:“分析某 AI 公司”。
- Go (Orchestrator) 接收请求,创建工作流 ID,决定分三步走:搜概况、搜融资、写报告。
- Go 发指令给 Rust (Agent Core) :“去执行搜索工具,查一下这个公司。”
- Rust 在沙箱里安全地执行了搜索代码,拿到了网页内容。
- Rust 把网页内容扔给 Python (LLM Service) :“喂,帮我总结一下这段话。”
- Python 调大模型,生成总结,传回给 Rust,再传回给 Go。
- Go 收到结果,继续下一步。
关键设计:Workflow ID 透传 无论请求流转到哪一层,HTTP Header 里必须带上 X-Workflow-ID。这样出了 Bug,我们能在日志系统(如 Jaeger)里看到完整的调用链路。
06. 架构师的劝退指南
虽然三层架构很美,但我必须泼一盆冷水。这套架构有昂贵的“税”:
- 部署复杂:原来只要
python app.py,现在你要编排 Docker、K8s,管理三个服务的版本兼容性。 - 调试困难:Go 报了个错,可能是 Rust 那边传回来的,Rust 的错又可能是 Python 那边超时的。查 Bug 像破案。
- 人才密度:你得招懂 Go 的后端,懂 Rust 的系统工程师,懂 Python 的 AI 工程师。这人不好招。
决策矩阵:
| 你的情况 | 推荐架构 |
|---|---|
| 个人开发者 / 内部工具 / 原型验证 | Python 单体(别折腾,LangChain 一把梭) |
| 中型 SaaS / 对外服务 / 追求并发 | Go + Python(Go 做网关和编排,Python 做业务) |
| 平台级 PaaS / 代码解释器 / 极高安全 | Go + Rust + Python(三层完全体) |
总结
架构设计的本质是 Trade-off(权衡) 。
- 我们引入 Go,是为了解决 并发和编排 的问题。
- 我们引入 Rust,是为了解决 安全和隔离 的问题。
- 我们保留 Python,是为了连接 AI 生态。
这就是 Agent 系统的“三国演义”。没有最好的语言,只有最适合的角色。
下一章预告
架构搭好了,服务也跑起来了。 但是,网络是不可靠的,服务器是会宕机的。如果 Agent 正在执行一个耗时 30 分钟的任务,跑到第 29 分钟时,机房断电了,怎么办? 难道让用户重来一遍?
下一章,我们将介绍 Temporal 工作流引擎:它是 Agent 系统的 “时光宝石” ,能让程序在崩溃后,像什么都没发生一样,从断点处 完美复活。