多 Agent 协作实战:Supervisor 模式构建专家团队,突破单一 Agent 能力边界

多 Agent 协作实战:Supervisor 模式构建专家团队,突破单一 Agent 能力边界

在前一篇文章中,我们构建了一个融合 Memory、Tools、RAG 的完整 Agent。它能够自主决策、调用工具、检索知识,在单线程任务中表现出色。但当你面对更复杂的真实业务场景时,单一 Agent 很快会遇到瓶颈:

  • 用户要求"写一个 Spring Boot 项目并生成测试用例和文档",一个 Agent 既当架构师又当程序员又当测试工程师,很容易顾此失彼;
  • 上下文窗口有限,不能把所有专业知识和工具塞进同一个 Agent;
  • 模型在长流程中容易"迷失方向",遗忘早期决定;
  • 不同任务的最优参数差异很大:写代码需要低 temperature,头脑风暴需要高 temperature。

解决这些问题的思路,与人类组织协作的方式完全一致:拆分职责,建立专家团队,并设置一个主管进行调度。本文将详细讲解多 Agent 协作的 Supervisor(主管)模式,并通过 Spring AI 实现一个包含 Researcher、Coder、Reviewer 的专家系统。


一、单一 Agent 的能力边界

先明确:单一 Agent 不是不能做复杂任务,而是做复杂任务的失败率和成本随着任务长度指数级增加。具体瓶颈包括:

1. 上下文长度限制

模型上下文窗口有限。一个 Agent 既需要存储任务背景,又要装入大量专业技术规范、历史对话、工具返回结果,很快就会超出窗口。超出部分要么被截断,要么需要压缩,信息丢失随之而来。

2. 工具与知识冲突

让一个 Agent 同时掌握"公司内部政策"和"Java 代码生成规则"和"网站内容审核规范",这些知识的启发式规则可能互相干扰。模型可能在写代码时忽然蹦出客服话术。

3. 注意力稀释

模型需要同时关注"用户需求"、"代码正确性"、"潜在 bug"、"文档风格",导致顾此失彼。HumanEval 等基准测试显示,分步细化往往比一步到位更可靠。

4. 难以调试与迭代

如果所有逻辑都在一个 Agent 中,某一步出错会影响全局,而且很难定位是哪个环节出了问题。如果拆分为多个 Agent,每一环节都能独立测试和优化。

因此,多 Agent 协作是突破这些瓶颈的自然选择。


二、多 Agent 协作模式概览

多 Agent 系统有若干经典组织架构:

模式 结构 适用场景
Supervisor(主管-工人) 一个主管 Agent 负责拆解任务并分派给多个专家 Agent,最后汇总结果 大多数复杂任务,灵活可控
Pipeline(流水线) 多个 Agent 线性接力,前一个输出作为后一个输入 文档处理、数据管道
Debate(辩论) 多个 Agent 围绕同一问题给出观点并相互质疑 决策支持、内容审核
Hierarchical(层级) 高层主管管理中层主管,中层管理基层执行 超大规模任务分解

其中 Supervisor 模式​ 是最实用、最容易落地的一种。它模拟了一个项目经理 + 数个专家的团队,既能发挥每个专家的专业性,又能通过主管动态调整策略。


三、Supervisor(主管)模式的架构与设计

3.1 核心概念

Supervisor 模式包含两类 Agent:

  • Supervisor Agent:负责理解用户需求、制定计划、将子任务分派给合适的专家、接收专家成果并整合为最终回复。它不直接执行具体业务,而是做"决策与协调"。

  • Worker Agent(专家 Agent) :每个 Worker 聚焦于特定领域,如 Researcher、Coder、Reviewer。它们接收明确的任务描述,执行专业操作后返回结果。

    用户请求

    Supervisor Agent ──路由──→ Researcher Agent → 返回研究报告
    │ Coder Agent → 返回代码
    │ Reviewer Agent → 返回审查意见

    Supervisor Agent 整合结果 → 最终回复

3.2 路由决策方式

主管如何决定将任务分派给哪个专家?有两种策略:

1. 基于规则的路由(Rule-based)

