Georgia State University — J. Mack Robinson College of Business PATH — Pathways for AI Training & Hiring CIS 4394 Agentic AI  ·  Fall 2026  ·  Dr. Xinyu Fu
01 · Patterns

Four topologies, one decision.

A multi-agent system is not a new kind of intelligence. It is the same agent loop from Week 4, instantiated several times, with rules about who may talk to whom and what travels across each line. Those rules are the whole design — so learn the four shapes, and learn what each one breaks on.

Where we start

You already wrote this agent. Here it is with names.

In Week 5 you built an agent in plain Python and could read every line. Multi-agent systems are where that stops scaling — so before we add a second agent, here is the single-agent loop you already know, with the names a framework gives it — @tool, bind_tools, ToolNode, tools_condition — and the gate attaches at exactly the place you would expect. Skim it now; come back when you need it.

Click any line — the matching line on the other side lights up too. Nothing new happens in the right-hand column; the same moves have simply been given names.

Plain Python — what you run on page 03
TOOLS = {"calculator": calculator, "issue_refund": issue_refund} for step in range(1, MAX_STEPS + 1): msg = ollama.chat(model=MODEL, messages=messages, tools=list(TOOLS.values())).message messages.append(msg) if not msg.tool_calls: return msg.content # done for call in msg.tool_calls: name, args = call.function.name, call.function.arguments if name in NEEDS_APPROVAL and not approve(name, args): result = "DENIED by a human reviewer." else: result = TOOLS[name](**args) messages.append({"role": "tool", "content": result, "tool_name": name})
LangGraph — the same moves, named
TOOLS = [calculator, issue_refund] llm_tools = llm.bind_tools(TOOLS) def call_model(state): return {"messages": [llm_tools.invoke(state["messages"])]} g = StateGraph(State) g.add_node("model", call_model) g.add_node("tools", ToolNode(TOOLS)) # ToolNode also appends each result to state["messages"] g.add_edge(START, "model") g.add_conditional_edges("model", tools_condition) g.add_edge("tools", "model") agent = g.compile(interrupt_before=["tools"]) # tools_condition routes to END when no tool was asked for
Click a line in either column, or pick a move above.
Read the last line carefully

interrupt_before=["tools"] stops the graph after the model has committed to a call and before anything executes — precisely the window from page 01. Your application then shows the pending call to a person and resumes the graph only on approval. A blunt version gates every tool; a real one checks which tool was requested and interrupts only for the gated ones.

The docstring is the schema

There is no separate schema file in this code. bind_tools reads your function signatures and docstrings and generates the JSON the model sees. Which means every rule on this page — enums, ranges, “use this when…”, “do not use this for…” — is written as ordinary Python type hints and prose.

🎯 Take it to your final project

Define two tools with clean schemas, return errors as data, and put a human gate on anything irreversible. That sentence is the headline Week 5 skill and it is what Group Assignment 2 grades.

Framework reference: LangChain — Tool calling ↗

Start here

The default is one agent with good tools

Pattern 0 — single agent, many tools

One loop, one context, one trace. Every capability you want arrives as a tool (Week 5), not as a colleague. Nothing is handed off, so nothing can be dropped in a hand-off. When people say "we built an agent", this is almost always what they built — and it is what your Capstone Milestone I should be.

It stops working for a specific, nameable reason: the context window fills with instructions and results for jobs that have nothing to do with each other, or the tool list gets long enough that the model picks wrong. Those are the symptoms worth measuring before you reach for a second agent.

The rule for the rest of this page

You are allowed to leave Pattern 0 when you can complete this sentence with evidence: "The task splits into subtasks that can run in parallel, and each subtask's output can be verified on its own."

If you cannot, the patterns below will make your system slower, costlier, and harder to debug while looking more sophisticated. That is the trap this week exists to prevent. Page 02 makes the case against in detail.

Interactive · the four shapes

Click a topology

Same four agents in every picture. What changes is who is allowed to talk to whom — and that single choice determines the failure modes you inherit.

agent search db calc write one loop · one context · one trace
Notice what is missing from all four pictures: the arrows do not say what crosses them. That payload — the hand-off contract — is where multi-agent systems actually succeed or fail, and it is the subject of the next section.
The pattern that shows up in production

Supervisor, in the wild

Anthropic published how they built the multi-agent research system behind Claude's Research feature. It is the orchestrator-worker pattern, and the write-up is unusually honest about what it cost.

The architecture, as described

A lead agent receives the user's query, thinks about how to approach it, and spawns subagents that search in parallel. Each subagent works in its own context window with its own tools, then returns findings to the lead, which decides whether to spawn more, and finally synthesizes an answer. The subagents do not talk to each other — a deliberate restriction, exactly the n−1 channels point from the week's home page.

Why the pattern fits: open-ended research is breadth-first. "What are the board members of the top five companies in X?" is genuinely four or five independent lookups, each verifiable on its own. That is the canonical shape.

