Architecting Agent-Based Systems

Explain this chapter with AI

Copy this prompt into ChatGPT, Claude, Gemini, a local model, or another AI.

Apply this chapter with AI

Copy this prompt into ChatGPT, Claude, Gemini, a local model, or another AI.

The previous chapters built up one agentic workflow: roles, tools, memory, reflection, revision, and versioning. This chapter changes scale.

An agent-based system is not one large assistant with a bigger prompt. It is a collection of components that divide responsibility, communicate through explicit channels, use shared or separate state, and preserve enough identity that you can tell which part did what.

The design question is:

Which responsibilities belong together,
which should be separated,
and how should the separated parts coordinate?

Architecture begins when those boundaries have to be chosen deliberately.


When One Agent Is Not Enough

A single agent is often the right starting point. It is cheaper, easier to inspect, and easier to debug.

Start from the failure, not from the architecture diagram. If one role keeps mixing research with judgment, separation may help. If a single prompt is losing track of state, explicit memory may help. If a tool call can change something important, an approval boundary may help. But every extra agent adds latency, cost, state synchronization, and another place for responsibility to blur.

Multiple agents become useful when the task benefits from separation:

Need Why multiple agents may help
Specialized context each role sees only the information it needs
Specialized tools risky tools can be exposed only to bounded roles
Parallel work research, drafting, and checking can happen separately
Independent review a critic can evaluate without owning generation
Clear accountability outputs can be traced to named roles
Cross-domain work bridge agents can translate between systems

The cost is real:

handoff errors
duplicated work
inconsistent state
latency
more tokens
role confusion
harder debugging

Do not add agents because the diagram looks more impressive. Add them when a responsibility boundary earns its cost.


Coordination Models

There is no single correct shape for a multi-agent system. The control structure should match the work.

Centralized

A centralized system has one manager, planner, or orchestrator that assigns work and decides what happens next.

manager
  โ”œโ”€ researcher
  โ”œโ”€ writer
  โ””โ”€ critic

Centralized systems are good for early prototypes, sequential workflows, tight control, and cases where one component should own the final decision. They are easier to understand because the route through the system is concentrated in one place.

They can also bottleneck. If the manager has weak instructions, poor state, or too much authority, the whole system inherits that weakness.

Decentralized

A decentralized system lets agents coordinate through messages, shared state, event logs, or task queues without one permanent central controller.

researcher <-> shared memory <-> critic
writer     <-> shared memory <-> reviewer

This can support parallel work, resilience, and dynamic routing. It is useful when no single role has enough context to control everything.

It is also harder to debug. Without strong identity, schemas, permissions, and conflict rules, decentralized systems become noisy quickly.

Hybrid

A hybrid system combines direction with local autonomy.

manager sets goal and constraints
        โ†“
specialized agents act within scope
        โ†“
manager or reviewer integrates results

Most practical agent systems become hybrid. A manager sets the frame; specialized roles decide how to perform their bounded part; a reviewer or policy layer decides what to accept.

    flowchart LR
    subgraph Centralized
        P[Planner]
        P --> C1[Researcher]
        P --> C2[Writer]
        P --> C3[Critic]
    end

    subgraph Hybrid
        L[Lead agent]
        L --> H1[Researcher]
        L --> H2[Writer]
        L --> H3[Reviewer]
        H1 <--> H2
        H2 <--> H3
    end

    subgraph Decentralized
        D1[Agent]
        D2[Agent]
        D3[Agent]
        D4[Agent]
        M[(Shared memory)]

        D1 <--> M
        D2 <--> M
        D3 <--> M
        D4 <--> M
        D1 <--> D2
        D3 <--> D4
    end
  

The choice is less about philosophy than operational need.

Model Best when Watch out for
Centralized you need simplicity and control bottlenecks, single point of failure
Decentralized work is parallel or distributed inconsistent state, hard debugging
Hybrid roles need autonomy under oversight unclear handoffs, duplicated authority

Shared Memory as a Coordination Layer

Agents can coordinate by passing messages directly, but many systems need a shared record.

Shared memory might be:

JSONL event log
database table
document store
vector index
task board
artifact repository

The important property is not the storage technology. It is that the system has a place where roles can leave structured traces for other roles to read.

A simple shared-memory log might look like this:

