Agent2Agent (A2A) Protocol | Building Multi-Agent Networks
The Agent2Agent (A2A) Protocol—originally developed by Google and donated to the Linux Foundation—is an open, standardized communication protocol designed to enable seamless interaction and interoperability between autonomous AI agents. Rather than serving as an agent development framework or SDK, A2A acts as a universal communication layer that abstracts away internal framework implementations, enabling agents hosted on disparate servers and built with different frameworks to discover, request, and execute tasks securely over standard network protocols.
1. Why Do We Need the Agent2Agent (A2A) Protocol?
In modern AI engineering, autonomous agents are frequently built using diverse stacks, such as Google GenAI SDK, LangChain, AutoGen, or custom in-house frameworks. Without a unified communication protocol, connecting these heterogeneous agents requires custom glue code, ad-hoc API wrappers, and tight coupling between client and server agent architectures.
The A2A Paradigm Shift
A2A eliminates integration friction by standardizing the request/response payloads, discovery metadata, and transport layers.
- Framework Agnostic: Client Agent A does not need to know whether Server Agent B uses LangChain, LlamaIndex, or raw API calls.
- Protocol Over Framework: A2A is not an agent-building SDK like LangChain; it is a communication protocol (similar to HTTP or SMTP) for AI agents.
- Decoupled Execution: Agents interact solely through standardized A2A messages, endpoints, and card metadata.
2. Core Mental Model & Real-World Analogy
Real-Life Analogy: The Specialized Data Analyst (Alice & Bob)
Imagine Alice (a product manager) needs complex data processing performed by Bob (a specialized data analyst).
Alice does not need to know Bob's internal thought process, what software tools Bob uses, or how Bob's desk is organized. Alice simply sends a standardized request to Bob's mailbox ("Calculate the derivative of "). Bob receives the request, acknowledges receipt, computes the answer using his internal toolset, and sends back a standardized response envelope containing the final result.
Alice (Client Agent)
|
| 1. Sends standardized A2A request payload
v
A2A Transport Layer (HTTPS / JSON / RPC v1.2)
|
| 2. Routes payload to Agent Endpoint (Port 9999)
v
Bob (Server Agent Analyst)
|
| 3. Processes prompt internally via Gemini LLM Engine
v
A2A Event Queue / Response Handler
|
| 4. Returns 200 OK + Formatted Response Envelope
v
Alice receives completed execution result
3. Key Capabilities & Architectural Benefits
The A2A protocol provides five core capabilities for enterprise multi-agent deployment:
- Secure Collaboration: Built natively on top of HTTPS and standard authentication protocols, ensuring tamper-proof, encrypted payload transmission between isolated server nodes.
- True Interoperability: Breaks down barriers between vendor ecosystems. A Google AI-based agent can effortlessly invoke tools provided by a LangChain agent hosted on a remote server.
- Agent Autonomy: Each agent operates as a self-contained entity. An agent does not alter its internal business logic or state machine to accommodate different clients; it strictly satisfies the A2A interface contract.
- Reduced Integration Complexity: Standardized request routing reduces communication overhead from custom integration points to uniform A2A endpoint bindings.
- Long-Running Operations (LRO) & Event Streaming: Supports asynchronous task handling for high-latency LLM operations. When an agent initiates an LRO, A2A returns a task identifier (
task_id), allowing the client to poll task status or subscribe to event response streams.
4. Metadata Constructs: Agent Skills and Agent Cards
For an agent to participate in an A2A network or marketplace, it must advertise its capabilities using two primary constructs: Agent Skills and Agent Cards.
Agent Skill
An AgentSkill defines a specific granular operational capability provided by the agent. It includes:
id: Unique skill identifier (e.g.,chat_agent_skill).name: Human-readable skill name.description: Summary of what the skill performs (used by routing agents for task assignment).tags: Categorization tags (e.g.,["chat", "agent", "math"]).examples: Sample input prompts demonstrating supported query patterns.
Agent Card
An AgentCard acts as the full public manifest for the agent server. It encapsulates:
- General identity details (Agent Name, Description, Version).
- Supported transport interfaces (
HTTPS,JSON,RPC v1.2). - Target URL endpoint (e.g.,
http://localhost:9999). - Supported modal I/O types (e.g.,
input_mode="text",output_mode="text"). - Feature capability flags (e.g.,
is_streaming=False). - List of attached
AgentSkillobjects.
5. Step-by-Step Code Walkthrough
The following implementation demonstrates a complete, working A2A multi-agent setup consisting of three modular Python files: agent.py, server.py, and client.py.
Module 1: The Core Agent Logic (agent.py)
This module defines the underlying ChatAgent responsible for interacting directly with the Google GenAI SDK and executing prompts using gemini-2.5-flash or gemini-3.1-pro-preview.
# agent.py
import os
from google import genai
from google.genai import types
class ChatAgent:
"""
Core LLM wrapper class encapsulating direct interaction with
Google Gemini models via the GenAI SDK.
"""
def __init__(self, model_name: str = "gemini-2.5-flash"):
# Retrieve API key from environment variables
api_key = os.environ.get("GEMINI_API_KEY")
if not api_key:
raise ValueError("GEMINI_API_KEY environment variable is missing.")
self.client = genai.Client(api_key=api_key)
self.model_name = model_name
def query(self, prompt: str) -> str:
"""
Executes a prompt against the configured Gemini model with custom system instructions.
"""
config = types.GenerateContentConfig(
temperature=1.0,
system_instruction="You are a helpful assistant designed to answer user questions accurately."
)
response = self.client.models.generate_content(
model=self.model_name,
contents=prompt,
config=config
)
return response.text
Module 2: The A2A Server Encapsulation (server.py)
To expose ChatAgent over the A2A protocol, we encapsulate it inside an AgentExecutor and host it using an A2A-compliant server runner on port 9999.
# server.py
import uvicorn
from a2a import AgentExecutor, AgentCard, AgentSkill, TaskStore, create_a2a_app
from agent import ChatAgent
class ChatAgentExecutor(AgentExecutor):
"""
Custom A2A Executor wrapping ChatAgent to handle inbound A2A context requests,
extract user prompts, execute LLM inference, and return event responses.
"""
def __init__(self, chat_agent: ChatAgent):
super().__init__()
self.chat_agent = chat_agent
async def execute(self, context, event_q):
"""
Extracts prompt from incoming context, queries ChatAgent,
and pushes response payload to A2A event queue.
"""
user_prompt = context.get_user_input()
# Execute underlying LLM agent query
agent_response = self.chat_agent.query(user_prompt)
# Wrap response into an A2A message structure and send to event queue
await event_q.put({"type": "message", "content": agent_response})
async def cancel(self, context):
"""
Dummy cancel method required by base AgentExecutor class.
In-flight cancellation is disabled for synchronous single-turn executions.
"""
pass
def run_server():
# 1. Instantiate Core Agent
base_agent = ChatAgent(model_name="gemini-2.5-flash")
executor = ChatAgentExecutor(chat_agent=base_agent)
# 2. Define Agent Skill Metadata
chat_skill = AgentSkill(
id="chat_agent_skill",
name="Simple Chat Skill",
description="Answers general user inquiries, mathematics queries, and AI engineering questions.",
tags=["chat", "agent", "ai_engineering"],
examples=[
"Calculate the derivative of 2x^2",
"What are some popular AI engineering design patterns?"
]
)
# 3. Define Agent Card Manifest
agent_card = AgentCard(
name="Chat Agent Server Node",
description="Exposes Gemini-powered conversational capabilities via A2A Protocol.",
supported_interfaces=["HTTPS", "JSON"],
rpc_version="1.2",
url="http://localhost:9999",
agent_version="1.0.0",
input_mode="text",
output_mode="text",
is_streaming=False,
skills=[chat_skill]
)
# 4. Initialize A2A Task Storage & Application Routes
task_store = TaskStore()
app = create_a2a_app(
agent_card=agent_card,
executor=executor,
task_store=task_store
)
print("Starting A2A Agent Server on http://localhost:9999...")
uvicorn.run(app, host="127.0.0.1", port=9999)
if __name__ == "__main__":
run_server()
Module 3: The A2A Client Node (client.py)
The client connects to the target server's base URL (http://localhost:9999), sends requests formatted per the A2A protocol, and parses the returned execution results.
# client.py
from a2a import A2AClient
def main():
# Define target host server endpoint
target_host = "127.0.0.1"
target_port = 9999
base_url = f"http://{target_host}:{target_port}"
print(f"Connecting to remote A2A Agent at: {base_url}")
# Initialize A2A Client binding to remote URL
client = A2AClient(base_url=base_url)
# Define User Query Payload
prompt = "What are some popular AI engineering design patterns?"
print(f"\n[Client Send] -> '{prompt}'")
# Send Request via A2A Protocol over HTTP/RPC
response = client.run(prompt=prompt)
# Process and Display HTTP 200 OK Response
if response and response.status_code == 200:
print("\n[Server Response Received - 200 OK]:")
print("--------------------------------------------------")
print(response.content)
print("--------------------------------------------------")
else:
print(f"\n[Error] Task failed with status code: {response.status_code}")
if __name__ == "__main__":
main()
6. Full End-to-End Execution Flow
Below is the vertical runtime flow when a client issues a request across an A2A-enabled network:
Client Terminal (python client.py)
|
| 1. Constructs prompt: "What are some popular AI engineering design patterns?"
| 2. Issues A2A Client HTTP POST request to base URL: http://127.0.0.1:9999
v
Network Transport Layer (HTTP / RPC v1.2)
|
| 3. Delivers JSON payload across localhost socket binding
v
A2A Server Application (uvicorn on port 9999)
|
| 4. Endpoint receives request and parses payload into execution Context
v
ChatAgentExecutor.execute(context, event_q)
|
| 5. Extracts user string: context.get_user_input()
v
ChatAgent.query(prompt)
|
| 6. Dispatches API call to Google Gemini endpoint
v
Google Gemini Model Engine (gemini-2.5-flash)
|
| 7. Returns response text containing architectural patterns
v
ChatAgentExecutor
|
| 8. Enqueues message payload into event_q
v
A2A Server Response Handler
|
| 9. Formats response into standard A2A JSON response envelope
| 10. Emits HTTP status 200 OK back to Client
v
Client Terminal
|
| 11. Prints formatted AI engineering design patterns response
7. Comparative Technical Synthesis
To understand where A2A fits within modern AI infrastructure, compare standard direct integration methods with the A2A protocol:
8. Real-World Production Pitfalls & Debugging Workflows
When deploying A2A agent networks in production environments, engineers frequently encounter specific operational pitfalls:
1. Port Binding and Route Collision Failures
- Symptom:
OSError: [Errno 98] Address already in usewhen initializingserver.py. - Root Cause: An existing background uvicorn worker or previous server process is still bound to port
9999. - Debugging Workflow:
BASH
# Find process occupying port 9999 lsof -i :9999 # Terminate target process ID kill -9 <PID>
2. Missing API Keys in Asynchronous Contexts
- Symptom:
ValueError: GEMINI_API_KEY environment variable is missingon server receipt of a request. - Root Cause: Environment variables loaded in the client process are not automatically present on isolated remote server processes.
- Solution: Ensure system environment variables or
.envloaders (e.g.,python-dotenv) are explicitly executed atserver.pystartup before instantiatingChatAgent.
3. Long-Running Operation (LRO) Timeouts
- Symptom: Client receives network gateway timeouts ( Gateway Timeout) when prompts require complex chain-of-thought or multi-step tool calls exceeding 30 seconds.
- Solution: Configure
is_streaming=TrueonAgentCardor utilize the asynchronous LRO task model. Instead of waiting synchronously forclient.run(), submit tasks asynchronously, capture the returnedtask_id, and continuously poll the A2A task status route.
9. Summary and Key Takeaways
- Protocol, Not SDK: A2A is an open standard created by Google and maintained by the Linux Foundation for inter-agent communication, not a framework for building internal agent logic.
- Framework Independence: Enables multi-agent networks where agents written in LangChain, Google AI SDK, AutoGen, or raw Python can seamlessly interact over HTTPS/RPC.
- Metadata-Driven Discovery: Uses Agent Skills (granularity definitions) and Agent Cards (server manifests) to advertise agent capabilities across multi-agent registries.
- Unified Payload Contracts: Client agents send queries without needing internal implementation knowledge of the receiving agent node; communications follow standard request/response envelopes.
- Native Support for Complex Execution Modes: Designed to natively handle Long-Running Operations (LROs) via task polling, streaming responses, and structured event queues.
- Production Readiness: Employs HTTPS encryption, standard HTTP status responses (
200 OK), and clean separation of concerns between agent execution (AgentExecutor) and web hosting infrastructure.