Anthropic Engineering — How we built our multi-agent research system ↗ (this week's reading)

The cost, as reported

Anthropic reports that the multi-agent system used roughly 15× more tokens than a chat interaction, and that it outperformed a single-agent baseline on their internal research evaluation by about 90%. Both figures are as reported in their engineering post and are approximate — do not quote them as general laws of multi-agent systems. They describe one system on one internal eval.

The right lesson is not "multi-agent is 15× worse" or "multi-agent is 90% better". It is: the value has to be large enough to survive the multiplier. Anthropic's own framing is that this only makes sense for tasks valuable enough to justify the spend. Most CRUD-shaped agent work is not.

The part everyone skips

What actually gets shared: state vs messages

Two agents can be connected in exactly two ways, and choosing between them is a bigger decision than choosing the topology.

Shared state

Both agents read and write the same object — a plan, a draft, a scratchpad, a LangGraph state dict. Nothing is "sent"; changes are simply visible.

Buys: no information is lost in translation; agents cannot hold contradictory pictures of a shared field.
Costs: the classic concurrency problems arrive with it — two agents editing the same field, last-write-wins, and an ever-growing shared blob that every agent must now read (which is the context problem you were trying to escape).

Messages / hand-offs

Agent A finishes and passes a payload to agent B. B's context contains only what A chose to send.

Buys: clean, small contexts and clear boundaries — each agent's window holds one job.
Costs: whatever A did not put in the payload is gone. B re-derives it, guesses it, or silently works from a different assumption. This is context fragmentation, and it is the single most common cause of confidently contradictory multi-agent output.

Context isolation is a feature, not an accident. In Week 3 you measured what happens when one window carries too much: retrieval degrades, earlier instructions decay, and the model starts answering the wrong question — context rot. Giving a subagent a clean window for one narrow job is a direct fix for that. The trade is exact and worth memorizing: isolation cures context rot and causes context fragmentation. Every hand-off design is you choosing where on that line to sit.

Write the hand-off contract before you write the agent. A payload that reliably survives a hand-off names all four of these — anything left implicit is a bug waiting for production.

# the hand-off contract, as a schema { "task": # what B must do, restated in full — # never "continue the above" "constraints": # budget, tone, format, hard limits # that A was given and B was not "evidence": # the observations B needs, with # sources — not A's conclusions alone "done_when": # the check B's output must pass, # so the result is verifiable alone }
The instruction-decay failure

The user says "keep it under 400 words and cite every claim." The supervisor passes the topic to a writer but not the word limit. The writer produces 900 excellent words. A formatter agent trims to 400 by deleting the citations — the only instruction it was given was the length.

No agent malfunctioned. Every agent did its job correctly on the input it received. The system still violated the user's requirement, because the requirement was never in the payload. That is a specification and design failure in the MAST taxonomy (Cemri et al., 2025) — and you will meet it again on page 02.

Watch

Orchestration patterns that survive production

From Chaos to Choreography (AI Engineer, 26m28s)

Sandipan Bhaumik surveys the orchestration patterns that hold up in real deployments and the ones that quietly fall over — the same four shapes you just clicked through, argued from production experience.

Fully local multi-agent systems with LangGraph (LangChain, 13m14s)

The vendor-official walkthrough, in the framework introduced at the top of this page. Watch specifically for where the graph decides routing — in LangGraph, "which agent goes next" is just another conditional edge.

Zoom out

Frameworks are dialects

Four popular libraries, one set of ideas. If you understand state, hand-offs, and who owns control flow, you can read any of them in an afternoon — and you should choose on operational grounds (observability, control, your team's language), not on which vocabulary sounds most impressive.

FrameworkIts vocabularyWhere control flow livesWhat it is good at
LangGraph
repo ↗
State, nodes, edges — agents are nodes, hand-offs are edgesExplicitly yours. The graph is the org chart; routing is a conditional edge you wrote (Week 4).Auditable control flow, loops with guards, teams that need to show an auditor the diagram.
crewAI
(this week's course)
Agents with roles and goals, tasks, crews, processes (sequential or hierarchical)In the crew configuration — you declare roles and a process, the library runs it.Getting a role-based team running quickly; the clearest on-ramp to the mental model.
AutoGen
(Wu et al., 2023 · arXiv:2308.08155)
Conversable agents exchanging messages; group chat with a chat managerIn the conversation: agents talk, and the message protocol drives the work.Agent-to-agent messaging as the primitive; human-in-the-loop configurations. repo ↗
MetaGPT
(Hong et al., 2023 · arXiv:2308.00352)
Roles from a software company (PM, architect, engineer) with standardized operating proceduresIn the encoded SOP: the procedure constrains what each role may produce and hand on.Its argument is worth the read on its own — structured, standardized hand-off artifacts as a defense against cascading errors.
The MetaGPT idea, stated plainly: if free-form hand-offs are where multi-agent systems lose information, then constrain the hand-off to a standard artifact — a spec document, a design doc, a typed record — instead of a paragraph of prose. That is the same instinct as the hand-off contract above, and the same instinct as a schema on a tool call in Week 5.
Concept check

Which pattern, and why?

← BackWeek 9 home