CrewAI dropped the LangChain dependency around 0.30 and is now a standalone framework. APIs are stable but
Flows, Knowledge, and the @CrewBase decorator pattern continue
to evolve. If a decorator import fails, check the official docs at
docs.crewai.com.
This sheet pins to names current as of May 2026.
Install · env · scaffoldSetup
bash
# pip — core + extras you'll likely need
pip install crewai
pip install 'crewai[tools]' # built-in tool suite
pip install crewai-tools # standalone tools package
# env — pick the providers you'll use
export OPENAI_API_KEY=sk-...
export ANTHROPIC_API_KEY=sk-...
export SERPER_API_KEY=... # optional, web search tool
# scaffold a new project (recommended layout)
crewai create crew my_project
cd my_project && crewai install
crewai run
Where things liveCommon imports
Core abstractions sit in crewai. The bundled tool catalogue lives in
crewai_tools (separate package). Flows and decorators are under
crewai.flow and crewai.project.
from crewai import Agent, Task, Crew, Process
The four core classes.
from crewai import LLM
Provider-agnostic LLM wrapper (LiteLLM under the hood).
from crewai.project import CrewBase, agent, task, crew, before_kickoff, after_kickoff
Decorators for YAML-driven projects.
from crewai.flow.flow import Flow, start, listen, router, and_, or_
Event-driven Flows API.
from crewai.tools import BaseTool, tool
Build custom tools.
from crewai_tools import SerperDevTool, ScrapeWebsiteTool, FileReadTool
Prebuilt tools (web, scraping, files).
from crewai_tools import RagTool, PDFSearchTool, DirectorySearchTool
RAG-style search tools.
from crewai.knowledge.source.text_file_knowledge_source import TextFileKnowledgeSource
Knowledge sources for agents/crews.
from crewai.memory import LongTermMemory, ShortTermMemory, EntityMemory
Built-in memory stores.
from pydantic import BaseModel
Used everywhere for structured output + tool args.
role · goal · backstoryAgents
Agents are LLM personas with role, goal, backstory. Keep each agent narrow — one job, one persona.
Broad agents pick the wrong tool and contradict their own goal.
Agent(role, goal, backstory)
Minimum viable agent.
Agent(…, tools=[tool_a, tool_b])
Bind tools the agent can call.
Agent(…, llm="openai/gpt-4o-mini")
Pin model via LiteLLM-style id.
Agent(…, llm=LLM(model="…", temperature=0.2))
Or pass a configured LLM instance.
Agent(…, allow_delegation=True)
Lets this agent hand work to crew-mates.
Agent(…, max_iter=15)
Cap reasoning loops. Default 25.
Agent(…, max_rpm=10)
Per-agent request rate limit.
Agent(…, verbose=True)
Stream the agent’s thinking to stdout.
Agent(…, memory=True)
Opt in to short-term memory between tasks.
Agent(…, cache=True)
Cache tool calls. Default true.
Agent(…, system_template="…")
Override the auto-generated system prompt.
Agent(…, respect_context_window=True)
Auto-summarise history when nearing token limit.
Treat the backstory as a behavior contract, not flavor text. “Cuts filler”
materially changes output style.
work the crew doesTasks
Task(description, expected_output, agent)
Minimum viable task.
Task(…, context=[other_task])
Wire upstream task output into this task’s prompt.
Task(…, output_file="out/report.md")
Persist result to disk.
Task(…, output_json=Schema)
Force JSON conforming to a Pydantic model.
Task(…, output_pydantic=Schema)
Return a typed Pydantic instance.
Task(…, tools=[tool_a])
Override the agent’s tools for this task only.
Task(…, async_execution=True)
Run in parallel with sibling async tasks.
Task(…, human_input=True)
Pause for human approval before completing.
Task(…, guardrail=fn)
Validator that can retry the task on failure.
Task(…, retry_count=2)
How many times the guardrail can retry.
expected_output is the single biggest lever on quality. Be concrete —
“Markdown list, 5 items, each ≤40 words” beats “a useful summary”.
Tasks run in declared order. Each gets prior outputs via context.
Process.hierarchical
A manager agent (LLM) routes tasks to crew-mates. Requires manager_llm.
manager_agent=Agent(…)
Use a custom manager instead of the default one.
async_execution=True on tasks
Within sequential, async tasks fan out in parallel.
Start sequential. Hierarchical adds an extra LLM hop per decision and tends to over-delegate
on simple pipelines. Reach for it only when task routing is genuinely dynamic.
event-driven orchestrationFlows
Flows wrap crews in an event-driven state machine. Use when you need branching, loops, or to chain multiple
crews. The state attribute is a typed Pydantic model shared across steps.
class MyFlow(Flow[State]): …
Typed flow. State is a BaseModel.
@start()
Marks the entry method.
@listen(prev_step)
Runs after prev_step completes.
@listen(or_(a, b))
Fires when either parent finishes.
@listen(and_(a, b))
Fires only after both parents finish.
@router(step)
Branch step. Return a string; methods @listen("that_string") fire.
flow.kickoff(inputs={…})
Run the flow.
flow.plot()
Render the flow graph as HTML.
self.state.field = value
Mutate shared state inside a step.
python
from crewai.flow.flow import Flow, listen, start, router
from pydantic import BaseModel
class State(BaseModel):
topic: str = ""
draft: str = ""
score: int = 0
class ContentFlow(Flow[State]):
@start()
def pick_topic(self):
self.state.topic = "vector databases in 2026"
@listen(pick_topic)
def draft(self):
self.state.draft = ContentCrew().crew().kickoff(
inputs={"topic": self.state.topic}
).raw
@router(draft)
def review(self):
self.state.score = score_draft(self.state.draft)
return "ship" if self.state.score >= 8 else "revise"
@listen("revise")
def revise(self):
# loops back into draft with feedback
...
@listen("ship")
def publish(self):
publish_to_cms(self.state.draft)
ContentFlow().kickoff()
give agents capabilityTools
Built-in (crewai_tools)
SerperDevTool()
Web search via Serper. Needs SERPER_API_KEY.
ScrapeWebsiteTool(website_url="…")
Fetch + clean HTML to text.
FileReadTool(file_path="…")
Read a single file.
DirectorySearchTool(directory="…")
RAG over a folder of docs.
PDFSearchTool(pdf="…")
RAG over a single PDF.
CodeInterpreterTool()
Sandboxed Python execution.
BraveSearchTool() / TavilySearchTool()
Alternative search backends.
Custom tools
@tool("name") def fn(query: str) -> str: …
Quickest path. Docstring becomes the description.
class T(BaseTool): name, description, args_schema
Preferred for anything non-trivial. Typed args, validation.
def _run(self, **kwargs) -> str:
Sync entry point.
async def _arun(self, **kwargs):
Optional async entry point.
python
from crewai.tools import BaseTool
from pydantic import BaseModel, Field
class SearchArgs(BaseModel):
query: str = Field(..., description="What to look up")
top_k: int = Field(5, description="Max results")
class InternalDocs(BaseTool):
name: str = "internal_docs_search"
description: str = "Search the company wiki. Use for product or policy questions."
args_schema: type[BaseModel] = SearchArgs
def _run(self, query: str, top_k: int = 5) -> str:
# Replace with your real retriever.
hits = my_vector_store.search(query, k=top_k)
return "\n\n".join(f"- {h.title}: {h.snippet}" for h in hits)
# Attach to an agent
support_agent = Agent(
role="Support Specialist",
goal="Answer customer questions using internal docs",
backstory="Polite, exact, never invents URLs.",
tools=[InternalDocs()],
)
persist across tasks & runsMemory
Crew(…, memory=True)
Enable all three default memories at crew level.
ShortTermMemory()
Per-run context. Cleared after kickoff.
LongTermMemory()
Survives runs. Stored in SQLite by default.
EntityMemory()
Tracks named entities (people, projects) across runs.
Memory writes happen at task completion. If a task crashes, that turn isn’t remembered — design tasks
to be idempotent before relying on long-term memory.
give agents documentsKnowledge
Knowledge sources are documents indexed once and queried by agents during a run. Lower friction than
wiring RAG tools manually when the corpus is fixed.
TextFileKnowledgeSource(file_paths=["…"])
Plain text files.
PDFKnowledgeSource(file_paths=["…"])
PDF files.
CSVKnowledgeSource(file_paths=["…"])
Structured CSV.
StringKnowledgeSource(content="…")
Inline string content.
Crew(…, knowledge_sources=[src])
Available to every agent in the crew.
Agent(…, knowledge_sources=[src])
Scoped to a single agent.
pick & configure modelsLLM integration
Model strings follow the LiteLLM convention: provider/model. Set the
matching *_API_KEY env var and CrewAI handles the rest.
llm="openai/gpt-4o-mini"
OpenAI — needs OPENAI_API_KEY.
llm="anthropic/claude-sonnet-4-6"
Anthropic — needs ANTHROPIC_API_KEY.
llm="gemini/gemini-2.5-flash"
Google — needs GEMINI_API_KEY.
llm="ollama/llama3.1"
Local via Ollama. Set OLLAMA_BASE_URL if non-default.
LLM(model="…", temperature=0.2, max_tokens=1024)
Configured instance, reusable across agents.
LLM(…, response_format=Schema)
Force structured output at the LLM level.
manager_llm="…"
Model for hierarchical crew’s default manager.
declarative crewsYAML project layout
crewai create crew scaffolds a project with agents.yaml,
tasks.yaml, and a thin Python file that uses
@CrewBase, @agent, @task,
@crew to wire them. Configs are interpolated against
kickoff(inputs=…).
agents.yaml
yaml
# config/agents.yaml — declarative agent definitions
researcher:
role: >
Senior {topic} Researcher
goal: >
Surface the 5 most consequential developments in {topic} this quarter
backstory: >
A meticulous analyst who values primary sources over hot takes.
llm: openai/gpt-4o-mini
verbose: true
writer:
role: >
Tech Editor
goal: >
Turn the research brief into a 600-word post for a developer audience
backstory: >
Former staff writer at a respected eng newsletter. Cuts filler.
llm: anthropic/claude-sonnet-4-6
tasks.yaml
yaml
# config/tasks.yaml — declarative task definitions
research_task:
description: >
Investigate recent advances in {topic}. Pull 5 primary sources from the
last 90 days and summarise each in 2-3 sentences.
expected_output: >
A markdown list of 5 items, each with title, URL, and a 2-sentence summary.
agent: researcher
write_task:
description: >
Using the research brief, write a 600-word post for working developers.
Lead with the most actionable finding.
expected_output: >
A markdown post with H2 sections and code blocks where relevant.
agent: writer
context: [research_task]
output_file: out/post.md
research → write · ~30 linesEnd-to-end · Minimal crew
Two agents, two tasks, sequential process. Replace the topic and you have a working content pipeline.
python
from crewai import Agent, Task, Crew, Process
from crewai_tools import SerperDevTool
search = SerperDevTool()
researcher = Agent(
role="Senior Researcher",
goal="Surface the most consequential developments in {topic}",
backstory="A meticulous analyst who prefers primary sources.",
tools=[search],
llm="openai/gpt-4o-mini",
verbose=True,
)
writer = Agent(
role="Tech Editor",
goal="Turn the brief into a tight 600-word post",
backstory="Former newsletter staff writer. Cuts filler.",
llm="anthropic/claude-sonnet-4-6",
)
brief = Task(
description="Investigate {topic}. Five primary sources, 2-3 sentences each.",
expected_output="Markdown list with title, URL, summary.",
agent=researcher,
)
post = Task(
description="Write a 600-word post from the brief. Lead with the action.",
expected_output="Markdown with H2 sections.",
agent=writer,
context=[brief],
output_file="out/post.md",
)
crew = Crew(
agents=[researcher, writer],
tasks=[brief, post],
process=Process.sequential,
verbose=True,
)
result = crew.kickoff(inputs={"topic": "vector databases in 2026"})
print(result.raw)
Best practiceGood to know
One job per agent.
A narrow role plus an outcome-shaped expected_output outperforms a generic
“assistant” with a long prompt. Split before tuning.
Wire data through context, not memory.
For sequential crews, pass upstream task outputs via context=[t1]. Memory is
for soft recall across runs, not deterministic data hand-off.
Reach for Flows the moment you need branching.
A Process.hierarchical crew burns tokens making routing decisions an
@router step would settle in one line of Python.
Common trapsWatch out for
YAML interpolation only fills {var} from kickoff(inputs=…).
Stray curly braces in your prompt — e.g. JSON examples — will raise
KeyError at runtime. Double them: {{ /
}}.
allow_delegation=True can stall a crew.
Agents will ping-pong work back and forth if their goals overlap. Leave it off unless the roles are
genuinely complementary, and set a low max_iter as a backstop.
Don’t mutate self.state from inside async tasks without care.
Flows’ state is shared. Two concurrent steps writing to the same field will race — merge in a
downstream @listen(and_(…)) step instead.
CrewAI is a Python framework for building multi-agent AI systems. You define agents with roles and backstories, assign tasks with expected outputs, and combine them into a crew that runs sequentially or hierarchically. It handles tool calling, memory, and LLM interactions so you focus on the workflow.
What is the difference between an Agent and a Task in CrewAI?
An Agent represents a specialized worker with a role, goal, backstory, and optional tools. A Task is a unit of work assigned to an agent, with a description of what to do and what a good output looks like. Agents are re-usable; tasks are the concrete jobs they execute.
Is CrewAI free to use?
CrewAI the framework is open source and free to use under the MIT license. You provide your own LLM API keys (OpenAI, Anthropic, Gemini, or local via Ollama). The crewai.com cloud platform offers a paid managed service, but the core library has no cost.
What LLMs does CrewAI support?
CrewAI uses LiteLLM under the hood, so it supports any provider LiteLLM covers — OpenAI, Anthropic Claude, Google Gemini, Mistral, Ollama (local), Azure OpenAI, Cohere, and more. Set the model with the LLM class or the OPENAI_MODEL_NAME environment variable.
How do CrewAI Flows work?
Flows are an event-driven orchestration layer on top of crews. You subclass Flow, decorate a method with @start to mark the entry point, and use @listen(event) to chain subsequent steps. Flows support conditional branching with @router, parallel fan-out with and_/or_ combinators, and persistent state via BaseModel.
What is the difference between CrewAI and LangChain agents?
CrewAI is opinionated about multi-agent collaboration — it gives each agent a role, goal, and backstory, then coordinates them through crews and tasks with explicit handoffs. LangChain agents are more composable primitives you wire together yourself. Use CrewAI when you need structured role-based teamwork; use LangChain when you need fine-grained control over a single agent's tool loop.