[A2A-001] · Template · Live
Multi-Agent Complaint Resolution
Area · A2A
Stack · A2A Protocol · Claude · Uvicorn · SQLite
Dataset · Synthetic, generated on setup
Live
Overview
Architecture
GitHub
The Problem
A single customer complaint often needs data owned by different teams. Resolving an unrecognized charge requires the transaction details from one system and the complaint patterns from another, and wiring those systems together means writing custom integration code every time one changes.
This project is a template for agent-to-agent (A2A) delegation. Instead of building point-to-point integrations between teams, each team publishes an agent. An orchestrator agent receives the complaint, discovers the available domain agents at runtime through their agent cards, and delegates questions to them in plain language — then consolidates the answers into a single resolution.
The example scenario: a customer reports a charge they do not recognize. The orchestrator asks the transactions agent what the charge was, asks the complaints agent whether others reported the same pattern, and combines both into one response — without ever touching either team's database directly.
What It Delivers
Runtime discovery
The orchestrator reads each agent card on every run and generates its delegation tools dynamically. Domains are never hardcoded, so a new agent is discovered without changing orchestrator code.
Plain-language delegation
The orchestrator sends natural-language questions, not tool specifications. Each domain agent decides on its own how to answer, running its own tool-calling loop.
Opaque boundaries
A domain agent owns its data, its tools and its prompt. Its internal queries never cross the protocol boundary, and the orchestrator has no visibility into how an answer was produced.
Horizontal scaling
Adding a domain is copying an agent folder, rewriting its tools, card and prompt, and registering its URL. The orchestrator picks it up automatically.
Key Terms
A2A
Agent-to-Agent. A protocol where agents expose capabilities to one another and exchange tasks, instead of teams building custom integrations between systems.
Agent card
A machine-readable description an agent publishes, declaring what it can do. The orchestrator reads it to discover capabilities at runtime.
Orchestrator
The agent that receives the request, delegates sub-questions to domain agents and consolidates the result. It holds no domain data or tools of its own.
JSON-RPC
The remote-call format tasks are sent over. Each delegation is a task dispatched to a domain agent's A2A server over HTTP.
Layered Architecture
Fig. 1 · Orchestrator delegates and consolidates, the A2A layer handles discovery and tasks over JSON-RPC, and domain agents own their data, tools and prompt.
Key Decisions
Orchestrator owns no data
The orchestrator has no database and no domain tools, only the ability to delegate. This forces every domain question through the protocol and keeps the orchestrator reusable across problems.
Discovery at runtime, not build time
Agent cards are read on every run and delegation tools are generated from them. Domains are not compiled into the orchestrator, so the system changes by adding agents, not by editing code.
Explicit knowledge boundaries
Each agent's prompt states what it cannot know. This stops an agent from guessing outside its domain and makes delegation the only path to information it does not own.
Delegation caps
A limit on agent-to-agent calls prevents infinite delegation loops between agents, which is the failure mode this kind of system is most prone to.
Protocol logic in one place
All A2A details — discovery and task sending — live in a2a_client.py. Domain agents and the orchestrator stay focused on their own job, not on the wire format.
Repository
a2a-001-multi-agent-complaint-resolution/
├── README.md
├── requirements.txt
├── .env.example
├── .gitignore
├── demo.py
├── config/
│ ├── __init__.py
│ └── a2a_config.py
├── orchestrator/
│ ├── __init__.py
│ ├── agent.py
│ ├── a2a_client.py
│ └── prompts/
│ └── system.md
├── agents/
│ ├── transactions/
│ │ ├── server.py
│ │ ├── agent_card.json
│ │ ├── agent.py
│ │ ├── tools.py
│ │ └── prompts/system.md
│ └── complaints/
│ └── … (identical structure)
└── data/
├── __init__.py
└── generate.py
Stack: A2A protocol over JSON-RPC, Anthropic Claude (a stronger model for the orchestrator, a smaller one for domain agents), Uvicorn, SQLAlchemy / SQLite. Python 3.13. Synthetic demo data is generated on setup via data/generate.py, with records constructed so both domains reference the same charge in the end-to-end demo.