通过关键词匹配或模型意图分类,将问题映射到固定专家。例如:

  • 包含"查询""搜索""研究" → Researcher
  • 包含"代码""实现""修复" → Coder
  • 包含"检查""审查""评价" → Reviewer

优点:简单可控、延迟低、成本低。

缺点:无法应对复杂混合请求,例如"写一个函数并帮我检查"。

2. 基于模型的路由(Model-based)

将专家列表作为工具注册给 Supervisor Agent,让模型自己决定调用哪个专家,甚至按顺序调用多个专家。这是 Spring AI 中最自然的方式,也是本文采用的方式。

ini 复制代码
Supervisor Agent 的 tools = [research(), code(), review()]

模型根据用户请求自主生成工具调用序列,例如:

css 复制代码
用户: "写一个快速排序,并审查我的代码。"
模型决策: code() → review()

3.3 专家 Agent 的设计原则

每个专家 Agent 应做到:

  • 职责单一:只做一类事,提示词中严格限定范围;
  • 上下文隔离:专家不直接访问用户主对话的历史,只接收主管传入的显式任务描述;
  • 可独立测试:每个专家的能力可以单独调用、评估;
  • 输出结构化:专家返回的结果尽量结构清晰,便于主管整合。

四、专家 Agent 实战设置

我们构建一个软件开发场景的专家团队:

  • Researcher:负责搜索网络或知识库,收集技术资料、文档、最佳实践;
  • Coder:负责编写代码,可调用代码解释器或生成代码片段;
  • Reviewer:负责审查代码质量,指出潜在问题和改进建议。

下面用 Spring AI 实现这三个专家 Agent。

4.1 Researcher Agent

它需要 RAG 或网络搜索能力。我们在这里让其通过工具从向量库检索(复用前文 RAG),也可以加一个 Web 搜索工具。

arduino 复制代码
@Component
public class ResearcherAgent {

    private final ChatClient researcherClient;

    public ResearcherAgent(ChatModel chatModel, VectorStore vectorStore) {
        this.researcherClient = ChatClient.builder(chatModel)
                .defaultSystem("""
                        你是一名专业研究员。你的职责是根据用户给出的研究课题,查找相关资料,梳理成结构化的研究报告。
                        回答必须基于事实,注明资料出处。如果资料不足,请明确说明。
                        输出格式:
                        ## 研究结论
                        ...
                        ## 主要依据
                        - 来源1:...
                        - 来源2:...
                        """)
                .defaultAdvisors(new QuestionAnswerAdvisor(vectorStore))  // 注入RAG
                .build();
    }

    public String research(String topic) {
        return researcherClient.prompt()
                .user(topic)
                .call()
                .content();
    }
}

4.2 Coder Agent

Coder 负责生成代码。它可以定义代码生成的 System Prompt,指定语言、风格、输出格式。

arduino 复制代码
@Component
public class CoderAgent {

    private final ChatClient coderClient;

    public CoderAgent(ChatModel chatModel) {
        this.coderClient = ChatClient.builder(chatModel)
                .defaultSystem("""
                        你是一位资深软件工程师。根据需求编写高质量代码。
                        要求:
                        1. 代码简洁、健壮,包含必要的注释。
                        2. 输出代码块(markdown格式)。
                        3. 提供简短的实现说明。
                        """)
                .build();
    }

    public String code(String requirement) {
        return coderClient.prompt()
                .user(requirement)
                .call()
                .content();
    }
}

4.3 Reviewer Agent

Reviewer 审查代码,给出改进意见。

arduino 复制代码
@Component
public class ReviewerAgent {

    private final ChatClient reviewerClient;

    public ReviewerAgent(ChatModel chatModel) {
        this.reviewerClient = ChatClient.builder(chatModel)
                .defaultSystem("""
                        你是一位代码审查专家。请审查以下代码,指出潜在问题(bug、安全漏洞、性能问题、可维护性),
                        并给出改进建议。用列表形式输出:问题 + 严重程度 + 建议。
                        """)
                .build();
    }

    public String review(String code) {
        return reviewerClient.prompt()
                .user("请审查这段代码:\n" + code)
                .call()
                .content();
    }
}

