CrewAI Structured Output: Stop Data Drift with Pydantic

2 min read

If you have seen one task return markdown this time and a free-form essay next time, you are not alone.
The fix is straightforward: define output schema with Pydantic.

Why structured output?

  • Downstream tasks can read fixed fields
  • No brittle string parsing every run
  • Failures are caught earlier (field mismatch throws errors)

It is basically an API contract. Stable collaboration needs a contract.

Create output models

from pydantic import BaseModel, Field
 
class Finding(BaseModel):
    title: str = Field(description="Finding title")
    summary: str = Field(description="Brief explanation")
    source: str = Field(description="Reference URL")
 
class ResearchReport(BaseModel):
    topic: str = Field(description="Topic name")
    findings: list[Finding] = Field(description="Key findings list")
    conclusion: str = Field(description="Final conclusion")

Use output_pydantic in task

from crewai import Task
 
research_task = Task(
    description="Research AI observability tools in 2026.",
    expected_output="Structured research result.",
    output_pydantic=ResearchReport,
)

After execution, you can access stable fields directly instead of guessing from text.

  • Keep expected_output quality requirements explicit
  • Define field semantics (summary length, source format)
  • Make downstream tasks rely on fields, not writing style

Common beginner mistakes

  1. Thinking Pydantic means expected_output is unnecessary
  2. Too few fields, resulting in missing information
  3. Too many granular fields, causing frequent omissions

⚠️ Start with 3-5 key fields first. Expand only when needed.

Next step

Now your single crew can output reliably. Next, we move to multi-crew orchestration.
👉 Flow Basics