✎ Edit content·DAY 078 · POST 4 OF 5 · Code Example

Multi-Agent Systems

AI Agents · 11 slides
DAY 078 · POST 4 OF 5
(REMINDER)
DAY 078
Build a Multi-Agent System in Code
@saurav_dnj_24github.com/SauravDnj · linkedin.com/in/sauravdnj
1 / 11

Theme

Palette

Download

4K — sharpest, slowest
🎬 Video options
Preparing preview…
Live preview · loops the “none” effect
All rendering runs in your browser. No server, no cost, no upload. MP4/WebM = full motion + effects · GIF = lightweight loop · PNG/PDF = static for the Instagram & LinkedIn carousel.

Caption (tap to copy)

📖 Deep dive (full written explanation)

The slides stay clean and scannable. Here's the in-depth explanation behind each one — great for the blog version, show notes, or studying the topic properly.
Slide 1 · Build a Multi-Agent System in Code

This cover sets expectations: the post is a working agent team, not a lecture. You will build a researcher-writer-critic system with a supervisor that decides who runs next — first as raw orchestration so every handoff is visible, then with a real framework's primitives so you see the production shape. The roles are just prompts; the coordination is just a loop with a routing decision.

The through-line is the supervisor loop from the previous post, now made concrete: define agents, define the shared state and message, write the supervisor that routes turns, run the orchestration loop with a cap, and finally express the same team in a framework. By the end you have a team you understand line by line.

Slide 2 · 1. Define agents as prompts

The agents step establishes the simplest possible contract: an agent is a function call to the model with a role-defining system prompt and a user prompt. A single helper, agent(system, prompt), wraps the Anthropic client and returns the text. The three roles — researcher, writer, critic — are nothing but three short system strings.

Two things deserve attention. The researcher is told to find facts and cite them with no prose, the writer to produce a clear answer from given facts, and the critic to list concrete problems or reply 'OK' — sharp, single-purpose instructions that keep roles from bleeding together. And the same base model and helper serve all three, underscoring the day's recurring point that a role lives entirely in its prompt.

Slide 3 · 2. The shared message + state

This slide defines the data the team passes around. A Msg dataclass captures a sender and content — the structured handoff the 'how' post argued for, in its minimal form. A State dataclass holds the task, a history of messages, and dedicated fields for the researcher's facts and the writer's draft. State is the shared scratchpad; the typed fields are how agents read each other's work without parsing prose.

The design choice worth noting is keeping facts and draft as explicit fields rather than digging them out of free-text history. This is scoped, structured state in practice: the writer reads state.facts directly, the supervisor checks whether state.draft exists. Typed state is what makes both routing and handoffs reliable instead of guesswork.

Slide 4 · 3. The supervisor routes turns

The supervisor is the routing brain, and here it is deliberately rule-based for clarity. It inspects the state and returns the next role: if there are no facts yet, run the researcher; if there is no draft, run the writer; if the last review was not 'OK', run the critic; otherwise finish. The entire control plane of the system is this one readable function.

Making routing explicit and rule-based first is a teaching choice. You could replace this with an LLM that decides the next role, and frameworks often do, but seeing deterministic routing makes the control flow obvious and debuggable. The lesson is that routing is just a decision function over state — whether a few if-statements or a model call, its job is identical.

Slide 5 · 4. The orchestration loop

The orchestration loop ties everything together and is worth reading slowly. It creates a fresh State, then loops up to max_turns. Each pass asks the supervisor for the next role. On 'finish' it returns the draft. On 'researcher' it fills state.facts; on 'writer' it fills state.draft from the facts; on 'critic' it runs a review, records it, and — if the review is not 'OK' — has the writer revise the draft using the critic's feedback.

The critic-then-revise branch is the heart of the value: an independent reviewer's feedback is fed back to the writer for a concrete fix, exactly the author-reviewer separation argued for in the 'why' post. And the for-loop bound on max_turns is the termination fuse made literal. This single function is a complete, self-contained agent team in well under thirty lines.

