Appeler un agent à l'aide de son point de terminaison A2A de registre

Les agents Agent2Agent (A2A) dans Agent Registry annoncent des interfaces de protocole contenant une URL de point de terminaison et une liaison de protocole (telle que HTTP_JSON). Vous pouvez découvrir l'URL d'un agent dans le registre pour appeler ses méthodes A2A à partir d'orchestrateurs ou de clients personnalisés.

En bref

Spécification Détails
API Discovery agentregistry.googleapis.com (v1)
Hôte proxy d'appel LOCATION-discoveryengine.googleapis.com
Liaison de protocole HTTP_JSON
Identifiant de projet d'URL Google Cloud Numéro du projet (et non l'ID du projet)
Méthodes A2A compatibles GET /v1/card, POST /v1/message:send, POST /v1/message:stream
Schéma de message requis message.role = "ROLE_USER", content[].text, messageId unique
Autorisations IAM requises roles/agentregistry.viewer (découverte) et discoveryengine.assistants.assist (appel)

Avant de commencer

  1. Activez l'API Agent Registry (agentregistry.googleapis.com) et l'API Discovery Engine (discoveryengine.googleapis.com) dans votre projet Google Cloud .
  2. Si l'agent n'a pas été créé directement dans votre application Gemini Enterprise, importez-le depuis le registre des agents et accordez-y l'accès aux utilisateurs finaux. Pour obtenir des instructions, consultez Importer des agents A2A depuis le registre d'agents.
  3. Accordez à votre compte principal appelant les autorisations IAM appropriées :
    • Pour lire le registre : Lecteur Agent Registry (roles/agentregistry.viewer).
    • Pour appeler l'agent : Éditeur Discovery Engine (roles/discoveryengine.editor) ou un rôle personnalisé incluant discoveryengine.assistants.assist.
  4. Si vous vous authentifiez à l'aide des Identifiants par défaut de l'application (ADC), configurez votre client pour qu'il envoie l'en-tête du projet de quota : -H "X-Goog-User-Project: PROJECT_ID".
  5. Si vous prévoyez d'encapsuler des agents distants en tant que sous-agents programmatiques, vous pouvez installer la bibliothèque Agent Development Kit (ADK) : pip install "google-adk[a2a]>=1.29.0".

Étape 1 : Découvrez l'agent et son point de terminaison A2A

Pour appeler un agent A2A, commencez par découvrir son url annoncé dans Agent Registry. Répertoriez les agents de l'emplacement de votre registre (par exemple, us ou eu, transmis en tant que paramètre de chemin d'accès sur l'hôte 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"

Vous pouvez également rechercher un agent par préfixe de nom à afficher à l'aide de la CLI Google Cloud  :

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

Dans la ressource d'agent renvoyée, inspectez le tableau protocols. Recherchez l'entrée où type est égal à A2A_AGENT et interfaces[].protocolBinding est égal à HTTP_JSON. Extrayez le url correspondant :

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

Consultez la documentation de référence de l'API REST projects.locations.agents pour obtenir le schéma complet de la ressource d'agent.

Étape 2 : Récupérer la fiche de l'agent

La carte d'agent fournit des métadonnées décrivant l'identité, la description et les capacités d'entrée/sortie de l'agent. Pour récupérer la fiche, envoyez une requête GET HTTP au chemin d'accès /v1/card ajouté à l'URL du point de terminaison A2A de l'agent :

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

Exemple de charge utile de réponse :

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

Étape 3 : Envoyez un message

Pour envoyer une requête utilisateur à l'agent, envoyez une requête POST à /v1/message:send. Le corps de la requête doit être conforme au schéma de message A2A, ce qui nécessite de définir role sur ROLE_USER, un tableau content contenant des parties de texte et un messageId généré de manière unique :

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

Dans la charge utile de la réponse, la réponse de l'agent est renvoyée dans l'objet 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..."
      }
    ]
  }
}

