2025, Sep 28 19:34
python-a2a में function_response की बजाय error: सही base URL और कनेक्टिविटी चेकलिस्ट
python-a2a एजेंट पर function_response की जगह error क्यों आता है और इसे कैसे ठीक करें: सही base URL, पोर्ट 5001, कनेक्टिविटी व endpoint पथ जांचें लोकल टेस्ट
python-a2a के साथ हल्का function-calling एजेंट जोड़ते समय एक आम अड़चन कुछ यूं दिखती है: अनुरोध पूरी तरह वैध लगता है, लेकिन function_response की जगह error वाला लिफाफा लौट आता है। कंसोल के संदेश स्पष्ट होते हैं—क्लाइंट ने एजेंट तक पहुंचने की कोशिश की, कई एंडपॉइंट वेरिएशन आज़माए, और फिर भी response type के रूप में error मिला।
A2A एजेंट से अप्रत्याशित response type: error. पूर्ण response सामग्री: ErrorContent(message='Failed to communicate with agent ... Tried multiple endpoint variations.')
समस्या को सामने लाने वाला कोड उदाहरण
नीचे दिया गया न्यूनतम एजेंट और क्लाइंट सेटअप दिखाते हैं। यह व्यवहार बुनियादी अंकगणित करता है और परिणाम function_response के जरिए लौटाता है। नीचे की लॉजिक एक काम करने वाले पैटर्न का अनुकरण करती है।
import math
from python_a2a import (
    A2AServer, Message, TextContent, FunctionCallContent,
    FunctionResponseContent, FunctionParameter, MessageRole, run_server,
    Task
)
class MathOpsNode(A2AServer):
    def handle_message(self, msg):
        if msg.content.type == "text":
            return Message(
                content=TextContent(
                    text="I'm a [Python A2A](python-a2a.html) calculator agent. You can call my functions:\n"
                         "- calculate: Basic arithmetic (operation, a, b)\n"
                         "- sqrt: Square root (value)"
                ),
                role=MessageRole.AGENT,
                parent_message_id=msg.message_id,
                conversation_id=msg.conversation_id
            )
        elif msg.content.type == "function_call":
            fname = msg.content.name
            args_map = {p.name: p.value for p in msg.content.parameters}
            try:
                if fname == "calculate":
                    op = args_map.get("operation", "add")
                    x = float(args_map.get("a", 0))
                    y = float(args_map.get("b", 0))
                    if op == "add":
                        out_val = x + y
                    elif op == "subtract":
                        out_val = x - y
                    elif op == "multiply":
                        out_val = x * y
                    elif op == "divide":
                        if y == 0:
                            raise ValueError("Cannot divide by zero")
                        out_val = x / y
                    else:
                        raise ValueError(f"Unknown operation: {op}")
                    return Message(
                        content=FunctionResponseContent(
                            name="calculate",
                            response={"result": out_val}
                        ),
                        role=MessageRole.AGENT,
                        parent_message_id=msg.message_id,
                        conversation_id=msg.conversation_id
                    )
                elif fname == "sqrt":
                    val = float(args_map.get("value", 0))
                    if val < 0:
                        raise ValueError("Cannot calculate square root of negative number")
                    out_val = math.sqrt(val)
                    return Message(
                        content=FunctionResponseContent(
                            name="sqrt",
                            response={"result": out_val}
                        ),
                        role=MessageRole.AGENT,
                        parent_message_id=msg.message_id,
                        conversation_id=msg.conversation_id
                    )
            except Exception as err:
                return Message(
                    content=FunctionResponseContent(
                        name=fname,
                        response={"error": str(err)}
                    ),
                    role=MessageRole.AGENT,
                    parent_message_id=msg.message_id,
                    conversation_id=msg.conversation_id
                )
if __name__ == "__main__":
    svc = MathOpsNode()
    run_server(svc, host="0.0.0.0", port=5001)
import python_a2a
from python_a2a import (
    A2AClient, Message, FunctionCallContent,
    FunctionParameter, MessageRole
)
class CalcA2AInvoker:
    """
    Encapsulates interaction with a Python A2A agent.
    """
    def __init__(self, base_url: str):
        """
        Args:
            base_url: The A2A agent base URL (e.g., "http://127.0.0.1:5001").
        """
        self.conn = A2AClient(base_url)
        print(f"CalcA2AInvoker initialized for URL: {base_url}")
    def request_compute(self, operation: str, a: int, b: int) -> int | None:
        print(f"Sending calculation request: {operation}(a={a}, b={b})")
        call_payload = FunctionCallContent(
            name="calculate",
            parameters=[
                FunctionParameter(name="operation", value=operation),
                FunctionParameter(name="a", value=a),
                FunctionParameter(name="b", value=b)
            ]
        )
        outbound_msg = Message(
            content=call_payload,
            role=MessageRole.USER
        )
        try:
            reply = self.conn.send_message(outbound_msg)
            if reply.content.type == "function_response":
                result = reply.content.response.get("result")
                if result is not None:
                    print(f"Received result from A2A agent: {result}")
                    return result
                else:
                    print("Function response received, but 'result' key is missing.")
                    return None
            else:
                print(f"Unexpected response type from A2A agent: {reply.content.type}")
                print(f"Full response content: {reply.content}")
                return None
        except Exception as ex:
            print(f"An error occurred while communicating with the A2A agent: {ex}")
            return None
