סוכני Agent2Agent (A2A) ב-Agent Registry מפרסמים ממשקי פרוטוקול שמכילים כתובת URL של נקודת קצה וקישור לפרוטוקול (כמו HTTP_JSON). אתם יכולים למצוא את כתובת ה-URL של הסוכן ב-Registry כדי להפעיל את השיטות שלו ל-A2A מלקוחות או מתזמנים בהתאמה אישית.
בקצרה
| מפרט | פרטים |
|---|---|
| Discovery API | agentregistry.googleapis.com (v1) |
| מארח של שרת proxy להפעלה | LOCATION-discoveryengine.googleapis.com |
| קישור לפרוטוקול | HTTP_JSON |
| מזהה הפרויקט בכתובת ה-URL | Google Cloud מספר הפרויקט (לא מזהה הפרויקט) |
| שיטות A2A נתמכות | GET /v1/card, POST /v1/message:send, POST /v1/message:stream |
| סכימת ההודעה הנדרשת | message.role = "ROLE_USER", content[].text, messageId ייחודיים |
| הרשאות IAM נדרשות | roles/agentregistry.viewer (גילוי) ו-discoveryengine.assistants.assist (הפעלה) |
לפני שמתחילים
- מפעילים את Agent Registry API (
agentregistry.googleapis.com) ואת Discovery Engine API (discoveryengine.googleapis.com) בפרויקט ב- Google Cloud . - אם הסוכן לא נוצר ישירות באפליקציית Gemini Enterprise, אתם צריכים לייבא אותו ממאגר הסוכנים ולתת למשתמשי הקצה גישה אליו. הוראות מפורטות זמינות במאמר ייבוא סוכני A2A מ-Agent Registry.
- נותנים לחשבון המשתמש שמבצע את הקריאה החוזרת את הרשאות ה-IAM המתאימות:
- כדי לקרוא את המרשם: צפייה במרשם הסוכנים (
roles/agentregistry.viewer). - כדי להפעיל את הנציג: עריכה ב-Discovery Engine (
roles/discoveryengine.editor) או תפקיד בהתאמה אישית שכולל אתdiscoveryengine.assistants.assist.
- כדי לקרוא את המרשם: צפייה במרשם הסוכנים (
- אם אתם מבצעים אימות באמצעות Application Default Credentials (ADC), הגדירו את הלקוח כך שישלח את הכותרת של הפרויקט לצורכי מכסה:
-H "X-Goog-User-Project: PROJECT_ID". - אם אתם מתכננים להגדיר סוכנים מרוחקים כסוכני משנה פרוגרמטיים, אתם יכולים להתקין את הספרייה של ערכת הפיתוח לסוכנים (ADK):
pip install "google-adk[a2a]>=1.29.0".
שלב 1: מוצאים את הסוכן ואת נקודת הקצה שלו ל-A2A
כדי להפעיל סוכן A2A, קודם צריך למצוא את ה-url שלו שפורסם במאגר הסוכנים. מציגים את הנציגים במיקום של המרשם (למשל us או eu, שמועברים כפרמטר של הנתיב במארח הגלובלי 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"
אפשר גם לחפש נציג לפי הקידומת של השם המוצג באמצעות Google Cloud CLI:
gcloud agent-registry agents search \
--project=PROJECT_ID \
--location=LOCATION \
--search-string="displayName:My_Agent_*"
במשאב הסוכן שמוחזר, בודקים את המערך protocols. מאתרים את הרשומה שבה type שווה ל-A2A_AGENT ו-interfaces[].protocolBinding שווה ל-HTTP_JSON. מחלצים את ה-url המתאים:
{
"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"
}
]
}
]
}
הסכימה המלאה של משאב הנציג מופיעה במאמרי העזרה של API בארכיטקטורת REST של projects.locations.agents.
שלב 2: שליפת כרטיס הנציג
כרטיס הסוכן מספק מטא-נתונים שמתארים את הזהות, התיאור ויכולות הקלט/פלט של הסוכן. כדי לאחזר את הכרטיס, שולחים בקשת HTTP GET לנתיב /v1/card שמצורף לכתובת ה-URL של נקודת הקצה של הנציג ל-A2A:
curl -X GET \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
"A2A_ENDPOINT_URL/v1/card"
דוגמה למטען ייעודי (payload) של תגובה:
{
"name": "My Agent",
"description": "What the agent does.",
"url": "A2A_ENDPOINT_URL",
"capabilities": {},
"defaultInputModes": ["text"],
"defaultOutputModes": ["text"],
"preferredTransport": "HTTP+JSON"
}
שלב 3: שולחים הודעה
כדי לשלוח שאילתת משתמש לסוכן, שולחים בקשת POST אל /v1/message:send. גוף הבקשה חייב להתאים לסכימת ההודעות של A2A, שדורשת להגדיר את role כ-ROLE_USER, מערך content שמכיל חלקי טקסט ו-messageId שנוצר באופן ייחודי:
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"
}
}'
במטען הייעודי (payload) של התגובה, התשובה של הנציג מוחזרת בתוך האובייקט 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..."
}
]
}
}
כדי להציג את התשובה המלאה, צריך לשרשר את מחרוזות הטקסט בתוך content[].text. כדי להמשיך את השיחה באותו סשן, שומרים את המחרוזת contextId שמוחזרת ומספקים אותה בתור message.contextId בבקשה הבאה.
אפשר לעיין במאמרי העזרה של API בארכיטקטורת REST של message:send A2A כדי לראות את הסכימה המלאה של תוכן ההודעה.
הצגת התשובות באופן שוטף
כדי להפיק פלט בסטרימינג, שולחים בקשת POST עם גוף הודעה זהה אל /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"
}
}'
נקודת הקצה מחזירה מערך JSON של אובייקטים של קטעים בסטרימינג דרך HTTP. מצרפים את מקטעי ה-content[].text ברצף כשהם מגיעים. החלקים שמועברים בסטרימינג מכילים גם את metadata.sessionInfo ו-metadata.assistToken.
ראו A2A message:streamמאמרי העזרה של ה-API בארכיטקטורת REST לקבלת מפרט המטען הייעודי (payload) בסטרימינג.
קריאה לנקודת קצה (endpoint) של A2A באמצעות Python
סקריפט Python הזה פותר נקודת קצה (endpoint) של A2A ב-Agent Registry ושולח הודעה באמצעות בקשות HTTP גולמיות:
# 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)
איך לפשט את התזמור באמצעות ADK
הערכה לפיתוח סוכנים (ADK) פותרת נקודות קצה (endpoint) של מרשם באופן אוטומטי, ועוטפת סוכני A2A מרוחקים כסוכני משנה:
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"
)
הערות נוספות
לנקודות קצה (endpoints) של A2A יש את ההתנהגויות הבאות:
- מתן שמות קפדני לנתיבים: רק
GET {url}/v1/card,POST {url}/v1/message:sendו-POST {url}/v1/message:streamנתמכים בקישורי HTTP+JSON. - אימות סכימה מחמיר: אם מעבירים את
"user"כטקסט פשוט בתור התפקיד, מוחזרת שגיאת HTTP400 Bad Request. צריך להעביר את מחרוזת ה-enum"ROLE_USER". באופן דומה, טקסט ההודעה חייב להיות בתוך המערךcontentולא בתוךparts, ו-messageIdהוא חובה. - שגיאה בהפעלת סוכן שאינו סוכן A2A: אם לסוכן אין רשומת פרוטוקול
A2A_AGENTבמרשם (כמו סוכנים מסוימים מנוהלים או מוגדרים מראש), קריאה ל-getCardבכתובת ה-Proxy שלו מחזירה את הערך501 UNIMPLEMENTED("... is not supported yet"), וקריאה ל-message:sendמחזירה את הערך400 INVALID_ARGUMENT("Unsupported agent"). - מספר הפרויקט בכתובת ה-URL: המרשם מחזיר כתובת URL מסוג A2A שמכילה את מספר הפרויקט במקום את מזהה הפרויקט. אל תשנו את המחרוזת המספרית הזו כשאתם שולחים בקשות HTTP.
פתרון בעיות
אתם יכולים להיעזר בטבלה הבאה כדי לפתור שגיאות נפוצות בנקודות קצה של A2A:
| תיאור הבעיה | סיבה אפשרית | רזולוציה |
|---|---|---|
שגיאת HTTP 404 בבקשה getCard |
שימוש בכינוי נתיב שגוי (כמו /v1:getCard או /.well-known/agent-card.json). |
שולחים את בקשת ה-GET רק אל GET {url}/v1/card. |
| HTTP 400 *"Unknown name 'parts'"* | שימוש בפורמט ישן או בפורמט של גוף לקוח שנוצר על ידי AI גנרטיבי. | מחרוזות טקסט צריכות להיות בתוך content, לא בתוך parts. |
HTTP 400 ערך enum לא תקין עבור role |
העברת "user" או "user_role" באותיות קטנות. |
מגדירים את message.role בדיוק לערך "ROLE_USER". |
| HTTP 501 *"is not supported yet"* | מתבצעת קריאה ל-getCard בסוכן שלא מפרסם ממשק A2A. |
לפני ששולחים קריאה, בודקים את המערך protocols של משאב המרשם כדי לוודא שיש תמיכה ב-A2A_AGENT. |
| HTTP 400 *"Unsupported agent"* | מתבצעת קריאה ל-message:send בסוכן שהוא לא סוכן A2A. |
בוחרים סוכן שהגדרת המרשם שלו כוללת קישור לפרוטוקול A2A_AGENT פעיל. |
HTTP 401 או HTTP 403 Permission Denied |
חסרים היקפי הרשאות של OAuth, חסרים תפקידי IAM או חסרה כותרת של פרויקט מכסות. | בודקים את תפקידי ה-IAM של מבצע הקריאה החוזרת (agentregistry.viewer ו-assistants.assist), מאמתים את ההיקף של cloud-platform ומעבירים את -H "X-Goog-User-Project: PROJECT_ID" אם משתמשים ב-ADC. |