如果你已经跟完一个智能体(Agent)开发的前四篇内容,可能会发现一个明显的趋势:
👉 Agent 越做越复杂,越不像“一个人”,
👉 越像“一个团队”。
这并非偶然,而是复杂系统在工程化过程中的必然演化。

单 Agent 的天花板在哪里?
即使你的智能体已经集成了以下能力:
单智能体架构依然面临三个绕不过去的核心瓶颈:
❌ 认知负载过高
一个Agent需要同时承担过多职责:
大型语言模型(LLM)在如此长的思维链中非常容易出现“思维退化”或遗忘上下文。
❌ 任务类型混杂
同一个Agent常常被迫处理性质迥异的任务:
- IO 密集任务(如网络请求、文件读写)
- 推理密集任务(需要复杂思考与规划)
- 规则性处理(固定流程或计算)
从架构角度看,这是一种责任混淆。
❌ 扩展性极差
随着需求增长,你很难清晰地定义:“这个 Agent,到底负责什么?” 其核心提示词(Prompt)会迅速变得臃肿和难以维护。
多 Agent 不是“更多 Agent”,而是角色分工
真正具备落地可能性的多Agent系统,其架构几乎都会收敛到一种经典模型:
┌─────────────┐
│ Supervisor │
│ (Planner) │
└──────┬──────┘
│
┌──────────┴───────────┐
│ │ │
┌───▼───┐ ┌───▼───┐ ┌───▼───┐
│Worker │ │Worker │ │Worker │
│ (IO) │ │ (IO) │ │(Logic)│
└───────┘ └───────┘ └───────┘
一句话概括核心思想:
Supervisor 负责“想清楚”
Worker 负责“把事做完”
这是“工程世界”早就验证过的模式
如果你有分布式系统或后端开发背景,会发现这个模型似曾相识:
| 系统 |
对应关系 |
| Kubernetes |
Controller / Pod |
| 大数据系统 |
Coordinator / Executor |
| 编译器 |
Planner / Pass |
| 数据库 |
Optimizer / Operator |
多Agent协作,只是在大语言模型(LLM)能力加持下,对经典系统设计模式的一次成功复现与演进。
Rust 中的核心抽象:Agent ≠ LLM
首先,我们需要建立一个至关重要的工程级抽象,将“Agent”定义为一个行为,而非某个具体的模型:
pub trait Agent {
async fn handle(&self, input: AgentInput) -> AgentOutput;
}
Supervisor Agent
pub struct Supervisor {
llm: Arc<dyn LlmClient>,
}
其职责非常明确,只有三项:
- 理解用户目标
- 生成任务执行图(Task Graph)
- 将任务分配给合适的 Worker
Worker Agent
pub struct Worker {
executor: Arc<AgentExecutor>,
}
Worker的职责则非常纯粹:
- 不进行全局规划
- 不进行事后反思
- 不生成最终总结
- 只专注于执行被分配的具体任务
Supervisor 的输入与输出:不是“对话”,而是“结构”
pub struct SupervisorInput {
pub goal: String,
pub context: Vec<Observation>,
}
Supervisor Output
pub struct SupervisorPlan {
pub graph: TaskGraph,
pub assignment: HashMap<TaskId, WorkerId>,
}
请注意关键词:assignment(分配)。Supervisor 的输出是一个结构化的计划,明确了“做什么”以及“谁来做”。
Worker 为什么必须“去智能化”?
这是一个关键且可能反直觉的工程原则。
❌ Worker 越“聪明”,系统越不稳定
✅ Worker 越“愚钝”,系统越可靠
Worker 的理想特性
- 无状态:不保存与会话或任务相关的长期上下文。
- 可重试:失败后可以安全地重新执行。
- 可并发:多个Worker实例可以并行处理任务。
- 可替换:Worker之间可以相互替代,实现负载均衡。
其实现应尽可能简单:
impl Agent for Worker {
async fn handle(&self, input: AgentInput) -> AgentOutput {
self.executor.run_task(input.task).await
}
}
核心要义:不要让 Worker 再浪费一次 LLM 调用来思考“我该怎么做?”,它应该直接调用预设的工具或函数。
Agent Pool:让 Worker 成为“资源”
一旦 Worker 被设计为无状态的,我们就可以将其池化管理,这与连接池、线程池的思想一脉相承。
pub struct AgentPool {
workers: Vec<Worker>,
semaphore: Semaphore,
}
这样做的好处显而易见:
- 并发上限控制:通过信号量限制同时活跃的Worker数量。
- 成本可控:避免无限制地创建昂贵资源(如LLM客户端)。
- 自动负载均衡:任务可以均匀分配到空闲的Worker上。
let worker = pool.acquire().await;
let result = worker.handle(task).await;
pool.release(worker);
当你实现到这一步时,你其实已经在构建一个微型的Agent运行时(Agent Runtime)了。
多 Agent 通信:消息,而不是函数调用
在生产级别的系统中,Agent之间不应通过直接的函数调用来耦合,而应通过异步的结构化消息进行通信。
pub enum AgentMessage {
Task(Task),
Result(TaskResult),
Control(ControlSignal),
}
消息通道的实现可以根据规模选择:
- Tokio channel:适用于单机部署,高性能。
- Kafka / Redis:适用于分布式部署,具备持久化和扩展性。
这揭示了一个更深刻的工程原则:定义清晰的通信协议,远比琢磨精巧的Prompt技巧更为重要和根本。
失败处理:Supervisor 才有“决策权”
当Worker执行失败时,它只负责如实上报结构化错误:
{
“task“: “C“,
“status“: “failed“,
“error“: “timeout“
}
而是否重试、如何降级、是否调整任务图(DAG)、乃至是否终止整个流程,这些决策权完全归属于Supervisor。
match failure {
Timeout => retry_subgraph(),
RateLimit => reduce_concurrency(),
LogicError => replan(),
}
至此,我们实现了彻底的解耦:“思考决策”(Supervisor)与“忠实执行”(Worker)各司其职。
多 Agent + Memory:组织级学习
在多Agent架构中,记忆的层级也随之进化:
- Worker:通常设计为无长期记忆,或仅有极短的上下文。
- Supervisor:拥有语义记忆(Semantic Memory),能够从历史交互中学习。
Supervisor可以逐渐学会:
- 哪一类任务更适合分配给哪一个特定类型的Worker。
- 哪一种DAG任务图结构具有更高的成功率。
- 哪一种失败处理策略成本最低、效果最好。
当系统具备这种能力时,你的多Agent系统已经迈入了自优化系统的范畴。
到这里,你已经写出了什么级别的东西?
如果你将构建智能体的系列能力——基础循环、执行器与并发、长期记忆、DAG调度以及本文的多Agent协作——叠加在一起,你所拥有的不再是一个“玩Prompt的脚本”。
你现在构建的,实际上是一个:
LLM 驱动的分布式任务操作系统(Agent OS)
这套系统具备了清晰的角色分工、结构化的通信、池化的资源管理、集中的决策与学习能力。这正是现代人工智能应用,特别是复杂Agent系统走向工程化、产品化的核心路径。希望这篇关于Rust实现多Agent协作的探讨,能为你构建更可靠的智能系统带来启发。欢迎在云栈社区交流更多系统架构的实践经验。