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

Les agents Agent2Agent (A2A) d'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 du proxy d'appel LOCATION-discoveryengine.googleapis.com
Liaison de protocole HTTP_JSON
Identifiant de projet de l'URL Google Cloud Numéro de projet (et non 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 Google Cloud projet.
  2. Si l'agent n'a pas été créé directement dans votre application Gemini Enterprise, importez-le depuis Agent Registry et accordez-y l'accès aux utilisateurs finaux. Pour obtenir des instructions, consultez Importer des agents A2A depuis Agent Registry.
  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écouvrir l'agent et son point de terminaison A2A

Pour appeler un agent A2A, découvrez d'abord son url annoncé dans Agent Registry. Répertoriez les agents dans 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 Google Cloud CLI :

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 fiche de l'agent fournit des métadonnées décrivant l'identité, la description et les capacités d'entrée/de 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 : Envoyer 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, qui nécessite que role soit défini 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 dans la même session, enregistrez la chaîne contextId renvoyée et fournissez-la en tant que message.contextId dans votre requête suivante.

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 la sortie en streaming, envoyez une requête POST avec un corps de 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 bloc diffusés via HTTP. Ajoutez les fragments content[].text de manière séquentielle à mesure qu'ils arrivent. Les blocs diffusés contiennent également metadata.sessionInfo et metadata.assistToken.

Consultez la documentation de référence de l'API REST A2A message:stream pour obtenir 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 Agent Registry 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 d'ADK

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 présentent les comportements suivants :

  • Nommage strict des chemins d'accès : seuls GET {url}/v1/card, POST {url}/v1/message:send et POST {url}/v1/message:stream sont compatibles avec les liaisons HTTP+JSON.
  • Validation stricte du schéma : le fait de transmettre "user" en texte brut en tant que rôle renvoie une erreur HTTP 400 Bad Request error. Vous devez transmettre la chaîne d'énumération "ROLE_USER". De même, le texte du message doit résider dans le tableau content plutôt que dans parts, et messageId est strictement requis.
  • 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 ("... non disponible pour le moment"), 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 erreurs courantes des points de terminaison A2A :

Problème constaté Cause probable Solution
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 format de corps de client d'IA ancien ou générative. Placez les chaînes de texte dans content, et non dans parts.
HTTP 400 valeur d'énumération non valide pour role Transmission de "user" ou "user_role" en minuscules. Définissez message.role exactement 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 ADC.