{"role":"planner","type":"plan","task_id":"t1","summary":"Summarize article in three stages"}
{"role":"researcher","type":"finding","task_id":"t1","claim":"The article's core claim is X","evidence":"paragraph 4"}
{"role":"writer","type":"draft","task_id":"t1","artifact":"draft-v1"}
{"role":"critic","type":"review","task_id":"t1","decision":"revise","reason":"missing limitation"}

This record helps in three ways. It decouples roles, so a critic can read the draft entry instead of interrupting a writer. It improves auditability, because you can inspect what happened instead of relying on a final answer. It also enables asynchronous work: agents can run at different times and still share context.

Shared memory is not automatically a source of truth. It can contain drafts, mistakes, stale facts, and conflicting claims. Treat it as a coordination surface unless a particular entry has been verified.

Freshness belongs in the memory contract. A market price, file status, calendar slot, or policy rule may be true when observed and false when acted on. For high-impact actions, record observation time, decision time, and commit time separately. If the state changed between those moments, the system should re-check before acting.


Interfaces Matter More Than Agent Names

Large systems fail when agents communicate in vague blobs.

Weak handoff:

I researched it. Looks good.

Useful handoff:

role: researcher
task_id: urban-transport-001
claim: "Micromobility is increasingly regulated through city-level safety rules."
evidence_type: background
source_status: unverified
open_questions:
  - Which cities changed policy in the last 12 months?
recommended_next_role: policy_researcher

An interface does not have to be complex. It has to make responsibility visible.

For every agent role, define:

name
version
purpose
inputs
outputs
allowed tools
memory access
authority
failure modes
handoff format

This turns a group of prompts into a system that can be inspected, tested, and changed.

Separate capability from authority. A component may know how to call a payment API, edit a file, or message a customer, but that does not mean it should be allowed to do so in every context. Capability says what the component can technically perform. Authority says what it is permitted to perform for this task, under these conditions, with this evidence and approval state.

For larger systems, also record the decision event:

decision_id
run_id
actor
input_state_id
proposed_action
authority_check
evidence_used
accepted_or_rejected
output_state_id

This is the minimum trace that lets you answer later: who decided, from which state, using what evidence, and what changed?

    flowchart LR
    M[Model proposal] --> A{Authority check}
    A -->|allowed| E[Execute tool]
    A -->|needs review| H[Human or policy review]
    A -->|rejected| R[Recorded rejection]
    H -->|approved| E
    H -->|denied| R
    E --> O[Observation]
    O --> S[Updated state]
  

Tagging and Versioning

Agent behavior is shaped by many moving parts:

model
prompt / instructions
tools
memory policy
retrieval configuration
temperature and decoding settings
output schema
coordination role
evaluation criteria

If one changes, behavior may change. Versioning gives you a way to discuss that change precisely.

A minimal role record might be:

name: critic
version: 1.3.0
model: recorded_at_runtime
prompt_id: critic_prompt_v4
input_schema: candidate_summary_v2
output_schema: critique_v1
tools:
  - citation_checker
memory_access:
  - current_task_log
authority: recommend_only
status: production

Versioning is not bureaucracy. It is how you answer the practical question:

Which version produced this decision?

Without that answer, regression becomes guesswork.


From COM to Modular Agent Systems

The older software world already solved parts of this problem.

Microsoft’s Component Object Model, COM, was a way to build systems from addressable components with known interfaces. COM components had identity. They could be registered, discovered, invoked through interfaces, versioned, and replaced without every caller knowing their internals.

Agent systems are different, but the analogy is useful.

COM idea Agent-system equivalent
Component identity named role with version
Registry agent catalog or metadata store
Interface input/output schema and tool contract
Loose coupling handoffs through messages or shared state
Late binding choose a role implementation at runtime
Versioning compare, roll back, deprecate, replace

The value of the analogy is restraint. It reminds us that modularity is not new. What is new is that some components contain probabilistic model behavior.

That makes interfaces more important, not less.

An agent registry can be simple:

agents:
  - name: researcher
    version: 1.0.0
    purpose: gather evidence
    outputs: finding_v1
    tools: [search, document_reader]
  - name: critic
    version: 1.1.0
    purpose: review candidate artifacts
    outputs: critique_v1
    tools: [checklist]
  - name: bridge_agent
    version: 0.4.0
    purpose: translate between legal and finance schemas
    outputs: transfer_review_request_v1

Once roles are registered, the system can swap implementations, route tasks by capability, and keep old versions available for rollback.


Bridge Agents

Bridge agents are one of the most distinctive ideas in this book.

