CrewAI Multi-Agents · Lesson 13 of 16
Sequential Process: Tasks Run in Order
What is the Sequential Process?
Process.sequential is the default CrewAI execution mode. Tasks run one at a time, in the order they appear in the tasks list. Each task's output is passed forward to subsequent tasks through two mechanisms:
- The next task's agent sees prior task outputs in its conversation context
- You can explicitly pass outputs using
context=[task]
Sequential is the right choice when tasks have natural dependencies — output A feeds into task B, which feeds into task C.
Basic Sequential Flow
from crewai import Agent, Task, Crew, Process
# Agents
researcher = Agent(
role="Drug Researcher",
goal="Research pharmaceutical compounds with clinical accuracy",
backstory="PhD pharmacologist with 15 years of clinical research experience",
verbose=True,
)
writer = Agent(
role="Medical Writer",
goal="Write clear, accurate patient-facing drug information",
backstory="Former pharmacist turned technical writer, specializes in patient education",
verbose=True,
)
reviewer = Agent(
role="Clinical Reviewer",
goal="Ensure medical accuracy and regulatory compliance of drug content",
backstory="Former FDA reviewer with expertise in drug labeling requirements",
verbose=True,
)
# Tasks — run in this exact order
research_task = Task(
description="Research Metformin comprehensively: mechanism, indications, side effects, contraindications, interactions",
expected_output=(
"Structured report with sections:\n"
"1. Mechanism of action\n"
"2. Approved indications\n"
"3. Common side effects (minimum 8)\n"
"4. Serious adverse events\n"
"5. Contraindications\n"
"6. Drug interactions (minimum 5)\n"
"7. Dosage ranges\n"
"8. Special populations"
),
agent=researcher,
)
write_task = Task(
description=(
"Write a 600-word patient information leaflet for Metformin "
"based on the research provided in your context."
),
expected_output=(
"Patient leaflet with sections: What Is Metformin, Why Is It Prescribed, "
"How to Take It, Side Effects, Warnings, When to Call Your Doctor"
),
agent=writer,
context=[research_task], # Explicit: receives researcher's output
)
review_task = Task(
description=(
"Review the Metformin patient leaflet against the research data. "
"Identify any inaccuracies, missing warnings, or unclear instructions."
),
expected_output=(
"Review report with: "
"(1) Confirmed accurate sections, "
"(2) Corrections required (if any), "
"(3) Missing information, "
"(4) Readability score 1-5, "
"(5) Final verdict: approved or revision required"
),
agent=reviewer,
context=[research_task, write_task], # Receives both
)
crew = Crew(
agents=[researcher, writer, reviewer],
tasks=[research_task, write_task, review_task],
process=Process.sequential,
verbose=True,
)
result = crew.kickoff()
print(result.raw) # Final task output (the review)How Output Flows in Sequential Mode
In sequential mode, CrewAI builds the context window progressively:
Task 1 runs → output stored
↓
Task 2 runs → sees Task 1 output in context (implicitly or via context=[task1])
↓
Task 3 runs → sees Task 2 output in context + any context=[] additions
↓
Final crew output = Task 3 outputThe context=[task] parameter is explicit — it tells CrewAI to inject that task's full output into the agent's prompt before it starts. Without it, the agent still receives prior outputs (in sequential mode) but they're buried in the conversation history rather than explicitly surfaced.
Recommendation: Always use explicit context=[task] rather than relying on implicit chaining. It makes dependencies visible and avoids context pollution from unrelated earlier tasks.
Task Templates and Input Variables
Use {variable} placeholders in task descriptions — they're filled at kickoff() time:
research_task = Task(
description=(
"Research {drug_name} comprehensively. "
"Target audience: {audience}. "
"Focus on: {focus_area}."
),
expected_output="Comprehensive research report covering all standard drug information fields",
agent=researcher,
)
crew.kickoff(inputs={
"drug_name": "Atorvastatin",
"audience": "patients with cardiovascular disease",
"focus_area": "drug interactions with other cardiac medications",
})All tasks in the crew receive the same inputs dict — placeholders in any task description are filled from this single source.
Full Pharmaceutical Content Pipeline
A four-task sequential pipeline for drug content production:
from crewai import Agent, Task, Crew, Process
from pydantic import BaseModel
class DrugProfile(BaseModel):
drug_name: str
drug_class: str
mechanism: str
indications: list[str]
contraindications: list[str]
interactions: list[str]
dosing: dict[str, str] # population -> dose
# Four specialized agents
data_researcher = Agent(
role="Pharmacological Data Researcher",
goal="Extract accurate drug data from medical literature",
backstory="Specializes in systematic review of pharmacological literature",
verbose=True,
)
clinical_writer = Agent(
role="Clinical Content Writer",
goal="Transform research data into accurate clinical summaries",
backstory="Medical writer with clinical pharmacy background",
verbose=True,
)
patient_educator = Agent(
role="Patient Education Specialist",
goal="Simplify medical content for patient audiences (Grade 8 reading level)",
backstory="Former health literacy researcher, expert in plain-language medical writing",
verbose=True,
)
compliance_reviewer = Agent(
role="Regulatory Compliance Reviewer",
goal="Ensure all drug content meets FDA/EMA labeling standards",
backstory="15 years reviewing drug package inserts at a regulatory agency",
verbose=True,
)
# Task 1: Structured data extraction
data_task = Task(
description="Research {drug_name} and extract all pharmacological data",
expected_output="Complete drug profile JSON matching DrugProfile schema",
agent=data_researcher,
output_pydantic=DrugProfile,
)
# Task 2: Clinical summary (uses structured data)
clinical_task = Task(
description=(
"Write a clinical summary of {drug_name} for healthcare providers. "
"Base it on the research data in your context."
),
expected_output=(
"Clinical summary (400 words) with: "
"Pharmacology, Clinical Use, Dosing Guidelines, Safety Considerations"
),
agent=clinical_writer,
context=[data_task],
)
# Task 3: Patient leaflet (uses clinical summary as source of truth)
patient_task = Task(
description=(
"Convert the clinical summary of {drug_name} into a patient information leaflet. "
"Grade 8 reading level. No medical jargon."
),
expected_output=(
"Patient leaflet (300 words) with plain-language sections: "
"What Is This Medicine, How To Take It, Side Effects, When To Call Your Doctor"
),
agent=patient_educator,
context=[clinical_task],
)
# Task 4: Compliance review (reviews all three)
compliance_task = Task(
description=(
"Review all {drug_name} content for regulatory compliance. "
"Check: accuracy of claims, required warnings present, no off-label promotion."
),
expected_output=(
"Compliance report: "
"Issues found (list), required changes (list), overall status: APPROVED / REVISION REQUIRED"
),
agent=compliance_reviewer,
context=[data_task, clinical_task, patient_task],
)
crew = Crew(
agents=[data_researcher, clinical_writer, patient_educator, compliance_reviewer],
tasks=[data_task, clinical_task, patient_task, compliance_task],
process=Process.sequential,
verbose=True,
)
result = crew.kickoff(inputs={"drug_name": "Atorvastatin"})
# Access all outputs
drug_data: DrugProfile = data_task.output.pydantic
print(f"Drug class: {drug_data.drug_class}")
print(f"Interactions: {drug_data.interactions}")
print(f"\nCompliance result:\n{result.raw}")Sequential vs Hierarchical: When to Use Which
| Scenario | Use Sequential | Use Hierarchical | |---|---|---| | Fixed, predictable task order | Yes | No | | Tasks feed into each other linearly | Yes | No | | Dynamic task routing needed | No | Yes | | A manager needs to evaluate and reroute | No | Yes | | Debugging and tracing is priority | Yes | No | | Simple multi-step pipelines | Yes | No |
Sequential process is the right default. Move to hierarchical only when you need dynamic routing or an orchestrating manager agent.
Controlling Output Quality
The quality of each task's output depends on expected_output. Vague descriptions produce summaries; specific descriptions produce complete content:
# Weak — agent will summarize
Task(
expected_output="A summary of the drug",
...
)
# Strong — agent produces complete, usable output
Task(
expected_output=(
"A structured drug research report with ALL of the following:\n"
"- Mechanism of action (2-3 sentences)\n"
"- At least 8 common side effects\n"
"- At least 5 drug interactions with clinical significance\n"
"- Contraindicated populations\n"
"- Dosage for adults, elderly, and renal impairment"
),
...
)The expected_output is the agent's primary instruction for what to produce. Treat it as seriously as the task description itself.