多 Agent:角色、职责与输入输出边界

给多个角色起名字并不等于完成了分工。每个角色需要明确收到什么、交出什么、能使用哪些工具,以及由谁处理冲突。下面先看任务怎样拆得清楚,再讨论独立上下文和并行的价值。

多 Agent 的核心是协调,不是让多个角色自由聊天。拆分必须带来至少一种明确收益:独立上下文、并行处理、专业工具隔离、独立复核或权限隔离。

1. 常见角色

  • Planning-only Planner:拆解目标并生成可验证子任务,由独立 Worker 执行。这是一种职责隔离模式;小型系统也可由同一 Agent 规划后执行。
  • Executor/Worker:执行限定任务并返回产物和证据。
  • Researcher:搜集来源、区分事实与推断。
  • Writer:基于给定证据组织内容。
  • Reviewer/Critic:按 rubric 找缺陷,不直接改变目标。
  • Router:根据请求类型选择执行路径。
  • Supervisor:分派任务、汇总状态、处理冲突和停止。

角色名没有价值,清晰契约才有价值。

2. Task Contract

Python
from dataclasses import dataclass @dataclass(frozen=True) class DelegatedTask: task_id: str parent_task_id: str objective: str input_refs: tuple[str, ...] allowed_tools: tuple[str, ...] write_scope: tuple[str, ...] output_schema: "JSONSchema" acceptance_criteria: tuple["Check", ...] deadline: str max_steps: int
Rust
struct DelegatedTask { task_id: String, parent_task_id: String, objective: String, input_refs: Vec<String>, allowed_tools: Vec<String>, write_scope: Vec<String>, output_schema: JsonSchema, acceptance_criteria: Vec<Check>, deadline: String, max_steps: u32, }
JavaScript
/** * @typedef {{ * taskId: string, * parentTaskId: string, * objective: string, * inputRefs: string[], * allowedTools: string[], * writeScope: string[], * outputSchema: JSONSchema, * acceptanceCriteria: Check[], * deadline: string, * maxSteps: number * }} DelegatedTask */
TypeScript
type DelegatedTask = { taskId: string parentTaskId: string objective: string inputRefs: string[] allowedTools: string[] writeScope: string[] outputSchema: JSONSchema acceptanceCriteria: Check[] deadline: string maxSteps: number }

Worker 返回:

Python
from dataclasses import dataclass from typing import Any, Literal @dataclass(frozen=True) class TaskResult: task_id: str status: Literal["completed", "partial", "blocked", "failed"] output: Any evidence_refs: tuple[str, ...] changes: tuple["ChangeSummary", ...] validation: "ValidationResult" remaining: tuple[str, ...]
Rust
enum TaskStatus { Completed, Partial, Blocked, Failed, } struct TaskResult { task_id: String, status: TaskStatus, output: serde_json::Value, evidence_refs: Vec<String>, changes: Vec<ChangeSummary>, validation: ValidationResult, remaining: Vec<String>, }
JavaScript
/** * @typedef {{ * taskId: string, * status: 'completed'|'partial'|'blocked'|'failed', * output: unknown, * evidenceRefs: string[], * changes: ChangeSummary[], * validation: ValidationResult, * remaining: string[] * }} TaskResult */
TypeScript
type TaskResult = { taskId: string status: 'completed' | 'partial' | 'blocked' | 'failed' output: unknown evidenceRefs: string[] changes: ChangeSummary[] validation: ValidationResult remaining: string[] }

3. 职责边界

  • 采用 planning-only 模式时,Planner 不直接写文件,以保持计划输出可独立审查;混合 Planner/Executor 则要显式记录它何时从规划切换到执行;
  • Writer 只使用 Researcher 提供的 Evidence;
  • Reviewer 依据固定 rubric,不凭风格偏好无限扩展;
  • Worker 的工具和写入范围是最小集合;
  • Supervisor 决定接受、重做、合并或结束。

4. 上下文隔离

子 Agent 不必继承全部历史。应只获得完成任务需要的目标、输入引用、约束、工具和验收标准。隔离能降低 token、减少无关偏见,也降低敏感信息扩散。

5. 何时不拆

  • 任务只需少量连续步骤;
  • 子任务强依赖同一上下文;
  • 协调成本高于并行收益;
  • 没有明确输出 schema;
  • Reviewer 只是重复主 Agent 的主观判断;
  • 工具或资源存在强写冲突。

先测单 Agent 基线,再用相同任务集比较成功率、成本、延迟和故障率。

给子任务一张足够用的任务单

让两个 Worker 分别检查接口和测试时,先写清各自能改哪些文件、输入基线是什么、最后要交什么证据。比如接口 Worker 交接口差异与相关用例,测试 Worker 交失败复现与结果;不要只说“你负责质量”。

Deep Agents 的子 Agent 中间件提供了独立任务调用的实现入口,但上下文分开不意味着文件系统、存储或权限自动分开。共享 backend 时,两个 Worker 仍可能碰到同一份文件。

练习先只允许两个 Worker 阅读,汇总它们引用的路径与结论。确认输出能够合并后,再允许各自修改不同文件,最后串行整合并跑一次完整检查。任务单应写入真实资源边界,不能只依赖角色名字。

本节的核验依据

2026-10-25 查阅。下面的链接支持本节的机制说明;练习场景和选型建议是本教程的教学设计。