Llama a un agente con su extremo A2A de registro

Los agentes de Agent2Agent (A2A) en el Registro de agentes 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 de A2A desde clientes o coordinadores personalizados.

Resumen

Especificación Detalles
API de Discovery agentregistry.googleapis.com (v1)
Host de proxy de invocación LOCATION-discoveryengine.googleapis.com
Vinculación de protocolo HTTP_JSON
Identificador de proyecto de URL Google Cloud Número del proyecto (no el ID del proyecto)
Métodos de 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

  1. Habilita la API de Agent Registry (agentregistry.googleapis.com) y la API de Discovery Engine (discoveryengine.googleapis.com) en tu proyecto de Google Cloud .
  2. Si el agente no se creó directamente en tu app de Gemini Enterprise, impórtalo desde Agent Registry y otorga acceso a los usuarios finales. Para obtener instrucciones, consulta Importa agentes A2A desde el Registro de agentes.
  3. Otorga a tu principal emisor 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 incluya discoveryengine.assistants.assist.
  4. Si te autenticas con las credenciales predeterminadas de la aplicación (ADC), configura tu cliente para que envíe el encabezado del proyecto de cuota: -H "X-Goog-User-Project: PROJECT_ID".
  5. De manera opcional, instala la biblioteca del Kit de desarrollo de agentes (ADK) si planeas unir agentes remotos como agentes secundarios programáticos: pip install "google-adk[a2a]>=1.29.0".

Paso 1: Descubre el agente y su extremo de A2A

Para invocar un agente A2A, primero descubre su url anunciado 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 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 CLI de Google Cloud :

gcloud agent-registry agents search \
  --project=PROJECT_ID \
  --location=LOCATION \
  --search-string="displayName:My_Agent_*"

En el recurso del 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 el 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 ver el esquema completo de recursos del agente.

Paso 2: Recupera la tarjeta del agente

La tarjeta de 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 adjunta a la URL del extremo A2A del agente:

curl -X GET \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
"A2A_ENDPOINT_URL/v1/card"

Ejemplo de carga útil de respuesta:

{
  "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 de 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 devuelve 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 de message:send para ver el esquema completo de la carga útil del mensaje.

Transmite respuestas de forma incremental

Para obtener un resultado 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 devuelve un array JSON de objetos de fragmentos transmitidos a través de HTTP. Agrega los fragmentos de content[].text de forma secuencial a medida que lleguen. Los fragmentos transmitidos también contienen metadata.sessionInfo y metadata.assistToken.

Consulta la referencia de la API de REST de A2A message:stream para conocer la especificación de la carga útil de transmisión.

Llama a un extremo de A2A con Python

Esta secuencia de comandos de Python resuelve un extremo de A2A en el Registro de agentes 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 automáticamente 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 de A2A tienen los siguientes comportamientos:

  • Asignación de nombres de ruta de acceso estricta: Solo se admiten GET {url}/v1/card, POST {url}/v1/message:send y POST {url}/v1/message:stream para las vinculaciones HTTP+JSON.
  • Validación estricta del esquema: Pasar "user" sin formato como rol devuelve un error de HTTP 400 Bad Request. Debes pasar la cadena de enumeración "ROLE_USER". Del mismo modo, el texto del mensaje debe residir dentro del array content en lugar de parts, y messageId es estrictamente obligatorio.
  • Error de invocación de agente que no es A2A: Si un agente no tiene una entrada de protocolo A2A_AGENT en el registro (como ciertos agentes precompilados o administrados), llamar a getCard en su URL de proxy devuelve 501 UNIMPLEMENTED ("... is not supported yet") y llamar a message:send devuelve 400 INVALID_ARGUMENT ("Unsupported agent").
  • Número de proyecto en la URL: El registro devuelve una URL de A2A que contiene el número de proyecto en lugar del ID del proyecto. No alteres esta cadena numérica cuando realices solicitudes HTTP.

Soluciona problemas

Usa la siguiente tabla para solucionar problemas comunes de los extremos de A2A:

Síntoma Causa probable Solución
HTTP 404 en la solicitud getCard Usar 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 *"Unknown name 'parts'"* Se usa el formato de cuerpo del cliente de IA antiguo o generativo. Coloca las cadenas de texto dentro de content, no de parts.
Valor de enum no válido de HTTP 400 para role Pasar "user" o "user_role" en minúsculas. Establece message.role exactamente en "ROLE_USER".
HTTP 501 *"is not supported yet"* Llamar a getCard en un agente que no publica una interfaz de A2A. Inspecciona el array protocols del recurso de registro para confirmar la compatibilidad con A2A_AGENT antes de llamar.
HTTP 400 *"Unsupported agent"* 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 emisor (agentregistry.viewer y assistants.assist), el permiso de cloud-platform y pasa -H "X-Goog-User-Project: PROJECT_ID" si usas ADC.