Skip to content

What Is a Multi-Agent System? How AI Agents Share Context

How multi-agent systems share context between agents, what a handoff actually carries, and the 15x token tax of coordinating independent AI actors.

Tuan Tran Van
11 min read
Contents (9 sections)
  1. What is a multi-agent system, and when do you need one?
  2. Why is context sharing the hardest part?
  3. What does the receiving agent actually get on a handoff?
  4. How shared memory stores work
  5. Structured message passing between agents
  6. How a coordinating agent filters context
  7. The cost: tokens, latency, and compounding errors
  8. When not to build a multi-agent system
  9. References

A multi-agent system is an architecture where independent AI agents delegate tasks or share state to reach a goal.

The moment you run more than one agent, the job stops being prompt writing and becomes state management. The hard part is context sharing, because two agents holding conflicting versions of reality will each confidently produce a half that does not fit the other half. Reliability comes out of the plumbing between the agents rather than the "intelligence" of the model underneath, and that ordering surprises most people the first time they build one.

In production you have to treat context as an engineering problem. Single-agent threads are easier to maintain, but they hit a ceiling when a task needs breadth-first exploration, or when it simply outgrows a 200,000-token context window. Moving to a multi-agent architecture lets you scale performance, but it introduces a "coordination tax" that shows up as latency and resource consumption.

Several AI agents working separately while passing context to one another in a multi-agent system

What is a multi-agent system, and when do you need one?

The move from single-agent threads to multi-agent architectures is a response to the limits of sequential reasoning. You need a multi-agent system for complex research or breadth-first queries, the kind that require pursuing several independent directions at the same time, because a single-threaded agent turns into a bottleneck the moment the work stops being a line. With an orchestrator-worker pattern, a lead agent works out a high-level strategy and spawns specialized subagents to search or execute in parallel. That lets the system chase data points that have nothing to do with each other — one agent digging through 2025 supply chain data while another works on historical market trends — without one bloated context losing the thread of both.

One coordinating agent handing work in parallel to several subagents, each holding its own separate context

The catch is that you should only make that move when the value of the outcome justifies the overhead, and the overhead is not subtle. Multi-agent systems use 15x more tokens than standard chat, and the individual agents inside those loops use 4x more tokens than a plain chat interaction. What you buy for the money is dynamism: these systems are path-dependent, built for open-ended problems where a hardcoded linear pipeline gives up. Unlike a static sequence, a multi-agent system follows leads as they appear and pivots on what it finds halfway through.

So the real distinction is between autonomous tools used by one model and a coordinated group of actors. Single-threaded agents are enough for isolated, linear tasks, while the multi-agent approach only becomes necessary once you need agents to collaborate on an evolving state or to spread work across separate context windows. If the task is not parallelizable, which is true of most direct coding work, the coordination complexity will usually cost you more than the parallelism returns.

Why is context sharing the hardest part?

Context engineering is the persistence layer for reliable agents. In a long-running production system, the prompt is the smallest part of the problem; the real work is managing how state is passed between actors that cannot see each other. Reliability rests on two principles. Principle 1: you must share full agent traces, not just individual messages. Sharing isolated messages creates structural misalignment, where a subagent gets the task but none of the nuance of the multi-turn conversation that produced it.

Two subagents building one product from different unstated assumptions, so the two halves do not fit together

Principle 2: actions carry implicit decisions. If Agent A and Agent B work from conflicting assumptions, the system fails, and it fails in a way that looks like success right up until you assemble the pieces. Ask a system to build a game asset and Agent A might build a background like Mario while Agent B builds a bird like Flappy Bird. Neither one can see the other's work-in-progress or its unstated assumptions, so the outputs are inconsistent by construction. An analysis of 1,600-plus annotated traces found that 36.9% of multi-agent failures come from exactly this misalignment, with agents contradicting, duplicating, or ignoring each other.

Missing shared traces is the biggest driver of those failures, and I want to be blunt about the implication: a better base model will not save you here. Structural misalignment is not a reasoning deficit, so fixing it takes memory engineering that makes every action aware of the relevant decisions of every other actor. Without that, your agents will independently call the same APIs or hallucinate state that never existed in the parent thread, and you will pay full token price for both.

What does the receiving agent actually get on a handoff?

A handoff is a tool-based transition where the active_agent state variable is updated. In the OpenAI Agents SDK and LangChain, that shows up as a tool call, for example transfer_to_specialist. The mechanics require a strict AIMessage and ToolMessage pairing: when an agent calls a handoff tool, the receiving agent has to see the AIMessage that triggered the call along with a developer-synthesized ToolMessage response. That artificial response looks like bookkeeping, but it is the part that matters, because it satisfies the large language model's expectation of a complete request-response cycle and keeps the conversation history from going malformed.

The handoff boundary: what crosses to the receiving agent and what stays with the sending agent

When you implement these transitions in LangGraph, Command.PARENT returns control to the orchestrator or moves execution to another node. It also prevents the context dump, where a subagent's entire internal reasoning gets pushed into the parent's window. Instead you pass only the handoff pair, which keeps the orchestrator's context on strategy. If the specialist needs specific metadata, the input_type mechanism carries structured data such as reason, priority, or summary.