五、Supervisor Agent 组装:将专家封装为工具

为了让 Supervisor Agent 能调用上述专家,我们需要将每个专家的方法封装为 @Tool。Spring AI 的工具调用机制天然支持这一模式。

5.1 将专家方法暴露为工具

创建一个 TeamTools组件,将各专家 Agent 的方法包装为 @Tool方法:

kotlin 复制代码
@Component
public class TeamTools {

    private final ResearcherAgent researcherAgent;
    private final CoderAgent coderAgent;
    private final ReviewerAgent reviewerAgent;

    public TeamTools(ResearcherAgent researcherAgent,
                     CoderAgent coderAgent,
                     ReviewerAgent reviewerAgent) {
        this.researcherAgent = researcherAgent;
        this.coderAgent = coderAgent;
        this.reviewerAgent = reviewerAgent;
    }

    @Tool(description = "调用研究员专家,进行资料搜索、技术调研、信息汇总。适用于需要查找资料、文档、最佳实践的场景。")
    public String research(@ToolParam(description = "研究课题或问题") String topic) {
        return researcherAgent.research(topic);
    }

    @Tool(description = "调用开发专家,根据需求生成代码。适用于编写、实现、修改、重构代码的场景。")
    public String code(@ToolParam(description = "代码开发需求,尽量详细") String requirement) {
        return coderAgent.code(requirement);
    }

    @Tool(description = "调用审查专家,对代码进行质量审查、bug检测、性能分析与改进建议。")
    public String review(@ToolParam(description = "需要审查的代码") String code) {
        return reviewerAgent.review(code);
    }
}

5.2 构建 Supervisor ChatClient

Supervisor Agent 只负责规划和汇报,不亲自实现业务逻辑。它的配置如下:

python 复制代码
@Configuration
public class SupervisorAgentConfig {

    @Bean
    public ChatClient supervisorClient(ChatModel chatModel, TeamTools teamTools) {
        return ChatClient.builder(chatModel)
                .defaultSystem("""
                        你是一个团队主管,手下有三位专家:研究员(Research)、程序员(Coder)、审查员(Reviewer)。
                        当用户提出请求时,你需要:
                        1. 分析用户意图,判断需要哪些专家协作。
                        2. 按顺序调用合适的专家工具,每个工具调用之间确保参数传递正确。
                        3. 将专家的成果整合成清晰、完整的最终报告回复用户。

                        注意:
                        - 如果任务需要代码,请调用coder。
                        - 如果代码写完后需要检查质量,请调用reviewer,并把代码作为参数传入。
                        - 如果任务需要了解外部资料或公司知识,请调用researcher。
                        - 不要自己编造专家结论,必须使用工具返回的真实结果。
                        """)
                .defaultTools(teamTools)   // 注册专家工具
                .build();
    }
}

5.3 与记忆结合

为了支持多轮对话,我们可以在 Supervisor 调用时绑定 ChatMemory:

less 复制代码
@RestController
@RequestMapping("/api/team")
public class TeamController {

    private final ChatClient supervisorClient;

    public TeamController(ChatClient supervisorClient) {
        this.supervisorClient = supervisorClient;
    }

    @GetMapping("/chat")
    public String chat(@RequestParam String sessionId, @RequestParam String message) {
        return supervisorClient.prompt()
                .user(message)
                .memory(sessionId)
                .call()
                .content();
    }

    @GetMapping(value = "/chat/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<String> chatStream(@RequestParam String sessionId, @RequestParam String message) {
        return supervisorClient.prompt()
                .user(message)
                .memory(sessionId)
                .stream()
                .content();
    }
}

5.4 完整工作流示例

假设用户请求: "请用 Java 写一个计算斐波那契数列的函数,并审查这段代码"

Supervisor Agent 的循环可能如下:

  1. 思考:用户需要代码和审查。我应该先调用 coder,再调用 reviewer。
  2. 行动 :调用 code(requirement="用Java写斐波那契数列函数")
  3. 观察:Coder Agent 返回代码 + 说明。
  4. 再思考:代码已生成,现在需要审查。
  5. 行动 :调用 review(code=上一步返回的代码部分)
  6. 观察:Reviewer 返回问题列表与建议。
  7. 再思考:信息完整,可以生成最终回答。
  8. 生成总结:包含代码、审查结果、最终建议。

