Evaluate role-based multi-agent workflows and their tradeoffs.
Trace why splitting work across named, specialized agents emerged as a pattern, and identify the structural difference between a role-based crew and a single-agent loop. The running scenario throughout this lesson is a research-and-report pipeline: a Researcher, an Analyst, and a Writer agent collaborating to produce a briefing document.
Explains why role-based multi-agent design emerged and how it structurally differs from a single-agent loop.
Why this matters: Understanding this pattern is the foundation for every multi-agent system you'll build — get the role boundaries wrong here and every downstream module compounds the mistake.
You've built a single-agent loop that can search, reason, and write. Now imagine asking it to research a topic, analyse findings, and produce a polished briefing — all in one context window. What breaks first?
The agent's instructions become a tangle of competing goals: be thorough (researcher), be critical (analyst), be concise (writer). Each role pulls the prompt in a different direction.
The deeper problem is : breaking a complex job into sub-tasks that can be owned, sequenced, and verified independently. A single loop can't own sub-tasks — it just does everything at once.
A is an whose system prompt is scoped to a single responsibility: a name, a goal, and a constraint on what it should and shouldn't do.
Each agent owns exactly one . Its output becomes the next agent's input via . Errors stay local and are easier to catch.
A of role-based agents can run (each hands off to the next) or (a manager routes and merges). The pattern earns its complexity only when sub-tasks genuinely differ in skill or context.
The lesson's running example is a research-and-report pipeline with three agents: a Researcher, an Analyst, and a Writer.
The Researcher searches the web and returns sourced findings — nothing more. It doesn't interpret or write prose.
The Analyst receives those findings via and produces a structured summary: key claims, confidence levels, and gaps. It doesn't search or write narrative.
The Writer takes the structured summary and produces the final briefing. It doesn't re-research or re-analyse.
def run_single_agent(topic: str) -> str: prompt = ( "You are a researcher, analyst, and writer. " f"Research '{topic}', analyse the findings, " "and write a polished briefing." ) response = llm.complete(prompt) # one call, one context return response.text
llm.complete(prompt)"You are a researcher, analyst, and writer."This is the obvious first attempt: one prompt, one agent, all three jobs. Predict what the output looks like before revealing.
The model produces a single block of text that blends raw facts, hedged opinions, and polished prose — none done well. Sources are paraphrased without citation, the analysis section is vague ('this could be significant'), and the briefing reads like a rough draft. There is no way to verify which step failed because there are no intermediate outputs. The model satisfied the prompt syntactically but decomposed nothing.
def make_agent(role: str, goal: str) -> dict: return {"role": role, "goal": goal, "history": []} researcher = make_agent("Researcher", "Find sourced facts about the topic. Return bullet points only.") analyst = make_agent("Analyst", "Given research findings, extract key claims and flag gaps.") writer = make_agent("Writer", "Turn the analyst's summary into a concise briefing document.") agents = [researcher, analyst, writer] # sequential order
make_agent(role, goal)agents = [researcher, analyst, writer]Each agent now has a single scoped goal. Predict what changes in the output quality when you run them in sequence versus the single-agent version.
Improvements: the Researcher returns only sourced bullets (verifiable), the Analyst's summary is structured (checkable), and the Writer's prose is grounded in a clean input. New problem: if the Researcher returns poor-quality or off-topic findings, the error propagates silently through the Analyst and Writer — the pipeline has no validation step between roles. Context passing without a quality gate is the next thing to solve.
def run_pipeline(topic: str, agents: list) -> str: context = topic for agent in agents: prompt = ( f"Role: {agent['role']}\n" f"Goal: {agent['goal']}\n" f"Input:\n{context}" ) # TODO: call llm.complete(prompt) and update context context = ___________________________ return context
for agent in agents:f"Role: {agent['role']}\nGoal: {agent['goal']}\nInput:\n{context}"context = llm.complete(prompt).textThe handoff loop is almost complete. Stop — attempt the TODO before revealing: what single line replaces the blank to wire each agent's output as the next agent's input?
context = llm.complete(prompt).text
Changed line: the blank becomes llm.complete(prompt).text — this calls the LLM with the scoped prompt and stores the text output as the next agent's input context. Every other line stays the same. This is the core of context passing: each agent's Task Output feeds directly into the next role's prompt, creating a verifiable chain rather than one opaque call.
Three failure modes dominate in practice — and two of them are silent.
Map the four CrewAI objects (Agent, Task, Crew, Process) onto the research-and-report scenario and read a worked code pattern showing how role, goal, backstory, and task description wire together. You'll complete a partial crew definition by filling in the missing task context_from field.
Maps CrewAI's four core objects — Agent, Task, Crew, and Process — onto the research-and-report pipeline and shows how role, goal, backstory, and context wiring connect them in code.
Why this matters: These four objects are the vocabulary you'll use in every CrewAI build; getting their relationships right is what separates a working multi-agent pipeline from one that silently fails.
Decision this forces: Sequential vs. hierarchical process for the research-and-report crew.
Module 1 showed that a single-agent loop accumulates every responsibility — research, analysis, writing — in one prompt, so quality degrades as the task grows. Splitting work across named with distinct keeps each agent's context focused and its outputs auditable.
Now the question is: how does CrewAI actually wire those roles together in code? This module maps the four core objects — Agent, Task, Crew, and Process — onto the research-and-report scenario you'll build throughout this lesson.
CrewAI has four objects that map onto the research-and-report pipeline. Each has one job and composes in predictable order.
Agent defines who. Task defines what. Crew defines how they assemble. Process defines in what order.
In the research-and-report pipeline, three agents cover three jobs. Each job becomes a Task whose output feeds the next.
Crew holds all three agents and tasks. Process determines whether Researcher finishes before Analyst starts (sequential) or manager reorders them (hierarchical).
The between Researcher and Analyst is the handoff point. Analyst's context list must explicitly name the research task, or it works blind.
researcher = Agent( role="Research Specialist", goal="Find credible sources on {topic} and extract key facts", backstory="You are a rigorous analyst who cites evidence.", tools=[search_tool], ) research_task = Task( description="Search for recent findings on {topic}.", expected_output="A bullet list of 5 key facts with sources.", agent=researcher, )
role=goal=backstory=tools=[search_tool]expected_output=agent=researcherThis is the minimal Agent + Task pair for the Researcher role. The backstory is not decoration — it shapes how the LLM reasons about its own authority and style.
research_task.output holds a TaskOutput object whose .raw field is the agent's text response — a bullet list of 5 key facts about climate tipping points. No other agent has seen it yet; context hasn't been wired.
analysis_task = Task( description="Synthesize the research into 3 key insights.", expected_output="A numbered list of insights with evidence.", agent=analyst, context=[research_task], # <-- output of research_task flows in ) crew = Crew( agents=[researcher, analyst, writer], tasks=[research_task, analysis_task, write_task], process=Process.sequential, ) result = crew.kickoff(inputs={"topic": "climate tipping points"})
context=[research_task]Process.sequentialcrew.kickoff(inputs={...})The context=[research_task] line is the wiring that makes the Analyst aware of the Researcher's output. Without it, the Analyst starts from scratch and the pipeline breaks silently.
With Process.sequential, tasks run in list order. analysis_task executes first, before research_task has produced any output, so context=[research_task] resolves to an empty or None output. The Analyst proceeds with no research data — a silent failure with no error raised.
write_task = Task( description="Write a 3-paragraph report section on {topic}.", expected_output="Polished prose with an intro, body, and conclusion.", agent=writer, context=[___________], # TODO: fill this in ) crew = Crew( agents=[researcher, analyst, writer], tasks=[research_task, analysis_task, write_task], process=Process.sequential, )
context=[analysis_task]# TODO: fill this inStop — attempt the TODO before revealing the answer. The Writer needs the Analyst's synthesized insights, not the raw research. Which task object should appear in context[], and why not both?
context=[analysis_task]
Changed line: context=[analysis_task] — the Writer receives the Analyst's numbered insight list, which already incorporates the research. Adding research_task as well would duplicate data in the prompt and risk hitting context-length limits. The crux: always wire to the most-processed upstream output, not every upstream task.
| Option | Output predictability | Handles dynamic task order | When to choose | Cost | Complexity |
|---|---|---|---|---|---|
| Sequential Process | High — deterministic execution order | No — order is fixed at definition time | Use when tasks have a fixed, known order — e.g. research → analyze → write — and each step's input is the previous step's output. | Lower token cost; no manager LLM call. | Low — list tasks in order and wire context[]. |
| Hierarchical Process | Lower — manager decisions vary by run | Yes — manager can reorder or retry | Use when a manager agent needs to decide which specialist to call next, retry a task, or delegate based on intermediate results. | Higher token cost; manager adds an extra LLM call per decision. | Higher — requires a manager agent and careful role prompting. |
Three failure patterns appear repeatedly in research-and-report crews.
context=[research_task] on Analyst task. Analyst runs without error but hallucinates findings. Fix: check every downstream task's context list before kickoff.analysis_task appears before research_task in tasks=[], context resolves to None. Fix: match list order to data-flow order.Examine how CrewAI moves context between agents — through task output chaining, the shared state object, and delegation — using the Researcher→Analyst→Writer handoff as the worked example. You'll complete a context-chain snippet where the Analyst's task is missing its input binding.
How CrewAI moves data between agents — through task output chaining, shared kickoff inputs, and delegation — traced through the Researcher→Analyst→Writer pipeline.
Why this matters: Getting context flow right is the difference between a crew that compounds each agent's work and one where every agent starts from scratch, producing incoherent final output.
Decision this forces: Whether to use explicit task context chaining vs. agent delegation for inter-agent communication.
The Crew object owns execution order. It supports two modes: sequential (tasks run one after another) and hierarchical (a manager agent delegates). Module 2 showed how role, goal, and backstory wire an agent to its task. But it left open a key question: once Task A finishes, how does its output reach Task B's agent?
CrewAI moves information between agents through three distinct mechanisms, and mixing them up is the most common source of silent data loss.
context=[upstream_task], so its agent automatically receives the prior task's output as part of its prompt.crew.kickoff(inputs={...}) is available to every task via template variables like {topic}.allow_delegation=True can hand a sub-task to another agent at runtime, without a pre-declared task edge.Sequential crews mostly rely on chaining; delegation is an escape hatch for dynamic sub-tasks you can't fully script in advance.
researcher = Agent( role="Research Specialist", goal="Find key facts about {topic}", backstory="You surface accurate, sourced findings.", ) research_task = Task( description="Research recent developments in {topic}.", expected_output="A bullet list of 5 key findings.", agent=researcher, )
Agent(role=, goal=, backstory=)Task(description=, expected_output=, agent=){topic}This is the Researcher's task in isolation — no context binding yet, so its output exists only on the task object and goes nowhere automatically.
Notice {topic} in both the agent goal and task description — these are filled from kickoff(inputs={}) at runtime.
Nothing — without context=[research_task] on the Analyst's task, the Researcher's output is never injected into the Analyst's prompt. The Analyst starts cold, with only its own task description.
analyst = Agent( role="Data Analyst", goal="Identify trends from research findings on {topic}", backstory="You turn raw findings into structured insights.", ) analysis_task = Task( description="Analyse the research findings and extract 3 key trends.", expected_output="A ranked list of trends with one-line rationale each.", agent=analyst, context=[research_task], # <-- injects Researcher output here ) writer_task = Task( description="Write a 300-word report on {topic} using the analysis.", expected_output="A polished report ready for publication.", agent=writer, context=[analysis_task], # <-- injects Analyst output here )
context=[research_task]context=[analysis_task]Adding context=[research_task] to the Analyst's task is the single line that closes the gap from Stage 1. CrewAI serialises the upstream task's output and prepends it to the downstream agent's prompt.
The Writer chains from the Analyst the same way — each hop is explicit, so you can trace the full data path just by reading the context= arguments.
The prompt contains: (1) the Analyst agent's role/goal/backstory, (2) the analysis_task description and expected_output, AND (3) the full text of research_task's output, injected by CrewAI because of context=[research_task]. The Analyst effectively sees the Researcher's bullet list before it reasons.
# Researcher and research_task are already defined (Stage 1). # Writer and writer_task are already defined (Stage 2). analyst = Agent( role="Data Analyst", goal="Identify trends from research findings on {topic}", backstory="You turn raw findings into structured insights.", ) analysis_task = Task( description="Analyse the findings and extract 3 key trends.", expected_output="A ranked list of trends with one-line rationale each.", agent=analyst, # TODO: bind the correct upstream task output here )
# TODO: bind the correct upstream task output hereStop — attempt the TODO before revealing. The Analyst must receive the Researcher's output. Which argument do you add, and what value does it take?
context=[research_task]
Changed line: replace the TODO comment with context=[research_task].
Why a list: CrewAI accepts multiple upstream tasks (e.g. context=[task_a, task_b]) so it can merge several outputs into one prompt — even when you only need one, the argument is always a list.
context=[writing_task] on the Analyst (a future task). CrewAI may raise an ordering error or inject an empty string. Symptom: AttributeError or blank context.allow_delegation=True delegate to each other. The crew never terminates. Tokens burn until timeout. Symptom: runaway LLM calls, no final output.context= argument. AI assistants often omit it. The crew runs silently wrong.{topic} value first. Print each task's raw output. Confirm the chain flows before using expensive inputs.Once your context chain is solid, the next question is cost. Adding agents multiplies latency and token spend. The next module quantifies these scalability and complexity tradeoffs.
Quantify how latency and token cost scale with agent count in the research-and-report crew, and identify the coordination overhead that appears when tasks have ambiguous boundaries. You'll revisit the role concept from Module 1 to evaluate whether each agent in a given crew earns its place.
Quantifies how latency and token cost grow with each agent added to a sequential crew, and teaches a three-part test to decide whether a proposed role earns its place.
Why this matters: Prevents you from building crews that are slower and more expensive than a single agent — a common and costly mistake in multi-agent systems.
Answer: each agent's result wraps in a object. The next task's list pulls that object in. This chain is the research-and-report spine — and it compounds cost and latency as agents multiply.
Module 4 asks: does every agent earn its place, or does each one just multiply the bill?
In a , total latency sums every agent's inference time. Total token cost sums every agent's input-plus-output tokens.
Each new agent adds one full LLM call: its prompt (including prior output) plus its response. Context grows downstream, so later agents cost more per call.
Break-even rule: an extra agent pays only if it cuts total work more than it adds in overhead.
Imagine the crew gains a fourth agent: a "Fact Checker" tasked to "verify the accuracy of research findings."
The Researcher's task already says "gather and validate sources." Both claim source validation — a overlap.
At runtime: Researcher calls web-search and checks sources (call #1). Fact Checker receives that output, re-reads the same sources, and verifies them (call #2). You paid twice for one judgment.
This is : the Fact Checker has a title but no exclusive capability. It holds no different tools, information, or decision rights. Fix it: merge validation into the Researcher's task, or give the Fact Checker a unique tool (e.g. a citation-database API).
agent to the crew, ask: does the proposed bring (1) different tools, (2) different information, or (3) different decision rights?
If all three answers are "no", the role is : you pay latency and tokens for a title, not a capability.
researcher = Agent(role="Researcher", goal="Gather and validate sources on the topic", tools=[web_search]) fact_checker = Agent(role="Fact Checker", goal="Verify the accuracy of the research findings", tools=[web_search]) # same tool! research_task = Task(description="Find and validate 5 sources", agent=researcher) check_task = Task(description="Re-verify the sources found", agent=fact_checker, context=[research_task])
tools=[web_search]context=[research_task]Both agents share the same tool and overlap on 'validate sources' — the Fact Checker will re-run web_search on material the Researcher already validated.
The symptom isn't an error: the crew finishes normally, but you'll see two near-identical tool calls in the logs and pay for both LLM responses.
No exception. The log shows web_search called twice with nearly identical queries — once by the Researcher, once by the Fact Checker. Total tokens roughly double for the validation step. The redundancy is invisible unless you inspect the trace.
researcher = Agent(role="Researcher", goal="Gather raw sources on the topic — no validation", tools=[web_search]) fact_checker = Agent(role="Fact Checker", goal="Cross-check sources against the citation database", tools=[citation_db]) # TODO: replace with the tool that # gives Fact Checker a capability # the Researcher does NOT have research_task = Task(description="Find 5 candidate sources", agent=researcher) check_task = Task(description="Validate each source via citation DB", agent=fact_checker, context=[research_task])
tools=[citation_db]context=[research_task]Stop — attempt this before revealing. The Researcher's goal has been narrowed to raw gathering; the Fact Checker now needs a genuinely distinct tool.
Fill in the TODO: what tool should the Fact Checker hold, and why does that tool satisfy the 'earns its place' test?
The TODO is filled with citation_db — a private citation-database API the Researcher's web_search cannot reach.
Changed lines vs Stage 1:
Result: two non-overlapping tool calls in the log, each justified by a distinct capability.
Drag to see how sequential agent count affects total latency and cost in the research-and-report crew (assumes ~5 s avg inference, ~1 k tokens/call, context growing 20% per hop).
With a clean crew definition, Module 5 pits it against a single-agent loop and deterministic pipeline — so you choose the right architecture for any job.
Compare role-based crews, single-agent loops, and deterministic pipelines across five decision dimensions — task parallelizability, skill diversity, cost tolerance, control needs, and output complexity — using the research-and-report scenario as the test case. You'll apply the framework to a new scenario and choose the right architecture.
A head-to-head comparison of role-based crews, single-agent loops, and deterministic pipelines across five decision dimensions.
Why this matters: Gives you a concrete framework to justify architecture choices with tradeoff reasoning rather than guesswork or habit.
Decision this forces: Role-based crew vs. single-agent loop vs. deterministic pipeline for a given workflow.
The answer: task boundaries. When two agents' responsibilities overlap, they re-request context, produce redundant output, and the coordinator must reconcile both — multiplying tokens and round-trips.
crew still beat a single-agent loop or a plain pipeline — and when does it not?
crew (CrewAI-style), a single-agent loop, and a deterministic pipeline (plain code calling the model at fixed steps).
Five decision dimensions separate them: (1) task parallelizability, (2) skill diversity, (3) cost tolerance, (4) control needs, and (5) output complexity. Each dimension has a threshold — cross it and the simpler architecture breaks down.
The rule of thumb: prefer the simplest thing that works, and add agents only when a single one demonstrably struggles.
Run the research-and-report scenario through each dimension to see why the role-based crew wins there — and where it would lose.
Verdict: the crew wins on skill diversity and output complexity; it loses on cost.
If budget is tight and the report is short, a single-agent loop with a rich prompt is a defensible alternative.
# Scenario: daily competitor price monitor # Sub-task: fetch prices → compare → emit JSON alert # No branching, no synthesis, fixed steps def run_price_monitor(competitors: list[str]) -> dict: raw = fetch_prices(competitors) # deterministic step 1 delta = compare_to_baseline(raw) # deterministic step 2 # TODO: return the alert dict — what goes here? # Hint 1: no LLM call needed; this is pure logic. # Hint 2: the output is a structured dict, not prose. ...
fetch_prices(competitors)compare_to_baseline(raw)build_alert(delta)...This completion task asks you to identify the right architecture for a new scenario — the competitor price monitor — using the same five-dimension framework you just applied to the research-and-report case.
The key move is recognizing that a deterministic pipeline needs no agent framework at all: plain Python functions, zero LLM coordination overhead, and a structured return value.
Replace TODO with: return build_alert(delta)
Changed lines: the return statement (line 8) — it's pure deterministic logic, no LLM call.
Architecture: deterministic pipeline.
Why: all five dimensions point away from a crew — tasks are sequential and fixed (no parallelism), skill diversity is zero (fetch/compare/format are the same 'skill'), cost tolerance is low (a JSON alert doesn't justify 3× LLM calls), control is fully deterministic (no branching on model output), and output complexity is minimal (a structured dict, not a synthesized report). A crew here would be over-decomposition.
| Option | Task parallelizability | Skill diversity needed | Output complexity | When to choose | Cost | Complexity |
|---|---|---|---|---|---|---|
| Role-based Crew (CrewAI) | Supports parallel and sequential task graphs | Each agent carries its own role, tools, and prompt | Designed for multi-section, synthesized outputs | Multi-skill, multi-section jobs where agents can work in parallel or hand off context — e.g. Researcher → Analyst → Writer producing a full report. | Highest — one LLM call per agent per task, plus coordination tokens. | Medium-high — role, goal, backstory, and task wiring; context-chain setup. |
| Single-Agent Loop | Sequential only; no native parallelism | One prompt/tool set; skill diversity is bolted on awkwardly | Fine for single answers; struggles with multi-part synthesis | Focused, sequential tasks where one prompt + tool set is enough — e.g. answering a factual question with web search. | Low — one agent, iterative calls only as needed. | Low — one agent definition, one tool list, one loop. |
| Deterministic Pipeline | Only if you code it explicitly; no agent-driven parallelism | Each step is a fixed function call; no role modeling | Works for structured outputs; poor at open-ended synthesis | Fixed, non-branching flows where every step is known in advance — e.g. extract → format → store with one LLM call per step. | Lowest — minimal LLM calls, no agent overhead. | Low — plain code; no agent framework needed. |
Three failure patterns appear when teams pick the wrong architecture — or the right one, badly configured.
You can now map any workflow onto the five dimensions and name the architecture that fits — with tradeoff reasoning, not just intuition.
The research-and-report crew earns its complexity on skill diversity and output synthesis.
The price monitor doesn't — a pipeline is the honest answer there.
But choosing the right architecture is only half the battle.
role theater over-decomposition task boundary drift.
The next module — Common Pitfalls and Best Practices — gives you a diagnostic framework to spot and fix all four before they reach production.
Diagnose the four most common failure modes in role-based crews — role theater, over-decomposition, missing termination, and task boundary drift — and apply a pre-flight checklist to the research-and-report crew to find and fix one planted bug. You'll also verify AI-generated crew scaffolding against the checklist.
A diagnostic module covering the four most common crew failure modes and a pre-flight checklist to catch them before deployment.
Why this matters: Prevents the most expensive mistakes when shipping a role-based crew — bad output with no error signal is harder to debug than a crash.
The five were: task parallelizability, skill diversity, cost tolerance, control needs, and output complexity. Those dimensions tell you when to use a crew — but not how to prevent failure once committed.
Module 6 is the final gate: you've built the crew, understand the tradeoffs, and now must know how it breaks and catch that before shipping.
Four structural problems cause most crew failures in production. Each is invisible in demos but surfaces under real load or real data.
Role theater and boundary drift are hardest to spot because the crew runs — it just produces mediocre or inconsistent output with no error to trace.
Your research-and-report crew has three agents: Researcher, Analyst, and Writer. A colleague hands you this crew definition and says it's ready to deploy. One planted bug is hiding in it — find it before reading on.
The bug: the Analyst task says "summarize what was found" — that's the Researcher's job. This is : the Analyst duplicates the summary instead of building on it, and the Writer's task has no explicit instruction to use the Analyst's trend output — so the synthesis may be silently dropped.
The fix: rewrite the Analyst task as "Given the Researcher's findings, identify the three most important trends and explain why each matters." The Writer task becomes "Using the Analyst's three trends, write a polished 500-word report." Each task now starts where the previous one ended.
def audit_crew(agents, tasks): issues = [] for agent in agents: if not agent.get("tools"): # role theater check issues.append(f"Role theater risk: '{agent['role']}' has no tools") if len(tasks) > len(agents) * 2: # over-decomposition check issues.append(f"Over-decomposition: {len(tasks)} tasks for {len(agents)} agents") for i, task in enumerate(tasks[1:], start=1): # boundary drift check if tasks[i-1]["expected_output"] not in task["description"]: issues.append(f"Boundary drift: task {i} may not consume task {i-1}'s output") return issues
agent.get("tools")len(tasks) > len(agents) * 2tasks[i-1]["expected_output"] not in task["description"]issues.append(...)This audit function encodes three of the four checklist rules as runnable assertions. It checks for role theater (no tools), over-decomposition (task count vs. agent count), and boundary drift (each task references the prior task's expected output).
Missing termination isn't checked here because it's a runtime property — you catch it by inspecting the crew's max_iter setting and whether each task has a defined expected_output field before kickoff.
It returns a list containing the boundary drift warning for task index 1, because the string "A bullet-point summary of findings" does not appear in the Analyst task's description. The role theater and over-decomposition checks may or may not fire depending on the agents and task count passed in.
agents = [
{"role": "Researcher", "tools": ["web_search"]},
{"role": "Analyst", "tools": []}, # ← is this a problem?
{"role": "Writer", "tools": ["doc_writer"]},
]
tasks = [
{"description": "Search and collect findings.",
"expected_output": "Bullet-point summary of findings"},
{"description": "TODO: rewrite this task description", # ← your task
"expected_output": "Three trends with explanations"},
{"description": "Using the Analyst's three trends, write a 500-word report.",
"expected_output": "Polished report"},
]
print(audit_crew(agents, tasks))"tools": []"TODO: rewrite this task description"This is your guided-practice rung: the crew definition has two issues planted in it. Your job is to fill in the TODO and decide whether the Analyst's empty tools list is a real problem or acceptable.
Changed line — tasks[1]['description']:
"Given the Researcher's 'Bullet-point summary of findings', identify the three most important trends and explain why each matters."
The string 'Bullet-point summary of findings' now appears in the description, so the boundary drift warning for task 1 is gone.
audit_crew prints:
["Role theater risk: 'Analyst' has no tools"]
The Analyst warning remains — that's intentional. Add a comment in the agent definition (e.g. tools=[] # reasoning-only by design) so the audit flag is acknowledged, not silenced.
Failure modes look different depending on which one you face. Here's what you actually observe.
output: None and no exception — the silent worst case.When an AI generates your crew scaffold, run the audit function first — then do these three manual checks the function can't automate.
expected_output field and the crew has a max_iter cap; AI scaffolds routinely omit both.You've traced the full arc: from why role-based crews exist, through how CrewAI wires agents and tasks together, to how context flows, how costs scale, how architectures compare, and finally how crews break and how to catch it.
The four failure modes — , , missing termination, and — are your pre-flight checklist for any crew, AI-generated or hand-written.
The capstone challenge asks you to design and audit a crew from scratch for a new domain. You'll apply every concept from this lesson: role design, task decomposition, context chaining, and the audit function. The checklist you just practiced is the tool you bring to that solo build.
Before reviewing the summary: reconstruct from memory the five decision criteria that separate a role-based crew from a flat architecture, and name the four failure modes that most commonly break a crew in production. Then check your answers against the module sequence.
Apply what you learned to Role-based Multi-Agent Workflows.
A colleague proposes splitting a content pipeline into five CrewAI agents: Researcher, Outliner, Drafter, Editor, and Formatter. Each agent uses the same LLM, the same tools, and receives the same context. Which pitfall does this crew most clearly exhibit?
Role theater is the specific pitfall where agents have convincing role names but no real differentiation — same tools, same LLM, same context means the roles are cosmetic. Task boundary drift describes tasks whose scopes bleed into each other, which isn't the core issue here. Over-decomposition is a real problem but it isn't defined by a fixed agent count — it's about unjustified splits. Sequential process has no hard agent-count ceiling.
You are reviewing a CrewAI crew. Consider this Task definition:
task_b = Task(description='Write the report', agent=writer)
A downstream editor agent needs the writer's output. What is missing?
In CrewAI, a downstream task must explicitly list its upstream tasks in its context field (e.g., context=[task_b]) to receive that output as input. Sequential process runs tasks in order but does not automatically inject prior outputs into every subsequent task's prompt — context chaining is the developer's responsibility. allow_delegation controls whether an agent can hand off subtasks mid-execution, which is unrelated to structured output passing. expected_output is a best practice but not required for the crew to run.
Your workflow has a strict, auditable sequence of steps, no need for dynamic task assignment, and a tight latency budget. Which architecture choice is best justified?
When the sequence is fixed, auditable, and latency-sensitive, a deterministic pipeline or single-agent loop is the right call — a crew adds at least one LLM call per agent, multiplying cost and latency without benefit. A sequential crew still incurs per-agent overhead and is better suited when agents genuinely differ in tools or decision rights. A hierarchical crew adds a manager LLM call on top, making latency worse. Specialization only adds value when agents have genuinely different capabilities — not as a blanket rule.
In your own words, describe the 'different tools, information, or decision rights' test. What question does it answer, and what should you do if an agent fails the test?
This test is the practical gate for justifying each agent in a crew. An agent that doesn't clear at least one of the three bars is a candidate for role theater or over-decomposition. The correct action is to consolidate or eliminate that agent, not to keep it for organizational tidiness.
When does enabling allow_delegation=True on a CrewAI agent make sense, and what is the main risk of enabling it by default on every agent?
Delegation is designed for hierarchical or dynamic scenarios where one agent needs to hand off a subtask to another at runtime — typically a manager-to-worker pattern. Enabling it on every agent by default means any agent can spawn calls to others mid-execution, making the total number of LLM calls unpredictable and potentially causing runaway cost and latency. It does not replace explicit context chaining, which is the correct mechanism for passing structured outputs in a sequential crew. External API rate limits are a separate concern unrelated to delegation.