Live Coding Interview Prep

Course Content

Live Coding Interview Prep

7 sections · 50 lessons

Build a multi-agent collaboration system with defined roles.


What you need to know

A multi-agent system splits one task among several LLM "agents", each with a narrower job. The benefits are real but specific:

  • Smaller, focused context — the critic does not need the researcher's raw search results, only the draft and the key notes.
  • Different tools or models per role — the researcher has web search; the writer does not. A cheap model can do research summaries; a strong one can write.
  • Checkable hand-offs — each output is stored and can be inspected or replayed.

The costs are just as real: more calls, more latency, and information lost at every hand-off.

The blackboard pattern is the simplest coordination design: a shared store of named entries. Each agent reads the keys it needs and writes its output under a new key. Because no agent calls another directly, you can test each one alone and replay any step.

Python
from collections.abc import Callablefrom dataclasses import dataclass, fieldLLM = Callable[[str, str], str]           # (system, user) -> reply@dataclassclass Agent:    name: str    system: str    llm_fn: LLM    def run(self, task: str, context: str = "") -> str:        return self.llm_fn(self.system, f"{context}\n\nTask: {task}".strip())@dataclassclass Blackboard:    task: str    notes: dict[str, str] = field(default_factory=dict)    def context(self, keys: list[str]) -> str:        return "\n\n".join(f"{k}:\n{self.notes[k]}" for k in keys if k in self.notes)def run_crew(task: str, researcher: Agent, writer: Agent, critic: Agent,             max_revisions: int = 2) -> Blackboard:    """Research -> draft -> (review -> revise) up to max_revisions times."""    board = Blackboard(task)    board.notes["research"] = researcher.run(task)    if not board.notes["research"].strip():        raise ValueError("researcher returned nothing; refusing to draft from no facts")    board.notes["draft"] = writer.run(task, board.context(["research"]))    for i in range(max_revisions):        verdict = critic.run(            "Reply APPROVED if the draft is accurate and complete; otherwise list the fixes.",            board.context(["research", "draft"]),        )        board.notes[f"review_{i}"] = verdict        if verdict.strip().upper().startswith("APPROVED"):            break        board.notes["draft"] = writer.run(            "Revise the draft to address every point in the review.",            board.context(["research", "draft", f"review_{i}"]),        )    return board

The tricky parts:

  • context(keys) passes each agent only the keys it needs. Passing the whole board to every agent grows the prompt with every round and brings back the context problem multi-agent was meant to solve.
  • The empty-research check stops a confident draft written from nothing.
  • startswith("APPROVED") after strip().upper() tolerates "approved." and leading spaces; still, a structured JSON verdict is more reliable in production.
  • Returning the board, not just the draft, keeps the whole run inspectable.

Complexity: 2 calls for research and draft, then up to 2 per revision round (review + revise). With max_revisions = 2 that is at most 6 model calls, against 1 for a single agent. Space is the sum of the notes.

A real-life example

Stub models let us trace the run; the critic rejects once, then approves:

Python
calls: list[str] = []def fake(role: str, replies: list[str]) -> LLM:    it = iter(replies)    def llm(system: str, user: str) -> str:        calls.append(role)        return next(it)    return llmresearcher = Agent("researcher", "Find facts.", fake("researcher", ["UPI refunds: T+5 days."]))writer = Agent("writer", "Write clearly.", fake("writer", ["Refunds take 5 days.",                                                            "UPI refunds take 5 working days."]))critic = Agent("critic", "Be strict.", fake("critic", ["Say 'working days' and name UPI.", "APPROVED"]))board = run_crew("Explain refund timelines", researcher, writer, critic)print(board.notes["draft"], calls)# UPI refunds take 5 working days. ['researcher', 'writer', 'critic', 'writer', 'critic']
callagentreadswrites
1researchertaskresearch
2writerresearchdraft v1
3criticresearch, draftreview_0: fixes
4writerresearch, draft, review_0draft v2
5criticresearch, draftreview_1: APPROVED → stop

Five calls for one paragraph. That is the number to have in mind when someone proposes a crew of seven agents.

A content team drafting product descriptions for thousands of SKUs uses this shape: a researcher pulls specs from the catalogue, a writer drafts, and a critic checks against brand rules.

Follow-up questions to expect

  • "How do you know the critic is useful?" — Feed it known-bad drafts and measure how often it catches them. A critic that approves everything is theatre; a critic that never approves just costs money.
  • "Is multi-agent better than one agent with all the tools?" — Usually not. Start with one agent; split only when the prompt is overloaded or roles need different tools or permissions.
  • "The last revision is never reviewed — is that a bug?" — If max_revisions is exhausted, the final draft was not approved. Return it with a flag like approved: False so the caller can route it to a human.