एजेंट-से-एजेंट (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संदेश भेजें, कार्य बनाएँ/फिर से शुरू करें
SendStreamingMessageSendMessage के समान, लेकिन SSE स्ट्रीम लौटाता है
GetTaskID द्वारा कार्य प्राप्त करें
CancelTaskचल रहे कार्य को रद्द करें
ListTasksफ़िल्टरिंग और पृष्ठांकन के साथ कार्यों की सूची बनाएँ
SubscribeToTaskSSE के माध्यम से कार्य अपडेट की सदस्यता लें
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 स्ट्रीम लौटाता है, जहाँ:

  1. पहली घटना एक पूर्ण Task ऑब्जेक्ट होती है (विशिष्टता §3.1.2 के अनुसार)
  2. बाद की घटनाएँ TaskStatusUpdateEvent होती हैं (Working, Completed आदि)
  3. आर्टिफैक्ट घटनाएँ 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)
खाली या केवल रिक्तस्थान वाला messageIdInvalidParams (-32602)
256 अक्षरों से अधिक messageIdInvalidParams (-32602)
रिक्त या केवल whitespace वाला taskIdInvalidParams (-32602)
256 अक्षरों से अधिक taskIdInvalidParams (-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-32001404
TaskNotCancelable-32002409
PushNotificationNotSupported-32003400
UnsupportedOperation-32004400
ContentTypeNotSupported-32005415
InvalidAgentResponse-32006502
VersionNotSupported-32009400
InvalidParams-32602400
MethodNotFound-32601404
आंतरिक-32603500

उदाहरण चलाना

दो पूर्ण 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, संस्करण वार्ता और त्रुटि पथ।

सर्वोत्तम प्रथाएँ

  1. क्षमताओं की सटीक घोषणा करें — streaming, pushNotifications को इस आधार पर सेट करें कि आपका एजेंट वास्तव में किसका समर्थन करता है
  2. लंबे संचालन के लिए स्ट्रीमिंग का उपयोग करें — SendStreamingMessage क्लाइंट को वास्तविक समय में प्रगति देता है
  3. बहु-चरणीय प्रवाहों को संभालें — संदेशों के बीच वार्तालाप स्थिति बनाए रखने के लिए contextId का उपयोग करें
  4. वेबहुक URLs को मान्य करें — SSRF सुरक्षा अंतर्निहित है, लेकिन उत्पादन में HTTPS का उपयोग करें
  5. उपयुक्त टाइमआउट सेट करें — दूरस्थ एजेंट कॉल के लिए अनुरोध टाइमआउट कॉन्फ़िगर करें
  6. आइडेम्पोटेंसी का उपयोग करें — क्लाइंट समान messageId के साथ SendMessage को सुरक्षित रूप से पुनः प्रयास कर सकते हैं

पिछला: ← सर्वर | अगला: मूल्यांकन →

संचालन कवरेज

सभी 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 = trueTaskArtifactUpdateEvent — append, अंतिम चंक नहीं
सामग्री, partial = falseTaskArtifactUpdateEvent — अंतिम खंड
प्रवाह समाप्त होता हैTaskStatusUpdateEvent — Completed
प्रवाह में त्रुटियाँTaskStatusUpdateEvent — Failed

एक ही प्रतिक्रिया के सभी खंड एक आर्टिफैक्ट ID साझा करते हैं। जुड़ा हुआ पाठ स्थायी रूप से सहेजा जाता है, इसलिए बाद का GetTask वही लौटाता है जो स्ट्रीम किया गया था। यह उस अनुबंध के अनुरूप है जिसे adk-python और adk-go अपने SDKs पर लागू करते हैं।