एजेंट-से-एजेंट (A2A) प्रोटोकॉल
ADK-Rust क्रॉस-नेटवर्क एजेंट संचार के लिए A2A प्रोटोकॉल v1.0.0 को लागू करता है। इसका कार्यान्वयन adk-server में a2a-v1 फीचर फ़्लैग के पीछे स्थित है और सभी 11 JSON-RPC ऑपरेशनों, REST बाइंडिंग्स, एजेंट कार्ड खोज और संस्करण वार्ता को कवर करता है। उस एक ऑपरेशन के लिए ऑपरेशन कवरेज देखें, जिसकी सिमेंटिक्स विनिर्देश द्वारा अनुमत दायरे से संकरी है। वायर प्रकार a2a-protocol-types द्वारा उपलब्ध कराए जाते हैं — @tomtom215 द्वारा बनाया गया Foundation-सत्यापित Rust A2A SDK (a2a-rust)।
अवलोकन
A2A इन स्थितियों में उपयोगी है:
- तृतीय-पक्ष एजेंट सेवाओं के साथ एकीकरण
- विशेषज्ञ एजेंटों के साथ माइक्रोसर्विस आर्किटेक्चर बनाना
- क्रॉस-भाषा एजेंट संचार सक्षम करना (A2A क्लाइंट वाली किसी भी भाषा के साथ)
- एजेंट प्रणालियों के बीच औपचारिक अनुबंध लागू करना
सरल आंतरिक संगठन के लिए, बेहतर प्रदर्शन हेतु A2A के बजाय स्थानीय सब-एजेंट का उपयोग करें।
v1.0.0 अनुपालन
यह कार्यान्वयन A2A प्रोटोकॉल v1.0.0 विनिर्देश के साथ पूरी तरह अनुपालक है:
| विशेषता | विनिर्देशन अनुभाग | स्थिति |
|---|---|---|
| क्षमताओं की घोषणा वाला एजेंट कार्ड | §8 | ✅ |
| सभी कार्य स्थिति परिवर्तनों पर RFC 3339 टाइमस्टैम्प | §5.6.1 | ✅ |
SendMessage के लिए संदेश ID की idempotency | §3.3.1 | ✅ |
| Push notification प्रमाणीकरण (Bearer + token) | §13.2 | ✅ |
| INPUT_REQUIRED का multi-turn resume flow | §3.4.3 | ✅ |
| इनपुट सत्यापन (parts, IDs, metadata आकार) | §3.3 | ✅ |
प्रतिक्रियाओं पर Content-Type: application/a2a+json | §9 | ✅ |
| प्रथम SSE स्ट्रीमिंग इवेंट के रूप में Task ऑब्जेक्ट | §3.1.2 | ✅ |
| multi-turn के लिए context-scoped Task lookup | §3.4.1 | ✅ |
संस्करण वार्ता (A2A-Version हेडर) | §9.1 | ✅ |
| स्टेट मशीन सत्यापन (टर्मिनल अवस्थाएँ) | §4.1.3 | ✅ |
एजेंट कार्ड
प्रत्येक A2A एजेंट अपनी क्षमताओं, कौशलों और समर्थित इंटरफ़ेस का वर्णन करने वाला एजेंट कार्ड /.well-known/agent-card.json पर उपलब्ध कराता है।
use adk_server::a2a::v1::card::build_v1_agent_card;
use a2a_protocol_types::{AgentCapabilities, AgentSkill};
let card = build_v1_agent_card(
"my-agent",
"A helpful research agent",
"http://localhost:3001/jsonrpc",
"1.0.0",
vec![AgentSkill {
id: "research".to_string(),
name: "Research & Summarize".to_string(),
description: "Researches topics and produces structured summaries".to_string(),
tags: vec!["research".to_string()],
examples: None,
input_modes: None,
output_modes: None,
security_requirements: None,
}],
AgentCapabilities::none()
.with_streaming(true)
.with_push_notifications(true),
);
एजेंट कार्ड में शामिल हैं:
- एजेंट का नाम, विवरण और संस्करण
- प्रोटोकॉल बाइंडिंग और संस्करण सहित समर्थित इंटरफ़ेस
- क्षमताएँ:
streaming,pushNotifications,extendedAgentCard - एजेंट कॉन्फ़िगरेशन से प्राप्त कौशल
- डिफ़ॉल्ट इनपुट/आउटपुट मोड
अब क्षमताएँ AgentCapabilities पैरामीटर के माध्यम से स्पष्ट रूप से घोषित की जाती हैं — अब हार्डकोड किए गए डिफ़ॉल्ट नहीं हैं।
A2A v1 के माध्यम से एजेंट को उपलब्ध कराना
LLM इंटीग्रेशन के साथ एक पूर्ण A2A v1.0.0 सर्वर बनाएँ:
use std::sync::Arc;
use a2a_protocol_types::{AgentCapabilities, AgentSkill};
use adk_agent::LlmAgentBuilder;
use adk_server::a2a::v1::card::{CachedAgentCard, build_v1_agent_card};
use adk_server::a2a::v1::executor::V1Executor;
use adk_server::a2a::v1::jsonrpc_handler::jsonrpc_handler;
use adk_server::a2a::v1::push::NoOpPushNotificationSender;
use adk_server::a2a::v1::request_handler::RequestHandler;
use adk_server::a2a::v1::rest_handler::rest_router;
use adk_server::a2a::v1::task_store::InMemoryTaskStore;
use adk_server::a2a::v1::version::version_negotiation;
use adk_runner::RunnerConfig;
use adk_session::InMemorySessionService;
use axum::Router;
use axum::routing::post;
use tokio::sync::RwLock;
// 1. Create your agent
let model = adk_model::GeminiModel::new(&api_key, "gemini-3.7-flash")?;
let agent = LlmAgentBuilder::new("my-agent")
.description("A helpful agent")
.model(Arc::new(model))
.instruction("You are a helpful assistant.")
.build()?;
// 2. Set up A2A infrastructure
let task_store = Arc::new(InMemoryTaskStore::new());
let executor = Arc::new(V1Executor::new(task_store.clone()));
let push_sender = Arc::new(NoOpPushNotificationSender);
// 3. Build agent card with capabilities
let card = build_v1_agent_card(
"my-agent", "A helpful agent",
"http://localhost:3001/jsonrpc", "1.0.0",
vec![/* skills */],
AgentCapabilities::none().with_streaming(true),
);
let cached_card = Arc::new(RwLock::new(CachedAgentCard::new(card)));
// 4. Create runner config for LLM invocation
let session_service = Arc::new(InMemorySessionService::new());
let runner_config = Arc::new(RunnerConfig {
app_name: "my-agent".to_string(),
agent: Arc::new(agent),
session_service,
artifact_service: None,
memory_service: None,
plugin_manager: None,
run_config: None,
compaction_config: None,
context_cache_config: None,
cache_capable: None,
request_context: None,
cancellation_token: None,
});
// 5. Wire up the handler and routes
let handler = Arc::new(RequestHandler::with_runner(
executor, task_store, push_sender, cached_card, runner_config,
));
let app = Router::new()
.route("/jsonrpc", post(jsonrpc_handler))
.with_state(handler.clone())
.merge(rest_router(handler))
.layer(axum::middleware::from_fn(version_negotiation));
// 6. Serve
let listener = tokio::net::TcpListener::bind("0.0.0.0:3001").await?;
axum::serve(listener, app).await?;
यह उपलब्ध कराता है:
GET /.well-known/agent-card.json— ETag कैशिंग वाला एजेंट कार्डPOST /jsonrpc— JSON-RPC एंडपॉइंट (सभी 11 v1 ऑपरेशन; ऑपरेशन कवरेज देखें)- सभी ऑपरेशन के लिए REST रूट
- सभी रूट पर
A2A-Versionहेडर नेगोशिएशन
JSON-RPC ऑपरेशन
सभी 11 A2A v1.0.0 ऑपरेशन समर्थित हैं:
| विधि | विवरण |
|---|---|
SendMessage | संदेश भेजें, कार्य बनाएँ/फिर से शुरू करें |
SendStreamingMessage | SendMessage के समान, लेकिन SSE स्ट्रीम लौटाता है |
GetTask | ID द्वारा कार्य प्राप्त करें |
CancelTask | चल रहे कार्य को रद्द करें |
ListTasks | फ़िल्टरिंग और पृष्ठांकन के साथ कार्यों की सूची बनाएँ |
SubscribeToTask | SSE के माध्यम से कार्य अपडेट की सदस्यता लें |
CreateTaskPushNotificationConfig | पुश सूचनाओं के लिए वेबहुक पंजीकृत करें |
GetTaskPushNotificationConfig | पुश सूचना कॉन्फ़िगरेशन प्राप्त करें |
ListTaskPushNotificationConfigs | किसी कार्य के लिए पुश कॉन्फ़िगरेशन की सूची बनाएँ |
DeleteTaskPushNotificationConfig | पुश सूचना कॉन्फ़िगरेशन हटाएँ |
GetExtendedAgentCard | विस्तारित एजेंट कार्ड प्राप्त करें |
SendMessage
{
"jsonrpc": "2.0",
"id": 1,
"method": "SendMessage",
"params": {
"message": {
"messageId": "msg-123",
"role": "ROLE_USER",
"parts": [{"text": "Research quantum computing"}]
}
}
}
प्रतिक्रिया में स्थिति, इतिहास और आर्टिफैक्ट वाले Task ऑब्जेक्ट शामिल होते हैं। प्रतिक्रिया Content-Type: application/a2a+json का उपयोग करती है।
SendStreamingMessage
SendMessage के समान अनुरोध प्रारूप। एक SSE स्ट्रीम लौटाता है, जहाँ:
- पहली घटना एक पूर्ण
Taskऑब्जेक्ट होती है (विशिष्टता §3.1.2 के अनुसार) - बाद की घटनाएँ
TaskStatusUpdateEventहोती हैं (Working, Completed आदि) - आर्टिफैक्ट घटनाएँ
TaskArtifactUpdateEventहोती हैं
बहु-टर्न वार्तालाप
जब कोई कार्य INPUT_REQUIRED स्थिति में पहुँचता है, तो उसे फिर से शुरू करने के लिए उसी contextId के साथ एक अनुवर्ती संदेश भेजें:
{
"jsonrpc": "2.0",
"id": 2,
"method": "SendMessage",
"params": {
"message": {
"messageId": "msg-456",
"role": "ROLE_USER",
"contextId": "ctx-original",
"parts": [{"text": "Yes, include more details on error correction"}]
}
}
}
हैंडलर contextId द्वारा मौजूदा कार्य को स्वचालित रूप से ढूँढता है, उसे INPUT_REQUIRED से Working में परिवर्तित करता है, नए संदेश को इतिहास में जोड़ता है और प्रोसेसिंग जारी रखता है।
इडेम्पोटेंसी
समान messageId वाले डुप्लिकेट SendMessage अनुरोध बिना दोबारा प्रोसेस किए पहले से बनाए गए कार्य को लौटाते हैं। यह SendMessage और SendStreamingMessage दोनों पर लागू होता है।
पुश अधिसूचना प्रमाणीकरण
जब कोई क्लाइंट CreateTaskPushNotificationConfig के माध्यम से वेबहुक पंजीकृत करता है, तो सर्वर वेबहुक डिलीवरी में प्रमाणीकरण हेडर शामिल करता है:
Authorization: Bearer <credentials>— जबauthenticationफ़ील्ड में bearer क्रेडेंशियल होंa2a-notification-token: <token>— जबtokenफ़ील्ड मौजूद हो
दोनों हेडर एक साथ सेट किए जा सकते हैं। SSRF सुरक्षा निजी IP रेंज और localhost के विरुद्ध वेबहुक URLs को मान्य करती है।
इनपुट सत्यापन
प्रोसेसिंग से पहले सभी आने वाले अनुरोधों का सत्यापन किया जाता है:
| सत्यापन | त्रुटि |
|---|---|
| शून्य भागों वाला संदेश | InvalidParams (-32602) |
| खाली या केवल रिक्तस्थान वाला messageId | InvalidParams (-32602) |
| 256 अक्षरों से अधिक messageId | InvalidParams (-32602) |
| रिक्त या केवल whitespace वाला taskId | InvalidParams (-32602) |
| 256 अक्षरों से अधिक taskId | InvalidParams (-32602) |
| 64 KB से अधिक मेटाडेटा | InvalidParams (-32602) |
रिमोट एजेंट का उपयोग
रिमोट A2A एजेंट के साथ संचार करने के लिए RemoteA2aAgent का उपयोग करें:
use adk_server::a2a::RemoteA2aAgent;
let remote_agent = RemoteA2aAgent::builder("prime_checker")
.description("Checks if numbers are prime")
.agent_url("http://localhost:8001")
.build()?;
// Use as a sub-agent in a local agent hierarchy
let root_agent = LlmAgentBuilder::new("root")
.model(Arc::new(model))
.sub_agent(Arc::new(remote_agent))
.build()?;
A2A क्लाइंट
सीधे प्रोटोकॉल-स्तरीय संचार के लिए:
use adk_server::a2a::client::v1_client::A2aV1Client;
// Discover agent card
let card = A2aV1Client::resolve_agent_card("http://localhost:3001").await?;
let client = A2aV1Client::new(card);
// Send message
let task = client.send_message(message).await?;
// Get task
let task = client.get_task(&task_id, Some(10)).await?;
// List tasks
let tasks = client.list_tasks(None, None, None, None).await?;
// Cancel task
client.cancel_task(&task_id).await?;
// Streaming
let response = client.send_streaming_message(message).await?;
// Push notification CRUD
let config = client.create_push_notification_config(config).await?;
client.delete_push_notification_config(&task_id, &config_id).await?;
त्रुटि प्रबंधन
A2A त्रुटियाँ JSON-RPC कोड और HTTP स्थिति कोड, दोनों से मैप होती हैं:
| त्रुटि | JSON-RPC कोड | HTTP स्थिति |
|---|---|---|
| TaskNotFound | -32001 | 404 |
| TaskNotCancelable | -32002 | 409 |
| PushNotificationNotSupported | -32003 | 400 |
| UnsupportedOperation | -32004 | 400 |
| ContentTypeNotSupported | -32005 | 415 |
| InvalidAgentResponse | -32006 | 502 |
| VersionNotSupported | -32009 | 400 |
| InvalidParams | -32602 | 400 |
| MethodNotFound | -32601 | 404 |
| आंतरिक | -32603 | 500 |
उदाहरण चलाना
दो पूर्ण A2A v1.0.0 उदाहरण एजेंट शामिल हैं:
cargo run --manifest-path examples/a2a-research-agent/Cargo.toml
cargo run --manifest-path examples/a2a-writing-agent/Cargo.toml --bin a2a-writing-agent
cargo run --manifest-path examples/a2a-writing-agent/Cargo.toml --bin client
क्लाइंट निम्न का सत्यापन करता है: एजेंट कार्ड खोज, SendMessage (दोनों एजेंट वास्तविक LLM के साथ), GetTask, ListTasks, CancelTask त्रुटि पथ, SendStreamingMessage, पुश अधिसूचना CRUD, GetExtendedAgentCard, संस्करण वार्ता और त्रुटि पथ।
सर्वोत्तम प्रथाएँ
- क्षमताओं की सटीक घोषणा करें —
streaming,pushNotificationsको इस आधार पर सेट करें कि आपका एजेंट वास्तव में किसका समर्थन करता है - लंबे संचालन के लिए स्ट्रीमिंग का उपयोग करें —
SendStreamingMessageक्लाइंट को वास्तविक समय में प्रगति देता है - बहु-चरणीय प्रवाहों को संभालें — संदेशों के बीच वार्तालाप स्थिति बनाए रखने के लिए
contextIdका उपयोग करें - वेबहुक URLs को मान्य करें — SSRF सुरक्षा अंतर्निहित है, लेकिन उत्पादन में HTTPS का उपयोग करें
- उपयुक्त टाइमआउट सेट करें — दूरस्थ एजेंट कॉल के लिए अनुरोध टाइमआउट कॉन्फ़िगर करें
- आइडेम्पोटेंसी का उपयोग करें — क्लाइंट समान
messageIdके साथSendMessageको सुरक्षित रूप से पुनः प्रयास कर सकते हैं
संबंधित
- LlmAgent — एजेंट बनाना
- बहु-एजेंट प्रणालियाँ — उप-एजेंट और पदानुक्रम
- सर्वर परिनियोजन — एजेंट को HTTP सर्वर के रूप में चलाना
पिछला: ← सर्वर | अगला: मूल्यांकन →
संचालन कवरेज
सभी 11 v1 JSON-RPC संचालन डिस्पैच और कार्यान्वित किए गए हैं।
| ऑपरेशन | स्थिति |
|---|---|
SendMessage | एजेंट को संचालित करता है और इसके आउटपुट को एक आर्टिफैक्ट के रूप में रिकॉर्ड करता है |
SendStreamingMessage | एजेंट को संचालित करता है और आर्टिफैक्ट के हिस्सों को तैयार होते ही स्ट्रीम करता है |
GetTask, ListTasks | पूर्ण |
CancelTask | पूर्ण |
SubscribeToTask (tasks/resubscribe) | केवल स्नैपशॉट — नीचे देखें |
CreateTaskPushNotificationConfig, GetTaskPushNotificationConfig, ListTaskPushNotificationConfigs, DeleteTaskPushNotificationConfig | पूर्ण |
GetExtendedAgentCard | पूर्ण |
SubscribeToTask एक स्नैपशॉट है
यह ऑपरेशन कार्य और उसकी वर्तमान स्थिति लौटाता है, फिर स्ट्रीम बंद कर देता है। यह बाद के अपडेट प्रदान नहीं करता, इसलिए किसी क्लाइंट को प्रगति के लिए इसके पूरा होने की प्रतीक्षा नहीं करनी चाहिए।
लाइव पुनः-अटैच के लिए प्रति-कार्य इवेंट कतार आवश्यक होती है, जो मूल अनुरोध के समाप्त होने के बाद भी बनी रहे। संदर्भ
कार्यान्वयन इसे अपने A2A SDKs से प्राप्त करते हैं — adk-python और adk-go दोनों
tasks/resubscribe को पूरी तरह SDK के कतार प्रबंधक को सौंपते हैं, और दोनों इसे ADK कोड में
कार्यान्वित नहीं करते।
यह सर्वर a2a-protocol-types पर स्वयं बनाया गया है, जो सर्वर रनटाइम के बजाय वायर प्रकार प्रदान करता है, इसलिए
कतार अभी मौजूद नहीं है।
जब लाइव अपडेट आवश्यक हों, तब SendStreamingMessage का उपयोग करें।
स्ट्रीमिंग इवेंट अनुबंध
SendStreamingMessage एजेंट इवेंट को प्राप्त होते ही रूपांतरित करता है:
| एजेंट इवेंट | A2A इवेंट |
|---|---|
| पहले, आउटपुट से पहले | Task, फिर TaskStatusUpdateEvent — Working |
सामग्री, partial = true | TaskArtifactUpdateEvent — append, अंतिम चंक नहीं |
सामग्री, partial = false | TaskArtifactUpdateEvent — अंतिम खंड |
| प्रवाह समाप्त होता है | TaskStatusUpdateEvent — Completed |
| प्रवाह में त्रुटियाँ | TaskStatusUpdateEvent — Failed |
एक ही प्रतिक्रिया के सभी खंड एक आर्टिफैक्ट ID साझा करते हैं। जुड़ा हुआ पाठ स्थायी रूप से सहेजा जाता है, इसलिए बाद का GetTask वही लौटाता है जो स्ट्रीम किया गया था। यह उस अनुबंध के अनुरूप है जिसे adk-python और adk-go अपने SDKs पर लागू करते हैं।