Agent-to-Agent (A2A) प्रोटोकॉल

Agent-to-Agent (A2A) प्रोटोकॉल एजेंट्स को नेटवर्क सीमाओं के पार संवाद और सहयोग करने में सक्षम बनाता है। ADK-Rust A2A के माध्यम से एजेंट्स को उजागर करने और रिमोट A2A एजेंट्स का उपभोग करने, दोनों के लिए पूर्ण समर्थन प्रदान करता है।

अवलोकन

A2A तब उपयोगी है जब:

  • थर्ड-पार्टी एजेंट सेवाओं के साथ एकीकृत करना
  • विशेषीकृत एजेंट्स के साथ माइक्रोसर्विसेज आर्किटेक्चर का निर्माण करना
  • क्रॉस-लैंग्वेज एजेंट संचार को सक्षम करना
  • एजेंट सिस्टम के बीच औपचारिक अनुबंधों को लागू करना

सरल आंतरिक संगठन के लिए, बेहतर प्रदर्शन के लिए A2A के बजाय स्थानीय सब-एजेंट्स का उपयोग करें।

एजेंट कार्ड

प्रत्येक A2A एजेंट एक एजेंट कार्ड को उजागर करता है जो उसकी क्षमताओं का वर्णन करता है। कार्ड स्वचालित रूप से जेनरेट होता है और /.well-known/agent.json पर परोसा जाता है।

use adk_server::a2a::build_agent_card;

let agent_card = build_agent_card(&agent, "http://localhost:8080");

println!("Agent: {}", agent_card.name);
println!("Skills: {}", agent_card.skills.len());
println!("Streaming: {}", agent_card.capabilities.streaming);

एजेंट कार्ड में शामिल हैं:

  • एजेंट का नाम और विवरण
  • संचार के लिए बेस URL
  • क्षमताएं (streaming, state history, आदि)
  • एजेंट और उसके सब-एजेंट्स से प्राप्त स्किल्स

A2A के माध्यम से एक एजेंट को उजागर करना

किसी एजेंट को उजागर करने के लिए ताकि अन्य एजेंट्स उसका उपयोग कर सकें, A2A एंडपॉइंट्स के साथ एक HTTP सर्वर बनाएं:

use adk_server::{create_app_with_a2a, ServerConfig};
use adk_agent::LlmAgentBuilder;
use adk_model::gemini::GeminiModel;
use std::sync::Arc;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Create your agent
    let model = GeminiModel::new(&api_key, "gemini-2.5-flash")?;
    let agent = LlmAgentBuilder::new("weather_agent")
        .description("Answers weather questions")
        .model(Arc::new(model))
        .build()?;

    // Create server config
    let config = ServerConfig::new(
        Arc::new(SingleAgentLoader::new(Arc::new(agent))),
        Arc::new(InMemorySessionService::new()),
    );

    // Create app with A2A support
    let app = create_app_with_a2a(config, Some("http://localhost:8080"));

    // Serve
    let listener = tokio::net::TcpListener::bind("0.0.0.0:8080").await?;
    axum::serve(listener, app).await?;

    Ok(())
}

यह उजागर करता है:

  • GET /.well-known/agent.json - एजेंट कार्ड
  • POST /a2a - A2A प्रोटोकॉल के लिए JSON-RPC एंडपॉइंट
  • POST /a2a/stream - SSE streaming एंडपॉइंट

एक रिमोट एजेंट का उपभोग करना

एक रिमोट 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
let root_agent = LlmAgentBuilder::new("root")
    .model(Arc::new(model))
    .sub_agent(Arc::new(remote_agent))
    .build()?;

RemoteA2aAgent:

  • रिमोट URL से एजेंट कार्ड को स्वचालित रूप से फ़ेच करता है
  • ADK इवेंट्स को A2A प्रोटोकॉल संदेशों में/से परिवर्तित करता है
  • स्ट्रीमिंग प्रतिक्रियाओं को संभालता है
  • एक सब-एजेंट के रूप में निर्बाध रूप से काम करता है

A2A क्लाइंट

रिमोट एजेंट्स के साथ सीधे संचार के लिए, A2aClient का उपयोग करें:

use adk_server::a2a::{A2aClient, Message, Part, Role};

// Create client from URL (fetches agent card)
let client = A2aClient::from_url("http://localhost:8080").await?;

// Build a message
let message = Message::builder()
    .role(Role::User)
    .parts(vec![Part::text("What's the weather?".to_string())])
    .message_id(uuid::Uuid::new_v4().to_string())
    .build();

// Send message (blocking)
let response = client.send_message(message.clone()).await?;

// Or send with streaming
let mut stream = client.send_streaming_message(message).await?;
while let Some(event) = stream.next().await {
    match event? {
        UpdateEvent::TaskArtifactUpdate(artifact) => {
            println!("Artifact: {:?}", artifact);
        }
        UpdateEvent::TaskStatusUpdate(status) => {
            println!("Status: {:?}", status.status.state);
        }
    }
}