这样一个复杂任务被分解为两个专家协作完成,且每个专家保持专注,质量远高于单个 Agent 硬着头皮生成。


六、深入:如何保证专家间的上下文传递

在 Supervisor 模式中,专家 Agent 之间不直接通信。它们只接收 Supervisor 传来的参数,返回自己的结果。因此,参数设计是上下文传递的关键。

6.1 简单参数传递

对于 Coder → Reviewer 的流程,Supervisor 需要从 Coder 的输出中提取代码块,传给 Reviewer。模型通常能够识别代码块。为了降低解析难度,我们可以在 Coder Agent 的 System Prompt 中强制要求输出 JSON 结构:

sql 复制代码
Coder Agent System Prompt 修改为:
"""
输出格式必须严格为JSON:
{
  "language": "Java",
  "code": "...代码内容...",
  "explanation": "...实现说明..."
}
"""

然后,Supervisor 模型可以获得结构化结果,更容易将 code字段提取出来传给 review工具。由于 Spring AI 的 BeanOutputConverter可以帮助解析,也可以在 Coder Agent 内部返回转换后的对象或字符串。简单起见,可以让 Coder 返回纯 Markdown 代码块,模型通常能正确提取。

6.2 使用 JSON Tool 参数

工具参数本身就是结构化的。review工具的 code参数会被模型填充。模型通过观察 coder 工具的结果,将代码部分抽取出来填入 review 参数。这是大模型的能力范围,通常工作良好。

6.3 深层上下文传递

如果任务非常复杂,一个部门可能需要多步协作。例如:

  • Researcher 收集资料 → 传给 Coder 作为开发依据 → 传给 Reviewer 审查。

此时,Supervisor 的提示词中应明确指示: "将先前研究结果中的关键结论作为需求的一部分传递给编程专家" 。模型能够自动完成这一聚合。


七、进阶:动态团队协作与条件分支

Supervisor 模式不一定是线性的。模型完全可以根据需要动态决定调用顺序和次数。例如:

  • 用户请求:"对比 Spring Boot 2 和 3 的差异,并写一个迁移指南。"
  • 模型可以:research("Spring Boot 2 vs 3 差异")→ 得到资料 → code("基于上述资料编写迁移步骤示例")review("检查示例代码")

再如:

  • 用户请求:"这段代码有性能问题吗?"
  • 模型直接 review(code),无需 research。

因此,只要工具描述清晰,模型的表现就是灵活的。我们还可以添加更多专家工具,例如 architecttesterdocumenter等,扩展团队能力。

7.1 并行调用多个工具

Spring AI 的 ChatClient 也支持一次生成多个工具调用。如果用户希望同时查天气和查订单,模型可能同时输出两个工具调用。但专家 Agent 之间存在依赖关系(如 Coder → Reviewer)时,模型会顺序执行。这种机制由模型自动决定,无需额外编码。

7.2 主管的记忆

Supervisor 的 ChatMemory 保存了整个多 Agent 协作历史。在后续对话中,模型可以记住之前生成过什么代码、审查结果如何,从而进行针对性修改。


八、生产环境多 Agent 系统的最佳实践

8.1 防止失控循环

多 Agent 系统中,模型可能反复调用工具而无法收尾。Spring AI 的自动循环有内部轮数限制,但为了安全和成本,建议:

  • 在基础设施层面设置超时(如 60 秒);
  • 监控每次调用的工具次数,异常时告警;
  • 在 Supervisor System Prompt 中严格要求"最多调用 X 次工具"或"一旦获得足够信息立即总结"。

8.2 成本控制

每个专家调用都会产生 token 费用。优化建议:

  • 专家 Agent 使用更小的模型(如 gpt-4o-mini),而 Supervisor 使用更强模型(如 gpt-4o);
  • 限制专家返回内容长度,例如让 Coder 只返回核心代码,不输出过多解释;
  • 对于 Reviewer,可以传入代码片段而非整个文件,减少 token。

