Agent Architecture¶
The most common architecture mistake is adding agents prematurely. Multi-agent setups add real complexity — handoff logic, shared state, routing decisions — and that complexity has to be paid for in maintenance and debuggability. Start with a single agent and add agents only when the single-agent design demonstrates concrete limitations.
Single-agent¶
A single agent handles the entire conversation. All tools, instructions, and state live in one place.
When to use¶
- The conversation follows a linear or near-linear flow
- State is simple enough to track in a handful of variables
- The agent has fewer than two distinct capabilities (e.g., one primary task with simple fallbacks)
- You're starting a new project and the full complexity isn't yet known
Trade-offs¶
| Benefit | Limitation |
|---|---|
| Simple to reason about — one instruction set, one state space | Instructions grow long as capabilities increase |
| Easy to test — all behavior in one place | A single very long instruction set degrades model reliability |
| Fast to build and iterate | Can feel awkward if the agent needs radically different personas for different tasks |
| No handoff logic to maintain | All tools visible in every turn, including irrelevant ones |
Workspace structure¶
bella_notte/
├── gecx-config.json
├── cxas_app/
│ ├── app.json
│ ├── agents/
│ │ └── Bella_Notte_Host/
│ │ ├── Bella_Notte_Host.json
│ │ ├── instruction.txt
│ │ ├── before_agent_callbacks/
│ │ │ └── before_agent_callbacks_01/
│ │ │ └── python_code.py
│ │ └── before_model_callbacks/
│ │ └── before_model_callbacks_01/
│ │ └── python_code.py
│ ├── tools/
│ │ ├── set_party_size/
│ │ │ ├── set_party_size.json
│ │ │ └── python_function/
│ │ │ └── python_code.py
│ │ └── create_reservation/
│ │ ├── create_reservation.json
│ │ └── python_function/
│ │ └── python_code.py
│ └── evaluations/
│ └── Happy_Path_-_Linear_Flow/
│ └── Happy_Path_-_Linear_Flow.json
Multi-agent¶
Multiple agents divide responsibility. One agent typically acts as the orchestrator (or "root agent"), routing the conversation to specialized sub-agents based on the user's intent.
When to use¶
- Different parts of the conversation need genuinely different personas (e.g., a triage agent vs. a billing specialist)
- The full set of critical user journeys is too complex for one instruction set to handle reliably
- A single-agent prototype has been built and tested, and you've confirmed it degrades under the full scope
- You need strict capability isolation — sub-agents that cannot accidentally perform actions outside their domain
Trade-offs¶
| Benefit | Limitation |
|---|---|
| Each agent's instructions stay focused and short | Handoff logic is a new failure surface |
| Agents can have distinct personas and tool sets | State must be explicitly shared across agents |
| Easier to test sub-agents in isolation | Routing errors can cause confusing user experiences |
| Scales more gracefully to large capability sets | More files, more moving parts, harder to onboard |
Workspace structure¶
my_agent/
├── gecx-config.json
├── cxas_app/
│ ├── app.json
│ ├── agents/
│ │ ├── Root_Agent/
│ │ │ ├── Root_Agent.json # Orchestrator — routes to sub-agents
│ │ │ ├── instruction.txt
│ │ │ └── before_model_callbacks/
│ │ │ └── before_model_callbacks_01/
│ │ │ └── python_code.py
│ │ ├── Reservation_Agent/
│ │ │ ├── Reservation_Agent.json
│ │ │ └── instruction.txt
│ │ └── Cancellation_Agent/
│ │ ├── Cancellation_Agent.json
│ │ └── instruction.txt
│ ├── tools/
│ │ ├── check_availability/
│ │ │ ├── check_availability.json
│ │ │ └── python_function/
│ │ │ └── python_code.py
│ │ └── cancel_reservation/
│ │ ├── cancel_reservation.json
│ │ └── python_function/
│ │ └── python_code.py
│ └── evaluations/
│ └── Happy_Path/
│ └── Happy_Path.json
How to decide¶
Decision guide
Start with these questions:
- Does this agent need more than one distinct persona? If yes, lean toward multi-agent.
- Does this agent have more than two substantially different capabilities? If yes, single-agent instructions will grow long. Consider splitting.
- Have you built a single-agent version? If no, build one first. Real failure modes are easier to see in a working prototype than in a design document.
- Is the single-agent version failing evals in ways that better instructions can't fix? If yes, that's the signal to split.
The decision isn't permanent. A single-agent design can be refactored into multi-agent later. The reverse is harder. When in doubt, start simple.
The "start simple" philosophy¶
Multi-agent architectures look appealing in design documents because they seem modular and clean. In practice, they introduce coordination problems that are hard to anticipate until you're debugging them in a failing eval.
The correct sequence is:
- Build a single-agent prototype. Get it working against your core user journeys.
- Run evals. Identify where it fails and why.
- Try to fix failures with better instructions, tools, or callbacks. Most failures can be addressed this way.
- If you've exhausted those options, and the root cause is genuinely that the instruction set is too large or the personas are too different, then split into multiple agents.
This sequence gives you a baseline to compare against. A multi-agent design that performs worse than the single-agent prototype is a signal that the problem was never architectural.
Avoid tool explosion
A common driver of premature multi-agent adoption is having too many tools. Before splitting into multiple agents, check whether you can reduce tool count instead. Tools with overlapping functionality, high-cardinality arguments, or poor naming are often better candidates for redesign than handoff. See Tool Design for guidance.