CrewAI Multi-Agents · Lesson 10 of 16
Task Dependencies and Context Passing
Task Dependencies in CrewAI
In a multi-task crew, later tasks often need the output from earlier tasks. CrewAI provides two mechanisms:
- Sequential dependency (implicit): in
Process.sequential, each task receives the output of the previous task automatically - Explicit context (recommended): use
context=[task1, task2]to pass specific task outputs to a task
Explicit context is clearer and gives you fine-grained control over which outputs flow where.
Sequential Dependency (Implicit)
In the default sequential process, tasks run in order. Each task's output is appended to the agent's context:
from crewai import Agent, Task, Crew, Process
researcher = Agent(
role="Drug Researcher",
goal="Research pharmaceutical compounds",
backstory="Expert in pharmacology with 15 years of experience",
verbose=True,
)
writer = Agent(
role="Medical Writer",
goal="Create patient-friendly drug information content",
backstory="Experienced medical writer focused on clarity and safety",
verbose=True,
)
research_task = Task(
description="Research ibuprofen: mechanism, side effects, contraindications, interactions",
expected_output="Comprehensive research report on ibuprofen covering all key clinical aspects",
agent=researcher,
)
write_task = Task(
description="Write a patient information leaflet for ibuprofen based on the research",
expected_output="Patient-friendly leaflet (500 words) covering what ibuprofen is, when to use it, side effects, and warnings",
agent=writer,
# In sequential process, the research_task output is automatically available
# But it's buried in the conversation context — not explicitly passed
)
crew = Crew(
agents=[researcher, writer],
tasks=[research_task, write_task],
process=Process.sequential,
)
result = crew.kickoff()Explicit Context (Recommended)
Use context=[task] to explicitly pass specific task outputs:
write_task = Task(
description=(
"Write a patient information leaflet for ibuprofen. "
"Use the research findings provided in your context."
),
expected_output="Patient-friendly leaflet (500 words) with sections: What Is It, How to Use, Side Effects, Warnings",
agent=writer,
context=[research_task], # Explicitly pass research_task output
)
safety_review_task = Task(
description="Review the patient leaflet for safety accuracy and completeness",
expected_output="Safety review report: list of accurate statements, any corrections needed, overall rating 1-5",
agent=safety_officer,
context=[research_task, write_task], # Needs both research AND the draft leaflet
)With explicit context:
- The writer sees only the research task output — clean, focused context
- The safety reviewer sees both the original research AND the draft leaflet
- Dependencies are explicit and visible in the code
Avoiding Information Loss
The most common mistake in multi-task pipelines: earlier tasks gather detailed information, but later tasks receive only a summary.
Problem pattern:
research_task = Task(
description="Research ibuprofen",
expected_output="A brief summary", # ← Too vague — agent will summarize heavily
agent=researcher,
)
write_task = Task(
description="Write a leaflet based on research",
context=[research_task], # Writer receives a brief summary, not the full research
...
)Fix — be specific in expected_output:
research_task = Task(
description="Research ibuprofen thoroughly",
expected_output=(
"A structured research report with these exact sections:\n"
"1. Mechanism of action\n"
"2. Approved indications\n"
"3. Common side effects (list at least 8)\n"
"4. Serious adverse events\n"
"5. Contraindications\n"
"6. Drug interactions (list at least 5)\n"
"7. Dosage ranges by population\n"
"8. Special populations (pregnancy, elderly, renal impairment)"
),
agent=researcher,
)expected_output is the primary mechanism that controls what the agent produces. If it's vague, the agent produces a summary. Be specific about structure and content.
Accessing Task Output
After crew.kickoff(), access individual task outputs:
result = crew.kickoff()
# Access the final crew output
print(result.raw) # Final task output as string
print(result.pydantic) # If output_pydantic was set
print(result.json_dict) # If output_json was set
# Access individual task outputs
for task in crew.tasks:
print(f"Task: {task.description[:50]}")
print(f"Output: {task.output.raw[:200]}")
print("---")Full Example: Drug Information Pipeline
Three tasks with explicit dependencies:
from crewai import Agent, Task, Crew, Process
from pydantic import BaseModel
class DrugResearch(BaseModel):
drug_name: str
mechanism: str
indications: list[str]
side_effects: list[str]
interactions: list[str]
contraindications: list[str]
# Agents
researcher = Agent(role="Pharmacologist", goal="Research drugs accurately", backstory="...", verbose=True)
writer = Agent(role="Medical Writer", goal="Write clear patient content", backstory="...", verbose=True)
reviewer = Agent(role="Safety Officer", goal="Ensure medical accuracy", backstory="...", verbose=True)
# Task 1: Research (structured output)
research_task = Task(
description="Research {drug_name} and return structured data",
expected_output="JSON matching DrugResearch schema with all fields complete",
agent=researcher,
output_pydantic=DrugResearch,
)
# Task 2: Write (uses research)
write_task = Task(
description="Write a patient information leaflet for {drug_name}",
expected_output="500-word patient leaflet with sections: Purpose, Usage, Side Effects, Warnings, When to See a Doctor",
agent=writer,
context=[research_task], # Receives structured research
)
# Task 3: Review (uses both research and draft)
review_task = Task(
description="Review the draft leaflet against the original research for accuracy",
expected_output="Review report: confirmed accurate sections, corrections needed, final verdict",
agent=reviewer,
context=[research_task, write_task], # Needs both
)
crew = Crew(
agents=[researcher, writer, reviewer],
tasks=[research_task, write_task, review_task],
process=Process.sequential,
)
result = crew.kickoff(inputs={"drug_name": "Ibuprofen"})The {drug_name} template syntax in task descriptions is filled at kickoff time via the inputs dictionary.