Executive Summary
AI agents are useful on their own — but exponentially more powerful together. Just as microservices revolutionized software development, Agent-to-Agent (A2A) communication is revolutionizing AI applications. But how should agents talk to each other? Through what protocol? Who decides when two agents give contradictory suggestions?
This whitepaper examines three layers:
- The A2A protocol — the open standard published by Google in 2025, aiming to become the HTTP of inter-agent communication
- MCP (Model Context Protocol) — Anthropic's standard defining the connection between agents and external tools
- Practical multi-agent architecture — how a production system works where multiple agent roles collaborate
The whitepaper presents the principles through a real, multi-tenant SaaS system implementation — with code snippets, configuration examples, and architectural decisions.
1. The Problem: Why Do Agents Need to "Talk"?
1.1 Limitations of a Standalone Agent
A typical AI agent does one thing well: responds to customers, analyzes emails, or generates tasks. But in business reality, tasks are not isolated:
Incoming email: "Hi! I'd like to book my usual appointment for tomorrow."
Required actions:
1. Email interpretation (intent detection) → Language agent
2. Customer identification (CRM lookup) → CRM agent
3. Finding available time slot (calendar) → Calendar agent
4. Creating the booking → Booking agent
5. Sending confirmation email → Communication agent
6. Updating revenue prediction → Analytics agent
If a single "super-agent" does all of this, it:
- Requires an overly complex system prompt (10+ pages of instructions)
- Doesn't scale (one agent can't know everything)
- Isn't modular (you can't swap out the calendar agent when a better one arrives)
- Is hard to debug (which part failed out of the 6?)
1.2 The Microservice Analogy
A multi-agent system does for AI exactly what microservices did for backends:
1.3 But How Should They Communicate?
With 5 agents, they need to coordinate somehow. Two key questions:
- Protocol: What format should they use to send messages to each other?
- Orchestration: Who decides when which agent acts?
A2A and MCP answer this — but each answers something different.
2. The A2A Protocol — Google's Answer
2.1 What Is A2A?
The Agent-to-Agent (A2A) protocol is the open standard published by Google in April 2025. Its goal: to enable AI agents from different developers, running on different platforms to communicate in a standardized way.
A2A aims to be the "HTTP" of inter-agent communication — just as REST APIs standardized service-to-service communication, A2A standardizes agent-to-agent communication.
2.2 A2A Core Concepts
2.3 The Agent Card — the Agent's "OpenAPI Spec"
Every A2A-compatible agent publishes an Agent Card (JSON):
{
"name": "CRM Agent",
"description": "Manages customer relationships, contacts, deals, and tasks",
"url": "https://api.example.com/agents/crm",
"version": "1.0.0",
"capabilities": [
{
"name": "lookup_customer",
"description": "Find customer by name, email, or phone",
"inputSchema": {
"type": "object",
"properties": {
"query": { "type": "string" }
}
}
}
],
"authentication": {
"type": "bearer",
"tokenUrl": "https://auth.example.com/token"
},
"protocol": "a2a/1.0"
}
This enables an unknown agent to reach another: it reads the Agent Card, understands the capabilities, and sends a request in a standardized format.
2.4 The A2A Task Lifecycle
Client Agent Server Agent
│ │
│── POST /tasks/create ──────────────▶ │
│ { capability: "lookup_customer", │
│ input: { query: "Kiss Anna" } } │
│ │
│◀── 202 Accepted ─────────────────── │
│ { taskId: "task-42", │
│ status: "in_progress" } │
│ │
│── GET /tasks/task-42 ──────────────▶ │
│ │
│◀── 200 OK ───────────────────────── │
│ { status: "completed", │
│ artifacts: [ │
│ { type: "customer_data", │
│ content: { ... } } │
│ ] } │
│ │
Task states: pending → in_progress → completed / failed / cancelled
2.5 Streaming and Long-Running Tasks
A2A supports Server-Sent Events (SSE) based streaming for long-running tasks:
Client Agent Server Agent
│ │
│── POST /tasks/create ──────────────▶ │
│ { capability: "analyze_emails", │
│ streaming: true } │
│ │
│◀── SSE stream ───────────────────── │
│ event: status │
│ data: { status: "analyzing" } │
│ │
│ event: progress │
│ data: { percent: 45 } │
│ │
│ event: artifact │
│ data: { type: "summary", ... } │
│ │
│ event: complete │
│ data: { taskId: "task-42" } │
│ │
2.6 How Is It Different From REST API?
The key difference: with a REST API, the client precisely tells the server what to do. With A2A, the client agent expresses a goal, and the server agent decides how to accomplish it.
3. MCP — Between the Agent and the World
3.1 MCP vs. A2A: Not Competitors, But Complementary
Using both protocols together is where the real power lies:
┌─────────────────────────────────────────────┐
│ Orchestrator Agent │
│ │
│ ┌──────────┐ A2A ┌──────────────┐ │
│ │ CRM Agent│◄────────►│ Email Agent │ │
│ └────┬─────┘ └──────┬───────┘ │
│ │ MCP │ MCP │
│ ┌────▼─────┐ ┌──────▼───────┐ │
│ │ CRM DB │ │ Gmail API │ │
│ │ (tool) │ │ (tool) │ │
│ └──────────┘ └──────────────┘ │
└─────────────────────────────────────────────┘
MCP: agent ↔ external tool (Gmail, Calendar, CRM)
A2A: agent ↔ agent (CRM agent ↔ Email agent)
3.2 In Practice: MCP Tools as Agent Capabilities
In a real system, MCP tools often define the agent's capabilities. Connectors (Gmail, Calendar, billing systems) publish MCP tools that the agent can use:
// Gmail connector — MCP tool registration
getTools() {
return [
{
definition: {
type: 'function',
function: {
name: 'gmail_send',
description: 'Send email via Gmail',
parameters: {
properties: {
to: { type: 'string', description: 'Recipient email' },
subject: { type: 'string', description: 'Subject' },
body: { type: 'string', description: 'Message body' },
cc: { type: 'string', description: 'CC' }
},
required: ['to', 'subject', 'body']
}
}
},
execute: async (args) => this._mcpSendEmail(args)
}
];
}
These tools register dynamically — the agent discovers at runtime which MCP tools are available:
async function getProviderMCPTools(providerId) {
const configs = await prisma.connectorConfig.findMany({
where: { providerId, isEnabled: true }
});
for (const config of configs) {
const connector = new ConnectorClass(providerId);
const tools = connector.getTools();
}
}
This means: when a provider enables the Gmail connector, the AI agent automatically "learns" that it can now send emails. If disabled, the capability disappears. No redeployment, no code changes.
4. Multi-Agent Architecture: The Reality
4.1 Orchestration Patterns
Three main approaches exist for how multiple agents work together:
1. Hierarchical (Orchestrator Pattern)
┌──────────────┐
│ Orchestrator │ ← Main decision maker
│ Agent │
└──────┬───────┘
┌─────┼──────┐
▼ ▼ ▼
┌────┐┌────┐┌────┐
│CRM ││Mail││Cal │ ← Specialized agents
└────┘└────┘└────┘
- The orchestrator delegates to specialized agents
- Advantage: clear control, easy debugging
- Disadvantage: the orchestrator is an SPF (single point of failure)
2. Market (Marketplace/Auction Pattern)
┌────┐ ┌────┐ ┌────┐
│ A1 │ │ A2 │ │ A3 │
└─┬──┘ └─┬──┘ └─┬──┘
│ │ │
▼ ▼ ▼
┌──────────────────┐
│ Task Board │ ← Shared task board
└──────────────────┘
- Tasks appear on a shared "marketplace"
- Agents "bid" — the most suitable one takes it
- Advantage: decentralized, scalable
- Disadvantage: complex coordination, slower
3. Pipeline (Chain Pattern)
Input → [Agent 1] → [Agent 2] → [Agent 3] → Output
Analysis Decision Execution
- Fixed order, each agent performs its own task
- Advantage: simple, predictable
- Disadvantage: not flexible, hard to backtrack
4.2 Practical Implementation: The Evaluator-Executor Pattern
Real production systems often implement a pragmatic variant of the hierarchical model, where agents aren't physically separate but are logical agent roles within a single system:
┌──────────────────────────────────────────────────────┐
│ Agent Loop │
│ │
│ ┌─── Trigger Layer ───┐ │
│ │ Event: email arrived │ │
│ │ Scheduled: 15min tick│ │
│ └──────────┬──────────┘ │
│ ▼ │
│ ┌─── Evaluator Agent ──┐ (LLM: GPT-4o-mini, T=0.3)│
│ │ "What happened?" │ │
│ │ "What should be done?"│ │
│ │ "How confident am I?" │ │
│ └──────────┬──────────┘ │
│ ▼ │
│ ┌─── Autonomy Gate ────┐ │
│ │ notify_only → log │ │
│ │ suggest_and_wait → ⏳ │ │
│ │ act_and_report → ▼ │ │
│ └──────────┬──────────┘ │
│ ▼ │
│ ┌─── Executor Agent ───┐ │
│ │ create_task │ │
│ │ send_email (MCP) │ │
│ │ create_event (MCP) │ │
│ │ update_contact │ │
│ │ flag_attention │ │
│ └──────────────────────┘ │
└──────────────────────────────────────────────────────┘
This is the Evaluator-Executor pattern:
- The Evaluator is the "brain": LLM-based, with low temperature (0.3) for deterministic decisions
- The Executor is the "hand": deterministic code that carries out the Evaluator's decisions
- The Autonomy Gate is the "supervisor": decides whether a decision needs human approval
4.3 The Evaluator Agent in Detail
The Evaluator is the system's most critical component. It operates in two modes:
Event mode — when something happens (email, webhook, CRM event):
const EVAL_CONFIG = {
provider: 'openai',
model: 'gpt-4o-mini',
maxTokens: 1024,
temperature: 0.3
};
async function evaluateEvent(providerId, triggerData) {
const eventContext = await buildEventContext(
providerId,
triggerData.source,
triggerData.eventType,
triggerData.eventId,
triggerData.eventData
);
const ragContext = await retrieveRAGContext(providerId, eventContext);
const recentActions = await getRecentActions(providerId, 5);
const response = await adapter.chat([
{ role: 'system', content: evaluatorPrompt },
{ role: 'user', content: contextMarkdown }
], EVAL_CONFIG);
return parseEvalResponse(response.content);
}
Scheduled mode — proactive checks every 15 minutes:
async function evaluateScheduledTick(providerId) {
const suggestions = await generateSuggestions(providerId);
await expirePendingActions(providerId);
const events = await getUpcomingEvents(providerId);
const deals = await getDealsSummary(providerId);
return evaluate(contextMarkdown);
}
The response is structured JSON:
{
"actions": [
{
"type": "create_task",
"params": {
"title": "Follow-up: Anna Kiss 30+ day deal",
"description": "The Premium package deal has been in NEGOTIATION for 35 days.",
"priority": "HIGH",
"dueDate": "2026-03-31"
},
"confidence": 0.85
}
],
"reasoning": "The stale deal is high-value, and overdue tasks require immediate attention.",
"confidence": 0.88
}
4.4 The Executor Agent: MCP as "Hands"
The Executor doesn't think — it executes what the Evaluator decided. Every action handler is a clean, deterministic function:
async function execute(action, providerId) {
switch (action.type) {
case 'create_task':
return executeCreateTask(action.params, providerId);
case 'send_email':
return executeMCPTool('gmail_send', action.params, providerId);
case 'create_event':
return executeMCPTool('calendar_create_event', action.params, providerId);
case 'update_contact':
return executeUpdateContact(action.params, providerId);
case 'flag_attention':
return executeFlagAttention(action.params, providerId);
}
}
8 action types — each with precisely defined inputs and outputs:
4.5 The Third Agent: The Chat Agent
Alongside the Evaluator and Executor, there's a third "agent": the Chat Agent — the one the user interacts with directly:
async function sendMessage(providerId, userId, providerName, { conversationId, message }, settings) {
const systemPrompt = buildSystemPrompt(providerName, customPrompt, knowledgeContext, mcpPromptSection);
const ragResult = await retrieveRAGContext(providerId, message);
while (iterations < 3) {
response = await adapter.chat(llmMessages, { tools: allTools });
if (!response.toolCalls?.length) break;
for (const toolCall of response.toolCalls) {
const result = await executeTool(toolCall.function.name, args, providerId);
llmMessages.push({ role: 'tool', content: JSON.stringify(result) });
}
}
}
The Chat Agent uses a different model, different temperature, and different tool set than the Evaluator:
4.6 Inter-Agent Communication
The three agents don't directly "talk" to each other — they coordinate through a shared data layer:
┌──────────────────┐
│ Knowledge Graph │
│ + CRM DB │
│ + Action Log │
└────────┬─────────┘
│
┌──────────────┼──────────────┐
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ Chat │ │ Evaluator│ │ Executor │
│ Agent │ │ Agent │ │ Agent │
└──────────┘ └──────────┘ └──────────┘
▲ │ │
│ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ User │ │ BullMQ │ │ MCP │
│ (SSE) │ │ Queue │ │ Tools │
└──────────┘ └──────────┘ └──────────┘
Communication methods:
- Event-based (BullMQ queue): The ingestion pipeline sends triggers to the agent-tasks queue → the Evaluator processes them
- Shared state (PostgreSQL): All three agents read/write the same data layer
- Implicit (RAG): The Chat Agent "sees" the Evaluator/Executor's previous actions via semantic search
This shared state model is simpler than A2A-style direct communication, and more reliable in production — no network latency between agents, no message loss risk.
5. Tool Calling as Proto-A2A
5.1 The Tool Calling Concept
LLM tool calling (function calling) is the seed of multi-agent communication. When an LLM "calls a tool," it essentially delegates to another system:
User: "What appointments do I have tomorrow?"
LLM thinking: "I need calendar data → calling get_upcoming_events tool"
Tool call:
→ get_upcoming_events({ days: 1 })
← [{ summary: "Haircut - Anna Kiss", start: "2026-03-31 10:00" }, ...]
LLM response: "You have one appointment tomorrow: 10:00 haircut with Anna Kiss."
5.2 The Multi-Iteration Tool Calling Loop
Our production system resolves tool calling in a maximum of 3 iterations:
Iteration 1:
LLM: "Searching for Anna Kiss in CRM"
→ Tool: search_knowledge("Anna Kiss")
← Result: { contacts: [{ id: 15, name: "Anna Kiss", lifecycle: "LOYAL" }] }
Iteration 2:
LLM: "Let me look at her deals and appointments"
→ Tool: get_entity_connections({ nodeId: "client_15" })
← Result: { deals: [...], appointments: [...], invoices: [...] }
Iteration 3:
LLM: "I now have enough information to answer"
→ No tool call → natural language response
This is the ReAct (Reasoning + Acting) pattern: the LLM thinks, acts, observes the result, and thinks again.
5.3 The Dynamic Tool Registry
Tools are not static — they are detected at runtime based on active connectors:
async function getAllTools(providerId) {
const crmTools = [
{ name: 'search_knowledge', ... },
{ name: 'get_recent_emails', ... },
{ name: 'get_upcoming_events', ... },
{ name: 'get_entity_connections', ... },
{ name: 'list_deals', ... },
{ name: 'get_dashboard_stats', ... },
{ name: 'create_task', ... },
{ name: 'create_deal', ... }
];
const { definitions: mcpTools } = await getProviderMCPTools(providerId);
return [...crmTools, ...mcpTools];
}
This is a simplified, pragmatic version of the A2A Agent Card concept: not an external JSON manifest, but runtime discovery. The concept is the same — the agent's capabilities expand dynamically.
6. The Adapter Pattern — Provider-Agnostic Agents
6.1 Why Is It Critical?
If the agent is tied to a single LLM provider, vendor lock-in occurs. The adapter pattern allows the agent's logic to be independent of the underlying LLM:
┌──────────────┐
│ Agent Logic │ ← Doesn't know which LLM runs behind it
└──────┬───────┘
│ adapter.chat(messages, options)
▼
┌──────────────┐
│ Adapter Layer │ ← Strategy Pattern
└──┬────┬────┬─┘
│ │ │
▼ ▼ ▼
OpenAI Claude Gemini
6.2 The Adapter Implementation
Every adapter implements the same interface. The challenge: the three LLM providers use different formats:
The adapter layer transforms these into a single unified format:
class AnthropicAdapter extends BaseAdapter {
async chat(messages, options = {}) {
const systemMessages = messages.filter(m => m.role === 'system');
const conversationMessages = messages.filter(m => m.role !== 'system');
const anthropicTools = options.tools?.map(t => ({
name: t.function.name,
description: t.function.description,
input_schema: t.function.parameters
}));
const response = await this.client.messages.create({
model: this.model,
system: systemMessages.map(m => m.content).join('\n'),
messages: this._convertMessages(conversationMessages),
tools: anthropicTools,
max_tokens: options.maxTokens
});
return {
content: response.content.find(c => c.type === 'text')?.text,
toolCalls: response.content.filter(c => c.type === 'tool_use')
.map(c => ({ id: c.id, function: { name: c.name, arguments: c.input } })),
usage: { input: response.usage.input_tokens, output: response.usage.output_tokens }
};
}
}
6.3 Per-Tenant Model Selection
In the multi-tenant system, each provider can use a different LLM:
model AiSettings {
providerId Int @unique
provider String @default("openai")
model String @default("gpt-4o-mini")
temperature Decimal @default(0.7)
maxTokens Int @default(2048)
systemPrompt String?
}
One provider uses GPT-4o, another Claude, a third Gemini — same system, same agent logic. Only the adapter changes.
7. Security Architecture: Multi-Agent System Controls
7.1 Why Extra Security?
In a multi-agent system, the "AI can make mistakes" risk grows exponentially: if the Evaluator decides wrong, the Executor takes the wrong action, the MCP tool sends the wrong email. Preventing cascade failures is the system's most important property.
7.2 The Autonomy Gate — Three-Level Control
async function processAction(action, providerId, config) {
if (config.blockedActions.includes(action.type)) return;
if (config.allowedActions.length > 0 &&
!config.allowedActions.includes(action.type)) return;
const todayCount = await getTodayActionCount(providerId);
if (todayCount >= config.dailyActionLimit) return;
switch (config.autonomyLevel) {
case 'notify_only':
await logAction({ ...action, status: 'notified' });
break;
case 'suggest_and_wait':
await logAction({ ...action, status: 'pending', expiresAt: +24h });
await sendNotification(providerId, 'New AI suggestion');
break;
case 'act_and_report':
const result = await executor.execute(action, providerId);
await logAction({ ...action, status: 'executed', output: result });
break;
}
}
7.3 The Daily Limit Mechanism
Maximum 50 actions per day — this prevents a misconfigured agent from "going rogue" and sending thousands of emails or creating tasks.
7.4 The Audit Trail — Everything Gets Logged
Every agent action goes to the AiActionLog table:
This granularity enables:
- Post-mortem analysis: Why did the AI send the wrong email?
- Performance measurement: What percentage of actions were approved?
- Optimization: 80% of actions with confidence below 0.6 were rejected → raise the threshold
7.5 The Evaluator's Maximum 3 Actions
The Evaluator can suggest at most 3 actions per evaluation. This prevents an "overzealous" AI:
function parseEvalResponse(content) {
const parsed = JSON.parse(content);
const validActions = parsed.actions.filter(a =>
VALID_ACTION_TYPES.includes(a.type)
);
return validActions.slice(0, 3);
}
8. The Connector as an "External Agent"
8.1 The Connector as an A2A Analogy
Connectors (Gmail, Google Calendar, billing systems) essentially function as agents of external systems. They're not LLM-based, but their interaction pattern is A2A-like:
8.2 The Normalized Event as Agent Message
Every connector converts external system data into a unified format:
{
source: 'gmail',
eventType: 'email.received',
externalId: 'msg-abc123',
timestamp: new Date(),
entities: [
{ type: 'email', externalId: 'msg-abc123', label: 'Re: Appointment', content: '...' },
{ type: 'client', externalId: 'contact-456', label: 'Anna Kiss', properties: { email: 'anna@...' } }
],
edges: [
{ fromExternalId: 'msg-abc123', toExternalId: 'contact-456', type: 'SENT_BY' }
],
textContent: 'Email body for embedding',
rawData: originalGmailPayload
}
This normalization is a pragmatic implementation of the A2A Part and Artifact concepts — the agent receives data in its own format and forwards it in a standardized format to the system.
8.3 The BaseConnector as "Agent Interface"
class BaseConnector {
async handleWebhook(payload) // Webhook → NormalizedEvent[]
async poll(since) // Incremental sync → NormalizedEvent[]
async fullSync() // Full sync → NormalizedEvent[]
getTools() // → [{ definition, execute }]
async authorize(authData) // OAuth2 setup
async refreshToken() // Token refresh
}
This interface is the imperative equivalent of the A2A Agent Card: not a JSON manifest, but a code-level contract.
9. Future Vision: A2A in the Product
9.1 Today: Internal Multi-Agent System
The current architecture is a closed, internal multi-agent system: the Evaluator, Chat Agent, Executor, and Connectors communicate within the same infrastructure.
9.2 Tomorrow: A2A-Compatible Agents
The A2A protocol enables agents to communicate across system boundaries:
Current architecture:
[AIMY Evaluator] ──shared DB──▶ [AIMY Executor] ──MCP──▶ [Gmail]
Future A2A architecture:
[AIMY CRM Agent]
│ A2A
▼
[Partner Booking Agent] ← Another company's agent
│ A2A
▼
[Payment Agent] ← Third-party payment agent
│ A2A
▼
[Notification Agent] ← Communication agent
Specific scenarios:
1. Cross-business booking — A client's medical AI assistant asks the salon's AI: "Anna Kiss is available tomorrow at 2:00 PM." The salon AI returns the available slot, both systems' calendars update.
2. Supply chain coordination — The inventory agent signals a shortage, the procurement agent orders from the supplier via A2A, the financial agent approves.
3. Client transfer between systems — The cosmetician's AI sends a "client card" to the hairdresser's AI, which suggests an appointment.
9.3 The Technical Transition
The transition from an internal multi-agent system to an A2A-compatible one is gradual:
The biggest challenge isn't implementing the protocol — it's the trust framework: how do you decide that an unknown agent's request is legitimate?
10. Practical Decision Matrix for CTOs
10.1 When Do You Need Multi-Agent Architecture?
10.2 When Do You Need A2A Protocol?
10.3 The Technology Selection Decision Tree
Do you need multiple "intelligent" components in the system?
│
├─ No (1 agent, 1-5 tools) → Single agent, tool calling
│
└─ Yes → Different tasks, different configurations?
│
├─ Yes → Multi-agent, Evaluator-Executor pattern
│ │
│ └─ Are the agents within one infrastructure?
│ │
│ ├─ Yes → Shared state (DB + Queue)
│ │
│ └─ No → A2A protocol
│
└─ No → Single agent, modular tool set
11. Summary: Multi-Agent System Layers
┌──────────────────────────────────────────────────────────────┐
│ User (Chat / Push / Dashboard) │
├──────────────────────────────────────────────────────────────┤
│ Chat Agent (LLM, T=0.7, streaming, tool calling) │
├──────────────────────────────────────────────────────────────┤
│ Evaluator Agent (GPT-4o-mini, T=0.3, structured JSON) │
│ Trigger: event (webhook) + scheduled (15min tick) │
├──────────────────────────────────────────────────────────────┤
│ Autonomy Gate (notify / suggest_and_wait / act_and_report) │
│ Safety: daily limit (50), allowed/blocked actions, 24h expiry│
├──────────────────────────────────────────────────────────────┤
│ Executor Agent (deterministic, 8 action types) │
│ CRM actions + MCP tools (Gmail, Calendar) │
├──────────────────────────────────────────────────────────────┤
│ Adapter Layer (OpenAI / Anthropic / Gemini) │
│ Per-tenant model selection, unified interface │
├──────────────────────────────────────────────────────────────┤
│ Knowledge Layer │
│ Knowledge Graph (pgvector) + RAG Pipeline + Connectors │
├──────────────────────────────────────────────────────────────┤
│ Infrastructure │
│ PostgreSQL + Redis + BullMQ + Firebase │
└──────────────────────────────────────────────────────────────┘
Key Takeaways
-
Evaluator ≠ Executor: The decision-making agent and the executing agent must be separated. This enables approval workflows, audit trails, and different autonomy levels.
-
MCP and A2A are complementary: MCP operates between the agent and tools (Gmail, Calendar), A2A between agents. Both are needed — at different levels.
-
Shared state is simpler than direct communication: As long as agents are within one infrastructure, PostgreSQL + BullMQ is more reliable and simpler than direct agent-to-agent messaging.
-
The dynamic tool registry is the seed of A2A: If the agent discovers capabilities at runtime, that's the same concept that A2A Agent Card formalizes. The transition is gradual.
-
Security is not optional: Autonomy levels, daily limits, action filtering, 24-hour approval windows, full audit trail — without these, a multi-agent system is dangerous.
-
Different LLM configs for different agents: The Chat Agent is more creative (T=0.7), the Evaluator more deterministic (T=0.3). The provider-agnostic adapter pattern enables each agent to use its optimal model.
-
A2A is needed when agents leave the system: As long as it's internal agents, shared state is sufficient. When you need to communicate with other organizations' agents, A2A will be the common language.
Planning a Multi-Agent Architecture or AI Integration?
The Atlosz team helps design and implement inter-agent communication, the Evaluator-Executor pattern, MCP integrations, and security controls — tailored to your system.
Let's Discuss Your AI Strategy →