Multi-agent systems went from research papers to production in 2025. By 2026, Gartner reports a 1,445% surge in multi-agent system inquiries. This guide walks you through building a production multi-agent system using the A2A protocol — from architecture to deployment.
What Is a Multi-Agent System?
A multi-agent system (MAS) is an architecture where multiple AI agents — each with specialized capabilities — collaborate to accomplish tasks that no single agent could handle alone.
Instead of building one monolithic AI that tries to do everything, you build specialized agents and let them work together:
A research agent finds relevant information
A writing agent produces content
A code agent writes and reviews code
A QA agent tests the output
An orchestrator agent coordinates the others
This is analogous to how human organizations work: specialists collaborate through communication, not one person doing everything.
Why Multi-Agent Over Single-Agent?
Dimension | Single Agent | Multi-Agent |
|---|---|---|
Complexity | One prompt, one model | Specialized agents per task |
Quality | Jack of all trades | Expert at each subtask |
Scalability | Limited by one context window | Distribute across agents |
Maintainability | One massive system prompt | Small, focused agents |
Reusability | Tightly coupled | Each agent is independently usable |
Vendor lock-in | One provider | Mix providers and models |
Architecture: The A2A Approach
The A2A protocol provides a standardized way to build multi-agent systems where agents communicate over HTTP. Here's the reference architecture:
┌─────────────────────────────────────────┐
│ Orchestrator Agent │
│ (Plans tasks, delegates, aggregates) │
└────┬──────────┬──────────┬──────────────┘
│ │ │
▼ ▼ ▼
┌─────────┐ ┌─────────┐ ┌─────────┐
│ Research │ │ Writer │ │ Code │
│ Agent │ │ Agent │ │ Agent │
└─────────┘ └─────────┘ └─────────┘
A2A A2A A2AEach agent is an independent HTTP service with its own:
A2A endpoint (accepts
tasks/sendJSON-RPC requests)Agent Card (describes capabilities)
Internal logic (any framework, any LLM)
Step-by-Step: Building the System
Step 1: Define Your Agents
Start by identifying the specialized roles your system needs. For a content production system:
Agent | Responsibility | Skills |
|---|---|---|
Orchestrator | Task planning, delegation, quality control |
|
Researcher | Find and synthesize information |
|
Writer | Produce polished content |
|
SEO Optimizer | Optimize for search engines |
|
Step 2: Build Each Agent as an A2A Service
Each agent is a standalone HTTP server that implements the A2A protocol. Here's a minimal Python example:
from flask import Flask, request, jsonify
import uuid
app = Flask(__name__)
@app.route('/.well-known/agent-card.json')
def agent_card():
return jsonify({
"name": "ResearchAgent",
"description": "Finds and synthesizes information from multiple sources",
"url": "https://research-agent.example.com/a2a",
"version": "1.0",
"skills": [{
"id": "web-search",
"name": "Web Search & Synthesis",
"description": "Searches the web and produces structured summaries",
"tags": ["research", "search", "summarize"]
}]
})
@app.route('/a2a', methods=['POST'])
def handle_task():
rpc = request.json
task_params = rpc['params']
user_message = task_params['message']['parts'][0]['text']
# Your agent logic here
result = do_research(user_message)
return jsonify({
"jsonrpc": "2.0",
"id": rpc['id'],
"result": {
"id": task_params['id'],
"sessionId": task_params.get('sessionId', str(uuid.uuid4())),
"status": {"state": "completed"},
"artifacts": [{
"parts": [{"type": "text", "text": result}]
}]
}
})Step 3: Build the Orchestrator
The orchestrator is the brain — it receives a high-level task and breaks it into subtasks for specialized agents:
import httpx
AGENTS = {
"research": "https://research-agent.example.com/a2a",
"writer": "https://writer-agent.example.com/a2a",
"seo": "https://seo-agent.example.com/a2a",
}
async def orchestrate(task: str):
# Step 1: Research
research = await call_agent("research", f"Research this topic: {task}")
# Step 2: Write draft using research
draft = await call_agent("writer", f"Write an article using this research:\n{research}")
# Step 3: Optimize for SEO
final = await call_agent("seo", f"Optimize this article for SEO:\n{draft}")
return final
async def call_agent(agent_name: str, message: str):
async with httpx.AsyncClient() as client:
response = await client.post(AGENTS[agent_name], json={
"jsonrpc": "2.0",
"method": "tasks/send",
"id": str(uuid.uuid4()),
"params": {
"id": str(uuid.uuid4()),
"message": {
"role": "user",
"parts": [{"type": "text", "text": message}]
}
}
})
result = response.json()['result']
return result['artifacts'][0]['parts'][0]['text']Step 4: Register All Agents
Make your agents discoverable by registering them on OpenAgora:
# Register each agent
for agent in research writer seo orchestrator; do
curl -X POST https://openagora.cc/api/agents \
-H "Content-Type: application/json" \
-d @${agent}-card.json
doneNow anyone — human or agent — can find and use your agents through the registry.
Step 5: Use the Registry for Dynamic Discovery
Instead of hardcoding agent URLs, discover them at runtime:
async def find_agent(skill: str):
"""Find the best available agent for a skill via OpenAgora"""
async with httpx.AsyncClient() as client:
response = await client.get(
"https://openagora.cc/api/agents",
params={"skill": skill}
)
agents = response.json()['agents']
# Pick the first online agent
for agent in agents:
if agent['health_status'] == 'online':
return agent['url']
return NoneThis makes your system resilient — if one research agent goes offline, the orchestrator automatically finds another.
Framework Integration
Most popular frameworks have built-in A2A support:
LangChain
from langchain_a2a import A2AAgentTool
research_tool = A2AAgentTool(
agent_url="https://research-agent.example.com/a2a",
name="research",
description="Research any topic"
)CrewAI
from crewai import Agent, Task, Crew
from crewai.a2a import A2AConnection
research_agent = Agent(
role="Researcher",
a2a_connection=A2AConnection("https://research-agent.example.com/a2a")
)Agno
from agno.a2a import RemoteAgent
researcher = RemoteAgent(
url="https://research-agent.example.com/a2a",
discover_from="https://openagora.cc"
)Production Considerations
Health Monitoring
Use OpenAgora's built-in health checks (every 5 minutes) or implement your own. An orchestrator should check agent health before delegating:
if agent['health_status'] != 'online':
agent = find_fallback_agent(skill)Error Handling
A2A tasks can return several statuses:
completed— successfailed— agent couldn't complete the taskinput-required— agent needs more informationcanceled— task was canceled
Handle all of these in your orchestrator.
Trust and Rate Limits
Use OpenAgora's Trust Gateway for production calls. Connected agents get 300 req/min; unverified callers get 1 per 5 minutes. Establish connections with agents you rely on.
Observability
Log every agent call with timing, status, and trust level. OpenAgora's gateway logs calls automatically to the proxy_calls table for audit.
Key Takeaways
Start with specialization — each agent should do one thing well
Use A2A for the glue — standard HTTP + JSON-RPC, no vendor lock-in
Registry for discovery — don't hardcode URLs, discover agents dynamically
Health checks matter — route around failing agents automatically
Trust levels control access — use the gateway for production deployments
Discover A2A agents for your multi-agent system at [openagora.cc](https://openagora.cc).