Slide 6 · What runs at each turn

The cycle diagram captures what runs at each turn as a repeating rhythm: the supervisor picks the next role, that agent runs (researcher, writer, or critic), the state is updated with new facts, a draft, or a review, and the loop checks whether it is done before looping or finishing. It is the supervisor loop, now grounded in the specific code you just wrote.

Seeing it as a cycle reinforces that the supervisor is consulted every turn and that all coordination flows through shared state. Each lap reads the current state and produces one update. Everything the team knows is in that State object, which is exactly why scoping and structuring it well — the previous slide's point — determines whether the team stays coherent.

Slide 7 · 5. The same team in a framework

This slide makes the leap to a framework by expressing the same team as a LangGraph state graph. Each agent becomes a node, and edges encode the routing: the entry point is the researcher, an edge runs the writer next, and a conditional edge after the critic either loops back to the writer for revision or ends. The graph compiles into a runnable app.

The payoff is that the framework handles state plumbing, conditional routing, and retries that you wrote by hand in the raw version. The lesson of building the loop yourself first is now obvious: a framework is the same supervisor-and-state idea with the boilerplate absorbed. You reach for it when routing grows complex enough that hand-rolled if-statements become a liability.

Slide 8 · Hand-rolled vs framework

The comparison contrasts the two implementations trait by trait so you can choose deliberately. The hand-rolled loop means you own the routing, get full visibility, carry no dependencies, and learn the most. A framework provides graph or role primitives, handles state and retries, removes boilerplate, and is the production default.

The honest takeaway is that both have a place. Build and learn with the hand-rolled loop because it exposes every handoff and routing decision; ship with a framework once your topology has enough nodes, conditional edges, and retry logic that maintaining it by hand becomes error-prone. They are the same pattern — the difference is only in how much plumbing you write versus inherit.

Slide 9 · 6. Guardrails: cap turns + log

This slide hardens the loop with guardrails, the difference between a demo and something deployable. safe_run records a start time and, on every iteration, checks both the turn count via the bounded for-loop and a wall-clock deadline, returning a graceful timeout message if either trips. Critically, it prints every handoff — the turn number and the chosen role — so the run is traceable.

These few additions close the most common holes. The deadline and turn cap together guarantee the team always terminates instead of ping-ponging forever. The per-turn log is observability in its simplest form: when a run misbehaves, you can see exactly which role ran at each turn and where it went wrong. Make this guarded, logged shape your default skeleton.

Slide 10 · Make it production-ready

The tips translate the team into operational discipline. Always cap max_turns and add a timeout so a confused team cannot run forever. Log every handoff so the flow is debuggable. Keep each agent's prompt short and single-purpose to preserve role boundaries. Pass structured state rather than giant text blobs so handoffs stay reliable. And reach for a framework once routing gets complex enough to be a maintenance burden.

Each tip closes a specific hole in the naive implementation you just built. Together they are the gap between a team that demos well once and one you can actually deploy — and every one of them reappears, inverted, as a failure mode in the mistakes post that follows.

Slide 11 · Save this. Follow for Day 79.

The CTA bridges to the failure modes. You now have a working agent team in two forms, which means you are now exposed to the subtler dangers: a team that runs but fails in expensive, hard-to-spot ways — looping on handoffs, overlapping roles, duplicated context, poisoned chains. The next post is the field guide to those traps.

Save this post as your implementation reference. When you sit down to build a real multi-agent system, these six steps — agents, state, supervisor, loop, framework, guardrails — are the skeleton you fill in with your own roles, model, tools, and limits.

🎨 AI image prompt (matches this theme + palette)

Paste into Midjourney, DALL·E, Ideogram, etc. to generate an on-brand image, then upload it on the Edit content page. The prompt updates automatically with the selected theme + palette.