# 快速入门：通过 A2A 消费远程智能体

Supported in ADKPythonExperimental

本快速入门涵盖了任何开发者最常见的起点：**“有一个远程智能体，如何让我的 ADK 智能体通过 A2A 使用它？”**。这对于构建复杂的多智能体系统至关重要，其中不同的智能体需要协作和交互。

A2A Python SDK 版本兼容性

ADK 的 A2A 集成兼容 A2A SDK 的两个主要版本 （`a2a-sdk` 0.3.x 和 1.x.x）。已安装的 A2A SDK 版本会被 自动检测，因此无需修改你的 ADK 应用代码。

虽然 `a2a-sdk` 0.3.x 在兼容模式下受支持，但新的 集成应以 1.x.x 为目标。如果你的代码直接引用了 `a2a-sdk` 类型 （例如，自定义执行器或手动构建的 `AgentCard` 实例）， 在迁移到 1.x.x 时请参阅 [A2A SDK v1.0 迁移指南](https://github.com/a2aproject/a2a-python/tree/main/docs/migrations/v1_0)。

## 概览

本示例演示了智能体开发工具包（ADK）中的\*\*智能体到智能体（A2A）\*\*架构，展示了多个智能体如何协同工作来处理复杂任务。该示例实现了一个可以滚动骰子并检查数字是否为质数的智能体。

```text
┌─────────────────┐    ┌──────────────────┐    ┌────────────────────┐
│   根智能体       │───▶│   滚动智能体     │    │   远程质数         │
│  (本地)         │    │   (本地)         │    │   智能体           │
│                 │    │                  │    │  (localhost:8001)  │
│                 │───▶│                  │◀───│                    │
└─────────────────┘    └──────────────────┘    └────────────────────┘
```

A2A 基础示例包含：

- **根智能体**（`root_agent`）：将任务委托给专门子智能体的主协调器
- **滚动智能体**（`roll_agent`）：处理骰子滚动操作的本地子智能体
- **质数智能体**（`prime_agent`）：检查数字是否为质数的远程 A2A 智能体，此智能体在单独的 A2A 服务器上运行

## 使用 ADK 服务器暴露你的智能体

ADK 提供了一个内置的 CLI 命令 `adk api_server --a2a` 来使用 A2A 协议暴露你的智能体。

在 `a2a_basic` 示例中，你首先需要通过 A2A 服务器暴露 `check_prime_agent`，以便本地根智能体可以使用它。

### 1. 获取示例代码

首先，确保安装了必要的依赖项：

```bash
pip install google-adk[a2a]
```

你可以克隆并导航到[**`a2a_basic`** 示例](https://github.com/google/adk-python/tree/main/contributing/samples/a2a/a2a_basic)：

```bash
git clone https://github.com/google/adk-python.git
```

正如你将看到的，文件夹结构如下：

```text
a2a_basic/
├── remote_a2a/
│   └── check_prime_agent/
│       ├── __init__.py
│       ├── agent.json
│       └── agent.py
├── README.md
├── __init__.py
└── agent.py # 本地根智能体
```

#### 主智能体 (`a2a_basic/agent.py`)

- **`roll_die(sides: int)`**：用于滚动骰子的函数工具
- **`roll_agent`**：专门从事骰子滚动的本地智能体
- **`prime_agent`**：远程 A2A 智能体配置
- **`root_agent`**：具有委托逻辑的主协调器

#### 远程质数智能体 (`a2a_basic/remote_a2a/check_prime_agent/`)

- **`agent.py`**：质数检查服务的实现
- **`agent.json`**：A2A 智能体的智能体卡片
- **`check_prime(nums: list[int])`**：质数检查算法

### 2. 启动远程质数智能体服务器

为了展示你的 ADK 智能体如何通过 A2A 消费（Consuming）远程智能体，你首先需要启动一个远程智能体服务器，它将托管质数智能体（在 `check_prime_agent` 下）。

```bash
# 启动远程 A2A 服务器，在端口 8001 上提供 check_prime_agent 服务
adk api_server --a2a --port 8001 contributing/samples/a2a/a2a_basic/remote_a2a
```

使用 `--log_level debug` 添加日志进行调试

要启用调试级日志记录，你可以在 `adk api_server` 中添加 `--log_level debug`，如下所示：

```bash
adk api_server --a2a --port 8001 contributing/samples/a2a/a2a_basic/remote_a2a --log_level debug
```

这将为你提供更丰富的日志，以便在测试智能体时进行检查。

为什么使用端口 8001？

在本快速入门中，当在本地测试时，你的智能体将使用 localhost，因此暴露智能体（远程质数智能体）的 A2A 服务器的 `port` 必须与消费智能体的端口不同。你将与之交互的消费智能体的 `adk web` 的默认端口是 `8000`，这就是为什么 A2A 服务器使用单独的端口 `8001` 创建的原因。

执行后，你应该看到类似以下内容：

```shell
INFO:     Started server process [56558]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     Uvicorn running on http://127.0.0.1:8001 (Press CTRL+C to quit)
```

### 3. 注意远程智能体所需的智能体卡片（`agent.json`）

A2A 协议要求每个智能体都必须有一个描述其功能的智能体卡片。

如果其他人已经构建了你希望在你的智能体中消费的远程 A2A 智能体，你应该确认他们提供了智能体卡片（`agent.json`）。`adk api_server --a2a` 命令只会通过 A2A 暴露包含名为 `agent.json` 文件的智能体文件夹。

在示例中，`check_prime_agent` 已经提供了一个智能体卡片：

a2a_basic/remote_a2a/check_prime_agent/agent.json

```json
{
  "capabilities": {},
  "defaultInputModes": ["text/plain"],
  "defaultOutputModes": ["application/json"],
  "description": "An agent specialized in checking whether numbers are prime. It can efficiently determine the primality of individual numbers or lists of numbers.",
  "name": "check_prime_agent",
  "skills": [
    {
      "id": "prime_checking",
      "name": "Prime Number Checking",
      "description": "Check if numbers in a list are prime using efficient mathematical algorithms",
      "tags": ["mathematical", "computation", "prime", "numbers"]
    }
  ],
  "url": "http://localhost:8001/a2a/check_prime_agent",
  "version": "1.0.0"
}
```

关于 ADK 中智能体卡片的更多信息

在 ADK 中，你可以使用 `to_a2a(root_agent)` 包装器，它会自动为你生成智能体卡片。如果你有兴趣了解更多关于如何暴露你现有的智能体以便他人使用的信息，请参阅 [A2A 快速入门（暴露）](https://adk.wiki/a2a/quickstart-exposing/index.md) 教程。

### 4. 运行主（消费）智能体

```bash
# 在另一个终端中，运行 adk web 服务器
adk web contributing/samples/a2a/
```

#### 工作原理

主智能体使用 `RemoteA2aAgent` 类来消费远程智能体（本示例中的 `prime_agent`）。如下所示，`RemoteA2aAgent` 需要 `name` 和 `agent_card`，其中 `agent_card` 可以是一个 `AgentCard` 对象、一个 URL（如下例所示）或一个本地智能体卡片文件的路径；`description` 字段是可选的，默认为空字符串。

a2a_basic/agent.py

```python
# ...省略部分代码...

from google.adk.agents.remote_a2a_agent import AGENT_CARD_WELL_KNOWN_PATH
from google.adk.agents.remote_a2a_agent import RemoteA2aAgent

# 配置远程 A2A 智能体
prime_agent = RemoteA2aAgent(
    name="prime_agent",
    description="处理质数检查任务的智能体。",
    agent_card=(
        f"http://localhost:8001/a2a/check_prime_agent{AGENT_CARD_WELL_KNOWN_PATH}"
    ),
)

# ...省略部分代码...
```

使用新的 A2A 集成

`use_legacy` 参数默认为 `True`，因此上面的示例使用旧版路径。设置 `use_legacy=False` 以使用新的 ADK-A2A 集成，它会向远程智能体发送 [A2A 扩展](https://adk.wiki/a2a/a2a-extension/index.md)。

然后，你只需在智能体中使用 `RemoteA2aAgent`。在本例中，`prime_agent` 被作为下面 `root_agent` 的子智能体之一使用：

a2a_basic/agent.py

```python
from google.adk.agents.llm_agent import Agent
from google.genai import types

root_agent = Agent(
    model="gemini-flash-latest",
    name="root_agent",
    instruction="""
      你是一个得力的助手，可以滚动骰子并检查数字是否为质数。
      你将滚动骰子的任务委托给 roll_agent，将质数检查任务委托给 prime_agent。
      请遵循以下步骤：
      1. 如果用户要求滚动骰子，请委托给 roll_agent。
      2. 如果用户要求检查质数，请委托给 prime_agent。
      3. 如果用户要求先滚动骰子然后检查结果是否为质数，请先调用 roll_agent，然后将结果传递给 prime_agent。
      在继续之前，请务必澄清结果。
    """,
    global_instruction=(
        "你是 DicePrimeBot，随时准备滚动骰子并检查质数。"
    ),
    sub_agents=[roll_agent, prime_agent],
    tools=[example_tool],
    generate_content_config=types.GenerateContentConfig(
        safety_settings=[
            types.SafetySetting(  # 避免关于滚动骰子的虚假警报
                category=types.HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT,
                threshold=types.HarmBlockThreshold.OFF,
            ),
        ]
    ),
)
```

### 高级配置：自定义转换器与拦截器

在内部，`RemoteA2aAgent` 在 A2A 协议格式与 ADK 的原生 `Event` 系统之间进行相互转换。你可以通过向 `RemoteA2aAgent` 的 `config` 参数传递一个 [`A2aRemoteAgentConfig`](https://github.com/google/adk-python/blob/main/src/google/adk/a2a/agent/config.py) 对象来自定义此行为。

这允许你定义自定义类型映射、注入请求参数以及拦截请求或响应。

#### 转换器

转换器负责将传入的 A2A 响应翻译为原生的 ADK 对象。你可以为以下钩子提供自己的映射函数：

- **`a2a_message_converter`**：将标准 A2A 消息转换为 ADK `Event` 对象。
- **`a2a_task_converter`**：将 A2A 任务转换为 ADK `Event`。
- **`a2a_status_update_converter`**：将 A2A `TaskStatusUpdateEvent` 转换为 ADK `Event` 对象。
- **`a2a_artifact_update_converter`**：将 A2A `TaskArtifactUpdateEvent` 转换为 ADK `Event` 对象。
- **`a2a_part_converter`**：一个基础的底层钩子，由其他转换器在内部使用，用于将单个 A2A 消息部分 (Parts) 转换为 GenAI `Part` 对象。

注意

这些自定义客户端转换器仅在响应来自 [智能体执行器 (agent executor)](https://github.com/google/adk-python/blob/main/src/google/adk/a2a/executor/a2a_agent_executor_impl.py) 的新实现时才会使用。有关更多详细信息，请参见 [A2A 扩展](https://adk.wiki/a2a/a2a-extension/index.md)。

#### 请求拦截器

你可以注入一个 `request_interceptors` 列表，以为 A2A 请求添加中间件逻辑：

- **`before_request`**：在智能体开始处理之前执行。你可以修改 `A2AMessage`，或返回一个 ADK `Event` 以立即中止请求并将该事件返回给调用者。
- **`after_request`**：在智能体处理完请求后执行。你可以修改生成的 ADK `Event`，或者返回 `None` 以过滤掉并完全丢弃该事件。

#### 请求参数配置

通过拦截器，你还可以修改 A2A 请求的 `ParametersConfig` 以注入：

- **`request_metadata`**：将自定义元数据字典传入请求头。
- **`client_call_context`**：为底层传输注入特定的客户端调用上下文。

```python
# ...省略部分代码...

from google.adk.a2a.agent import A2aRemoteAgentConfig
from google.adk.agents.remote_a2a_agent import AGENT_CARD_WELL_KNOWN_PATH
from google.adk.agents.remote_a2a_agent import RemoteA2aAgent

# 带高级配置的远程 A2A 智能体
prime_agent = RemoteA2aAgent(
    name="prime_agent",
    description="处理质数检查任务的智能体。",
    agent_card=(
        f"http://localhost:8001/a2a/check_prime_agent{AGENT_CARD_WELL_KNOWN_PATH}"
    ),
    use_legacy=False,
    config=A2aRemoteAgentConfig(
        a2a_message_converter=my_a2a_message_converter,
        request_interceptors=[my_request_interceptor],
    ),
)

# ...省略部分代码...
```

## 交互示例

一旦你的主智能体和远程智能体都在运行，你就可以与根智能体交互，看看它如何通过 A2A 调用远程智能体：

**简单骰子滚动：** 此交互使用本地子智能体 `roll_agent`：

```text
用户：滚动一个 6 面骰子
机器人：我为你滚动了一个 4。
```

**质数检查：**

此交互通过 A2A 使用远程智能体 `prime_agent`：

```text
用户：7 是质数吗？
机器人：是的，7 是质数。
```

**组合操作：**

此交互同时使用本地滚动智能体和远程质数智能体：

```text
用户：滚动一个 10 面骰子并检查它是否是质数
机器人：我为你滚动了一个 8。
机器人：8 不是质数。
```

## 下一步

现在你已经创建了一个通过 A2A 服务器使用远程智能体的智能体，下一步是学习如何从另一个智能体连接到它。

- [**A2A 快速入门（暴露）**](https://adk.wiki/a2a/quickstart-exposing/index.md)：了解如何暴露你的现有智能体，以便其他智能体通过 A2A 协议使用它。
- [**A2A 快速入门（消费）Go**](https://adk.wiki/a2a/quickstart-consuming-go/index.md)：了解如何使用 Go 消费 A2A 远程智能体。