if __name__ == "__main__":
    endpoint = "http://127.0.0.1:5001"
    client = CalcA2AInvoker(endpoint)
    res = client.request_compute(operation="add", a=5, b=3)
    if res is not None:
        print(f"Addition Result: {res}")
    print("-" * 30)
असल में गड़बड़ी कहां है
क्लाइंट बताता है कि उसने calculate अनुरोध भेजा और फिर error प्रकार का रिस्पॉन्स मिला। Error payload साफ कहता है कि एजेंट से संचार असफल रहा और /tasks/send या जोड़े गए /a2a/a2a जैसे ठोस पथ दिखाता है। पैकेज पृष्ठभूमि में कई एंडपॉइंट वेरिएशन आज़माता है; यदि कोई भी सफल नहीं होता, तो वह type error वाले ErrorContent के साथ लौटता है।
स्थानीय रूप से, ऊपर की तरह एजेंट और क्लाइंट चलाने पर अपेक्षित संख्यात्मक परिणाम के साथ एक वैध function_response मिलता है। इससे संकेत मिलता है कि कोड स्वयं ठीक है। यह विफलता मोड आम तौर पर base URL और पोर्ट के संयोजन तक कनेक्टिविटी समस्या या ऐसा base URL उपयोग करने से मेल खाता है जो चल रहे एजेंट प्रोसेस तक रिज़ॉल्व नहीं होता।
इसे आधार देने वाले परिवेश-सम्बंधी संकेत भी हैं। एक सेटअप में Linux Mint पर Python 3.13 और python-a2a 0.5.9 के साथ यही पैटर्न सफल रहा। दूसरे सेटअप में Ubuntu पर फ़ायरवॉल अक्षम होने के बावजूद विफलता दिखी—यह बताता है कि समस्या उदाहरण की लॉजिक में अंतर्निहित नहीं है और संभवतः पहुंच-योग्यता तथा सही लक्ष्य पते पर निर्भर करती है।
समाधान
एजेंट का base URL सीधे उपयोग करें और अतिरिक्त path सेगमेंट न जोड़ें। उदाहरण में एजेंट पोर्ट 5001 पर शुरू किया गया है, और एक सफल रन में क्लाइंट का base URL http://127.0.0.1:5001 था। यदि आप किसी अन्य होस्ट या non‑local पते की ओर इशारा कर रहे हैं, तो सुनिश्चित करें कि पता सही और पहुंच योग्य है, और पोर्ट 5001 पर दोनों दिशाओं में ट्रैफिक अनुमत है। यह ब्राउज़र में जांच लेना भी मददगार है कि एजेंट इच्छित पते पर चल रहा है। यदि आप अलग मशीनों पर काम कर रहे हैं, तो पक्का करें कि गंतव्य वही है जहां एजेंट सेवा वास्तव में चल रही है और आपकी रूटिंग वहीं ट्रैफिक भेज रही है।
नीचे दिया गया कोड वही कॉलिंग पैटर्न है, बस base URL एजेंट के listening address पर सेट है।
if __name__ == "__main__":
    endpoint = "http://127.0.0.1:5001"  # अतिरिक्त path जोड़े बिना base URL का उपयोग करें
    client = CalcA2AInvoker(endpoint)
    res = client.request_compute(operation="add", a=5, b=3)
    if res is not None:
        print(f"Addition Result: {res}")
    print("-" * 30)
यह क्यों मायने रखता है
जब क्लाइंट ऐसा ErrorContent लौटाता है जिसमें लिखा हो “Failed to communicate with agent … Tried multiple endpoint variations,” तो शंका आसानी से पैकेज या वर्ज़न की ओर चली जाती है। वास्तव में base URL, उपयोग में लिया गया सटीक पता, और पोर्ट की पहुंच-योग्यता की पुष्टि प्रायः समय बचा देती है—डिपेंडेंसी की जांच में भटकने की बजाय असली बाधा अक्सर ट्रांसपोर्ट पाथ ही होती है।
मुख्य बातें
सबसे सरल रास्ते से शुरुआत करें: दोनों हिस्सों को लोकल पर http://127.0.0.1:5001 के साथ चलाएं और देखें कि function_response मिलता है या नहीं। यदि non‑local पते का उपयोग आवश्यक है, तो सत्यापित करें कि एजेंट वास्तव में उसी पते पर चालू है, base URL एजेंट के एक्सपोज़ होने के तरीके से मेल खाता है, और पोर्ट 5001 अनुमत है। कम से कम एक ज्ञात-सफल संयोजन—Linux Mint, Python 3.13, python-a2a 0.5.9—मौजूद है, जो कोड बदलने से पहले कनेक्टिविटी की जांच के महत्व पर जोर देता है। यदि आपके परिवेश में फ़ायरवॉल अक्षम करने से भी मदद नहीं मिलती, तो URL और रूटिंग की जांच पर लौटें; एरर आउटपुट पहले से ही संकेत देता है कि क्लाइंट इच्छित एंडपॉइंट तक अनुरोध पूरा नहीं कर पा रहा।