Google Just Made AI on Encrypted Data Practical
HEIR converts pre-trained models to run on encrypted inputs. No decryption. No server access to your data. And it actually works now.
Multi-agent systems sound elegant until you measure the latency, token waste, and coordination complexity. When does the cost actually justify the split?
LindleyLabs Editorial
2026-08-10
Everyone's building multi-agent systems now. The pitch is seductive: decompose your problem into specialized agents, let them work in parallel, coordinate the results. Clean separation of concerns, scalability, maintainability. Except most implementations burn money for no gain, and the problems they introduce are often worse than what they solve.
The real question isn't whether multi-agent can work. It's whether it should. And the answer for most use cases is: not yet.
Multi-agent architecture sounds right in theory. Take a complex task—say, financial analysis—and split it: one agent researches market data, another analyzes fundamentals, a third evaluates risk, and a coordinator synthesizes findings. Parallel execution. Modular design. Each agent is smaller and theoretically easier to reason about.
This framing has massive appeal to teams coming from traditional software engineering, where service-oriented architecture and microservices proved their worth. The analogy feels natural: if breaking monoliths into services works, why not break monolithic reasoning into distributed agents?
The problem: LLMs are not services. They don't return deterministic results. They have latency tails that are vicious. They cost money per token. And coordination overhead—especially in systems where agents need to make decisions based on other agents' outputs—can dwarf the benefits of parallelism.
Let's be concrete. A single well-engineered agent with a good prompt might solve a problem in one forward pass: 2-5 seconds of wall time, ~5,000 tokens, ~$0.08. A poorly designed multi-agent system solving the same problem might spawn five agents in parallel (10 seconds of coordination overhead, dead time waiting for slow agents), consume 25,000 tokens total (agents repeating context, explaining results to coordinators), and cost $0.40. Four agents for the same output quality, plus cascading failures if one agent hallucinates.
Teams discover this during production scaling and switch back to single-agent designs. This isn't a failure of ambition; it's a reality check about cost and latency in large-scale LLM systems.
There's another reason multi-agent feels inevitable: it matches how human teams actually work. A human legal team has junior associates, senior associates, partners, and management. They specialize. They parallelize naturally. We extrapolate: LLM teams should work the same way.
But humans have cheap context switching, rich communication, and built-in error detection. They catch mistakes. An LLM agent that's wrong doesn't self-correct; it propagates the error downstream to the coordinator, which now has to detect the mistake, route it back, and retry—burning more tokens and time.
Before we dig into costs, let's be precise about what we're building.
A multi-agent system needs:
Most teams implement one of three patterns:
Sequential orchestration is the simplest: Agent A runs, passes output to Agent B, which passes to Agent C. Think pipeline. It's easy to reason about, but you lose all parallelism benefits—it's strictly worse than a single agent with the same logic.
# Sequential multi-agent: Agent -> Agent -> Agent
# This is just a single agent with extra steps
async def sequential_analysis(query):
research = await research_agent(query) # Token cost: 3000, Time: 3s
analysis = await analysis_agent(research) # Token cost: 5000, Time: 3s
decision = await decision_agent(analysis) # Token cost: 4000, Time: 3s
# Total: 12000 tokens, 9 seconds, 3 API calls
# Single agent: ~8000 tokens, 4 seconds, 1 API call
return decision
Parallel orchestration spawns multiple agents at once, waits for all, then coordinates:
# Parallel multi-agent: Run independent agents, coordinate results
async def parallel_analysis(query):
# All agents work simultaneously
market_data = await market_agent(query) # 3000 tokens, 2s
fundamentals = await fundamentals_agent(query) # 4000 tokens, 3s
risk_profile = await risk_agent(query) # 3000 tokens, 2s
# Wait for slowest agent (3s), then coordinate
coordinator_input = f"""
Market Data: {market_data}
Fundamentals: {fundamentals}
Risk Profile: {risk_profile}
Synthesize into final recommendation.
"""
final = await coordinator_agent(coordinator_input) # 8000 tokens, 3s
# Total: 18000 tokens, ~3s wall time (wait for slowest + coordinator)
# But: token cost is 2.25x a single agent, latency is similar
return final
Hierarchical orchestration creates a tree: manager agents delegate to worker agents, who report back up:
# Hierarchical: Manager spawns workers, coordinates hierarchically
async def hierarchical_analysis(query):
# Manager agent decides decomposition
plan = await manager_agent(f"Plan analysis: {query}")
# Worker agents execute plan in parallel
results = await asyncio.gather(
worker_agent("research", plan),
worker_agent("analysis", plan),
worker_agent("risk", plan)
)
# Manager synthesizes results
final = await manager_agent(f"Synthesize: {results}")
# The extra management layer burns tokens and adds decision-making latency
return final
Each pattern has trade-offs:
Every agent reads the same query (context repeated). Every agent produces output. Every coordinator reads all outputs (more context). Then the coordinator produces more output.
A query about financial analysis to a single agent:
User: Analyze Apple's Q3 earnings and recommend hold/sell/buy.
Agent response: ~2000 tokens (analysis + recommendation)
Total tokens: ~3000 (prompt + response)
The same task split across 4 agents:
Query: ~300 tokens (context cost)
Agent 1 (market research): reads query (300), produces output (1500 tokens)
Agent 2 (fundamentals): reads query (300), produces output (1800 tokens)
Agent 3 (risk): reads query (300), produces output (1200 tokens)
Agent 4 (sentiment): reads query (300), produces output (1000 tokens)
Coordinator: reads query (300) + all 4 outputs (5500) = 5800 tokens input
Coordinator output: ~1500 tokens
Total: (300×5) + (1500+1800+1200+1000) + 5800 + 1500 = 17,100 tokens
For roughly equivalent output, you've spent 5.7x more tokens. At $0.003 per 1K input tokens, that's a significant difference at scale.
Single agent with good prompt: fails gracefully, you retry once or use a different prompt.
Multi-agent system: If Agent B depends on output from Agent A, and Agent A hallucinates, Agent B now builds reasoning on false premises. The coordinator detects inconsistency, but by then you've burned tokens on both agents and coordination overhead. You retry Agent A, retransmit to Agent B, retry coordination. Three retries across agents versus one retry for a single agent.
Complex dependencies create exponential failure surface area. A 5-agent system where Agent C depends on Agents A and B, which both depend on Agent D, creates dependency chains where a single failure requires backtracking and retrying multiple agents.
Let's model an actual example: a chatbot that needs to handle customer support queries with access to order history, product catalog, and billing records.
# Single agent with context window
system_prompt = """
You are a customer support specialist. You have access to:
- Customer order history
- Product catalog
- Billing information
Answer customer questions directly, pulling from all sources as needed.
"""
customer_query = "I bought the Pro plan last month but was charged twice. Can you help?"
# Single forward pass
response = client.messages.create(
model="claude-opus-4-6",
max_tokens=1024,
system=system_prompt,
messages=[{"role": "user", "content": customer_query}]
)
# Costs: ~4000 input tokens (system + context + query), ~300 tokens output
# Time: ~2.5s
# Cost: $0.012
async def multi_agent_support(customer_id, query):
# Order history agent
order_task = fetch_orders_agent(customer_id)
# Billing investigation agent
billing_task = investigate_billing_agent(customer_id)
# Product lookup agent
product_task = product_agent(query)
# All run in parallel
orders, billing_issues, products = await asyncio.gather(
order_task, billing_task, product_task
)
# Coordinator synthesizes
coordinator_input = f"""
Customer Query: {query}
Orders: {orders}
Billing Issues: {billing_issues}
Relevant Products: {products}
Provide a solution.
"""
solution = await coordinator_agent(coordinator_input)
return solution
# Costs breakdown:
# Order agent: 2000 input (context + customer history), 400 output
# Billing agent: 2000 input, 600 output
# Product agent: 2500 input, 300 output
# Coordinator: 5000 input (all outputs concatenated), 400 output
# Total: 17,800 input tokens, 1,700 output = ~19,500 tokens
# Time: ~3s wall time (wait for slowest agent + coordinator)
# Cost: $0.058 (4.8x single agent cost)
The multi-agent approach is slower and more expensive for the same output quality.
Now imagine the same system, but optimized:
# Only fetch relevant context
system_prompt_order_agent = """
Extract only the order that matches this query. Be concise.
"""
system_prompt_billing_agent = """
Check for billing issues related to duplicate charges. Return only anomalies.
"""
system_prompt_coordinator = """
Given order and billing data, provide a clear resolution.
Don't repeat the input data. Assume you've already seen it.
"""
async def optimized_multi_agent(customer_id, query):
orders = await order_agent(customer_id, query) # ~1500 tokens
billing = await billing_agent(customer_id) # ~1200 tokens
# Coordinator references, doesn't repeat
result = await coordinator(f"""
Order data: {orders}
Billing issue: {billing}
Query: {query}
Resolve.""") # ~2500 tokens input
return result
# Costs: ~1500 + ~1200 + ~2500 + ~400 output = ~5,600 tokens
# Time: ~2.5s wall time
# Cost: ~$0.017
Still slightly more expensive and slower than a single agent, but the gap narrowed. The multi-agent approach added negligible value here because the problem doesn't decompose cleanly—the coordinator still needs to synthesize everything anyway.
Multi-agent systems win in specific, constrained scenarios:
If you have genuinely independent subtasks that don't need to inform each other until the very end, parallelism wins:
The key: these are not LLM tasks primarily. You're using agents as orchestrators over independent I/O-bound work. The LLM reasoning is minimal per agent, and the parallelism directly reduces wall-clock time.
# This actually benefits from parallelism
async def price_comparison(products):
# I/O bound, not token bound
prices = await asyncio.gather(
fetch_amazon_price(products),
fetch_ebay_price(products),
fetch_walmart_price(products),
fetch_target_price(products)
)
# Single agent synthesizes
best_deal = await synthesize_agent(prices)
return best_deal
If you have genuinely specialized expert agents with non-overlapping domains, and each agent is invoked only once in a chain:
This works if each expert agent:
The problem: most real-world decisions need back-and-forth between experts. The legal agent finds a clause that affects financials. The financial agent needs to revisit feasibility. You're back to coordination overhead.
If you're modeling an actual human team structure and agents represent real role handoffs (quality assurance, review, approval workflows), multi-agent can mirror your actual business process:
This only works if:
Before you build multi-agent, ask:
1. Can a single agent with a good prompt solve this?
Start here. The answer is yes for ~80% of use cases. Test it. Measure latency and cost. Only move to multi-agent if single-agent genuinely fails.
2. If not, what are the agent boundaries?
Draw them on paper. Can Agent A work without Agent B's output? If no, you don't have parallelism—you have a pipeline. Use sequential execution; don't pretend to parallelize.
If yes, are the agents truly independent, or do they need to coordinate later? If later, you're adding coordination overhead.
3. What's the parallelism win worth?
Measure: wall-clock time saved × value per second saved. If a task currently takes 10 seconds and parallelism cuts it to 6 seconds, that's only worth pursuing if you have high throughput or real-time constraints. For batch processing, it's irrelevant.
4. What's the token cost multiplier?
Estimate total tokens for a single-agent approach. Estimate for multi-agent (remember: prompt repetition, coordinator overhead, possible retries). Is the cost multiplier acceptable? If it's >2x, think hard about whether you need it.
5. How will you handle failure?
A single agent failing: retry with different temperature or model. Multiple agents failing: detect inconsistency, retry some or all agents, coordinate again. Write out your error paths. If they're complex, multi-agent wasn't worth it.
6. Can you actually measure the improvement?
Set up logging for latency, token usage, error rates, quality metrics. Compare single-agent baseline to multi-agent. If multi-agent doesn't improve the metric you care about (quality, latency, cost, throughput), don't use it.
Multi-agent architecture is intellectually satisfying. It feels like you're building something sophisticated. Your team wants it because it feels like engineering best practices.
But engineering best practices come from problems you've actually faced, not patterns you've imported from other domains. Microservices were invented because monoliths had scaling and autonomy problems. But LLM agents don't have those problems—they have token cost and latency problems that multi-agent often makes worse.
The ship a single-agent system that works. Measure it. Find the real bottleneck. Then split agents if needed.
Most teams skip straight to multi-agent because it feels modern. They're burning money for architecture, not for results.
Multi-agent systems introduce coordination overhead and token amplification that usually outweigh parallelism benefits. A single well-engineered agent is faster and cheaper for 80% of problems.
Parallelism only wins when tasks are truly independent, non-overlapping in expertise, or primarily I/O-bound. If agents need to share context or iterate, you've lost the parallelism win.
Token cost is the real constraint. Every agent reads duplicated context. Every coordinator reads all outputs. A 5-agent system can easily cost 5-10x more tokens than a single agent solving the same problem.
Failure modes cascade. One agent hallucinating means dependent agents build on false premises. Multi-agent failure recovery is more complex and more expensive than single-agent retries.
Use the decision framework: Can one agent do it? Do you have true parallelism? Is the cost multiplier acceptable? Can you measure the win? If you can't answer yes to all four, stick with single-agent.
Multi-agent makes sense for independent I/O-bound tasks, genuinely specialized expert teams with clear handoffs, or modeling actual human team workflows. Outside those narrow cases, it's premature abstraction.
The next time you're tempted to split an agent, ask: "Would a better prompt solve this?" Usually, it would.
Tags: llms, agents, system-design, architecture
// RELATED ARTICLES
HEIR converts pre-trained models to run on encrypted inputs. No decryption. No server access to your data. And it actually works now.
A psychology test from 1935 just exposed a fundamental flaw in transformer attention. GPT-4o went from 91% accuracy to 15%. Here's what that actually means.
Three AI coding tools, three fundamentally different philosophies. Here's how to pick the right one for your actual workflow.