// blog

Multi-agent patterns that survive contact with production

2 min read
  • agentic-ai
  • multi-agent
  • google-adk
  • architecture

Multi-agent systems have a reputation problem: most demos are agents role-playing a company org chart, burning tokens on inter-agent small talk. But under the theatre there are a handful of shapes that genuinely work. Three of them account for essentially everything I ship.

1. Orchestrator–workers

One agent owns the goal, decomposes it, and fans out narrow subtasks to workers that each get a clean context and a small toolset. The orchestrator never sees the workers' raw process — only their results.

This is the pattern for context isolation. A worker that reads 30 files to answer "where is retry logic implemented?" returns one paragraph; the 30 files never pollute the orchestrator's context. You're spending worker tokens to keep the coordinator smart.

In Google ADK this maps to an Agent with sub_agents, or explicit AgentTool wrapping. The mistake to avoid: giving workers write access to shared state. Results flow up, decisions flow down, and the moment workers coordinate laterally you've built a distributed system with no debugger.

2. The pipeline

When the task has a known shape — extract, transform, verify, publish — don't make an LLM rediscover the shape on every run. Encode it:

from google.adk.agents import SequentialAgent, ParallelAgent

review = SequentialAgent(
    name="review_pipeline",
    sub_agents=[
        ParallelAgent(name="find", sub_agents=[bug_finder, perf_finder]),
        deduplicator,
        verifier,
        reporter,
    ],
)

Deterministic control flow, stochastic steps. Pipelines are boring, testable, and cheap — every step can run a smaller model than a monolithic agent would need, because each step's job fits in a sentence.

3. Generator–judge

For anything with quality stakes, split producing from evaluating. The generator writes the migration, the judge — a separate agent with fresh context and an adversarial prompt — tries to reject it. Loop until the judge passes it or a budget runs out (ADK's LoopAgent exists for exactly this).

The two roles genuinely need to be separate contexts. A model reviewing its own output inherits its own blind spots; a judge with a "find the flaw" instruction and none of the generator's rationalizations catches things self-review never will. Adding an independent verify pass to a code-review agent roughly halved the false positives it shipped for me.

Patterns I've abandoned

  • The agent society. Free-form agent-to-agent chat. Fascinating to watch, impossible to debug, never converges under deadline.
  • The router that's smarter than the routes. If your dispatch agent needs deep domain knowledge to choose a specialist, the specialists are sliced wrong.
  • Consensus voting on everything. Three agents voting costs 3× and mostly agrees. Save panels for judgments that are genuinely subjective, and give each panelist a different lens, not the same prompt three times.

The heuristic

Add an agent when you need isolation (context, tools, or failure), not when you need "more intelligence". Every agent boundary is an API boundary: it needs a contract, a budget, and a trace. If you wouldn't split it into a microservice, think twice about splitting it into an agent.

← All posts