And on_handoff callbacks let you fetch data or log state at the moment a handoff fires, before the specialist takes control, so the environment already holds the dependencies the next agent needs. Managing handoffs at this granularity is fussy work, but it is what keeps the model from re-deriving information that should have been sitting in front of it.

How shared memory stores work

Production memory architecture is a tradeoff triangle of latency, consistency, and cost. Centralized memory, the whiteboard, is simple and strongly consistent, and it becomes a bottleneck as soon as you scale the number of agents. Distributed memory gives you privacy and scalability, but it makes state consistency painful: keeping Agent A aware of what Agent B just did is the problem you spend the rest of the project on. Most production systems land on a hybrid, with private tiers for specialized context and a central store for global state.

Three shared-memory arrangements side by side: centralized, distributed, and a hybrid of the two

Modern memory layers like Mem0 scope memories across four dimensions: user, agent, session, and application. That scoping is what prevents context pollution, so a billing agent sees only billing memories while still sharing a user_id with a support agent to stay consistent. Underneath, these systems mix storage backends by need, using vector stores for semantic similarity, key-value stores for exact retrieval, and graph stores for relationship modeling.

The CoALA framework (Cognitive Architectures for Language Agents) is popular in research and insufficient here, because it was designed for a single agent talking to a single user. It has nothing to say about concurrent state updates, or about locking and consensus protocols. Memory engineering picks up where it stops, by deciding what happens when two agents update the same fact differently. Every answer costs you something: optimizing for consistency adds latency through locking, while pruning aggressively to cut cost degrades retrieval quality until agents redo work they already finished.

Structured message passing between agents

To get interoperability between independent, opaque agent systems, you move toward layered protocols like A2A (Agent2Agent). The architecture splits into Layer 1, the canonical data model, and Layer 2, abstract operations. Layer 1 keeps the protocol neutral by using Protocol Buffer definitions, so you can swap JSON-RPC for gRPC without touching the core model logic. That decoupling is what lets agents built in different frameworks work together without either one reaching into the other's memory.

Two independent agent systems exchanging structured objects, with neither able to see inside the other

Discovery runs through the Agent Card, a JSON metadata document that declares an agent's skills, identity, and security requirements, which lets your orchestrator know what a potential worker can do before it hands over any task. Communication is decoupled from output through the A2A Artifact system: rather than passing results back to each other as messages, agents generate Parts — text, files, or structured data — that persist on their own.

Context identifiers then group related tasks logically across different services, so work spread over remote agents stays tied to the same user session. This opaque execution model is the whole point of A2A: agents collaborate on declared capabilities and exchanged references instead of sharing one massive and increasingly expensive context window.

How a coordinating agent filters context

The biggest risk in a multi-agent system is context dumping, where agents pass full histories on every turn and token costs grow linearly with the conversation. The fix is to make the lead agent an intelligent filter that compresses subagent findings down to the tokens the final synthesis actually needs. You want distilled insight, not propagated raw text.

A coordinating agent compressing long subagent output into a short summary while saving its plan to external memory

The input_filter pattern strips irrelevant tool calls and internal reasoning before a handoff happens, which keeps the specialist's context window clean. For long-running processes there is also a checkpointing move worth building early: the lead agent thinks through an approach and saves that plan to external memory. That one is cheap insurance, because if the context window exceeds 200,000 tokens and truncates, the system can pull the overarching plan back out of memory and carry on.

Filtering also prevents information loss, which sounds backwards until you see it work. If subagents summarize their work phases and store that data in external memory before returning to the lead agent, the orchestrator only ever handles the state that matters. That is what lets you spawn fresh subagents with clean contexts and keep scaling reasoning capacity instead of running into the wall of context overflow.

The cost: tokens, latency, and compounding errors

The operational overhead here is severe. A single agent is already a 4x token multiplier over chat, and a multi-agent system is a 15x multiplier. Performance in browsing agents is largely a function of token spend: on the BrowseComp evaluation, token usage by itself explains 80% of the performance variance. The system works because it spends enough tokens to cover the landscape, which is an uncomfortable thing to read on an invoice.

You also have to account for the game-of-telephone effect. If one agent hallucinates an API format in step two, every downstream agent builds on that fiction, and by step five the whole system is reasoning carefully about something that does not exist. The MAST taxonomy (Multi-Agent System Failure Taxonomy) documents this shape of collapse, identifying 14 distinct failure modes across three categories. Observability is not optional in that world, because you need validation checkpoints to catch bad data before it propagates down the chain.

Then there is the execution bottleneck. A synchronous system, where the lead agent waits for all workers to finish, is simple and slow. Asynchronous coordination buys you more parallelism, and it sharply increases the complexity of coordinating results and holding state consistent. Most systems today swallow the latency of synchronous execution rather than manage concurrent state conflicts, and I think that is the right trade for almost everyone.

When not to build a multi-agent system

Default to single-threaded linear agents. Most tasks, coding and direct data entry in particular, do not get anything back for the fragmentation a multi-agent system introduces, while the coordination complexity grows fast enough to produce agents that duplicate each other's work or cycle endlessly on vague instructions.

Accept the complexity only when the task is heavily parallelizable, or when the data it requires genuinely exceeds a single context window. You are paying a 15x token tax plus an engineering premium for managing shared state. If the task does not justify that, a single agent with a sharp prompt and the right tools will be more reliable, faster, and much cheaper in production.

References

Share this article