Studying Agentic Architecture and Orchestration: the CCA Exam's Largest Domain
Agentic Architecture & Orchestration is worth 27% of the CCA Foundations exam, more than any other domain.
Search across all documentation pages
Agentic Architecture & Orchestration is worth 27% of the CCA Foundations exam, more than any other domain.
It covers how you design systems where Claude doesn't just answer one question, but plans, calls tools, hands work to other agents, and decides when it's done.
This article walks through the orchestration patterns that show up most often in exam scenarios, with runnable Python illustrations built on the anthropic SDK.
Multi-agent systems trade simplicity for capability, and the exam tests whether you know when that trade is worth making.
A single well-scoped agent with good tools beats a poorly decomposed multi-agent system almost every time.
The core patterns worth knowing are sequential pipelines, supervisor-worker topologies, and parallel fan-out with a merge step.
Every pattern needs an explicit termination condition, or it risks looping past the point of being useful.
Orchestration questions on the exam usually hinge on picking the smallest architecture that solves the problem, not the most sophisticated one.
Quick-reference recipe card - the minimal shape of a supervisor-worker loop.
from anthropic import Anthropic
client = Anthropic()
def run_worker(task: str, model: str = "claude-sonnet-5") -> str:
"""A single-purpose worker agent that does one job and returns."""
response = client.messages.create(
model=model,
max_tokens=1024,
system="You are a focused worker agent. Do exactly the task given. Return only the result.",
messages=[{"role": "user", "content": task}],
)
return response.content[0].text
def run_supervisor(goal: str, max_steps: int = 5) -> str:
"""A supervisor that decomposes a goal into worker tasks and stops on completion."""
completed_work = []
for step in range(max_steps):
plan_prompt = f"Goal: {goal}\nCompleted so far: {completed_work}\nNext single subtask, or DONE if finished:"
plan = run_worker(plan_prompt, model="claude-sonnet-5")
if plan.strip().upper().startswith("DONE"):
break
result = run_worker(plan)
completed_work.append({"task": plan, "result": result})
return "\n".join(w["result"] for w in completed_work)When to reach for this:
from anthropic import Anthropic
from dataclasses import dataclass
client = Anthropic()
@dataclass
class AgentResult:
agent_name: str
output: str
def draft_agent(topic: str) -> AgentResult:
response = client.messages.create(
model="claude-sonnet-5",
max_tokens=512,
system="You draft a short technical outline. Return only the outline, no preamble.",
messages=[{"role": "user", "content": f"Outline: {topic}"}],
)
return AgentResult("draft", response.content[0].text)
def critic_agent(draft: str) -> AgentResult:
response = client.messages.create(
model="claude-opus-4-8",
max_tokens=512,
system="You critique a technical outline for gaps and factual risk. Be terse. Return only the critique.",
messages=[{"role": "user", "content": draft}],
)
return AgentResult("critic", response.content[0].text)
def reviser_agent(draft: str, critique: str) -> AgentResult:
response = client.messages.create(
model="claude-sonnet-5",
max_tokens=768,
system="You revise a draft outline given a critique. Return only the revised outline.",
messages=[{"role": "user", "content": f"Draft:\n{draft}\n\nCritique:\n{critique}"}],
)
return AgentResult("reviser", response.content[0].text)
def orchestrate_draft_critique_revise(topic: str) -> str:
"""A three-agent sequential pipeline: draft -> critic -> reviser.
Each agent has one job and a narrow system prompt, which is the
pattern the exam calls 'single-responsibility agent design.'
"""
draft = draft_agent(topic)
critique = critic_agent(draft.output)
final = reviser_agent(draft.output, critique.output)
return final.output
if __name__ == "__main__":
result = orchestrate_draft_critique_revise("Zero-downtime database migration strategy")
print(result)What this demonstrates:
| Pattern | Shape | Best for | Termination |
|---|---|---|---|
| Sequential pipeline | A -> B -> C | Known, fixed number of transformation steps | Fixed length, no loop needed |
| Supervisor-worker | Supervisor plans, dispatches to workers | Unknown subtask count, decomposable goals | Supervisor emits DONE or hits step budget |
| Parallel fan-out | One dispatcher, N concurrent workers, one merge | Independent subtasks, latency-sensitive | All workers return, or a timeout fires |
| Single agent + tools | One agent, multiple tool calls in one loop | Most production tasks; simplest to reason about and debug | Agent stops requesting tools |
MAX_STEPS = 8
def safe_supervisor_loop(goal: str) -> str:
step = 0
history = []
while step < MAX_STEPS:
step += 1
next_action = run_worker(f"Goal: {goal}\nHistory: {history}\nNext step or DONE:")
if "DONE" in next_action.upper():
break
history.append(next_action)
else:
# Loop exhausted MAX_STEPS without a DONE signal - treat as a failure, not a success.
raise RuntimeError(f"Supervisor did not terminate within {MAX_STEPS} steps for goal: {goal}")
return "\n".join(history)A hard step budget combined with an explicit failure path (rather than silently returning a partial result) is the pattern the exam rewards: an agent that can't tell you it failed is worse than one that raises.
# Prefer typed dataclasses or TypedDicts for inter-agent payloads over raw dicts,
# so a schema mismatch between agents fails fast instead of surfacing as a
# confusing downstream prompt-formatting bug.
from typing import TypedDict
class SubtaskResult(TypedDict):
agent: str
task: str
output: str| Alternative | Use When | Don't Use When |
|---|---|---|
| Single agent with a tool loop | The task is bounded and one agent with tools can reason through it end to end | The task genuinely requires distinct roles or independent parallel work |
| Sequential pipeline | Steps and their order are known ahead of time | The number or order of steps depends on intermediate results |
| Supervisor-worker | Subtask count is unknown until runtime and the goal decomposes cleanly | The goal is simple enough that decomposition adds overhead without benefit |
| Parallel fan-out | Subtasks are independent and latency matters more than coordination cost | Subtasks depend on each other's output, which forces you back to sequential |
Because orchestration decisions (single agent vs. multi-agent, which topology, how termination is handled) tend to be the decisions that make or break a production system's reliability, more than any single prompt or tool definition does.
No. A single well-scoped agent with good tools is often more reliable and cheaper than a poorly decomposed multi-agent system; the exam specifically tests judgment about when multi-agent adds real value versus just coordination overhead.
Any loop where the exit condition depends on the model's own output (like emitting "DONE") needs a hard step ceiling as a backstop, since a model can fail to emit that signal.
Not necessarily. Matching a stronger model to judgment-heavy steps (like critique or synthesis) and a faster model to mechanical steps (like drafting or formatting) is a cost-and-quality trade-off the exam expects you to reason about.
It refers to deciding exactly what information passes from one agent to the next, rather than defaulting to passing the entire conversation history, which inflates token cost with every additional agent in the chain.
No, it's typically not cheaper. Fan-out reduces wall-clock latency by running independent calls concurrently, but each call still costs the same in tokens; don't confuse "faster" with "cheaper."
Defaulting to the most complex architecture (multi-agent, multi-step) when a single agent with better tool design solves the scenario more reliably and cheaply.
They overlap heavily: whether an agent needs a helper agent or just a better tool is itself an orchestration decision, and a badly scoped tool often masquerades as an "orchestration problem" on the exam.
The merge strategy should be decided before dispatch, whether that's a supervisor arbitrating between outputs, majority vote, or straightforward concatenation, rather than improvised after the fact.
The domain tests the underlying patterns (sequential, supervisor-worker, parallel fan-out, single-agent-plus-tools) and the judgment behind choosing between them, not memorization of any particular third-party framework's API.
Typed payloads make schema mismatches between agents fail fast and visibly, instead of surfacing later as a confusing formatting bug inside a downstream prompt.
Stack versions: Written against the Claude model lineup current as of ~June 2026 - Claude Fable 5, Claude Opus 4.8, Claude Sonnet 5 (the default), and Claude Haiku 4.5 - and the official
anthropicPython SDK (latest 0.x release). Model names, pricing, exam format, and SDK versions move quickly - verify current specifics at platform.claude.com/docs and the official CCA exam guide before relying on them.
Reviewed by Chris St. John·Last updated Jul 13, 2026