Los agentes de Agent2Agent (A2A) en Agent Registry anuncian interfaces de protocolo que contienen una URL de extremo y una vinculación de protocolo (como HTTP_JSON). Puedes descubrir la URL de un agente en el registro para llamar a sus métodos A2A desde clientes o organizadores personalizados.
Resumen
| Especificación | Detalles |
|---|---|
| API de Discovery | agentregistry.googleapis.com (v1) |
| Host del proxy de invocación | LOCATION-discoveryengine.googleapis.com |
| Vinculación de protocolo | HTTP_JSON |
| Identificador de proyecto de URL | Google Cloud Número de proyecto (no es el ID del proyecto) |
| Métodos A2A admitidos | GET /v1/card, POST /v1/message:send, POST /v1/message:stream |
| Esquema de mensaje obligatorio | message.role = "ROLE_USER", content[].text, messageId único |
| Permisos de IAM obligatorios | roles/agentregistry.viewer (descubrimiento) y discoveryengine.assistants.assist (invocación) |
Antes de comenzar
- Habilita la API de Agent Registry (
agentregistry.googleapis.com) y la API de Discovery Engine (discoveryengine.googleapis.com) en tu Google Cloud proyecto. - Si el agente no se creó directamente en tu app de Gemini Enterprise, impórtalo desde Agent Registry y otorga a los usuarios finales acceso a él. Si deseas obtener instrucciones, consulta Importa agentes A2A desde Agent Registry.
- Otorga a tu principal de llamada los permisos de IAM adecuados:
- Para leer el registro: Visualizador de Agent Registry (
roles/agentregistry.viewer). - Para invocar al agente: Editor de Discovery Engine (
roles/discoveryengine.editor) o un rol personalizado que incluyadiscoveryengine.assistants.assist.
- Para leer el registro: Visualizador de Agent Registry (
- Si te autenticas con las credenciales predeterminadas de la aplicación (ADC), configura tu cliente para enviar el encabezado del proyecto de cuota:
-H "X-Goog-User-Project: PROJECT_ID". - De manera opcional, instala la biblioteca del Kit de desarrollo de agentes (ADK) si planeas encapsular agentes remotos como agentes secundarios programáticos:
pip install "google-adk[a2a]>=1.29.0".
Paso 1: Descubre el agente y su extremo A2A
Para invocar un agente A2A, primero descubre su url anunciada en Agent Registry. Enumera los agentes en la ubicación de tu registro (como us o eu, que se pasan como un parámetro de ruta de acceso en el host global 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"
También puedes buscar un agente por prefijo de nombre visible con la Google Cloud CLI:
gcloud agent-registry agents search \
--project=PROJECT_ID \
--location=LOCATION \
--search-string="displayName:My_Agent_*"
En el recurso de agente que se muestra, inspecciona el array protocols. Busca la entrada en la que type sea igual a A2A_AGENT y interfaces[].protocolBinding sea igual a HTTP_JSON. Extrae la url correspondiente:
{
"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"
}
]
}
]
}
Consulta la referencia de la API de REST de projects.locations.agents para obtener el esquema completo de recursos del agente.
Paso 2: Recupera la tarjeta del agente
La tarjeta del agente proporciona metadatos que describen la identidad, la descripción y las capacidades de entrada y salida del agente. Para recuperar la tarjeta, envía una solicitud GET HTTP a la ruta de acceso /v1/card agregada a la URL del extremo A2A del agente:
curl -X GET \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
"A2A_ENDPOINT_URL/v1/card"
Carga útil de respuesta de ejemplo:
{
"name": "My Agent",
"description": "What the agent does.",
"url": "A2A_ENDPOINT_URL",
"capabilities": {},
"defaultInputModes": ["text"],
"defaultOutputModes": ["text"],
"preferredTransport": "HTTP+JSON"
}
Paso 3: Envía un mensaje
Para enviar una consulta de usuario al agente, realiza una solicitud POST a /v1/message:send. El cuerpo de la solicitud debe cumplir con el esquema de mensajes A2A, que requiere que role se establezca en ROLE_USER, un array content que contenga partes de texto y un messageId generado de forma única:
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"
}
}'
En la carga útil de la respuesta, la respuesta del agente se muestra dentro del objeto 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..."
}
]
}
}
Concatena las cadenas de texto dentro de content[].text para mostrar la respuesta completa. Para continuar la conversación dentro de la misma sesión, guarda la cadena contextId que se muestra y proporciónala como message.contextId en tu próxima solicitud.
Consulta la referencia de la API de REST de A2A message:send para obtener el esquema completo de la carga útil del mensaje.
Transmite respuestas de forma incremental
Para la salida de transmisión, envía una solicitud POST con un cuerpo de mensaje idéntico a /v1/message:stream:
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"
}
}'
El extremo muestra un array JSON de objetos de fragmentos transmitidos a través de HTTP. Agrega los fragmentos content[].text de forma secuencial a medida que llegan. Los fragmentos transmitidos también contienen metadata.sessionInfo y metadata.assistToken.
Consulta la referencia de la API de REST de A2A message:stream para obtener la especificación de la carga útil de transmisión.
Llama a un extremo A2A con Python
Esta secuencia de comandos de Python resuelve un extremo A2A en Agent Registry y envía un mensaje con solicitudes HTTP sin procesar:
# 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)
Simplifica la organización con el ADK
El Kit de desarrollo de agentes (ADK) resuelve los extremos del registro de forma automática y encapsula los agentes A2A remotos como agentes secundarios:
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"
)
Notas adicionales
Los extremos A2A tienen los siguientes comportamientos:
- Nombres de ruta de acceso estrictos: Solo se admiten
GET {url}/v1/card,POST {url}/v1/message:send, yPOST {url}/v1/message:streampara las vinculaciones de HTTP+JSON. - Validación de esquema estricta: Si se pasa
"user"sin formato como el rol, se muestra un error HTTP400 Bad Requesterror. Debes pasar la cadena de enumeración"ROLE_USER". Del mismo modo, el texto del mensaje debe residir dentro del arraycontenten lugar departs, ymessageIdes estrictamente obligatorio. - Error de invocación del agente que no es A2A: Si un agente no tiene una entrada de protocolo
A2A_AGENTen el registro (como ciertos agentes integrados o administrados), llamar agetCarden su URL de proxy muestra501 UNIMPLEMENTED("... aún no se admite"), y llamar amessage:sendmuestra400 INVALID_ARGUMENT("Agente no admitido"). - Número de proyecto en la URL: El registro muestra una URL A2A que contiene el número de proyecto en lugar del ID del proyecto. No modifiques esta cadena numérica cuando realices solicitudes HTTP.
Soluciona problemas
Usa la siguiente tabla para solucionar problemas comunes de extremos A2A:
| Síntoma | Causa probable | Solución |
|---|---|---|
HTTP 404 en la solicitud getCard |
Uso de un alias de ruta de acceso incorrecto (como /v1:getCard o /.well-known/agent-card.json). |
Envía la solicitud GET estrictamente a GET {url}/v1/card. |
| HTTP 400 *"Nombre desconocido 'partes'"* | Uso de un formato de cuerpo de cliente de IA generativa o antiguo. | Coloca cadenas de texto dentro de content, no parts. |
HTTP 400 valor de enumeración no válido para role |
Paso de "user" o "user_role" en minúscula. |
Establece message.role exactamente en "ROLE_USER". |
| HTTP 501 *"aún no se admite"* | Llamar a getCard en un agente que no publica una interfaz A2A. |
Inspecciona el array protocols del recurso de registro para confirmar la compatibilidad con A2A_AGENT antes de llamar. |
| HTTP 400 *"Agente no admitido"* | Llamar a message:send en un agente que no es A2A. |
Elige un agente cuya definición de registro incluya una vinculación de protocolo A2A_AGENT activa. |
HTTP 401 o HTTP 403 Permission Denied |
Faltan permisos de OAuth, roles de IAM o el encabezado del proyecto de cuota. | Verifica los roles de IAM del llamador (agentregistry.viewer y assistants.assist); verifica el permiso de cloud-platform; pasa -H "X-Goog-User-Project: PROJECT_ID" si usas ADC. |