एजेंट-टू-एजेंट (A2A) प्रोटोकॉल
ADK-Rust क्रॉस-नेटवर्क एजेंट संचार के लिए A2A Protocol v1.0.0 को लागू करता है। यह इम्प्लीमेंटेशन adk-server में a2a-v1 feature flag के पीछे स्थित है और सभी 11 JSON-RPC operations, REST bindings, agent card discovery, और version negotiation को कवर करता है। specification द्वारा अनुमति दिए गए semantics से अधिक संकीर्ण अर्थ वाले एक operation के लिए Operation coverage देखें। Wire types a2a-protocol-types द्वारा प्रदान किए जाते हैं — Foundation-verified Rust A2A SDK by @tomtom215 (a2a-rust).
अवलोकन
A2A तब उपयोगी है जब:
- तृतीय-पक्ष agent services के साथ एकीकरण करना
- विशेषीकृत agents के साथ microservices architectures बनाना
- क्रॉस-भाषा agent communication सक्षम करना (A2A client वाली कोई भी भाषा)
- agent systems के बीच formal contracts लागू करना
साधारण आंतरिक संगठन के लिए, बेहतर प्रदर्शन के लिए A2A के बजाय local sub-agents का उपयोग करें।
v1.0.0 अनुपालन
यह implementation A2A Protocol v1.0.0 specification के साथ पूरी तरह compliant है:
| विशेषता | स्पेक अनुभाग | स्थिति |
|---|---|---|
| क्षमताओं की घोषणा के साथ एजेंट कार्ड | §8 | ✅ |
| सभी कार्य स्थिति परिवर्तनों पर RFC 3339 टाइमस्टैम्प | §5.6.1 | ✅ |
SendMessage के लिए Message ID idempotency | §3.3.1 | ✅ |
| Push notification authentication (Bearer + token) | §13.2 | ✅ |
| INPUT_REQUIRED multi-turn resume flow | §3.4.3 | ✅ |
| Input validation (parts, IDs, metadata size) | §3.3 | ✅ |
Content-Type: application/a2a+json प्रतिक्रियाओं पर | §9 | ✅ |
| स्ट्रीमिंग इवेंट के रूप में पहला SSE टास्क ऑब्जेक्ट | §3.1.2 | ✅ |
| मल्टी-टर्न के लिए कॉन्टेक्स्ट-स्कोप्ड टास्क लुकअप | §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-2.5-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 ऑपरेशन; Operation coverage देखें)- सभी ऑपरेशनों के लिए REST रूट्स
- सभी रूट्स पर
A2A-Versionहेडर नेगोशिएशन
JSON-RPC ऑपरेशन्स
सभी 11 A2A v1.0.0 ऑपरेशन्स समर्थित हैं:
| विधि | विवरण |
|---|---|
SendMessage | एक संदेश भेजें, एक कार्य बनाएं/फिर से शुरू करें |
SendStreamingMessage | SendMessage जैसा ही, लेकिन SSE स्ट्रीम लौटाता है |
GetTask | ID द्वारा एक कार्य प्राप्त करें |
CancelTask | चल रहे कार्य को रद्द करें |
ListTasks | फ़िल्टरिंग और पेजिनेशन के साथ कार्यों की सूची बनाएं |
SubscribeToTask | SSE के माध्यम से कार्य अपडेट की सदस्यता लें |
CreateTaskPushNotificationConfig | पुश सूचनाओं के लिए एक वेबहुक पंजीकृत करें |
GetTaskPushNotificationConfig | एक पुश सूचना कॉन्फ़िग प्राप्त करें |
ListTaskPushNotificationConfigs | किसी task के लिए push configs की सूची बनाएं |
DeleteTaskPushNotificationConfig | एक पुश सूचना कॉन्फ़िग हटाएं |
GetExtendedAgentCard | विस्तारित एजेंट कार्ड पुनः प्राप्त करें |
SendMessage
{
"jsonrpc": "2.0",
"id": 1,
"method": "SendMessage",
"params": {
"message": {
"messageId": "msg-123",
"role": "ROLE_USER",
"parts": [{"text": "Research quantum computing"}]
}
}
}
प्रतिक्रिया में status, history, और artifacts के साथ एक Task object शामिल होता है। प्रतिक्रिया Content-Type: application/a2a+json का उपयोग करती है।
SendStreamingMessage
SendMessage के समान request format। एक SSE stream लौटाता है, जहाँ:
- पहला event एक complete
Taskobject होता है (spec §3.1.2 के अनुसार) - उसके बाद के events
TaskStatusUpdateEvent(Working, Completed, आदि) होते हैं - Artifact events
TaskArtifactUpdateEventहोते हैं
Multi-Turn Conversations
जब कोई task INPUT_REQUIRED state पर पहुँचता है, तो उसे resume करने के लिए उसी contextId के साथ एक follow-up message भेजें:
{
"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"}]
}
}
}
Handler स्वचालित रूप से contextId के आधार पर मौजूदा task ढूँढता है, उसे INPUT_REQUIRED से Working में transition करता है, नए message को history में जोड़ता है, और processing जारी रखता है।
Idempotency
एक ही messageId के साथ duplicate SendMessage requests बिना re-processing के पहले से बनाए गए task को लौटाती हैं। यह SendMessage और SendStreamingMessage दोनों पर लागू होता है।
Push Notification Authentication
जब कोई client CreateTaskPushNotificationConfig के माध्यम से एक webhook register करता है, तो server webhook deliveries पर authentication headers शामिल करता है:
Authorization: Bearer <credentials>— जबauthenticationfield में bearer credentials होंa2a-notification-token: <token>— जबtokenfield मौजूद हो
दोनों headers एक साथ set किए जा सकते हैं। SSRF protection webhook URLs को private IP ranges और localhost के विरुद्ध validate करती है।
Input Validation
सभी incoming requests को processing से पहले validate किया जाता है:
| सत्यापन | त्रुटि |
|---|---|
| शून्य भागों वाला संदेश | InvalidParams (-32602) |
| रिक्त या केवल whitespace वाला messageId | InvalidParams (-32602) |
| संदेश ID 256 वर्णों से अधिक | InvalidParams (-32602) |
| रिक्त या केवल whitespace वाला taskId | InvalidParams (-32602) |
| taskId 256 वर्णों से अधिक | 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 | एजेंट को चलाता है, उसके आउटपुट को एक artifact के रूप में रिकॉर्ड करता है |
SendStreamingMessage | एजेंट को चलाता है, जैसे-जैसे वे उत्पन्न होते हैं, artifact chunks को stream करता है |
GetTask, ListTasks | पूर्ण |
CancelTask | पूर्ण |
SubscribeToTask (tasks/resubscribe) | केवल स्नैपशॉट — नीचे देखें |
CreateTaskPushNotificationConfig, GetTaskPushNotificationConfig, ListTaskPushNotificationConfigs, DeleteTaskPushNotificationConfig | पूर्ण |
GetExtendedAgentCard | पूर्ण |
SubscribeToTask एक स्नैपशॉट है
यह ऑपरेशन task और उसकी वर्तमान स्थिति लौटाता है, फिर stream को बंद कर देता है। यह बाद के updates deliver नहीं करता, इसलिए client को progress के लिए इस पर wait नहीं करना चाहिए।
Live re-attach के लिए एक per-task event queue की आवश्यकता होती है जो originating request से अधिक समय तक जीवित रहे। Reference implementations यह अपने A2A SDKs से प्राप्त करते हैं — adk-python और adk-go दोनों tasks/resubscribe को पूरी तरह SDK के queue manager को delegate करते हैं, और कोई भी इसे ADK code में implement नहीं करता। यह server a2a-protocol-types पर hand-rolled है, जो server runtime के बजाय wire types प्रदान करता है, इसलिए queue अभी मौजूद नहीं है।
जब live updates की आवश्यकता हो, तब SendStreamingMessage का उपयोग करें।
Streaming event contract
SendStreamingMessage आने वाले agent events को arriving के साथ translate करता है:
| एजेंट घटना | A2A घटना |
|---|---|
| पहले, आउटपुट से पहले | Task, फिर TaskStatusUpdateEvent — Working |
सामग्री, partial = true | TaskArtifactUpdateEvent — append, अंतिम खंड नहीं |
सामग्री, partial = false | TaskArtifactUpdateEvent — अंतिम खंड |
| स्ट्रीम समाप्त होती है | TaskStatusUpdateEvent — Completed |
| स्ट्रीम त्रुटियाँ | TaskStatusUpdateEvent — Failed |
सभी एक प्रतिक्रिया के chunks एक artifact ID साझा करते हैं ताकि client उन्हें पुनः जोड़ सके। जुड़ा हुआ text persisted रहता है, इसलिए बाद में GetTask वही लौटाता है जो streamed किया गया था। यह contract adk-python और adk-go उनके SDKs पर implement करते हैं, से मेल खाता है।