JSON-RPC प्रोटोकॉल

ADK-Rust, JSON-RPC 2.0 का उपयोग करके A2A प्रोटोकॉल को लागू करता है। समर्थित विधियाँ:

message/send

एजेंट को एक संदेश भेजें:

{
  "jsonrpc": "2.0",
  "method": "message/send",
  "params": {
    "message": {
      "role": "user",
      "messageId": "msg-123",
      "parts": [{"text": "Hello!"}]
    }
  },
  "id": 1
}

प्रतिक्रिया में स्थिति और आर्टिफैक्ट के साथ एक टास्क ऑब्जेक्ट शामिल होता है।

message/stream

message/send के समान, लेकिन स्ट्रीमिंग प्रतिक्रियाओं के लिए Server-Sent Events (SSE) लौटाता है।

tasks/cancel

चल रहे कार्य को रद्द करें:

{
  "jsonrpc": "2.0",
  "method": "tasks/cancel",
  "params": {
    "taskId": "task-123"
  },
  "id": 1
}

मल्टी-एजेंट उदाहरण

स्थानीय और दूरस्थ एजेंटों को संयोजित करें:

// Local agent
let roll_agent = LlmAgentBuilder::new("roll_agent")
    .description("Rolls dice")
    .model(Arc::new(model.clone()))
    .tool(Arc::new(roll_die_tool))
    .build()?;

// Remote agent
let prime_agent = RemoteA2aAgent::builder("prime_agent")
    .description("Checks if numbers are prime")
    .agent_url("http://localhost:8001")
    .build()?;

// Root agent orchestrates both
let root_agent = LlmAgentBuilder::new("root_agent")
    .instruction("Delegate dice rolling to roll_agent and prime checking to prime_agent")
    .model(Arc::new(model))
    .sub_agent(Arc::new(roll_agent))
    .sub_agent(Arc::new(prime_agent))
    .build()?;

त्रुटि प्रबंधन

A2A ऑपरेशन मानक ADK त्रुटियाँ लौटाते हैं:

match client.send_message(message).await {
    Ok(response) => {
        if let Some(error) = response.error {
            eprintln!("RPC error: {} (code: {})", error.message, error.code);
        }
    }
    Err(e) => {
        eprintln!("Request failed: {}", e);
    }
}

सामान्य त्रुटि कोड:

  • -32600: अमान्य अनुरोध
  • -32601: विधि नहीं मिली
  • -32602: अमान्य पैरामीटर
  • -32603: आंतरिक त्रुटि

सर्वोत्तम अभ्यास

  1. एजेंट कार्ड का उपयोग करें: संचार से पहले हमेशा एजेंट कार्ड प्राप्त करें और मान्य करें
  2. स्ट्रीमिंग को संभालें: लंबे समय तक चलने वाले ऑपरेशंस के लिए स्ट्रीमिंग का उपयोग करें
  3. त्रुटि से उबरना: नेटवर्क विफलताओं के लिए पुनः प्रयास तर्क लागू करें
  4. टाइमआउट: दूरस्थ कॉलों के लिए उचित टाइमआउट सेट करें
  5. सुरक्षा: उत्पादन में HTTPS का उपयोग करें और प्रमाणीकरण लागू करें

सुरक्षा कॉन्फ़िगरेशन

उत्पादन डिप्लॉयमेंट के लिए CORS, टाइमआउट और सुरक्षा हेडर कॉन्फ़िगर करें:

use adk_server::{ServerConfig, SecurityConfig};
use std::time::Duration;

// Production configuration
let config = ServerConfig::new(agent_loader, session_service)
    .with_allowed_origins(vec![
        "https://myapp.com".to_string(),
        "https://admin.myapp.com".to_string(),
    ])
    .with_request_timeout(Duration::from_secs(30))
    .with_max_body_size(10 * 1024 * 1024);  // 10MB

// Or use presets
let dev_config = ServerConfig::new(agent_loader, session_service)
    .with_security(SecurityConfig::development());  // Permissive for dev

let prod_config = ServerConfig::new(agent_loader, session_service)
    .with_security(SecurityConfig::production(allowed_origins));

सुरक्षा विशेषताओं में शामिल हैं:

  • CORS: कॉन्फ़िगर करने योग्य अनुमत ओरिजिन्स (डिफ़ॉल्ट: विकास के लिए अनुमेय)
  • अनुरोध टाइमआउट: कॉन्फ़िगर करने योग्य टाइमआउट (डिफ़ॉल्ट: 30 सेकंड)
  • बॉडी आकार सीमा: अधिकतम अनुरोध बॉडी आकार (डिफ़ॉल्ट: 10MB)
  • सुरक्षा हेडर: X-Content-Type-Options, X-Frame-Options, X-XSS-Protection
  • त्रुटि सैनिटाइजेशन: आंतरिक त्रुटियों को लॉग किया जाता है लेकिन उत्पादन में क्लाइंट्स के सामने उजागर नहीं किया जाता है

संबंधित


पिछला: ← Server | अगला: Evaluation →