Concaténez les chaînes de texte dans content[].text pour afficher la réponse complète. Pour poursuivre la conversation au cours de la même session, enregistrez la chaîne contextId renvoyée et fournissez-la en tant que message.contextId dans votre prochaine requête.

Consultez la documentation de référence de l'API REST A2A message:send pour obtenir le schéma complet de la charge utile du message.

Diffuser les réponses de manière incrémentielle

Pour une sortie en flux continu, envoyez une requête POST avec un corps du message identique à /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"
    }
  }'

Le point de terminaison renvoie un tableau JSON d'objets de fragments diffusés en streaming via HTTP. Ajoutez les fragments content[].text de manière séquentielle à mesure qu'ils arrivent. Les fragments diffusés en streaming contiennent également metadata.sessionInfo et metadata.assistToken.

Consultez la documentation de référence de l'API REST A2A message:stream pour connaître la spécification de la charge utile de streaming.

Appeler un point de terminaison A2A à l'aide de Python

Ce script Python résout un point de terminaison A2A dans le registre d'agents et envoie un message à l'aide de requêtes HTTP brutes :

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

Simplifier l'orchestration à l'aide de l'ADK

L'Agent Development Kit (ADK) résout automatiquement les points de terminaison du registre et encapsule les agents A2A distants en tant que sous-agents :

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

Remarques supplémentaires

Les points de terminaison A2A ont les comportements suivants :

  • Nommage strict des chemins : seuls GET {url}/v1/card, POST {url}/v1/message:send et POST {url}/v1/message:stream sont acceptés pour les liaisons HTTP+JSON.
  • Validation stricte du schéma : transmettre un "user" brut en tant que rôle renvoie une erreur HTTP 400 Bad Request. Vous devez transmettre la chaîne d'énumération "ROLE_USER". De même, le texte du message doit se trouver dans le tableau content plutôt que dans parts, et messageId est strictement obligatoire.
  • Erreur d'appel d'agent non-A2A : si un agent ne dispose pas d'une entrée de protocole A2A_AGENT dans le registre (comme certains agents prédéfinis ou gérés), l'appel de getCard sur son URL de proxy renvoie 501 UNIMPLEMENTED ("... n'est pas encore compatible") et l'appel de message:send renvoie 400 INVALID_ARGUMENT ("Agent non compatible").
  • Numéro de projet dans l'URL : le registre renvoie une URL A2A contenant le numéro de projet plutôt que l'ID du projet. Ne modifiez pas cette chaîne numérique lorsque vous effectuez des requêtes HTTP.

Dépannage

Utilisez le tableau suivant pour résoudre les problèmes courants liés aux points de terminaison A2A :

Problème constaté Cause probable Solution
Erreur HTTP 404 sur la requête getCard Utilisation d'un alias de chemin d'accès incorrect (tel que /v1:getCard ou /.well-known/agent-card.json). Envoyez la requête GET strictement à GET {url}/v1/card.
HTTP 400 *"Unknown name 'parts'"* Utilisation d'un ancien formatage du corps du client ou d'un formatage d'IA générative. Placez les chaînes de texte dans content, et non dans parts.
Valeur d'énumération HTTP 400 non valide pour role Transmettre "user" ou "user_role" en minuscules. Définissez message.role sur "ROLE_USER".
HTTP 501 *"is not supported yet"* Appel de getCard sur un agent qui ne publie pas d'interface A2A. Inspectez le tableau protocols de la ressource de registre pour confirmer la compatibilité avec A2A_AGENT avant d'appeler.
HTTP 400 *"Unsupported agent"* Appel de message:send sur un agent non A2A. Choisissez un agent dont la définition de registre inclut une liaison de protocole A2A_AGENT active.
HTTP 401 ou HTTP 403 Permission Denied Champs d'application OAuth manquants, rôles IAM manquants ou en-tête de projet de quota manquant. Vérifiez les rôles IAM de l'appelant (agentregistry.viewer et assistants.assist), vérifiez le champ d'application cloud-platform et transmettez -H "X-Goog-User-Project: PROJECT_ID" si vous utilisez les ADC.