Strands Agents A2A 协议实战:让多个 AI Agent 互相对话

Strands Agents A2A 协议实战:让多个 AI Agent 互相对话

最近在搞一个业务场景——订单处理 Agent 需要调用库存查询 Agent 的能力,库存不够时还要找采购 Agent 下补货单。

三个 Agent 各有各的职责,问题是怎么让它们互相"交流"。

翻了一下 Strands Agents SDK 的最新版本,发现它刚加了 A2A(Agent-to-Agent)协议支持,专门解决多 Agent 通信的问题。Agent 之间不用共享内存或数据库,而是通过标准 HTTP 协议互相发消息。

A2A 协议是什么

A2A 是一个开放协议(由 Google 发起,AWS 跟进支持),定义了 Agent 之间的通信标准:

  • 每个 Agent 暴露一个 AgentCard(类似 API 文档)
  • Agent 之间通过 HTTP JSON 消息通信
  • 支持同步请求-响应和异步任务
  • 有标准的能力发现机制

类比一下:MCP 是"Agent 调工具",A2A 是"Agent 调 Agent"。

搭建第一个 A2A Agent

安装 Strands SDK(需要 0.3.0+):

pip install strands-agents strands-agents-tools

先写一个库存查询 Agent,让它暴露 A2A 接口:

from strands import Agent
from strands.tools import tool
from strands.a2a import A2AServer

@tool
def check_inventory(product_id: str) -> dict:
    """查询产品库存数量"""
    # 实际场景连 DynamoDB
    inventory_db = {
        "SKU-001": {"name": "机械键盘", "stock": 42, "warehouse": "华东"},
        "SKU-002": {"name": "无线鼠标", "stock": 0, "warehouse": "华东"},
        "SKU-003": {"name": "显示器支架", "stock": 15, "warehouse": "华南"},
    }
    item = inventory_db.get(product_id)
    if not item:
        return {"error": f"产品 {product_id} 不存在"}
    return item

@tool
def batch_check(product_ids: list) -> list:
    """批量查询多个产品库存"""
    results = []
    for pid in product_ids:
        results.append({"product_id": pid, **check_inventory(pid)})
    return results

# 创建库存 Agent
inventory_agent = Agent(
    model="us.anthropic.claude-sonnet-4-20250514-v1:0",
    system_prompt="""你是库存查询助手。
    - 收到产品ID时查询库存
    - 返回库存数量、仓库位置
    - 库存为0时标记"缺货"
    """,
    tools=[check_inventory, batch_check]
)

# 启动 A2A Server
server = A2AServer(
    agent=inventory_agent,
    name="inventory-agent",
    description="查询产品库存数量和仓库位置",
    port=8001
)
server.run()

订单 Agent 调用库存 Agent

另一个服务里,订单 Agent 通过 A2A 协议调用库存 Agent:

from strands import Agent
from strands.a2a import A2AClient
from strands.tools import tool

# 连接库存 Agent
inventory_client = A2AClient(
    agent_card_url="http://inventory-agent:8001/.well-known/agent.json"
)

@tool
def query_inventory(product_id: str) -> dict:
    """通过 A2A 协议调用库存 Agent 查询库存"""
    response = inventory_client.send_message(
        message=f"查询产品 {product_id} 的库存"
    )
    return response.result

@tool
def create_order(product_id: str, quantity: int, customer_id: str) -> dict:
    """创建订单"""
    # 先检查库存
    stock_info = query_inventory(product_id)
    if stock_info.get("stock", 0) < quantity:
        return {
            "status": "failed",
            "reason": f"库存不足,当前库存: {stock_info.get('stock', 0)}"
        }
    return {
        "status": "success",
        "order_id": f"ORD-{customer_id}-{product_id}",
        "product_id": product_id,
        "quantity": quantity,
        "warehouse": stock_info.get("warehouse")
    }

order_agent = Agent(
    model="us.anthropic.claude-sonnet-4-20250514-v1:0",
    system_prompt="你是订单处理助手。收到下单请求时先查库存再创建订单。",
    tools=[query_inventory, create_order]
)

# 这个 Agent 也可以暴露 A2A 接口
order_server = A2AServer(
    agent=order_agent,
    name="order-agent",
    description="处理订单创建、查询库存、生成物流单",
    port=8002
)
order_server.run()

部署到 ECS

三个 Agent 部署为 ECS 服务,互相通过 Service Discovery 发现:

# docker-compose.yml(本地开发用)
version: "3.8"
services:
  inventory-agent:
    build: ./inventory-agent
    ports:
      - "8001:8001"
    environment:
      - AWS_REGION=us-east-1
      - BEDROCK_MODEL_ID=us.anthropic.claude-sonnet-4-20250514-v1:0

  order-agent:
    build: ./order-agent
    ports:
      - "8002:8002"
    environment:
      - AWS_REGION=us-east-1
      - INVENTORY_AGENT_URL=http://inventory-agent:8001
      - BEDROCK_MODEL_ID=us.anthropic.claude-sonnet-4-20250514-v1:0

  procurement-agent:
    build: ./procurement-agent
    ports:
      - "8003:8003"
    environment:
      - AWS_REGION=us-east-1
      - INVENTORY_AGENT_URL=http://inventory-agent:8001
      - ORDER_AGENT_URL=http://order-agent:8002
      - BEDROCK_MODEL_ID=us.anthropic.claude-sonnet-4-20250514-v1:0

生产环境用 ECS Service Connect 或 Cloud Map 做服务发现:

# 创建 namespace
aws servicediscovery create-private-dns-namespace \
  --name agents.local \
  --vpc vpc-0123456789abcdef0

# 注册服务
aws servicediscovery create-service \
  --name inventory-agent \
  --namespace-id ns-xxx \
  --dns-config "NamespaceId=ns-xxx,DnsRecords=[{Type=A,TTL=30}]"

AgentCard 自动发现

A2A 协议的核心是 AgentCard——每个 Agent 在 /.well-known/agent.json 暴露自己的能力描述:

{
  "name": "inventory-agent",
  "description": "查询产品库存数量和仓库位置",
  "url": "http://inventory-agent:8001",
  "version": "1.0.0",
  "capabilities": {
    "streaming": true,
    "pushNotifications": false
  },
  "skills": [
    {
      "id": "check-inventory",
      "name": "查询单个产品库存",
      "description": "输入产品ID,返回库存数量和仓库位置"
    },
    {
      "id": "batch-check",
      "name": "批量库存查询",
      "description": "同时查询多个产品的库存状态"
    }
  ]
}

其他 Agent 只需要知道 AgentCard URL,就能自动发现对方的能力并调用。

踩坑记录

  1. 超时设置:Agent 调 Agent 比调普通 API 慢(因为中间有 LLM 推理),默认 30s 超时可能不够。建议设到 120s。

  2. 重试策略:LLM 推理偶尔会失败(throttling、模型过载),A2A 调用要加指数退避重试。

  3. 消息大小:如果 Agent 返回的结果很大(比如批量查询 1000 个 SKU),可能超出下游 Agent 的 context window。建议分页。

  4. 认证:A2A 默认不带认证。生产环境要加 IAM Auth 或 mutual TLS:

server = A2AServer(
    agent=inventory_agent,
    name="inventory-agent",
    port=8001,
    auth_handler=iam_auth_handler  # 自定义 IAM 认证
)
  1. 可观测性:A2A 调用链不会自动上报 X-Ray。需要手动在 A2AClient 里注入 trace header。

参考链接

posted @ 2026-06-12 08:06  亚马逊云开发者  阅读(6)  评论(0)    收藏  举报