8.3 可观测性与调试

多 Agent 系统难以调试,必须记录完整链路:

c 复制代码
log.info("Supervisor准备调用工具,工具名称: {}", toolName);
log.info("工具参数: {}", args);
log.info("工具返回: {}", result);

也可以自定义 Advisor 记录每次请求响应。实现方式可参考本文 4.2 节。

8.4 专家 Agent 的独立测试

每一个专家都可以单独作为接口暴露,便于测试:

less 复制代码
@RestController
@RequestMapping("/api/team/agents")
public class AgentController {

    private final ResearcherAgent researcher;
    private final CoderAgent coder;
    private final ReviewerAgent reviewer;

    // 构造函数注入...

    @PostMapping("/research")
    public String research(@RequestBody String topic) {
        return researcher.research(topic);
    }

    @PostMapping("/code")
    public String code(@RequestBody String requirement) {
        return coder.code(requirement);
    }

    @PostMapping("/review")
    public String review(@RequestBody String code) {
        return reviewer.review(code);
    }
}

这样可以在集成 Supervisor 前,单独验证每个专家的效果,并针对性地调整其 System Prompt。

8.5 权限与安全

专家 Agent 可能包含更敏感的工具(如 Coder 调用代码执行器、Researcher 调用 Web 搜索)。必须确保这些工具经过授权,不能因为模型被提示词注入而执行危险操作。建议:

  • 每个专家 Agent 的 System Prompt 中加入安全约束;
  • 高权限专家(如 Coder 中的代码执行)不应随意外放给终端用户;
  • 工具执行过程做好审计。

九、总结

多 Agent 协作是解决复杂任务的必然趋势。Supervisor 模式通过一个主管 Agent 动态调度多个专家 Agent,将问题分解、专业分工、结果整合,类似于一个高效的团队。

在 Spring AI 中实现 Supervisor 模式的步骤可以概括为:

  1. 定义专家 Agent :每个专家是一个独立的 ChatClient,有自己特有的 System Prompt、工具和记忆。
  2. 将专家封装成工具 :用 @Tool注解暴露专家的核心方法,供 Supervisor 调用。
  3. 构建主管 Agent :注册专家工具,通过 ChatClient自动的 ReAct 循环实现"思考 → 调用专家 → 查看结果 → 再决策"。
  4. 加入记忆与会话隔离:使用 ChatMemory + conversationId 维持多轮对话。
  5. 监控与优化:记录日志、控制成本、独立测试每个专家。

现在我们拥有了一个可扩展的 Agent 团队。将来要新增能力,只需增加一个专家 Agent,再将其封装为工具注册给主管即可。这种架构让 AI 应用拥有了"组织能力",能够应对真实世界中高度复杂的任务。

相关推荐
BingoGo1 小时前
PHP Trait 为何可能成为语言的关键特性
后端·php
名字还没想好☜1 小时前
Python 的 __call__ 实战:让实例像函数一样被调用,做带状态计数器、缓存器与可配置策略
开发语言·后端·python·缓存·编程语言
杨利杰YJlio1 小时前
ITSK PE 26U5 测试版解读:组件完善、VMD 修复与服务器支持边界
前端·javascript·后端
PragmaticWorks1 小时前
充血模型该充到什么地步?
后端·领域驱动设计
雨辰AI1 小时前
信创多租户项目 9 大踩坑|数据隔离失效、权限越权终极解决(金仓 / 达梦 / 高斯全库适配)
java·大数据·数据库·后端
广州山泉婚姻1 小时前
微服务时代,前后端分离架构该怎样高效协同?
前端·后端
孙启超1 小时前
【AI开发之Rust】第 5 课:引用与生命周期 —— 借用能活多久?
人工智能·后端·rust·llm·ai应用开发
EatFan1 小时前
多租户系统到底怎么设计?从 tenant_id 到 JWT 租户隔离的真实实践
前端·后端·全栈·多租户
Bs_MoneyMagnet1 小时前
基于springboot+vue的旅游行程分享与推荐小程序的设计与实现 源码+文档
java·vue.js·spring boot·后端·微信小程序·毕业设计·计算机毕业设计