Agent Registry 中的 Agent2Agent (A2A) 智能体会通告协议接口,其中包含端点网址和协议绑定(例如 HTTP_JSON)。您可以在注册表中发现智能体的网址,以便从自定义编排器或客户端调用其 A2A 方法。
概览
| 规范 | 详细信息 |
|---|---|
| Discovery API | agentregistry.googleapis.com (v1) |
| 调用代理主机 | LOCATION-discoveryengine.googleapis.com |
| 协议绑定 | HTTP_JSON |
| 网址项目标识符 | Google Cloud 项目编号(而非项目 ID) |
| 支持的 A2A 方式 | GET /v1/card、POST /v1/message:send、POST /v1/message:stream |
| 必需的消息架构 | message.role = "ROLE_USER",content[].text,messageId 个不重复 |
| 必需的 IAM 权限 | roles/agentregistry.viewer(发现)和 discoveryengine.assistants.assist(调用) |
准备工作
- 在 Google Cloud 项目中启用 Agent Registry API (
agentregistry.googleapis.com) 和 Discovery Engine API (discoveryengine.googleapis.com)。 - 如果代理不是直接在 Gemini Enterprise 应用中创建的,请从代理注册表中导入代理,并向最终用户授予访问权限。如需查看相关说明,请参阅从智能体注册表导入 A2A 智能体。
- 向调用方主账号授予适当的 IAM 权限:
- 如需读取注册表:Agent Registry Viewer (
roles/agentregistry.viewer)。 - 如需调用代理:Discovery Engine Editor (
roles/discoveryengine.editor) 或包含discoveryengine.assistants.assist的自定义角色。
- 如需读取注册表:Agent Registry Viewer (
- 如果您使用应用默认凭据 (ADC) 进行身份验证,请将客户端配置为发送配额项目标头:
-H "X-Goog-User-Project: PROJECT_ID"。 - (可选)如果您打算将远程智能体封装为程序化子智能体,请安装智能体开发套件 (ADK) 库:
pip install "google-adk[a2a]>=1.29.0"。
第 1 步:发现代理及其 A2A 端点
如需调用 A2A 智能体,请先在智能体注册表中发现其通告的 url。列出注册表位置(例如 us 或 eu,作为路径参数传递到全局 agentregistry.googleapis.com 主机)中的代理:
curl -X GET \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
-H "Content-Type: application/json" \
"https://agentregistry.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/agents?pageSize=100"
您还可以使用 Google Cloud CLI 按显示名称前缀搜索代理:
gcloud agent-registry agents search \
--project=PROJECT_ID \
--location=LOCATION \
--search-string="displayName:My_Agent_*"
在返回的代理资源中,检查 protocols 数组。找到 type 等于 A2A_AGENT 且 interfaces[].protocolBinding 等于 HTTP_JSON 的条目。提取相应的 url:
{
"name": "projects/PROJECT_ID/locations/LOCATION/agents/AGENT_RESOURCE_ID",
"displayName": "My Agent",
"protocols": [
{
"type": "A2A_AGENT",
"protocolVersion": "0.3.0",
"interfaces": [
{
"url": "https://LOCATION-discoveryengine.googleapis.com/v1/projects/PROJECT_NUMBER/locations/LOCATION/collections/default_collection/engines/ENGINE_ID/assistants/default_assistant/agents/AGENT_ID/a2a",
"protocolBinding": "HTTP_JSON"
}
]
}
]
}
如需查看完整的代理资源架构,请参阅 projects.locations.agents REST API 参考文档。
第 2 步:提取智能体卡片
智能体卡片提供元数据,用于描述智能体的身份、说明和输入/输出功能。如需检索卡片,请向附加到代理 A2A 端点网址的 /v1/card 路径发送 HTTP GET 请求:
curl -X GET \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
"A2A_ENDPOINT_URL/v1/card"
响应载荷示例:
{
"name": "My Agent",
"description": "What the agent does.",
"url": "A2A_ENDPOINT_URL",
"capabilities": {},
"defaultInputModes": ["text"],
"defaultOutputModes": ["text"],
"preferredTransport": "HTTP+JSON"
}
第 3 步:发送消息
如需向智能体发送用户查询,请向 /v1/message:send 发出 POST 请求。请求正文必须符合 A2A 消息架构,要求将 role 设置为 ROLE_USER,包含一个包含文本部分的 content 数组,以及一个唯一生成的 messageId:
curl -X POST \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
-H "Content-Type: application/json" \
"A2A_ENDPOINT_URL/v1/message:send" \
-d '{
"message": {
"role": "ROLE_USER",
"content": [
{
"text": "What can you help me with?"
}
],
"messageId": "UNIQUE_UUID_STRING"
}
}'
在响应载荷中,智能体的回复会在 message 对象中返回:
{
"message": {
"contextId": "projects/PROJECT_NUMBER/locations/LOCATION/collections/default_collection/engines/ENGINE_ID/sessions/SESSION_ID",
"role": "ROLE_AGENT",
"content": [
{
"text": "I am an AI assistant..."
}
]
}
}
将 content[].text 中的文本字符串串联起来,以显示完整的回答。如需在同一会话中继续对话,请保存返回的 contextId 字符串,并在下次请求中将其作为 message.contextId 提供。
如需查看完整的消息载荷架构,请参阅 A2A message:send REST API 参考文档。
以增量方式流式传输回答
对于流式输出,请向 /v1/message:stream 发送包含相同消息正文的 POST 请求:
curl -N -X POST \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
-H "Content-Type: application/json" \
"A2A_ENDPOINT_URL/v1/message:stream" \
-d '{
"message": {
"role": "ROLE_USER",
"content": [
{
"text": "Say hello."
}
],
"messageId": "UNIQUE_UUID_STRING"
}
}'
该端点会通过 HTTP 返回一个由流式分块对象组成的 JSON 数组。在 content[].text 片段到达时按顺序附加这些片段。流式传输的分块还包含 metadata.sessionInfo 和 metadata.assistToken。
如需了解流式载荷规范,请参阅 A2A message:stream REST API 参考文档。
使用 Python 调用 A2A 端点
此 Python 脚本会解析 Agent Registry 中的 A2A 端点,并使用原始 HTTP 请求发送消息:
# Install dependencies: pip install google-auth requests
import uuid
import google.auth
from google.auth.transport.requests import AuthorizedSession
# TODO(developer): Replace placeholder values with your project ID and location.
project_id = "PROJECT_ID"
location = "LOCATION" # Registry location (for example: "us" or "eu")
target_display_name = "My Agent"
query_text = "What can you help me with?"
# Initialize credentials and authorized session
creds, _ = google.auth.default(
scopes=["https://www.googleapis.com/auth/cloud-platform"]
)
session = AuthorizedSession(creds)
# Step 1: Resolve the A2A endpoint URL from the Agent Registry
registry_url = (
f"https://agentregistry.googleapis.com/v1/"
f"projects/{project_id}/locations/{location}/agents"
)
response = session.get(registry_url)
response.raise_for_status()
agents = response.json().get("agents", [])
def get_a2a_url(agent_resource):
for proto in agent_resource.get("protocols") or []:
if proto.get("type") == "A2A_AGENT":
for iface in proto.get("interfaces", []):
if iface.get("protocolBinding") == "HTTP_JSON":
return iface.get("url")
return None
target_agent = next(
(a for a in agents if a.get("displayName") == target_display_name),
None
)
if not target_agent:
raise SystemExit(f"Agent '{target_display_name}' not found in registry.")
endpoint_url = get_a2a_url(target_agent)
if not endpoint_url:
raise SystemExit("Target agent does not publish an HTTP_JSON A2A endpoint.")
# Step 2: Fetch and verify the agent card
card_resp = session.get(f"{endpoint_url}/v1/card")
card_resp.raise_for_status()
card = card_resp.json()
print("Resolved Agent:", card.get("name"))
# Step 3: Send an A2A message
body = {
"message": {
"role": "ROLE_USER",
"content": [{"text": query_text}],
"messageId": str(uuid.uuid4()),
}
}
send_resp = session.post(f"{endpoint_url}/v1/message:send", json=body)
send_resp.raise_for_status()
reply_message = send_resp.json().get("message", {})
full_reply_text = "".join(
part.get("text", "") for part in reply_message.get("content", [])
)
print("Agent Reply:", full_reply_text)
使用 ADK 简化编排
智能体开发套件 (ADK) 会自动解析注册表端点,并将远程 A2A 智能体封装为子智能体:
from google.adk.integrations.agent_registry import AgentRegistry
# Initialize registry client
registry = AgentRegistry(project_id="PROJECT_ID", location="LOCATION")
# Resolve remote A2A agent directly by resource name
remote_agent = registry.get_remote_a2a_agent(
agent_name="agents/AGENT_RESOURCE_ID"
)
补充说明
A2A 端点具有以下行为:
- 严格的路径命名:HTTP+JSON 绑定仅支持
GET {url}/v1/card、POST {url}/v1/message:send和POST {url}/v1/message:stream。 - 严格架构验证:将纯
"user"作为角色传递会返回 HTTP400 Bad Request错误。您必须传递枚举字符串"ROLE_USER"。同样,消息文本必须位于content数组(而非parts)中,并且messageId是严格要求的。 - 非 A2A 智能体调用错误:如果智能体在注册表中缺少
A2A_AGENT协议条目(例如某些预构建或代管式智能体),则在其代理网址上调用getCard会返回501 UNIMPLEMENTED(“… is not supported yet”),调用message:send会返回400 INVALID_ARGUMENT(“Unsupported agent”)。 - 网址中的项目编号:注册表会返回包含项目编号(而非项目 ID)的 A2A 网址。发出 HTTP 请求时,请勿更改此数字字符串。
问题排查
请参阅下表,排查常见的 A2A 端点错误:
| 症状 | 可能的原因 | 解决方法 |
|---|---|---|
getCard 请求出现 HTTP 404 错误 |
使用不正确的路径别名(例如 /v1:getCard 或 /.well-known/agent-card.json)。 |
严格向 GET {url}/v1/card 发送 GET 请求。 |
| HTTP 400 *"Unknown name 'parts'"* | 使用旧版或生成式 AI 客户端正文格式。 | 将文本字符串放在 content(而非 parts)中。 |
HTTP 400 role 的枚举值无效 |
传递小写 "user" 或 "user_role"。 |
将 message.role 精确设置为 "ROLE_USER"。 |
| HTTP 501 *“尚不支持”* | 在未发布 A2A 接口的智能体上调用 getCard。 |
在调用之前,请检查注册表资源的 protocols 数组,以确认 A2A_AGENT 支持。 |
| HTTP 400 *“不支持的代理”* | 对非 A2A 智能体调用 message:send。 |
选择其注册表定义包含有效 A2A_AGENT 协议绑定的代理。 |
HTTP 401 或 HTTP 403 Permission Denied |
缺少 OAuth 范围、缺少 IAM 角色或缺少配额项目标头。 | 检查调用方的 IAM 角色(agentregistry.viewer 和 assistants.assist);验证 cloud-platform 范围;如果使用 ADC,请传递 -H "X-Goog-User-Project: PROJECT_ID"。 |