Yesterday we made agents observable with traces, metrics, and logs. Today we put them somewhere real. Day 26 covers multi-agent deployment strategies: how to run an orchestrator and a team of worker agents as services that stay available, fast, secure, and affordable.

Save this sheet. The rest of this note walks through it section by section.
Why deployment is its own problem
A single agent hits limits on context, tools, and complexity, which is why we split work across agents. But a multi-agent system that works in a notebook is a long way from one that serves users. Several model calls per request, shared state, and agents that depend on each other create new failure modes: one slow agent stalls the whole run, a retried request double-books a meeting, a crashed worker loses half-finished work.
Proper deployment buys you high availability, predictable performance, safety, better resource use, cost control, and fault isolation so one failing agent does not take the system down. The sheet's summary is fair: good deployment means happy users, lower costs, and reliable systems.
The reference architecture
Users / clients
-> API gateway
-> Orchestrator (planner / router)
-> Agent mesh (worker agents)
-> Tools and services
Shared infrastructure: vector DB, memory store, message queue,
cache, monitoring and observability, secrets and config
CI/CD and infrastructure-as-code pipeline underneath
The loop to run it: monitor, scale, optimize, secure, repeat.
The design choice that matters most is where state lives. If worker agents keep conversation state or task progress in process memory, you cannot scale them horizontally, restart them safely, or retry their work on another instance. Push state into the memory store and database, and pass work through the queue. Then agents become stateless workers that can be added, removed, or replaced freely.
Five deployment strategies
| Strategy | How it runs | Strengths | Trade-offs |
|---|---|---|---|
| Centralized | All agents in a single environment | Simple to start and manage | Scaling is limited |
| Distributed | Agents across multiple services or machines | Better scaling, lower latency | More complex |
| Microservices | Each agent is an independent service | Independent scaling, fault isolation | More operational overhead |
| Serverless | Event-driven, auto-scaling per request | Auto-scale, pay per use | Cold starts, execution time limits |
| Hybrid | Combines approaches per requirement | Best of each where it fits | Requires good orchestration |
My default for most teams: start centralized. One deployable service containing the orchestrator and agents as modules, backed by a real database and queue. Split an agent into its own service only when you have a reason, such as different scaling needs, a GPU dependency, a separate team owning it, or a security boundary. Serverless suits short, bursty agents triggered by events, but watch execution time limits, since agent runs with several model calls can be long.
The request flow
The sheet's six-step flow:
- Request received. The user sends a request.
- Orchestrator plans. It decides which agents to use.
- Agents execute. Independent tasks run in parallel.
- Share and sync. Agents exchange data through the memory store or message queue.
- Aggregate results. The orchestrator combines outputs.
- Respond. The final response goes to the user.
Observability spans the whole flow, and a feedback loop improves plans, memory, and performance over time. Step 3 is where latency is won or lost. Sequential dependencies add up fast, so let the orchestrator identify which subtasks are independent and run those concurrently.
An API that survives retries
The sheet's FastAPI example runs the orchestrator inside the request. That works for short runs, but long agent runs should not hold an HTTP connection open. A sturdier pattern accepts the job, queues it, and lets clients poll for the result, with an idempotency key so retried requests do not start duplicate runs.
from fastapi import FastAPI, Header
from pydantic import BaseModel
app = FastAPI()
class RunRequest(BaseModel):
query: str
user_id: str
@app.post("/runs", status_code=202)
async def create_run(req: RunRequest, idempotency_key: str = Header(...)):
existing = await runs.get(idempotency_key) # runs: Postgres or Redis
if existing:
return existing # same request, same run
run = {"run_id": idempotency_key, "status": "queued"}
await runs.put(idempotency_key, run)
await queue.publish("agent-runs", {**run, "query": req.query, "user_id": req.user_id})
return run
@app.get("/runs/{run_id}")
async def get_run(run_id: str):
return await runs.get(run_id)
Workers consume agent-runs, execute the orchestrator's plan, and write status and results back to the store. Package the API and workers as containers and deploy them with Docker, Kubernetes, or a managed platform. The deployment tips on the sheet apply: containerize agents, use Kubernetes when you need to scale, store secrets safely, monitor and alert, and automate everything.
Key considerations
| Consideration | The question to answer |
|---|---|
| Scalability | Can it handle more users and more agents? |
| Reliability | What happens when an agent fails? |
| Latency | How fast must responses be? |
| Cost | What do infrastructure, tokens, and tool calls cost per run? |
| Security | Auth, secrets, and data isolation between agents and tenants |
| Monitoring | Are we tracking everything that matters? |
| Data consistency | Do memory and state stay in sync across agents? |
Reliability is the one to answer in writing before launch. For each agent, decide what happens on failure: retry, fall back to a simpler path, skip with a partial result, or escalate to a human.
Best practices and the checklist
The best practices on the sheet are the right ones: clear agent roles and goals, a strong orchestrator, stateless agents with external state, message queues for async communication, retries, timeouts, and circuit breakers, idempotent tool calls, continuous monitoring and alerts, versioned agents, prompts, and tools, regular failure testing, and CI/CD for deployments.
Idempotent tool calls deserve emphasis. Retries are inevitable in distributed systems, so any tool that changes something, such as sending an email, creating a ticket, or charging a card, needs a deduplication key so a second call does nothing harmful.
The common challenges: complex orchestration and dependencies, rising token costs, state management, debugging multi-agent conversations, unreliable tools, latency from sequential steps, security and data leakage, and keeping prompts and code in sync. Before launch, walk the sheet's checklist: roles defined, orchestrator configured, tools connected, memory store set up, infrastructure provisioned, security configured, CI/CD ready, monitoring and alerts in place, load testing done, fallbacks and retries ready, and docs and runbooks prepared.
Key Takeaways
- Keep agents stateless and push state into a store and queue so they can scale and restart safely.
- Start centralized and split agents into services only when a concrete reason appears.
- Run long agent jobs asynchronously behind an accept, queue, and poll API.
- Make every side-effecting tool call idempotent, because retries will happen.
- Decide in writing what happens when each agent fails before you go live.
FAQs
Should each agent be its own microservice?
Not by default. It multiplies operational overhead. Split when scaling, ownership, dependencies, or security genuinely differ.
Is serverless a good fit for agents?
For short, event-driven tasks, yes. For long multi-step runs, execution limits and cold starts often push you toward containers and queue workers.
How do I version a multi-agent system?
Version prompts, tools, and agent code together, record the versions on every trace, and roll out changes gradually.
Up Next
Day 27 is Fine-Tuning AI Agents: when fine-tuning beats prompting and RAG, the data it needs, LoRA and QLoRA, and how to measure whether it helped. If you are taking a multi-agent system to production, we can help.




Letters to the editor
No letters yet. Questions and counterpoints are welcome.