Chamar um agente usando o endpoint A2A do registro dele

Os agentes Agent2Agent (A2A) no Agent Registry anunciam interfaces de protocolo que contêm um URL de endpoint e uma vinculação de protocolo (como HTTP_JSON). É possível descobrir o URL de um agente no registro para chamar os métodos A2A dele em orquestradores ou clientes personalizados.

Resumo

Especificação Detalhes
API Discovery agentregistry.googleapis.com (v1)
Host de proxy de invocação LOCATION-discoveryengine.googleapis.com
Vinculação de protocolo HTTP_JSON
Identificador do projeto de URL Google Cloud número do projeto (não o ID do projeto)
Métodos A2A compatíveis GET /v1/card, POST /v1/message:send, POST /v1/message:stream
Esquema de mensagem obrigatório message.role = "ROLE_USER", content[].text, messageId exclusivo
Permissões do IAM obrigatórias roles/agentregistry.viewer (descoberta) e discoveryengine.assistants.assist (invocação)

Antes de começar

  1. Ative a API Agent Registry (agentregistry.googleapis.com) e a API Discovery Engine (discoveryengine.googleapis.com) no seu Google Cloud projeto.
  2. Se o agente não foi criado diretamente no app Gemini Enterprise, importe-o do Agent Registry e conceda acesso a ele aos usuários finais. Para instruções, consulte Importar agentes A2A do Agent Registry.
  3. Conceda ao principal do autor da chamada as permissões do IAM adequadas:
    • Para ler o registro: leitor do Agent Registry (roles/agentregistry.viewer).
    • Para invocar o agente: editor do Discovery Engine (roles/discoveryengine.editor) ou um papel personalizado que inclua discoveryengine.assistants.assist.
  4. Se você fizer a autenticação usando as Application Default Credentials (ADC), configure o cliente para enviar o cabeçalho do projeto de cota: -H "X-Goog-User-Project: PROJECT_ID".
  5. Opcionalmente, instale a biblioteca do Kit de Desenvolvimento de Agente (ADK) se você planeja encapsular agentes remotos como subagentes programáticos: pip install "google-adk[a2a]>=1.29.0".

Etapa 1: descobrir o agente e o endpoint A2A dele

Para invocar um agente A2A, primeiro descubra o url anunciado no Agent Registry. Liste os agentes no local do registro (como us ou eu, transmitido como um parâmetro de caminho no 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"

Também é possível pesquisar um agente pelo prefixo do nome de exibição usando a Google Cloud CLI:

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

No recurso do agente retornado, inspecione a matriz protocols. Localize a entrada em que type é igual a A2A_AGENT e interfaces[].protocolBinding é igual a HTTP_JSON. Extraia o url correspondente:

{
  "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"
        }
      ]
    }
  ]
}

Consulte a referência da API REST projects.locations.agents para o esquema completo de recursos do agente.

Etapa 2: buscar o card do agente

O card do agente fornece metadados que descrevem a identidade, a descrição e os recursos de entrada/saída do agente. Para recuperar o card, envie uma solicitação GET HTTP para o caminho /v1/card anexado ao URL do endpoint A2A do agente:

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

Exemplo de payload de resposta:

{
  "name": "My Agent",
  "description": "What the agent does.",
  "url": "A2A_ENDPOINT_URL",
  "capabilities": {},
  "defaultInputModes": ["text"],
  "defaultOutputModes": ["text"],
  "preferredTransport": "HTTP+JSON"
}

Etapa 3: enviar uma mensagem

Para enviar uma consulta do usuário ao agente, faça uma solicitação POST para /v1/message:send. O corpo da solicitação precisa estar em conformidade com o esquema de mensagens A2A, exigindo que role seja definido como ROLE_USER, uma matriz content que contenha partes de texto e um messageId gerado de maneira exclusiva:

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"
    }
  }'

No payload de resposta, a resposta do agente é retornada no 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..."
      }
    ]
  }
}

Concatene as strings de texto dentro de content[].text para mostrar a resposta completa. Para continuar a conversa na mesma sessão, salve a string contextId retornada e forneça-a como message.contextId na próxima solicitação.

Consulte a referência da API REST A2A message:send para o esquema completo de payload de mensagens.

Respostas de stream de forma incremental

Para saída de streaming, envie uma solicitação POST com um corpo da mensagem idêntico para /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"
    }
  }'

O endpoint retorna uma matriz JSON de objetos de blocos transmitidos por HTTP. Anexe os fragmentos content[].text sequencialmente à medida que chegam. Os blocos transmitidos também contêm metadata.sessionInfo e metadata.assistToken.

Consulte a referência da API REST A2A message:stream para a especificação de payload de streaming.

Chamar um endpoint A2A usando Python

Esse script Python resolve um endpoint A2A no Agent Registry e envia uma mensagem usando solicitações HTTP brutas:

# 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)

Simplificar a orquestração usando o ADK

O Kit de Desenvolvimento de Agente (ADK) resolve endpoints de registro automaticamente e encapsula agentes A2A remotos como subagentes:

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"
)

Outras observações

Os endpoints A2A têm os seguintes comportamentos:

  • Nomenclatura de caminho estrita: apenas GET {url}/v1/card, POST {url}/v1/message:send e POST {url}/v1/message:stream são compatíveis com vinculações HTTP+JSON.
  • Validação de esquema estrita: transmitir simples "user" como o papel retorna um erro HTTP 400 Bad Request error. É necessário transmitir a string de enumeração "ROLE_USER". Da mesma forma, o texto da mensagem precisa residir na matriz content em vez de parts, e messageId é estritamente obrigatório.
  • Erro de invocação de agente não A2A: se um agente não tiver uma entrada de protocolo A2A_AGENT no registro (como alguns agentes pré-criados ou gerenciados), chamar getCard no URL do proxy retornará 501 UNIMPLEMENTED ("... ainda não é compatível"), e chamar message:send retornará 400 INVALID_ARGUMENT ("Agente não compatível").
  • Número do projeto no URL: o registro retorna um URL A2A que contém o número do projeto em vez do ID do projeto. Não altere essa string numérica ao fazer solicitações HTTP.

Solução de problemas

Use a tabela a seguir para resolver problemas comuns de endpoints A2A:

Sintoma Causa provável Resolução
HTTP 404 na solicitação getCard Usar um alias de caminho incorreto (como /v1:getCard ou /.well-known/agent-card.json). Envie a solicitação GET estritamente para GET {url}/v1/card.
HTTP 400 *"Nome desconhecido 'parts'"* Usar formatação de corpo do cliente de IA generativa ou antiga. Coloque strings de texto dentro de content, não parts.
HTTP 400 valor de enumeração inválido para role Transmitir "user" ou "user_role" em letras minúsculas. Defina message.role exatamente como "ROLE_USER".
HTTP 501 *"indisponível"* Chamar getCard em um agente que não publica uma interface A2A. Inspecione a matriz protocols do recurso de registro para confirmar o suporte A2A_AGENT antes de chamar.
HTTP 400 *"Agente não compatível"* Chamar message:send em um agente não A2A. Escolha um agente cuja definição de registro inclua uma vinculação de protocolo A2A_AGENT ativa.
HTTP 401 ou HTTP 403 Permission Denied Escopos OAuth ausentes, papéis do IAM ausentes ou cabeçalho do projeto de cota ausente. Verifique os papéis do IAM do autor da chamada (agentregistry.viewer e assistants.assist); verifique o escopo cloud-platform; transmita -H "X-Goog-User-Project: PROJECT_ID" se estiver usando o ADC.