A bridge agent connects two systems that do not share the same language, schema, assumptions, or workflow. It does not merely summarize. It translates between contexts.

For example, a finance system may produce:

portfolio exposure
risk category
counterparty
asset class

A legal system may need:

contract obligation
jurisdiction
consent requirement
review status

A bridge agent sits between them:

finance output
      โ†“
bridge agent
      โ†“
legal review request

The bridge should not silently invent compatibility. It should map fields, identify missing information, preserve uncertainty, and escalate when the translation is unsafe.

In larger organizations, this pattern becomes important because agent systems will not all be built by the same team. They will have different models, policies, schemas, logs, and definitions of success.

Bridge agents make collaboration possible across boundaries, but they also create risk. A bad bridge can convert a careful statement in one domain into an overconfident action in another.

The bridge should therefore separate content from control. A document received from another organization can supply facts to inspect; it should not silently supply instructions about which internal tools to call, which permissions to grant, or which approval rules to skip. The receiving system should treat outside material as untrusted content until its own policy layer decides otherwise.

Good bridge design therefore needs:

source schema
target schema
mapping rules
unknown / missing field behavior
validation
audit log
human escalation path

Interorganizational Coordination

Consider two companies coordinating a complex transaction.

Company A has an internal data agent that can assemble an asset bundle. Company B has a compliance agent that can review the bundle. A bridge agent translates Company A’s package into Company B’s intake format. A risk agent flags missing consent documents. A human reviewer approves or rejects the final transfer.

The architecture might look like this:

Company A data system
      โ†“
Data Custodian Agent
      โ†“
Bridge Agent
      โ†“
Company B Compliance Agent
      โ†“
Risk Review
      โ†“
Human approval

Such transfers should not run without oversight. As coordination becomes more automated, boundaries, logs, schemas, and authority become more important.

The promise is speed and clarity. The danger is misplaced trust.

Interorganizational agents need contracts, authentication, permissions, audit trails, revocation, and human accountability. Otherwise the system can move faster than anyone can understand.


Designing Your Own Agent Framework

You can design a small framework before writing much code. Start with the architecture.

  1. Identify the roles.
planner
researcher
writer
critic
reviewer
memory manager
bridge
  1. Define the communication model.
sequential chain
central manager
shared memory
event log
hybrid
  1. Define each interface.
input schema
output schema
allowed tools
memory access
authority
error behavior
  1. Add versioning.
role version
prompt version
tool version
memory policy version
model recorded at runtime
  1. Add evaluation and rollback.
what counts as success?
who can accept a candidate?
what happens when a new version is worse?

A micro-agent article summarizer might have only three roles:

Planner:
  split article into sections

Summarizer:
  produce section summaries

Critic:
  check accuracy, missing context, and clarity

All three can read and write a shared task log. That is enough to practice the architecture without pretending you have built a full platform.


Learning From Experience

Agent systems can use experience, but the word “learning” needs care.

A system can log past interactions, score outputs, compare versions, store accepted examples, retrieve useful memories, and change future prompts. That is experience at the system level.

The model’s weights usually have not changed.

Useful experience loops include:

Pattern Mechanism
Reflection review an output and propose a change
Grading loop score against explicit criteria
Memory anchor store a useful example or preference
Version comparison decide whether a candidate beats the baseline
Pause threshold stop and ask for help when confidence or evidence is insufficient

The last pattern is especially important. A capable system should know when not to continue.

repeated failures
missing evidence
tool unavailable
low confidence
high-risk action
policy boundary

Any of those should be able to trigger a pause, fallback, or human review.

This is control logic, not self-awareness. It is what makes agent systems safer and more useful.


What Chapter 6 Adds

Chapter 3 explained the mechanisms of agent behavior. Chapter 6 turns those mechanisms into system architecture.

The core ideas are:

separate responsibilities
define interfaces
choose a coordination model
share memory carefully
register agents as components
version behavior
bridge domains explicitly
preserve human authority where stakes require it

The future of agent systems is not one giant agent doing everything. It is many bounded components, some deterministic and some model-driven, working through clear contracts.

Once a system has those contracts, the next pressure appears: a human still has to work with it. The architecture may contain roles, tools, memory, bridge agents, and authority checks, but the person at the edge needs a way to express intent, inspect what will happen, and steer the system without learning every internal interface.

That is where natural language becomes more than a prompt. It becomes the surface through which people coordinate with the architecture.