Files
Agent-Docs/ADKLearning/google-adk-tutorial/05-multi-agent-systems.md
Nelson 514723dbe7 init
2026-04-06 12:36:04 +08:00

632 lines
22 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 第05章多智能体系统
## 📌 本章目标
- 理解多智能体系统的设计理念
- 掌握 Agent 层级结构的构建方法
- 学习三种工作流 AgentSequential、Parallel、Loop
- 掌握常见多 Agent 协作模式
- 了解 Agent 间的通信机制
---
## 5.1 多智能体系统概述
### 5.1.1 为什么需要多智能体?
当应用变得复杂时,使用单个"巨型"Agent 会面临以下问题:
| 问题 | 说明 |
|------|------|
| **指令膨胀** | 系统指令过长LLM 难以同时遵循所有规则 |
| **工具过多** | 工具列表过长LLM 选择工具的准确率下降 |
| **难以维护** | 修改一个功能可能影响其他功能 |
| **难以调试** | 出错时难以定位问题来源 |
**多智能体系统**通过将复杂任务分解为多个专门的 Agent 来解决这些问题。
### 5.1.2 ADK 多智能体架构
```
root_agent根智能体
┌─────────────┼─────────────┐
│ │ │
LlmAgent SequentialAgent ParallelAgent
(协调器) (顺序流水线) (并行执行器)
│ │ │
┌────┼────┐ ┌────┼────┐ ┌───┴───┐
│ │ │ │ │ │ │ │
Agent Agent Agent Agent Agent Agent Agent
(子1) (子2) (子3) (步骤1)(步骤2)(任务A) (任务B)
```
---
## 5.2 Agent 层级结构
### 5.2.1 父子关系
```python
"""
Agent 层级结构基础
通过 sub_agents 参数建立父子关系
"""
from google.adk.agents import LlmAgent # 导入 LlmAgent 类
# ========================================
# 第一步:定义叶子节点 Agent最底层的 Agent
# ========================================
# 定义一个专门处理问候的 Agent
greeter_agent = LlmAgent(
name="Greeter", # Agent 名称
model="gemini-2.0-flash", # 使用 Gemini 模型
description="负责向用户打招呼和寒暄。", # 描述:用于路由决策
instruction=( # 系统指令
"你是一个友好的问候助手。\n"
"热情地向用户打招呼,并询问有什么可以帮助的。"
),
)
# 定义一个专门处理任务执行的 Agent
task_agent = LlmAgent(
name="TaskExecutor", # Agent 名称
model="gemini-2.0-flash", # 使用 Gemini 模型
description="负责执行用户的具体任务。", # 描述:用于路由决策
instruction=( # 系统指令
"你是一个任务执行助手。\n"
"认真完成用户交给你的任务。"
),
)
# ========================================
# 第二步:定义父 Agent通过 sub_agents 建立层级
# ========================================
coordinator = LlmAgent(
name="Coordinator", # 父 Agent 名称
model="gemini-2.0-flash", # 使用 Gemini 模型
description="主协调器,负责分配任务。", # 描述
instruction=( # 系统指令
"你是一个协调器。\n"
"根据用户的请求,将任务分配给合适的子 Agent。\n"
"问候和寒暄类请求交给 Greeter。\n"
"具体任务交给 TaskExecutor。\n"
"使用 transfer_to_agent 工具来委派任务。"
),
sub_agents=[ # 🔑 注册子 Agent 列表
greeter_agent, # 问候 Agent
task_agent, # 任务执行 Agent
],
)
# ========================================
# 层级关系说明
# ========================================
# coordinator
# ├── greeter_agent
# └── task_agent
#
# ADK 会自动设置:
# greeter_agent.parent_agent == coordinator
# task_agent.parent_agent == coordinator
#
# 注意:一个 Agent 只能有一个父 Agent
# 尝试将同一个 Agent 添加到多个父 Agent 会抛出 ValueError
```
### 5.2.2 多层级嵌套
```python
"""
多层级嵌套的 Agent 结构
构建更复杂的多 Agent 系统
"""
from google.adk.agents import LlmAgent, SequentialAgent # 导入 Agent 类型
# ========================================
# 第三层:具体执行 Agent
# ========================================
code_reviewer = LlmAgent(
name="CodeReviewer", # 代码审查 Agent
model="gemini-2.0-flash", # 模型
description="审查代码质量,提出改进建议。", # 描述
instruction="你是代码审查专家,审查代码并给出改进建议。", # 指令
)
test_writer = LlmAgent(
name="TestWriter", # 测试编写 Agent
model="gemini-2.0-flash", # 模型
description="为代码编写单元测试。", # 描述
instruction="你是测试工程师,为给定的代码编写单元测试。", # 指令
)
# ========================================
# 第二层:开发流水线(顺序执行)
# ========================================
dev_pipeline = SequentialAgent(
name="DevPipeline", # 流水线名称
sub_agents=[ # 按顺序执行子 Agent
code_reviewer, # 先审查代码
test_writer, # 再编写测试
],
)
# ========================================
# 第二层:其他专门 Agent
# ========================================
doc_writer = LlmAgent(
name="DocWriter", # 文档编写 Agent
model="gemini-2.0-flash", # 模型
description="编写技术文档。", # 描述
instruction="你是技术文档工程师,编写清晰的技术文档。", # 指令
)
# ========================================
# 第一层:根 Agent协调器
# ========================================
root_agent = LlmAgent(
name="RootCoordinator", # 根协调器
model="gemini-2.0-flash", # 模型
description="开发团队协调器。", # 描述
instruction=( # 指令
"你是一个开发团队协调器。\n"
"代码审查和测试任务交给 DevPipeline。\n"
"文档编写任务交给 DocWriter。"
),
sub_agents=[ # 子 Agent 列表
dev_pipeline, # 开发流水线
doc_writer, # 文档编写
],
)
# 完整层级结构:
# root_agent根协调器
# ├── dev_pipeline开发流水线 - SequentialAgent
# │ ├── code_reviewer代码审查
# │ └── test_writer测试编写
# └── doc_writer文档编写
```
---
## 5.3 工作流 Agent
### 5.3.1 SequentialAgent顺序执行
```python
"""
SequentialAgent — 顺序执行工作流
子 Agent 按照列表顺序依次执行
适用于数据处理流水线等场景
"""
from google.adk.agents import LlmAgent, SequentialAgent # 导入 Agent 类型
# ========================================
# 定义流水线的各个步骤
# ========================================
# 步骤一:信息提取 Agent
extractor = LlmAgent(
name="Extractor", # 信息提取 Agent
model="gemini-2.0-flash", # 模型
instruction="从用户输入中提取关键信息。只输出提取的关键信息。", # 指令
output_key="extracted_info", # 🔑 将输出保存到 state['extracted_info']
)
# 步骤二:信息分析 Agent
analyzer = LlmAgent(
name="Analyzer", # 信息分析 Agent
model="gemini-2.0-flash", # 模型
instruction=( # 指令:引用上一步的输出
"分析以下提取的信息,给出深度分析报告。\n"
"提取的信息:{extracted_info}" # 通过 {key} 引用 state 中的值
),
output_key="analysis_result", # 将分析结果保存到 state
)
# 步骤三:报告生成 Agent
reporter = LlmAgent(
name="Reporter", # 报告生成 Agent
model="gemini-2.0-flash", # 模型
instruction=( # 指令:引用前两步的输出
"根据分析结果生成一份简洁的报告。\n"
"原始信息:{extracted_info}\n" # 引用提取的信息
"分析结果:{analysis_result}" # 引用分析结果
),
)
# ========================================
# 创建顺序流水线
# ========================================
pipeline = SequentialAgent(
name="InfoPipeline", # 流水线名称
sub_agents=[ # 🔑 按顺序执行
extractor, # 第一步:提取信息
analyzer, # 第二步:分析信息
reporter, # 第三步:生成报告
],
)
# 执行流程:
# 1. Extractor 运行 → 输出保存到 state['extracted_info']
# 2. Analyzer 运行 → 读取 state['extracted_info'] → 输出保存到 state['analysis_result']
# 3. Reporter 运行 → 读取两个 state 值 → 生成最终报告
```
### 5.3.2 ParallelAgent并行执行
```python
"""
ParallelAgent — 并行执行工作流
子 Agent 同时执行,互不阻塞
适用于多任务同时处理的场景
"""
from google.adk.agents import LlmAgent, ParallelAgent # 导入 Agent 类型
# ========================================
# 定义并行执行的任务
# ========================================
# 任务一:天气查询 Agent
weather_agent = LlmAgent(
name="WeatherFetcher", # 天气查询 Agent
model="gemini-2.0-flash", # 模型
instruction="查询并返回用户指定城市的天气信息。只返回天气数据。", # 指令
output_key="weather_data", # 输出保存到 state['weather_data']
)
# 任务二:新闻查询 Agent
news_agent = LlmAgent(
name="NewsFetcher", # 新闻查询 Agent
model="gemini-2.0-flash", # 模型
instruction="查询并返回用户指定城市的最新新闻。只返回新闻摘要。", # 指令
output_key="news_data", # 输出保存到 state['news_data']
)
# 任务三:交通查询 Agent
traffic_agent = LlmAgent(
name="TrafficFetcher", # 交通查询 Agent
model="gemini-2.0-flash", # 模型
instruction="查询并返回用户指定城市的交通状况。只返回交通信息。", # 指令
output_key="traffic_data", # 输出保存到 state['traffic_data']
)
# ========================================
# 创建并行执行器
# ========================================
gatherer = ParallelAgent(
name="InfoGatherer", # 并行执行器名称
sub_agents=[ # 🔑 这些 Agent 将同时执行
weather_agent, # 天气查询(并行)
news_agent, # 新闻查询(并行)
traffic_agent, # 交通查询(并行)
],
)
# 执行流程:
# 1. WeatherFetcher、NewsFetcher、TrafficFetcher 同时开始执行
# 2. 各自独立运行,互不影响
# 3. 所有 Agent 完成后,后续 Agent 可以读取三个 state 值
#
# 注意事项:
# - 并行 Agent 共享同一个 session.state
# - 使用不同的 output_key 避免数据覆盖
# - 事件Event可能交错输出
```
### 5.3.3 LoopAgent循环执行
```python
"""
LoopAgent — 循环执行工作流
子 Agent 按顺序循环执行,直到满足退出条件
适用于轮询、迭代优化等场景
"""
from google.adk.agents import ( # 导入所需类型
LlmAgent, # LLM 智能体
LoopAgent, # 循环工作流
BaseAgent, # 基础智能体(用于自定义)
)
from google.adk.events import Event, EventActions # 导入事件和事件动作
from google.adk.agents.invocation_context import InvocationContext # 导入调用上下文
from typing import AsyncGenerator # 导入异步生成器类型
# ========================================
# 自定义条件检查 Agent
# ========================================
class QualityChecker(BaseAgent):
"""
质量检查 Agent
检查内容质量是否达标,决定是否继续循环
"""
async def _run_async_impl(
self,
ctx: InvocationContext, # 调用上下文
) -> AsyncGenerator[Event, None]: # 返回异步事件生成器
"""异步执行方法"""
# 从会话状态中获取当前质量分数
quality_score = ctx.session.state.get( # 读取状态
"quality_score", # 状态键名
0, # 默认值
)
# 判断质量是否达标(分数 >= 80 则通过)
is_passed = quality_score >= 80 # 质量阈值
# 生成事件,设置 escalate 标志
# escalate=True 表示退出循环
# escalate=False 表示继续循环
yield Event(
author=self.name, # 事件作者
actions=EventActions(
escalate=is_passed, # 🔑 达标则退出循环
),
content=f"质量分数: {quality_score}, {'通过' if is_passed else '未通过'}",
)
# ========================================
# 内容优化 Agent
# ========================================
content_improver = LlmAgent(
name="ContentImprover", # 内容优化 Agent
model="gemini-2.0-flash", # 模型
instruction=( # 指令
"你是一个内容优化专家。\n"
"根据当前内容的质量分数进行优化。\n"
"优化后评估质量分数0-100并更新到 state['quality_score']。"
),
)
# ========================================
# 创建循环执行器
# ========================================
optimizer_loop = LoopAgent(
name="ContentOptimizer", # 循环执行器名称
max_iterations=5, # 🔑 最大循环次数(防止无限循环)
sub_agents=[ # 每次循环依次执行
content_improver, # 第一步:优化内容
QualityChecker(name="Checker"), # 第二步:检查质量
],
)
# 执行流程:
# 迭代1: ContentImprover → Checker(分数<80, 继续)
# 迭代2: ContentImprover → Checker(分数<80, 继续)
# 迭代3: ContentImprover → Checker(分数>=80, 退出)
#
# 退出条件(满足任一即退出):
# 1. QualityChecker 设置 escalate=True
# 2. 达到 max_iterations 上限
```
---
## 5.4 常见多 Agent 协作模式
### 5.4.1 协调器/调度器模式
```python
"""
协调器/调度器模式Coordinator/Dispatcher Pattern
最常用的多 Agent 模式
父 Agent 根据用户请求动态分配任务给子 Agent
"""
from google.adk.agents import LlmAgent # 导入 LlmAgent
# 定义专门的子 Agent
math_agent = LlmAgent(
name="MathExpert", # 数学专家
model="gemini-2.0-flash", # 模型
description="擅长数学计算和统计分析。", # 描述
instruction="你是数学专家,解决数学问题。", # 指令
)
writing_agent = LlmAgent(
name="WritingExpert", # 写作专家
model="gemini-2.0-flash", # 模型
description="擅长文案撰写和内容创作。", # 描述
instruction="你是写作专家,帮助用户撰写内容。", # 指令
)
coding_agent = LlmAgent(
name="CodingExpert", # 编程专家
model="gemini-2.0-flash", # 模型
description="擅长编程和代码调试。", # 描述
instruction="你是编程专家,帮助用户解决编程问题。", # 指令
)
# 定义协调器
coordinator = LlmAgent(
name="Coordinator", # 协调器
model="gemini-2.0-flash", # 模型
description="根据问题类型分配给合适的专家。", # 描述
instruction=( # 指令
"你是一个任务协调器。\n"
"根据用户的问题类型,将任务分配给合适的专家:\n"
"- 数学相关 → MathExpert\n"
"- 写作相关 → WritingExpert\n"
"- 编程相关 → CodingExpert\n"
"使用 transfer_to_agent 工具进行任务分配。"
),
sub_agents=[ # 注册所有专家 Agent
math_agent, # 数学专家
writing_agent, # 写作专家
coding_agent, # 编程专家
],
)
```
### 5.4.2 评审/批评模式Generator-Critic
```python
"""
评审/批评模式Generator-Critic Pattern
生成器创建内容,评审器评估并给出改进建议
通过 LoopAgent 实现迭代优化
"""
from google.adk.agents import LlmAgent, LoopAgent, BaseAgent # 导入类型
from google.adk.events import Event, EventActions # 导入事件类型
from google.adk.agents.invocation_context import InvocationContext # 导入上下文
from typing import AsyncGenerator # 导入异步生成器
# 生成器 Agent创建初稿
generator = LlmAgent(
name="Generator", # 生成器
model="gemini-2.0-flash", # 模型
instruction=( # 指令
"你是一个创意写手。\n"
"根据用户需求创作内容。\n"
"将创作的内容保存到 state['draft']。"
),
output_key="draft", # 输出保存到 state['draft']
)
# 评审器 Agent评估内容质量
critic = LlmAgent(
name="Critic", # 评审器
model="gemini-2.0-flash", # 模型
instruction=( # 指令
"你是一个严格的内容评审。\n"
"评审以下内容给出评分1-10和改进建议。\n"
"当前草稿:{draft}\n"
"如果评分 >= 8将 state['approved'] 设为 True。\n"
"否则,将改进建议保存到 state['feedback']。"
),
)
# 条件检查 Agent决定是否继续循环
class ApprovalChecker(BaseAgent):
"""检查内容是否通过审批"""
async def _run_async_impl(
self,
ctx: InvocationContext, # 调用上下文
) -> AsyncGenerator[Event, None]: # 返回事件生成器
"""执行检查"""
approved = ctx.session.state.get("approved", False) # 获取审批状态
yield Event( # 生成事件
author=self.name, # 事件作者
actions=EventActions(
escalate=approved, # 通过则退出循环
),
)
# 创建迭代优化循环
review_loop = LoopAgent(
name="ReviewLoop", # 循环名称
max_iterations=3, # 最多迭代3次
sub_agents=[ # 循环体
critic, # 第一步:评审
ApprovalChecker(name="Checker"), # 第二步:检查是否通过
generator, # 第三步:如果未通过,重新生成
],
)
# 执行流程:
# 1. Generator 创建初稿 → state['draft']
# 2. Critic 评审 → 评分 < 8 → state['feedback']
# 3. Checker → approved=False → 继续循环
# 4. Generator 根据反馈修改 → state['draft']
# 5. Critic 再次评审 → 评分 >= 8 → state['approved']=True
# 6. Checker → approved=True → 退出循环
```
---
## 5.5 Agent 间通信机制
### 5.5.1 共享状态Shared State
```python
"""
Agent 间通过共享状态通信
最基础、最常用的通信方式
"""
from google.adk.agents import LlmAgent, SequentialAgent # 导入类型
# Agent A收集信息
collector = LlmAgent(
name="Collector", # 信息收集 Agent
model="gemini-2.0-flash", # 模型
instruction="收集用户需求信息。", # 指令
output_key="user_requirements", # 输出保存到 state
)
# Agent B基于 Agent A 的输出进行设计
designer = LlmAgent(
name="Designer", # 设计 Agent
model="gemini-2.0-flash", # 模型
instruction=( # 指令:引用 Agent A 的输出
"根据用户需求进行系统设计。\n"
"用户需求:{user_requirements}" # 通过 {key} 引用
),
output_key="design_doc", # 输出保存到 state
)
# Agent C基于 Agent B 的输出进行评审
reviewer = LlmAgent(
name="Reviewer", # 评审 Agent
model="gemini-2.0-flash", # 模型
instruction=( # 指令:引用 Agent A 和 B 的输出
"评审系统设计文档。\n"
"用户需求:{user_requirements}\n" # 引用需求
"设计文档:{design_doc}" # 引用设计
),
)
# 创建流水线
pipeline = SequentialAgent(
name="DesignPipeline", # 流水线名称
sub_agents=[collector, designer, reviewer], # 顺序执行
)
```
### 5.5.2 通信机制对比
| 机制 | 说明 | 适用场景 |
|------|------|----------|
| **共享 State** | 通过 `session.state` 读写数据 | 顺序流水线、数据传递 |
| **output_key** | 自动将输出保存到 State | 简单的数据传递 |
| **LLM Transfer** | LLM 动态决定委派给哪个 Agent | 灵活的任务路由 |
| **AgentTool** | 将 Agent 作为工具调用 | Agent 复用 |
| **temp: State** | 临时状态,当前调用有效 | 工具间数据传递 |
---
## 📌 本章小结
- 多智能体系统通过 `sub_agents` 参数建立层级关系
- **SequentialAgent**:子 Agent 按顺序执行,适合流水线
- **ParallelAgent**:子 Agent 并行执行,适合多任务同时处理
- **LoopAgent**:子 Agent 循环执行,适合迭代优化
- Agent 间通信主要通过共享 State 和 LLM Transfer
- `output_key` 是最简单的数据传递方式
**下一章**[第06章 - 会话与状态管理](./06-session-and-state.md) → 深入了解会话和状态管理机制。