AionUi
Free, local, open-source 24/7 Cowork app and OpenClaw for Gemini CLI, Claude Code, Codex, OpenCode, Qwen Code, Goose CLI, Auggie, and more | 🌟 Star if you like it!
Crawler Summary
crewai-interview-questions CrewAI Interview Questions & Answers A curated list of CrewAI interview questions covering Fundamentals, Agents, Tasks, Crews, Processes & Orchestration, Tools Integration, Memory & Context Management, RAG & Knowledge Integration, LLM Integration, Flows, Observability & Debugging, Security & Governance, Testing & Evaluation, and Design & Scenario-Based Questions — each with a clear explanation and Python code example Capability contract not published. No trust telemetry is available yet. 1 GitHub stars reported by the source. Last updated 10/9/2026.
Freshness
Last checked 10/9/2026
Best For
crewai-interview-questions is best for crewai, multi-agent workflows where OpenClaw compatibility matters.
Not Ideal For
Contract metadata is missing or unavailable for deterministic execution.
Evidence Sources Checked
editorial-content, GITHUB REPOS, runtime-metrics, public facts pack
crewai-interview-questions CrewAI Interview Questions & Answers A curated list of CrewAI interview questions covering Fundamentals, Agents, Tasks, Crews, Processes & Orchestration, Tools Integration, Memory & Context Management, RAG & Knowledge Integration, LLM Integration, Flows, Observability & Debugging, Security & Governance, Testing & Evaluation, and Design & Scenario-Based Questions — each with a clear explanation and Python code example
Public facts
5
Change events
1
Artifacts
0
Freshness
Oct 9, 2026
Capability contract not published. No trust telemetry is available yet. 1 GitHub stars reported by the source. Last updated 10/9/2026.
Trust score
Unknown
Compatibility
OpenClaw
Freshness
Oct 9, 2026
Vendor
Interviewroadmap
Artifacts
0
Benchmarks
0
Last release
Unpublished
Key links, install path, and a quick operational read before the deeper crawl record.
Summary
Capability contract not published. No trust telemetry is available yet. 1 GitHub stars reported by the source. Last updated 10/9/2026.
Setup snapshot
Setup complexity is LOW. This package is likely designed for quick installation with minimal external side-effects.
Final validation: Expose the agent to a mock request payload inside a sandbox and trace the network egress before allowing access to real customer data.
Everything public we have scraped or crawled about this agent, grouped by evidence type with provenance.
Vendor
Interviewroadmap
Protocol compatibility
OpenClaw
Adoption signal
1 GitHub stars
Handshake status
UNKNOWN
Crawlable docs
6 indexed pages on the official domain
Merged public release, docs, artifact, benchmark, pricing, and trust refresh events.
Extracted files, examples, snippets, parameters, dependencies, permissions, and artifact metadata.
Extracted files
0
Examples
6
Snippets
0
Languages
python
python
from crewai import Agent, Task, Crew, Process
researcher = Agent(
role="Senior Research Analyst",
goal="Find accurate, up-to-date information on {topic}",
backstory="You are a meticulous analyst who always cites reliable sources.",
)
research_task = Task(
description="Research the latest developments in {topic}.",
expected_output="A concise bulleted summary of 5 key findings with sources.",
agent=researcher,
)
crew = Crew(agents=[researcher], tasks=[research_task], process=Process.sequential)
result = crew.kickoff(inputs={"topic": "agentic AI frameworks"})
print(result.raw)python
from crewai import Agent
writer = Agent(
role="Technical Content Writer",
goal="Write clear, engaging articles that explain {topic} to developers",
backstory=(
"You are an experienced developer-advocate who turns complex "
"technical topics into approachable, well-structured prose."
),
allow_delegation=False,
max_iter=15,
verbose=True,
)python
from crewai import Task
write_task = Task(
description="Write a 600-word article on {topic} using the research provided.",
expected_output="A markdown article with an intro, 3 sections, and a conclusion.",
agent=writer,
context=[research_task], # receives research_task's output as context
output_file="article.md",
)python
from crewai import Crew, Process
crew = Crew(
agents=[researcher, writer, editor],
tasks=[research_task, write_task, edit_task],
process=Process.sequential,
memory=True,
verbose=True,
)
result = crew.kickoff(inputs={"topic": "vector databases"})python
manager = Agent(
role="Editorial Manager",
goal="Coordinate research and writing to produce a polished article",
backstory="You delegate to specialists and synthesize their work.",
allow_delegation=True, # can ask/delegate to other agents
)python
review_task = Task(
description="Draft the final customer email and await human approval.",
expected_output="An approved, ready-to-send email.",
agent=support_agent,
human_input=True, # pauses for human review/feedback
)Full documentation captured from public sources, including the complete README when available.
Docs source
GITHUB REPOS
Editorial quality
ready
crewai-interview-questions CrewAI Interview Questions & Answers A curated list of CrewAI interview questions covering Fundamentals, Agents, Tasks, Crews, Processes & Orchestration, Tools Integration, Memory & Context Management, RAG & Knowledge Integration, LLM Integration, Flows, Observability & Debugging, Security & Governance, Testing & Evaluation, and Design & Scenario-Based Questions — each with a clear explanation and Python code example
A curated list of CrewAI interview questions covering Fundamentals, Agents, Tasks, Crews, Processes & Orchestration, Tools Integration, Memory & Context Management, RAG & Knowledge Integration, LLM Integration, Flows, Observability & Debugging, Security & Governance, Testing & Evaluation, and Design & Scenario-Based Questions — each with a clear explanation and Python code example where applicable.
| No. | Questions | | --- | --------- | | | CrewAI Fundamentals | | 1 | What is CrewAI and what problem does it solve? | | 2 | How does CrewAI differ from single-agent applications? | | 3 | What are the core components of CrewAI? | | 4 | What is an agent in CrewAI? | | 5 | What is a task in CrewAI? | | 6 | What is a crew in CrewAI? | | 7 | What is a process in CrewAI? | | 8 | What are the benefits of multi-agent systems? | | 9 | How does CrewAI enable agent collaboration? | | 10 | What are common use cases of CrewAI? | | 11 | How does CrewAI compare with LangChain? | | 12 | How does CrewAI compare with AutoGen? | | 13 | How does CrewAI compare with the OpenAI Assistants API? | | 14 | What is CrewAI Flows and how does it relate to Crews? | | 15 | What are the limitations of CrewAI? | | 16 | What is agent autonomy in CrewAI? | | 17 | How does CrewAI support human-in-the-loop workflows? | | 18 | What is the lifecycle of a CrewAI execution? | | 19 | How do you install and set up CrewAI? | | 20 | What is the difference between crewai and crewai-tools? | | | Agents | | 21 | What attributes define a CrewAI agent? | | 22 | What is the role of an agent? | | 23 | What is the purpose of an agent's goal? | | 24 | What is agent backstory and why is it important? | | 25 | How do you create an agent in CrewAI? | | 26 | What are verbose agents? | | 27 | How do agents maintain context? | | 28 | How do agents communicate with each other? | | 29 | How can an agent delegate work? | | 30 | What is max_iter and how does it constrain an agent? | | 31 | How do you configure agent tools? | | 32 | How do agents decide which tool to invoke? | | 33 | What are specialized agents? | | 34 | How do you limit agent behavior? | | 35 | How do you prevent agents from hallucinating? | | 36 | How do you make agents more deterministic? | | 37 | How do you assign different LLMs to different agents? | | 38 | What is role-based agent design? | | 39 | How do you build a research agent? | | 40 | How do you build a coding agent? | | 41 | How do you build a review agent? | | 42 | How do you build a planning/manager agent? | | 43 | What are best practices for agent design? | | 44 | How do you debug agent reasoning? | | 45 | How do you test individual agents? | | | Tasks | | 46 | What is a task in CrewAI (in depth)? | | 47 | How do tasks differ from agents? | | 48 | How do you define task descriptions? | | 49 | What is expected_output in a task? | | 50 | How are tasks assigned to agents? | | 51 | How do task dependencies and context work? | | 52 | What is task chaining? | | 53 | What are sequential vs parallel (async) tasks? | | 54 | How do you produce structured output with Pydantic? | | 55 | How do you enforce JSON outputs? | | 56 | What are task guardrails? | | 57 | How can tasks consume external data? | | 58 | How do you create dynamic tasks? | | 59 | How do you write task output to a file? | | 60 | How do you reuse tasks with templates? | | 61 | How do you handle failed tasks and retries? | | 62 | How do you test task execution? | | 63 | What are common task design mistakes? | | | Crews | | 64 | What is a crew in CrewAI (in depth)? | | 65 | How do you create a crew? | | 66 | What are the components of a crew? | | 67 | How do agents collaborate inside a crew? | | 68 | What is crew kickoff and kickoff_for_each? | | 69 | How do you pass inputs to a crew? | | 70 | How do you retrieve crew outputs? | | 71 | What is CrewOutput and what does it contain? | | 72 | How do crews handle failures? | | 73 | How do you scale crews? | | 74 | How do you run a crew asynchronously? | | 75 | What is the @CrewBase decorator pattern? | | 76 | What are crew design best practices? | | | Processes & Orchestration | | 77 | What are CrewAI processes? | | 78 | What is a Sequential Process? | | 79 | What is a Hierarchical Process? | | 80 | How does a hierarchical manager agent work? | | 81 | When would you use sequential vs hierarchical? | | 82 | What is manager_llm vs manager_agent? | | 83 | How does delegation work in hierarchical workflows? | | 84 | What are process design patterns? | | 85 | What are common process anti-patterns? | | 86 | How do you implement approval and review cycles? | | 87 | How do you implement iterative refinement? | | 88 | How do you handle long-running workflows? | | | Tools Integration | | 89 | What are tools in CrewAI? | | 90 | Why are tools important for agents? | | 91 | How do you create a custom tool with BaseTool? | | 92 | How do you create a tool with the @tool decorator? | | 93 | How do agents invoke tools? | | 94 | How do you integrate web search tools? | | 95 | How do you integrate database and SQL tools? | | 96 | How do you integrate REST and GraphQL APIs? | | 97 | How do you integrate vector databases? | | 98 | How do you validate tool inputs with args_schema? | | 99 | How do you handle tool failures? | | 100 | What is tool caching and how do you use it? | | 101 | How do you secure tool access? | | 102 | How do you rate-limit tools? | | 103 | How do you implement asynchronous tools? | | 104 | What are best practices for tool design? | | | Memory & Context Management | | 105 | What types of memory are supported in CrewAI? | | 106 | What is short-term memory? | | 107 | What is long-term memory? | | 108 | What is entity memory? | | 109 | How do you enable memory in a crew? | | 110 | How do agents access memory? | | 111 | How is memory persisted? | | 112 | How do you use external memory and custom storage? | | 113 | How do you prevent context loss in long workflows? | | 114 | How do you reduce token consumption? | | 115 | How do you reset or clear memory? | | 116 | What are common memory pitfalls? | | | RAG & Knowledge Integration | | 117 | What is the Knowledge feature in CrewAI? | | 118 | How does Knowledge differ from RAG tools? | | 119 | What knowledge sources does CrewAI support? | | 120 | How do you add knowledge to an agent or crew? | | 121 | What role does a vector database play in CrewAI? | | 122 | How do you build a RAG tool with a vector store? | | 123 | What are chunking strategies for RAG? | | 124 | How do you improve retrieval accuracy? | | 125 | How do you reduce hallucinations using RAG? | | 126 | How do you configure embeddings in CrewAI? | | 127 | How do you evaluate RAG performance? | | 128 | How do you handle stale knowledge? | | 129 | How do agents collaborate in RAG workflows? | | | LLM Integration | | 130 | Which LLM providers does CrewAI support? | | 131 | How do you configure an LLM in CrewAI? | | 132 | How does CrewAI use LiteLLM under the hood? | | 133 | How do you integrate local LLMs (Ollama)? | | 134 | How do you switch between LLM providers? | | 135 | What is temperature and how does it affect agents? | | 136 | How do you manage token limits? | | 137 | How do you handle rate limits and max_rpm? | | 138 | How do you optimize inference costs? | | 139 | How do you select the right model for each agent? | | 140 | How do you implement model fallback strategies? | | 141 | How do you build hybrid LLM architectures? | | | Flows | | 142 | What is a CrewAI Flow? | | 143 | What are @start and @listen decorators? | | 144 | How does state management work in Flows? | | 145 | What are router, or_, and and_ in Flows? | | 146 | How do Flows combine with Crews? | | 147 | When should you use a Flow vs a Crew? | | | Observability, Monitoring & Debugging | | 148 | How do you monitor CrewAI applications? | | 149 | How do you log agent activities? | | 150 | How do you trace task execution? | | 151 | How do you analyze token consumption and cost? | | 152 | How do you integrate observability platforms? | | 153 | How do you use callbacks and event listeners? | | 154 | How do you audit agent actions? | | 155 | What metrics should be monitored in production? | | 156 | What are common debugging techniques? | | | Security & Governance | | 157 | How do you secure CrewAI applications? | | 158 | How do you manage API secrets? | | 159 | How do you prevent prompt injection attacks? | | 160 | How do you secure tool execution? | | 161 | How do you prevent data leakage? | | 162 | How do you implement guardrails? | | 163 | How do you comply with GDPR and manage PII? | | 164 | What are governance best practices for multi-agent systems? | | | Testing & Evaluation | | 165 | How do you test a CrewAI application? | | 166 | How do you use the crewai test command? | | 167 | How do you mock LLM calls in tests? | | 168 | How do you evaluate multi-agent output quality? | | 169 | How do you set up CI/CD for CrewAI? | | | Design & Scenario-Based Questions | | 170 | Design a multi-agent research assistant | | 171 | Design a customer support automation system | | 172 | Design a software development lifecycle assistant | | 173 | Design a code review workflow | | 174 | Design a financial report generation system | | 175 | Design a recruitment screening platform | | 176 | Design a legal document analysis solution | | 177 | Design an enterprise knowledge assistant | | 178 | Design a RAG chatbot with CrewAI | | 179 | How would you scale a CrewAI app to millions of users? | | 180 | How would you reduce costs in a large CrewAI deployment? | | 181 | How would you migrate a LangChain application to CrewAI? | | 182 | How would you implement human approval before critical actions? | | 183 | Design a content marketing pipeline | | 184 | Design a data analysis pipeline | | 185 | How would you debug a crew that produces inconsistent results? | | | Advanced & Internals | | 186 | How does CrewAI build the prompt sent to the LLM? | | 187 | How does the agent execution loop (ReAct) work internally? | | 188 | How does CrewAI handle tool-calling under the hood? | | 189 | How does delegation get implemented as a tool? | | 190 | How does hierarchical task assignment work internally? | | 191 | How does memory retrieval get injected into prompts? | | 192 | How does the Knowledge feature inject context internally? | | 193 | How does CrewAI handle context window overflow? | | 194 | How does Flow state persistence work internally? | | 195 | How would you extend CrewAI with a custom process? | | | Production & Operations | | 196 | How do you deploy a CrewAI application to production? | | 197 | How do you handle concurrency and parallel crew runs? | | 198 | How do you implement caching across a deployment? | | 199 | How do you version agents, tasks, and prompts? | | 200 | What are the most common CrewAI production issues and fixes? |
</details>CrewAI is a lean, standalone Python framework for orchestrating role-playing, autonomous AI agents. It lets you compose multiple LLM-powered agents into a coordinated team (a "crew") that collaborates, delegates, and executes complex, multi-step tasks. It solves the limitations of single-prompt LLM applications: limited reasoning depth, no separation of concerns, brittle one-shot prompts, and the difficulty of coordinating tools and context across a long workflow. By assigning each agent a focused role and wiring them together with structured tasks, CrewAI produces clearer reasoning, better outputs, and a maintainable architecture.
Unlike many alternatives, CrewAI is built from scratch — it does not depend on LangChain — which gives it a smaller footprint and faster execution.
from crewai import Agent, Task, Crew, Process
researcher = Agent(
role="Senior Research Analyst",
goal="Find accurate, up-to-date information on {topic}",
backstory="You are a meticulous analyst who always cites reliable sources.",
)
research_task = Task(
description="Research the latest developments in {topic}.",
expected_output="A concise bulleted summary of 5 key findings with sources.",
agent=researcher,
)
crew = Crew(agents=[researcher], tasks=[research_task], process=Process.sequential)
result = crew.kickoff(inputs={"topic": "agentic AI frameworks"})
print(result.raw)
A single-agent design relies on one LLM prompt to perform all reasoning, tool use, and output generation. As the task grows, that single prompt becomes overloaded — it must hold all instructions, context, and intermediate state at once, which degrades quality and inflates token usage.
CrewAI instead decomposes the work into specialized agents (e.g., researcher, planner, coder, reviewer), each with its own role, goal, backstory, tools, and even its own model. Benefits:
| Component | Role |
| --- | --- |
| Agent | An autonomous unit with a role, goal, backstory, LLM, and tools that reasons and acts |
| Task | A unit of work with a description and expected_output, assigned to an agent |
| Crew | The container that holds agents + tasks and orchestrates their execution |
| Process | The execution strategy: sequential or hierarchical |
| Tools | Functions or integrations agents call to act beyond text generation |
| Memory | Short-term, long-term, and entity memory that persists context |
| Knowledge | A retrieval layer that grounds agents in external documents/data |
| Flow | An event-driven orchestration layer for deterministic, branching pipelines |
An agent is an autonomous entity backed by an LLM that performs tasks, makes decisions, calls tools, and optionally delegates to other agents. Think of it as a specialized team member. Each agent is defined by attributes such as role, goal, backstory, llm, tools, allow_delegation, max_iter, verbose, and memory.
from crewai import Agent
writer = Agent(
role="Technical Content Writer",
goal="Write clear, engaging articles that explain {topic} to developers",
backstory=(
"You are an experienced developer-advocate who turns complex "
"technical topics into approachable, well-structured prose."
),
allow_delegation=False,
max_iter=15,
verbose=True,
)
A task is a structured description of a single unit of work. At minimum it has a description (what to do) and an expected_output (the desired result/format). It is usually bound to an agent, and can declare context (dependencies on other tasks), tools, output_pydantic/output_json (structured output), output_file, guardrail, and async_execution.
from crewai import Task
write_task = Task(
description="Write a 600-word article on {topic} using the research provided.",
expected_output="A markdown article with an intro, 3 sections, and a conclusion.",
agent=writer,
context=[research_task], # receives research_task's output as context
output_file="article.md",
)
A crew is the top-level orchestrator that bundles a set of agents and tasks and runs them according to a chosen process. It manages task scheduling, passes outputs between tasks, coordinates delegation, handles memory, and returns the final CrewOutput. A crew is started with kickoff().
from crewai import Crew, Process
crew = Crew(
agents=[researcher, writer, editor],
tasks=[research_task, write_task, edit_task],
process=Process.sequential,
memory=True,
verbose=True,
)
result = crew.kickoff(inputs={"topic": "vector databases"})
A process defines how a crew executes its tasks. CrewAI ships two built-in processes:
Process.sequential — tasks run one after another in list order; each task can receive prior outputs as context.Process.hierarchical — a manager agent (or manager_llm) plans, delegates tasks to worker agents, validates results, and aggregates the final answer.The process is set on the Crew. Sequential is predictable and easy to reason about; hierarchical is adaptive and better for open-ended problems.
async_execution).Collaboration happens through three mechanisms:
context parameter (or automatically in a sequential process).allow_delegation=True, an agent can hand a sub-question to another agent through the built-in Delegate work and Ask question tools.manager = Agent(
role="Editorial Manager",
goal="Coordinate research and writing to produce a polished article",
backstory="You delegate to specialists and synthesize their work.",
allow_delegation=True, # can ask/delegate to other agents
)
| | LangChain | CrewAI | | --- | --- | --- | | Primary abstraction | Chains, runnables, and tool-using agents | Role-based multi-agent crews | | Focus | General-purpose LLM pipelines and integrations | Collaborative agent orchestration | | Dependency | Large ecosystem | Standalone (no LangChain dependency) | | Best for | Single-agent flows, custom chains, broad integrations | Teams of specialized agents solving multi-step problems |
They're not mutually exclusive — you can wrap LangChain tools as CrewAI tools. CrewAI shines when the problem benefits from distinct roles and delegation; LangChain shines for flexible, low-level pipeline construction.
AutoGen (Microsoft) models multi-agent collaboration as free-form conversations between agents, which is powerful but can be hard to control and may loop. CrewAI adds structure: explicit roles, typed tasks with expected_output, sequential/hierarchical processes, built-in memory, and guardrails. CrewAI's structure makes workflows more predictable and production-friendly, whereas AutoGen's conversational flexibility suits exploratory or research-style agent interactions. CrewAI also offers Flows for deterministic, event-driven control that AutoGen lacks natively.
The OpenAI Assistants API provides a single managed assistant with tool-calling, file search, and threads — but it is tied to OpenAI and centers on one assistant per conversation. CrewAI is provider-agnostic (OpenAI, Anthropic, Google, local models via LiteLLM), orchestrates multiple cooperating agents, and gives you full control over memory backends, processes, and tools. Use the Assistants API for simple single-assistant apps within the OpenAI ecosystem; use CrewAI when you need multi-agent collaboration, model flexibility, and custom orchestration.
Flows are CrewAI's event-driven orchestration layer for building deterministic, branching, stateful pipelines. Where a Crew is an autonomous team that figures out how to accomplish tasks, a Flow gives you precise, code-level control over when steps run, how state passes between them, and which branches execute. Flows use decorators like @start and @listen, support conditional routing (@router, or_, and_), and can invoke entire crews as steps. In practice: use Flows for the high-level control plane and Crews for the autonomous "thinking" sub-steps.
Autonomy is how much independent decision-making an agent has. A highly autonomous agent (with allow_delegation=True and a rich tool set) can decide which tools to call, when to ask other agents for help, and how many reasoning steps to take. You constrain autonomy with:
allow_delegation=False — prevents creating/delegating sub-tasks.max_iter — caps reasoning iterations.max_rpm — limits request rate.Balancing autonomy and control is key: too little and agents are rigid; too much and they wander or burn tokens.
CrewAI supports human oversight via the task-level human_input=True flag. When set, after the agent produces its result the execution pauses and prompts a human to review, approve, or provide feedback before continuing. This is essential for high-impact actions (sending emails, executing transactions, publishing content).
review_task = Task(
description="Draft the final customer email and await human approval.",
expected_output="An approved, ready-to-send email.",
agent=support_agent,
human_input=True, # pauses for human review/feedback
)
crew.kickoff(inputs=...), which interpolates inputs into templates.CrewOutput with the final result, per-task outputs, and token usage.CrewAI requires Python 3.10–3.13 and is installed via pip. The CLI (crewai) scaffolds projects.
# Install the framework (and the optional tools package)
pip install crewai crewai-tools
# Scaffold a new project with the recommended structure
crewai create crew my_project
cd my_project
# Set your API key(s) in .env
echo "OPENAI_API_KEY=sk-..." >> .env
# Install project deps and run
crewai install
crewai run
The scaffold produces config/agents.yaml, config/tasks.yaml, a crew.py using the @CrewBase decorator, and a main.py entry point.
crewai — the core framework: Agent, Task, Crew, Process, Flow, memory, and knowledge.crewai-tools — a separate, optional package of ready-made tools (e.g., SerperDevTool for web search, ScrapeWebsiteTool, FileReadTool, PDFSearchTool, CodeInterpreterTool, database and RAG tools). It also provides BaseTool and the @tool decorator for building custom tools.You can use the core framework alone, but crewai-tools saves you from reimplementing common integrations.
| Attribute | Purpose |
| --- | --- |
| role | The agent's function/persona (e.g., "Research Analyst") |
| goal | The objective the agent works toward |
| backstory | Context/system instructions shaping behavior and tone |
| llm | The language model (and its parameters) the agent uses |
| tools | List of tools the agent may call |
| allow_delegation | Whether the agent can delegate/ask other agents (default False) |
| max_iter | Max reasoning iterations before forcing an answer (default 20) |
| max_rpm | Max requests per minute (rate limiting) |
| verbose | Log the agent's reasoning and tool calls |
| memory | Whether the agent retains context (default True) |
| cache | Cache tool results (default True) |
| max_execution_time | Timeout for the agent's work |
| allow_code_execution | Permit running generated code (sandboxed) |
agent = Agent(
role="Data Analyst",
goal="Analyze sales data and surface actionable insights",
backstory="You are a rigorous analyst who validates every number.",
llm="gpt-4o",
max_iter=20,
max_rpm=30,
allow_delegation=False,
verbose=True,
)
The role is a concise label describing what the agent does — e.g., "Senior Python Developer", "Market Research Analyst", "Copy Editor". It anchors the LLM's behavior by setting expectations and persona. A specific, well-chosen role yields more focused, on-theme output than a generic one. Roles also make a crew self-documenting: reading the roles tells you the team's composition at a glance.
The goal states the outcome the agent is trying to achieve. If the role says who the agent is, the goal says what it must accomplish. Goals should be specific and measurable where possible — "Produce a 5-bullet executive summary with sources" is better than "Summarize the topic." Goals can contain interpolation placeholders (e.g., {topic}) that are filled from kickoff inputs.
The backstory is the richest behavioral lever — it functions as the agent's system prompt. It can encode persona, domain expertise, tone, rules, and constraints. A strong backstory keeps the agent consistent and on-task, reduces drift, and improves output quality. Keep it focused: enough context to guide behavior, but not so verbose that it wastes tokens.
backstory = (
"You are a senior financial analyst with 15 years of experience. "
"You never speculate without data, you always show your calculations, "
"and you flag any assumptions explicitly."
)
You can create agents in code or declaratively in YAML (the recommended project structure).
In code:
from crewai import Agent
researcher = Agent(
role="Research Analyst",
goal="Gather and summarize information on {topic}",
backstory="You are a meticulous researcher who cites reliable sources.",
llm="gpt-4o",
verbose=True,
allow_delegation=False,
)
In YAML (config/agents.yaml):
researcher:
role: >
Research Analyst
goal: >
Gather and summarize information on {topic}
backstory: >
You are a meticulous researcher who cites reliable sources.
llm: gpt-4o
The YAML is wired up in a @CrewBase class via the @agent decorator.
Setting verbose=True makes an agent (or the whole crew) log its internal reasoning, tool calls, and intermediate outputs to the console. This is invaluable during development for understanding why an agent made a decision, which tool it chose, and where things went wrong. In production you typically disable verbose logging (or route it to a structured logger/observability platform) to avoid noise and accidental leakage of sensitive content.
Agents maintain context through several layers:
context, and a sequential process passes prior results automatically.Agents communicate indirectly through the crew, not via direct method calls. Mechanisms:
allow_delegation=True, an agent gets Delegate work to coworker and Ask question to coworker tools, letting it route sub-questions to teammates by role.This indirection keeps coupling low and makes the workflow easier to reason about and test.
When allow_delegation=True, CrewAI automatically equips the agent with two delegation tools. The agent can call Delegate work to coworker (hand off a full sub-task) or Ask question to coworker (request a specific answer) targeting another agent by its role name. Delegation is the backbone of the hierarchical process, where a manager breaks work apart and assigns it to specialists.
manager = Agent(
role="Project Manager",
goal="Deliver a complete, reviewed report",
backstory="You plan, delegate to specialists, and synthesize results.",
allow_delegation=True,
)
max_iter caps the number of reasoning iterations (think → act → observe cycles) an agent may take before it must return a final answer. The default is 20. Lower it to constrain autonomy, control cost, and avoid runaway loops; raise it for genuinely complex tasks that need more tool calls and reasoning steps. If the agent hits the limit, CrewAI forces it to produce its best answer with the information gathered so far.
agent = Agent(
role="Quick Classifier",
goal="Label the ticket with one category",
backstory="You classify decisively in a single step.",
max_iter=3, # tight cap — simple, fast task
)
Pass a list of tool instances to the agent's tools parameter. Tools can come from crewai-tools or be custom-built. Tools assigned at the agent level are available for any task the agent runs; tools can also be assigned at the task level to scope them to one task.
from crewai_tools import SerperDevTool, ScrapeWebsiteTool
search_tool = SerperDevTool()
scrape_tool = ScrapeWebsiteTool()
researcher = Agent(
role="Web Researcher",
goal="Find and extract relevant information online",
backstory="You are an expert at finding authoritative sources.",
tools=[search_tool, scrape_tool],
)
The LLM chooses tools based on each tool's name and description plus the current task. CrewAI presents the available tools and their descriptions to the model; when the model judges that a tool would help, it emits a tool call with arguments. This makes the tool description critical — it must clearly state what the tool does and what inputs it expects. Vague descriptions lead to wrong or missed tool calls. Ordering and limiting tools also nudges selection.
Specialized agents focus on a single domain or function — a SQL analyst, a legal-clause extractor, a unit-test writer. Their backstory, goal, tools, and even model are tailored to that niche. Specialization improves accuracy and coherence because the prompt and tools are aligned to one job, and it makes the crew composable: you can swap a specialist in or out without touching the rest.
allow_delegation=False — stop the agent from creating/delegating sub-tasks.max_iter — cap reasoning steps.max_rpm — cap request rate to protect quotas and APIs.max_execution_time — wall-clock timeout.Set the LLM temperature to 0 (or near it), keep prompts explicit and example-driven, and avoid open-ended phrasing. Use structured outputs (output_pydantic/output_json) so the format is fixed, and add guardrails to enforce that structure. For repeatability across runs, pin the model version and seed where the provider supports it.
from crewai import LLM
deterministic_llm = LLM(model="gpt-4o", temperature=0.0)
agent = Agent(role="Extractor", goal="Extract fields exactly",
backstory="You output only the requested fields.",
llm=deterministic_llm)
Pass a distinct llm to each agent. A common cost optimization is using a powerful model for planning/reasoning and a cheaper, faster model for routine work like summarizing or formatting.
from crewai import Agent, LLM
planner = Agent(role="Planner", goal="Plan the work",
backstory="Strategic thinker.",
llm=LLM(model="gpt-4o", temperature=0.2))
summarizer = Agent(role="Summarizer", goal="Condense text",
backstory="Concise writer.",
llm=LLM(model="gpt-4o-mini", temperature=0.0))
Role-based design assigns each agent a clear persona and responsibility so the team mirrors how humans organize work. Typical roles:
Each role drives its backstory, goal, and tool set. Clear, non-overlapping roles prevent agents from duplicating work or stepping on each other.
Give it a goal centered on accuracy, a backstory emphasizing diligence and citation, and web/RAG tools.
from crewai import Agent
from crewai_tools import SerperDevTool, ScrapeWebsiteTool
researcher = Agent(
role="Senior Research Analyst",
goal="Collect accurate, well-sourced information on {topic}",
backstory=(
"You are a diligent researcher. You prefer primary sources, "
"cross-check facts, and always cite where information came from."
),
tools=[SerperDevTool(), ScrapeWebsiteTool()],
verbose=True,
)
Configure it as an expert developer, optionally enable sandboxed code execution, and give it a code-interpreter tool.
from crewai import Agent
from crewai_tools import CodeInterpreterTool
coder = Agent(
role="Senior Python Engineer",
goal="Implement clean, tested Python solutions for {feature}",
backstory=(
"You write idiomatic, well-documented Python and validate it by "
"running the code before returning it."
),
tools=[CodeInterpreterTool()],
allow_code_execution=True, # run code in a sandbox
max_iter=25,
)
A review agent inspects another agent's output for quality, correctness, and style, returning approval or concrete change requests.
reviewer = Agent(
role="Senior Editor",
goal="Ensure the article is accurate, clear, and follows the style guide",
backstory=(
"You have a sharp eye for detail. You check facts, flag weak "
"arguments, fix grammar, and only approve when quality is high."
),
allow_delegation=False,
)
review_task = Task(
description="Review the drafted article and either approve it or list required fixes.",
expected_output="Either 'APPROVED' or a numbered list of required changes.",
agent=reviewer,
context=[write_task],
)
A manager decomposes a high-level goal into sub-tasks and delegates them. It needs allow_delegation=True and a backstory that rewards strategic thinking. In a hierarchical crew, the manager is set via manager_agent (or auto-created from manager_llm).
manager = Agent(
role="Engagement Manager",
goal="Break the objective into sub-tasks and coordinate specialists to deliver it",
backstory=(
"You think strategically, delegate to the right expert, and "
"synthesize their outputs into a coherent final deliverable."
),
allow_delegation=True,
)
Set verbose=True to stream the agent's chain of thought, tool selections, tool inputs/outputs, and final answer. Inspect where instructions were misread or where a tool errored. Run the agent in isolation on a single task with controlled input, and add event listeners or callbacks (see Q153) to capture structured traces. For tool problems, log the raw tool responses.
Before wiring an agent into a crew, exercise it on representative tasks and assert on the output. Mock external tools to make tests deterministic and fast.
def test_summarizer_returns_bullets():
task = Task(
description="Summarize: CrewAI orchestrates multiple AI agents.",
expected_output="3 bullet points.",
agent=summarizer,
)
crew = Crew(agents=[summarizer], tasks=[task])
result = crew.kickoff()
assert "-" in result.raw # crude check; prefer structured output + schema asserts
For robust tests, use structured outputs and validate against a Pydantic schema.
A task is a structured, single unit of work. Beyond description and expected_output, it can configure how the work is executed and validated:
| Parameter | Purpose |
| --- | --- |
| description | What to do (supports {placeholders}) |
| expected_output | The desired result/format |
| agent | The agent that executes it |
| context | List of tasks whose outputs feed this task |
| tools | Task-scoped tools |
| async_execution | Run this task concurrently |
| output_pydantic / output_json | Structured, validated output |
| output_file | Write the result to a file |
| guardrail | A validation function/criteria for the output |
| human_input | Pause for human review |
| callback | Function invoked with the task output |
A task is static — it describes what to do and what the output should look like. An agent is dynamic — it figures out how to do it, choosing tools and reasoning steps. Tasks have no autonomy; they are instructions consumed by agents. This separation lets you reuse the same agent across many tasks and the same task template across many inputs.
Write clear, unambiguous instructions that state the work, constraints, and any required format. Avoid vague pronouns and open-ended phrasing. Use placeholders for runtime inputs.
task = Task(
description=(
"Analyze the customer reviews for {product}. "
"Identify the top 3 complaints and top 3 praises. "
"Base every point strictly on the provided reviews — do not invent."
),
expected_output="Two markdown lists: 'Complaints' and 'Praises', 3 items each.",
agent=analyst,
)
expected_output describes the shape and content of the desired result. It serves two purposes: it tells the agent what "done" looks like (improving adherence), and it provides a basis for validation. Be concrete — specify format, length, and structure.
expected_output = (
"A JSON object with keys 'summary' (string) and "
"'citations' (list of URLs). No prose outside the JSON."
)
Each task references the agent that should run it via its agent parameter. In a sequential process the assignment is explicit. In a hierarchical process, you can omit agent and let the manager decide which worker handles each task at runtime.
write_task = Task(
description="Write the article from the research.",
expected_output="A polished markdown article.",
agent=writer, # explicit assignment (sequential)
)
The context parameter declares which tasks' outputs are injected into the current task's prompt. This builds an explicit dependency graph. In a sequential process, the previous task's output is also passed forward automatically, but context lets you pull from any earlier task — even multiple at once.
final_task = Task(
description="Combine the research and the competitor analysis into one brief.",
expected_output="A one-page strategic brief.",
agent=strategist,
context=[research_task, competitor_task], # depends on two tasks
)
Task chaining links tasks so each output feeds the next, forming a pipeline: Research → Outline → Draft → Review. In a sequential crew this happens by ordering; with context you can chain precisely and even fan multiple inputs into one task. Chaining keeps each step small and focused while building toward a complex deliverable.
async_execution=True. Independent work (e.g., researching two unrelated subtopics) runs at the same time, and a later task can gather both via context.market_task = Task(description="Research market trends for {topic}.",
expected_output="Bulleted trends.", agent=researcher,
async_execution=True)
competitor_task = Task(description="Research competitors for {topic}.",
expected_output="Bulleted competitor profiles.", agent=researcher,
async_execution=True)
synthesis_task = Task(description="Combine the two analyses.",
expected_output="A unified report.", agent=strategist,
context=[market_task, competitor_task]) # waits for both
Attach a Pydantic model via output_pydantic. CrewAI instructs the model to conform and parses the result into a typed object, accessible on the task output's .pydantic attribute.
from pydantic import BaseModel
from crewai import Task
class Article(BaseModel):
title: str
summary: str
tags: list[str]
task = Task(
description="Summarize {topic} into a structured article record.",
expected_output="An Article object with title, summary, and tags.",
agent=writer,
output_pydantic=Article,
)
result = crew.kickoff(inputs={"topic": "RAG"})
article = result.pydantic # typed Article instance
print(article.title, article.tags)
Use output_json with a Pydantic model (or instruct JSON in expected_output and validate with a guardrail). output_json makes the task return parsed JSON conforming to the schema.
from pydantic import BaseModel
class Sentiment(BaseModel):
label: str
confidence: float
task = Task(
description="Classify the sentiment of: {text}",
expected_output="A JSON object with 'label' and 'confidence'.",
agent=classifier,
output_json=Sentiment,
)
For extra safety, add a guardrail that re-validates and triggers a retry on malformed output.
A guardrail is a validation function attached to a task that inspects the output and either accepts it or rejects it with feedback, causing the agent to retry. Guardrails enforce correctness deterministically (schema checks, business rules) rather than relying on the LLM alone.
from crewai import Task, TaskOutput
def must_be_under_280_chars(output: TaskOutput):
text = output.raw
if len(text) <= 280:
return (True, text)
return (False, "Output exceeds 280 characters; shorten it.")
tweet_task = Task(
description="Write a tweet announcing {feature}.",
expected_output="A tweet under 280 characters.",
agent=marketer,
guardrail=must_be_under_280_chars, # validated; retried on failure
)
Tasks consume external data through tools the executing agent calls (web search, API requests, database queries, file readers, RAG retrieval). You can scope a tool to a specific task by setting the task's tools parameter, ensuring the agent uses the right integration for that step.
from crewai_tools import FileReadTool
ingest_task = Task(
description="Read sales.csv and report total revenue by region.",
expected_output="A table of revenue by region.",
agent=analyst,
tools=[FileReadTool(file_path="sales.csv")],
)
Dynamic tasks emerge at runtime. In a hierarchical process, the manager generates and assigns sub-tasks based on intermediate results. In Flows, you can branch and build tasks programmatically. You can also construct tasks in a loop from data.
# Build one task per document discovered at runtime
tasks = [
Task(description=f"Summarize the document titled '{doc}'.",
expected_output="A 3-sentence summary.",
agent=summarizer)
for doc in discovered_docs
]
crew = Crew(agents=[summarizer], tasks=tasks, process=Process.sequential)
Set output_file on the task. CrewAI writes the task's result to that path, which is handy for reports, generated code, or markdown deliverables.
report_task = Task(
description="Compile the final quarterly report.",
expected_output="A complete markdown report.",
agent=writer,
output_file="reports/q3_report.md",
)
Wrap task creation in a factory function so the same structure can be parameterized for different inputs — a clean way to scale workflows without duplicating definitions.
def research_task_for(topic: str, agent) -> Task:
return Task(
description=f"Research the latest developments in {topic}.",
expected_output="5 sourced bullet points.",
agent=agent,
)
tasks = [research_task_for(t, researcher) for t in ["LLMs", "RAG", "agents"]]
Placeholders like {topic} interpolated from kickoff inputs are another reuse mechanism.
max_retry_limit — cap how many times a failing task retries.kickoff — catch exceptions and apply fallback logic.task = Task(
description="Extract structured data from the invoice.",
expected_output="Valid JSON matching the schema.",
agent=extractor,
guardrail=validate_invoice_json,
max_retry_limit=3,
)
Instantiate the task with controlled input, run it in a minimal crew (or mock the agent's LLM), and assert on the structured output. Prefer output_pydantic/output_json so assertions are precise.
def test_sentiment_task():
result = Crew(agents=[classifier], tasks=[sentiment_task]).kickoff(
inputs={"text": "I love this product!"}
)
assert result.pydantic.label.lower() == "positive"
expected_output — the agent doesn't know what "done" means.context, so a task lacks needed inputs.A crew is the orchestration container that owns a list of agents and tasks and runs them under a chosen process. It is responsible for scheduling tasks, passing context between them, coordinating delegation, managing memory and knowledge, enforcing rate limits, and assembling the final CrewOutput. Key crew-level parameters include agents, tasks, process, memory, knowledge, manager_llm/manager_agent (hierarchical), verbose, cache, max_rpm, and planning.
Provide agents, tasks, and a process. The simplest form:
from crewai import Crew, Process
crew = Crew(
agents=[planner, researcher, writer, reviewer],
tasks=[plan_task, research_task, write_task, review_task],
process=Process.sequential,
memory=True,
verbose=True,
)
result = crew.kickoff(inputs={"topic": "agentic workflows"})
In a scaffolded project you'd instead define a @CrewBase class and assemble the crew from YAML-configured agents and tasks (see Q75).
manager_llm or manager_agent.verbose, cache, max_rpm, planning, callbacks.In a sequential crew, each agent consumes the prior task's output, forming an assembly line. In a hierarchical crew, the manager agent assigns tasks to workers, collects their results, and synthesizes a final answer. Across both, shared memory and delegation tools let agents reference each other's work and ask each other questions, increasing reliability and reducing redundant effort.
kickoff(inputs=...) — runs the crew once, interpolating inputs into task/agent templates, and returns a CrewOutput.kickoff_for_each(inputs=[...]) — runs the crew once per input dict in a list, returning a list of outputs. Ideal for batch processing.kickoff_async / kickoff_for_each_async — async variants for concurrency.topics = [{"topic": "RAG"}, {"topic": "agents"}, {"topic": "evals"}]
results = crew.kickoff_for_each(inputs=topics) # one run per topic
for r in results:
print(r.raw)
Pass a dict to kickoff. Any {placeholder} in agent goals/backstories or task descriptions/expected outputs is replaced with the corresponding value at runtime.
crew.kickoff(inputs={"topic": "vector search", "audience": "beginners"})
This makes a single crew definition reusable across many concrete requests.
kickoff returns a CrewOutput. The final result is in .raw; structured results are in .pydantic or .json_dict when tasks declare schemas; per-task results are in .tasks_output; and token usage is in .token_usage.
result = crew.kickoff(inputs={"topic": "embeddings"})
print(result.raw) # final text
print(result.tasks_output[0]) # first task's output
print(result.token_usage) # prompt/completion token stats
CrewOutput is the structured return value of a crew run:
| Attribute | Contents |
| --- | --- |
| raw | The final raw string output |
| pydantic | Parsed Pydantic object (if the final task declared one) |
| json_dict | Parsed JSON dict (if declared) |
| tasks_output | A list of each task's individual output |
| token_usage | Aggregate token usage metrics for cost tracking |
This makes it easy to consume results programmatically and to monitor cost.
Crews surface exceptions raised by agents or tools. You manage failure via:
max_retry_limit at the task level.kickoff for run-level recovery.try:
result = crew.kickoff(inputs=inputs)
except Exception as e:
logger.error("Crew run failed: %s", e)
result = run_fallback_pipeline(inputs)
async_execution.kickoff_for_each / kickoff_for_each_async.Use kickoff_async to await a single run, or kickoff_for_each_async for concurrent batch runs. This integrates cleanly with async web frameworks.
import asyncio
async def main():
result = await crew.kickoff_async(inputs={"topic": "agents"})
print(result.raw)
asyncio.run(main())
@CrewBase is the recommended project structure. It wires YAML-defined agents and tasks to Python via decorators: @agent, @task, and @crew. This separates configuration (YAML) from logic (Python), keeping crews clean and maintainable.
from crewai import Agent, Crew, Task, Process
from crewai.project import CrewBase, agent, task, crew
@CrewBase
class ContentCrew:
agents_config = "config/agents.yaml"
tasks_config = "config/tasks.yaml"
@agent
def researcher(self) -> Agent:
return Agent(config=self.agents_config["researcher"])
@task
def research_task(self) -> Task:
return Task(config=self.tasks_config["research_task"])
@crew
def crew(self) -> Crew:
return Crew(agents=self.agents, tasks=self.tasks,
process=Process.sequential, verbose=True)
A process is the execution strategy a crew uses to run its tasks: how order is determined, how dependencies resolve, and how agents are invoked. CrewAI provides Process.sequential and Process.hierarchical. The process is the orchestration backbone — it decides whether work flows linearly or is dynamically delegated by a manager.
In a sequential process, tasks execute in list order, and each task can receive prior outputs as context. It's the simplest, most predictable pattern — ideal for linear pipelines like research → draft → edit.
crew = Crew(
agents=[researcher, writer, editor],
tasks=[research_task, write_task, edit_task],
process=Process.sequential,
)
In a hierarchical process, a manager agent coordinates the work: it reviews tasks, decides which worker agent should handle each, delegates, validates results, and assembles the final output. You must provide either a manager_llm (CrewAI auto-creates a manager) or a custom manager_agent. This pattern suits open-ended or large problems that benefit from dynamic delegation.
crew = Crew(
agents=[researcher, writer, reviewer], # workers
tasks=[big_task],
process=Process.hierarchical,
manager_llm="gpt-4o", # manager is auto-created
)
The manager receives the overall objective, breaks it into sub-tasks, and uses delegation tools to assign them to the most suitable worker by role. It monitors results, may re-delegate or create follow-up tasks, and finally synthesizes everything into a coherent answer. It effectively automates the planning-and-coordination role a human team lead would play.
| Use sequential when… | Use hierarchical when… | | --- | --- | | The steps and order are known up front | The problem is open-ended or exploratory | | Dependencies are strictly linear | Sub-tasks emerge dynamically | | You want predictability and easy debugging | You want adaptive delegation to specialists | | The workflow is simple | The workflow is large or branches |
Sequential is cheaper and more deterministic; hierarchical is more flexible but adds manager overhead and variability.
manager_llm — you pass a model and CrewAI auto-creates a default manager agent that uses it. Quick to set up.manager_agent — you supply a fully customized manager Agent (custom role, goal, backstory, tools). Use this when you need fine control over how planning and delegation happen.You provide one or the other for a hierarchical crew, not both.
The manager has allow_delegation=True and therefore the Delegate work and Ask question tools. It uses them to route sub-tasks to workers by role, gathers their outputs, and integrates them. If a result is insufficient, the manager can re-delegate or ask clarifying questions. Delegation offloads specialized work to the right agent and keeps the manager focused on coordination.
Combine a reviewer agent with human-in-the-loop. The writer drafts, the reviewer critiques, and a human approves the final step.
draft_task = Task(description="Draft the proposal.", expected_output="A draft.",
agent=writer)
review_task = Task(description="Review the draft; approve or request changes.",
expected_output="'APPROVED' or a list of fixes.",
agent=reviewer, context=[draft_task])
approval_task = Task(description="Present the final proposal for sign-off.",
expected_output="An approved proposal.",
agent=writer, context=[review_task],
human_input=True) # human approves
Chain alternating generate/review tasks, or use a guardrail that re-runs a task until it passes. For a fixed number of cycles, build the tasks in a loop and pass each iteration's output as context to the next.
tasks = []
prev = None
for i in range(2): # two refinement cycles
draft = Task(description=f"Refine the draft (pass {i+1}).",
expected_output="An improved draft.",
agent=writer, context=[prev] if prev else [])
review = Task(description="Critique the latest draft.",
expected_output="Specific, actionable feedback.",
agent=reviewer, context=[draft])
tasks += [draft, review]
prev = review
@persist) so work survives restarts.max_execution_time) to bound stuck agents.Tools are functions or integrations that agents call to act beyond text generation — web search, API calls, database queries, file I/O, code execution, and RAG retrieval. They extend an agent's capabilities into the real world. CrewAI tools come from the crewai-tools package or are custom-built via BaseTool or the @tool decorator. Each tool exposes a name, a description (used by the LLM to decide when to call it), and a callable that runs the logic.
LLMs are frozen at their training cutoff and can't access live data, run computations reliably, or affect external systems on their own. Tools bridge that gap: they let agents fetch current information, query databases, call services, execute code, and write files. Without tools, agents can only reason over what's in their prompt; with tools, they can ground answers in real data and take real actions — dramatically reducing hallucination and expanding usefulness.
Subclass BaseTool, set name and description, define an args_schema (Pydantic) for typed inputs, and implement _run.
from crewai.tools import BaseTool
from pydantic import BaseModel, Field
import requests
class WeatherInput(BaseModel):
city: str = Field(..., description="City name to look up")
class WeatherTool(BaseTool):
name: str = "get_weather"
description: str = "Get the current weather for a given city."
args_schema: type[BaseModel] = WeatherInput
def _run(self, city: str) -> str:
resp = requests.get(f"https://api.example.com/weather?q={city}", timeout=10)
data = resp.json()
return f"The weather in {city} is {data['temp']}°C, {data['conditions']}."
weather_tool = WeatherTool()
For lightweight tools, decorate a function with @tool. The first line/docstring becomes the description; type hints define the inputs.
from crewai.tools import tool
@tool("Multiply Numbers")
def multiply(a: int, b: int) -> int:
"""Multiply two integers and return the product."""
return a * b
The decorator approach is concise; BaseTool is better when you need validation schemas, state, or caching control.
During its reasoning loop, the agent's LLM decides a tool is needed and emits a tool call with arguments. CrewAI intercepts the call, validates arguments against the tool's args_schema, runs the tool, and feeds the returned result back into the agent's context as an observation. The agent then continues reasoning, possibly calling more tools, until it produces a final answer. Tools are only invoked when the agent chooses to call them.
Use ready-made tools from crewai-tools such as SerperDevTool (Google via Serper), ScrapeWebsiteTool, or WebsiteSearchTool. Most require an API key via environment variable.
from crewai_tools import SerperDevTool, ScrapeWebsiteTool
# export SERPER_API_KEY=...
search = SerperDevTool() # web search
scrape = ScrapeWebsiteTool() # fetch and extract page content
researcher = Agent(role="Researcher", goal="Find sources on {topic}",
backstory="You find authoritative info.",
tools=[search, scrape])
You can also build a custom search tool wrapping requests + an API like SerpAPI.
Wrap your DB access in a tool, parameterize queries to prevent SQL injection, and return results as text or structured data.
from crewai.tools import BaseTool
from pydantic import BaseModel, Field
import psycopg2
class QueryInput(BaseModel):
region: str = Field(..., description="Region to filter sales by")
class SalesQueryTool(BaseTool):
name: str = "query_sales"
description: str = "Return total sales for a given region."
args_schema: type[BaseModel] = QueryInput
def _run(self, region: str) -> str:
conn = psycopg2.connect(dsn="...")
try:
cur = conn.cursor()
cur.execute("SELECT SUM(amount) FROM sales WHERE region = %s", (region,))
total = cur.fetchone()[0]
return f"Total sales for {region}: {total}"
finally:
conn.close()
crewai-tools also ships database helpers (e.g., NL2SQLTool) for natural-language querying.
Build a tool that constructs the request, sends it, and parses the response. Store secrets in environment variables.
from crewai.tools import tool
import os, requests
@tool("Create GitHub Issue")
def create_issue(repo: str, title: str, body: str) -> str:
"""Open a GitHub issue in owner/repo with the given title and body."""
token = os.environ["GITHUB_TOKEN"]
r = requests.post(
f"https://api.github.com/repos/{repo}/issues",
headers={"Authorization": f"Bearer {token}"},
json={"title": title, "body": body}, timeout=15,
)
r.raise_for_status()
return f"Created issue #{r.json()['number']}"
For GraphQL, POST a query string and variables to the endpoint and return the JSON data field.
Use a RAG-oriented tool from crewai-tools (e.g., PDFSearchTool, QdrantVectorSearchTool) or write a custom tool that embeds the query and runs a similarity search.
from crewai.tools import BaseTool
from pydantic import BaseModel, Field
import chromadb
class RetrieveInput(BaseModel):
query: str = Field(..., description="The search query")
class ChromaRetrieveTool(BaseTool):
name: str = "knowledge_search"
description: str = "Retrieve the most relevant passages from the knowledge base."
args_schema: type[BaseModel] = RetrieveInput
def __init__(self, collection):
super().__init__()
self._collection = collection
def _run(self, query: str) -> str:
res = self._collection.query(query_texts=[query], n_results=4)
return "\n\n".join(res["documents"][0])
Built-in Knowledge (see Q117) handles much of this automatically.
Define a Pydantic model as the tool's args_schema. CrewAI validates the LLM's arguments against it before running the tool, catching type errors and missing fields early and giving the model clear, self-documenting input specs.
from pydantic import BaseModel, Field
class TransferInput(BaseModel):
account_id: str = Field(..., description="Destination account ID")
amount: float = Field(..., gt=0, description="Positive transfer amount")
Validation also acts as a guardrail — malformed calls are rejected rather than silently misbehaving.
Wrap the tool body in try/except, return a clear error message (so the agent can react or retry), and optionally add retries with backoff for transient failures.
from crewai.tools import tool
import requests, time
@tool("Fetch URL")
def fetch(url: str) -> str:
"""Fetch the text content of a URL, retrying on transient errors."""
for attempt in range(3):
try:
r = requests.get(url, timeout=10)
r.raise_for_status()
return r.text[:5000]
except requests.RequestException as e:
if attempt == 2:
return f"ERROR: could not fetch {url}: {e}"
time.sleep(2 ** attempt) # exponential backoff
Returning a descriptive error keeps the run alive and lets the agent adapt.
CrewAI can cache tool results so identical calls don't re-execute, saving time and cost. Caching is on by default (cache=True on the agent). You can also define a custom cache_function on a tool to decide when a result is cacheable (e.g., cache successful lookups but not error responses).
from crewai.tools import BaseTool
class PriceTool(BaseTool):
name: str = "get_price"
description: str = "Look up a product price by SKU."
def _run(self, sku: str) -> str:
return lookup_price(sku)
def cache_function(self, args, result) -> bool:
return "ERROR" not in result # don't cache failures
args_schema plus sanitization to prevent injection.Use the agent/crew max_rpm to cap overall request rate, and implement limiting inside the tool for external APIs — respect provider limits and handle HTTP 429 gracefully with backoff.
from crewai.tools import tool
import time, requests
_last_call = [0.0]
@tool("Rate-limited API")
def call_api(q: str) -> str:
"""Call an API no more than once per second."""
elapsed = time.time() - _last_call[0]
if elapsed < 1.0:
time.sleep(1.0 - elapsed)
_last_call[0] = time.time()
r = requests.get(f"https://api.example.com?q={q}", timeout=10)
if r.status_code == 429:
return "Rate limited; try again shortly."
return r.text
For I/O-bound work, you can define async logic and use it within async crew runs. A common pattern is to wrap async calls so the tool returns a concrete result.
from crewai.tools import tool
import asyncio, aiohttp
@tool("Async Fetch")
def async_fetch(url: str) -> str:
"""Fetch a URL using an async HTTP client."""
async def _go():
async with aiohttp.ClientSession() as s:
async with s.get(url, timeout=10) as r:
return (await r.text())[:5000]
return asyncio.run(_go())
Async tools shine when combined with async_execution tasks and kickoff_async.
args_schema for validation and clarity.CrewAI's memory system has several layers that work together when memory=True:
| Type | What it stores | | --- | --- | | Short-term memory | Context within the current run (recent interactions), via embeddings/RAG | | Long-term memory | Insights persisted across runs (stored in SQLite by default) | | Entity memory | Structured facts about entities (people, places, concepts) encountered | | Contextual memory | A combination layer that assembles relevant context for each step | | External memory | Pluggable custom/third-party backends (e.g., Mem0) |
Short-term memory holds context relevant to the current execution — recent agent interactions, tool results, and intermediate outputs. It uses embeddings and similarity search (RAG-style) so agents can recall pertinent recent information without stuffing the entire history into the prompt. It is scoped to the run and helps maintain coherence across tasks within one kickoff.
Long-term memory persists valuable insights across multiple runs. After a crew finishes, useful learnings are stored (by default in a local SQLite database) and can be retrieved in future runs, letting the system improve over time and avoid re-deriving the same conclusions. It's how a crew "remembers" lessons between sessions.
Entity memory captures and organizes structured information about specific entities — people, organizations, products, concepts — that agents encounter. It enables targeted recall ("what do we know about Customer X?") and keeps facts about an entity consistent across tasks and runs, improving relevance and reducing contradictions.
Set memory=True on the crew. CrewAI then activates short-term, long-term, and entity memory using a default embedder (you can override it).
crew = Crew(
agents=[researcher, writer],
tasks=[research_task, write_task],
process=Process.sequential,
memory=True,
embedder={"provider": "openai", "config": {"model": "text-embedding-3-small"}},
)
When memory is enabled, CrewAI automatically retrieves relevant memories and injects them into each agent's context before reasoning — agents don't call memory explicitly. The contextual memory layer queries short-term, long-term, and entity stores for items relevant to the current task and prepends them to the prompt. You can also expose a memory-search tool for explicit lookups if needed.
By default, CrewAI persists long-term and entity memory to a local SQLite database and stores short-term embeddings in a local vector store (ChromaDB). The storage location follows the platform's app-data directory. For production and multi-instance deployments, point memory to external/shared storage so all instances share the same knowledge.
CrewAI supports external memory providers and custom storage backends so memory survives across deployments and scales horizontally. For example, you can integrate Mem0 or supply your own storage implementation.
from crewai import Crew
from crewai.memory.external.external_memory import ExternalMemory
crew = Crew(
agents=[...],
tasks=[...],
external_memory=ExternalMemory(
embedder_config={"provider": "mem0", "config": {"user_id": "user_123"}}
),
)
Custom storage lets you back memory with Postgres, Redis, or a managed vector DB.
context to explicitly forward needed prior task outputs.Use the CLI to wipe stored memories between experiments or deployments, ensuring stale long-term insights don't leak into new runs.
# Reset all memory stores for the project
crewai reset-memories --all
# Or target specific stores
crewai reset-memories --long # long-term only
crewai reset-memories --short # short-term only
crewai reset-memories --entities # entity memory only
Programmatically, you can also clear via the memory objects on the crew.
Knowledge is CrewAI's built-in capability to give agents access to external reference material (documents, files, text, structured data) that grounds their responses. You attach knowledge sources to an agent or crew; CrewAI chunks, embeds, and indexes them, then automatically retrieves the most relevant pieces during execution. It's a first-class RAG layer that requires far less plumbing than wiring up your own vector store and retrieval tool.
from crewai import Agent, Crew
from crewai.knowledge.source.string_knowledge_source import StringKnowledgeSource
policy = StringKnowledgeSource(content="Refunds are allowed within 30 days of purchase...")
support_agent = Agent(role="Support", goal="Answer policy questions accurately",
backstory="You answer strictly from company policy.",
knowledge_sources=[policy])
Use Knowledge for stable, always-relevant reference material; use a RAG tool when retrieval should be conditional or when you need full control over the query and store.
CrewAI ships several source types, including:
| Source | Use |
| --- | --- |
| StringKnowledgeSource | Inline text |
| TextFileKnowledgeSource | .txt files |
| PDFKnowledgeSource | PDF documents |
| CSVKnowledgeSource | CSV data |
| ExcelKnowledgeSource | Spreadsheets |
| JSONKnowledgeSource | JSON files |
| CrewDoclingSource | Rich document parsing (web/docs) |
You can also implement a custom knowledge source by subclassing the base source class.
Pass knowledge_sources at the agent level (scoped to that agent) or the crew level (shared by all agents). Crew-level knowledge is convenient for shared reference material.
from crewai import Crew
from crewai.knowledge.source.pdf_knowledge_source import PDFKnowledgeSource
handbook = PDFKnowledgeSource(file_paths=["employee_handbook.pdf"])
crew = Crew(
agents=[hr_agent, support_agent],
tasks=[answer_task],
knowledge_sources=[handbook], # shared across the crew
embedder={"provider": "openai", "config": {"model": "text-embedding-3-small"}},
)
A vector database stores embeddings of text chunks so that, given a query embedding, the system can retrieve the most semantically similar chunks. CrewAI uses a vector store (ChromaDB by default) under both memory and Knowledge. When an agent needs grounding, the query is embedded, nearest chunks are fetched, and they're injected into the prompt — turning the LLM's open-ended guess into an evidence-backed answer.
When you need conditional retrieval, build a tool that embeds the query, searches the store, and returns top-K chunks.
from crewai.tools import BaseTool
from pydantic import BaseModel, Field
from sentence_transformers import SentenceTransformer
import chromadb
class RAGInput(BaseModel):
query: str = Field(..., description="What to look up in the knowledge base")
class RAGTool(BaseTool):
name: str = "search_docs"
description: str = "Search the document knowledge base for relevant passages."
args_schema: type[BaseModel] = RAGInput
def __init__(self, collection, model_name="all-MiniLM-L6-v2"):
super().__init__()
self._collection = collection
self._embedder = SentenceTransformer(model_name)
def _run(self, query: str) -> str:
emb = self._embedder.encode(query).tolist()
res = self._collection.query(query_embeddings=[emb], n_results=4)
return "\n---\n".join(res["documents"][0])
Keep chunks small enough for precise retrieval but large enough to carry meaning; tune size and overlap to your documents. CrewAI's Knowledge sources support configurable chunk size and overlap.
RAG grounds the agent in retrieved evidence rather than its parametric memory. To maximize the effect: instruct the agent to answer only from retrieved context, to cite sources, and to say "I don't know" when the context lacks the answer. Pair RAG with a reviewer agent or guardrail that checks claims against the retrieved passages.
task = Task(
description=(
"Answer the question using ONLY the retrieved context. "
"If the answer is not in the context, say you don't know. Cite sources."
),
expected_output="A grounded answer with citations, or an explicit 'I don't know'.",
agent=answer_agent,
)
Pass an embedder config to the crew (or knowledge source). CrewAI supports multiple providers (OpenAI, Google, Ollama, etc.). Consistency matters — index and query with the same model.
crew = Crew(
agents=[...], tasks=[...],
knowledge_sources=[handbook],
embedder={
"provider": "ollama",
"config": {"model": "nomic-embed-text"},
},
)
Using a local embedder (e.g., via Ollama) keeps data on-premises for privacy-sensitive deployments.
Track hallucination rate as a key quality signal.
crewai reset-memories).A common division of labor: a retrieval agent queries the knowledge base, a synthesis agent composes an answer from the retrieved passages, and a citation/review agent verifies grounding and attaches sources. A manager (hierarchical) or sequential chain coordinates them. Splitting retrieval from synthesis improves both grounding and quality, since each agent focuses on one responsibility.
Through LiteLLM, CrewAI supports a wide range of providers: OpenAI (GPT-4o, GPT-4o-mini, etc.), Anthropic (Claude family), Google (Gemini), Azure OpenAI, AWS Bedrock, Groq, Mistral, Cohere, and local models via Ollama or any OpenAI-compatible endpoint. You select a model by its string identifier and provide the corresponding API key via environment variables.
Use the LLM class (or just pass a model string) and assign it to an agent. The LLM class exposes parameters like temperature, max_tokens, top_p, and more.
from crewai import Agent, LLM
llm = LLM(
model="gpt-4o",
temperature=0.3,
max_tokens=2000,
)
agent = Agent(role="Analyst", goal="Analyze data",
backstory="You are precise and concise.", llm=llm)
A bare string (llm="gpt-4o") uses provider defaults.
CrewAI delegates model calls to LiteLLM, a unified client that translates a single API into each provider's native format. This is why switching providers is usually just changing the model string and the relevant API key — LiteLLM handles authentication, request shaping, and response normalization. It also centralizes features like retries and (provider-permitting) streaming and token accounting.
Run a model in Ollama and point CrewAI at the local endpoint using the ollama/ model prefix. This keeps data on-premises — useful for privacy/air-gapped requirements.
from crewai import Agent, LLM
local_llm = LLM(
model="ollama/llama3.1",
base_url="http://localhost:11434",
)
agent = Agent(role="On-Prem Analyst", goal="Analyze sensitive data locally",
backstory="You operate fully offline.", llm=local_llm)
Pair with a local embedder (e.g., nomic-embed-text) for fully local memory/knowledge.
Assign different LLM objects per agent, or change the global model string and API key. Because LiteLLM normalizes the interface, no code changes beyond the model identifier and credentials are typically required.
planner = Agent(role="Planner", goal="Plan", backstory="...",
llm=LLM(model="claude-3-5-sonnet-20241022", temperature=0.2))
executor = Agent(role="Executor", goal="Execute", backstory="...",
llm=LLM(model="gpt-4o-mini", temperature=0.0))
Temperature controls output randomness. 0.0 yields deterministic, focused responses; higher values (up to ~1.0+) increase diversity and creativity. For factual, structured, or extraction tasks use low temperature; for brainstorming or creative writing use higher. In multi-agent crews, you often set planners/extractors low and creative writers higher.
max_tokens — cap completion length.CrewAI also manages context assembly so memory/knowledge inject only the most relevant snippets rather than everything.
Set max_rpm on agents or the crew to throttle requests and stay within provider quotas. For transient 429s, LiteLLM retries; you can add your own backoff in tools that call external APIs.
crew = Crew(agents=[...], tasks=[...], max_rpm=20) # cap requests/minute
kickoff_for_each to amortize setup.token_usage to find expensive agents/tasks and tune them.Match model capability to task difficulty and cost tolerance. Use a strong reasoning model (e.g., GPT-4o or Claude Sonnet) for planning, complex analysis, and the manager; use smaller, cheaper models for summarizing, formatting, and classification. Validate choices with evaluations comparing quality vs. cost on your real tasks.
Catch LLM errors and route to a backup model, or pre-configure fallbacks. A simple pattern wraps agent construction so a secondary model is used if the primary fails.
from crewai import Agent, LLM
def make_agent(primary="gpt-4o", fallback="gpt-4o-mini"):
try:
llm = LLM(model=primary)
_ = llm.call("ping") # health check
except Exception:
llm = LLM(model=fallback)
return Agent(role="Resilient Agent", goal="...", backstory="...", llm=llm)
LiteLLM also supports configured fallback lists at the call layer.
Combine models within one crew: a large model plans and reasons; small/local models execute routine sub-tasks. Keep context consistent across them via shared memory/knowledge, and ensure outputs are structured so a downstream model can consume an upstream model's result reliably. This balances quality, latency, and cost.
manager = Agent(role="Manager", goal="Coordinate", backstory="...",
llm=LLM(model="gpt-4o"), allow_delegation=True)
summarizer = Agent(role="Summarizer", goal="Condense", backstory="...",
llm=LLM(model="ollama/llama3.1"))
A Flow is an event-driven workflow abstraction for building structured, stateful, deterministic AI pipelines. While a Crew is an autonomous team, a Flow is explicit application logic: you define discrete steps as methods, connect them with decorators, share typed state across them, and branch conditionally. Flows can orchestrate multiple crews, plain Python functions, and direct LLM calls — making them the right tool when you need precise control over execution order and data flow.
from crewai.flow.flow import Flow, start, listen
class GreetingFlow(Flow):
@start()
def begin(self):
return "world"
@listen(begin)
def greet(self, name):
return f"Hello, {name}!"
flow = GreetingFlow()
print(flow.kickoff()) # Hello, world!
@start() marks the entry point(s) of a flow — methods that run when the flow kicks off.@listen(step) marks a method that runs when the referenced step completes, receiving its output. This wires steps into a directed graph of events.class Pipeline(Flow):
@start()
def fetch(self):
return get_data()
@listen(fetch)
def process(self, data):
return transform(data)
@listen(process)
def save(self, processed):
persist(processed)
Flows carry shared state accessible to every step. You can use unstructured state (a dict-like self.state) or structured state (a Pydantic model) for type safety. Steps read and mutate this state, enabling data to flow without manually threading it through every method. With @persist, state can be saved so a flow can resume.
from pydantic import BaseModel
from crewai.flow.flow import Flow, start, listen
class State(BaseModel):
topic: str = ""
draft: str = ""
class ArticleFlow(Flow[State]):
@start()
def set_topic(self):
self.state.topic = "agentic AI"
@listen(set_topic)
def write(self):
self.state.draft = f"An article about {self.state.topic}"
These control conditional and combined execution:
@router(step) — branch to different next steps based on the step's return value.or_(a, b) — trigger a listener when any of the listed steps complete.and_(a, b) — trigger a listener only when all listed steps complete.from crewai.flow.flow import Flow, start, router, listen
class SupportFlow(Flow):
@start()
def classify(self):
return "billing" # or "technical"
@router(classify)
def route(self, category):
return category # name of the next step to run
@listen("billing")
def handle_billing(self):
return "Handled billing"
@listen("technical")
def handle_technical(self):
return "Handled technical"
A Flow step can invoke a full crew via crew.kickoff(), using the crew's result to update flow state and drive subsequent branching. This composition is powerful: the Flow provides deterministic control and routing, while each crew handles an autonomous, reasoning-heavy sub-problem.
class ResearchFlow(Flow):
@start()
def run_research(self):
result = research_crew.kickoff(inputs={"topic": self.state.topic})
self.state.research = result.raw
@listen(run_research)
def run_writing(self):
return writing_crew.kickoff(inputs={"research": self.state.research})
| Use a Crew when… | Use a Flow when… | | --- | --- | | You want autonomous, collaborative agents | You need deterministic, explicit control | | The path to the answer is open-ended | The path has clear branches/conditions | | Delegation and emergent behavior help | You must guarantee order and state handling | | The task is a single cohesive objective | You're orchestrating multiple stages/crews |
They're complementary: Flows for the control plane, Crews for the reasoning sub-steps.
CrewAI emits events throughout execution and integrates with observability platforms (e.g., AgentOps, Langfuse, Langtrace, OpenLIT, MLflow, Weights & Biases Weave, Arize Phoenix). At minimum, enable verbose=True during development; in production, attach an observability integration or custom event listeners to capture traces, token usage, latency, and errors centrally.
Turn on verbose=True to stream reasoning, tool calls, and outputs. For structured logs, use Python's logging and/or CrewAI event listeners to record task start/end, tool invocations, and results with agent name, task id, and timestamps. Route logs to a central aggregator in production.
import logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("crew")
crew = Crew(agents=[...], tasks=[...], verbose=True)
result = crew.kickoff(inputs={...})
logger.info("Tokens used: %s", result.token_usage)
Use a callback per task to capture each task's output as it completes, and/or register event listeners for fine-grained tracing. Assign correlation IDs so you can follow a request across agents and tool calls. Observability integrations (Langfuse, Langtrace) provide ready-made distributed traces.
def on_task_done(output):
print(f"[{output.agent}] finished: {output.raw[:120]}...")
task = Task(description="...", expected_output="...",
agent=writer, callback=on_task_done)
Every CrewOutput includes token_usage (prompt, completion, total tokens, and request count). Multiply tokens by per-token pricing to estimate cost, aggregate by agent/task, and alert on thresholds. Observability platforms chart this automatically.
result = crew.kickoff(inputs={...})
usage = result.token_usage
print(usage.total_tokens, usage.prompt_tokens, usage.completion_tokens)
Most integrations are a few lines — initialize the platform's SDK before running the crew, and it auto-instruments CrewAI's events.
import agentops
agentops.init(api_key="...") # auto-captures crew/agent/tool events
# ...define and run your crew as usual...
result = crew.kickoff(inputs={...})
Langtrace, Langfuse, OpenLIT, and MLflow follow similar init-then-run patterns and surface traces, token usage, latency, and errors in their dashboards.
callback — a function called with each task's output.step_callback (agent/crew) — called on each intermediate reasoning step.def step_logger(step):
print("STEP:", step)
crew = Crew(agents=[...], tasks=[...], step_callback=step_logger)
These hooks power custom logging, metrics, and real-time UIs.
Maintain an immutable, timestamped log of every tool call, delegation, and output, tagged with agent and task IDs. Persist it to append-only storage; for regulated environments add integrity checks. Mask or redact sensitive data before logging. Audit trails support compliance, incident review, and reproducibility.
| Metric | Why | | --- | --- | | Request latency (p50/p95/p99) | User experience and SLAs | | Token usage & cost | Budget control | | Error/failure rate | Reliability | | Tool call rate & latency | Integration health | | Task completion time | Bottleneck detection | | Retry/guardrail-failure rate | Output-quality signal | | Memory/knowledge retrieval relevance | Grounding quality | | Hallucination/quality score | Correctness |
Apply least privilege to agents and tools, store secrets in environment variables or a vault, encrypt sensitive data at rest and in transit, validate all external inputs, sandbox code execution, and add guardrails plus human-in-the-loop for high-impact actions. Maintain audit logs and enforce authentication/authorization at the application boundary.
import os
api_key = os.environ["WEATHER_API_KEY"] # never inline the literal key
Validate inputs with args_schema, restrict file access to allowlisted directories, limit outbound network calls to known hosts, set timeouts and resource limits, and sandbox any code execution (containers/VMs). Audit tool code for vulnerabilities and avoid passing raw, unsanitized agent output into shells or SQL.
Use task guardrails (validation functions) to enforce structure and policy, content filters to block disallowed topics, and reviewer agents for nuanced checks. Combine deterministic checks (schema, regex, allow/deny lists) with LLM-based review for defense in depth.
def no_pii(output):
import re
if re.search(r"\b\d{3}-\d{2}-\d{4}\b", output.raw): # SSN pattern
return (False, "Output contains PII; remove it.")
return (True, output.raw)
task = Task(description="...", expected_output="...",
agent=agent, guardrail=no_pii)
Test at multiple levels: unit-test tools in isolation (including failure paths), test individual agents/tasks with controlled inputs and structured-output assertions, and integration-test crews end-to-end with mocked LLMs for determinism. Use the crewai test command for built-in quality evaluation across multiple runs.
The CLI runs your crew multiple times and scores task outputs using an evaluator model, giving an aggregate quality signal that's useful for regression testing prompt/model changes.
# Run the crew 5 times and evaluate with gpt-4o as the scorer
crewai test --n_iterations 5 --model gpt-4o
Compare scores before/after a change to catch quality regressions.
Replace the LLM with a stub so tests are fast and deterministic. You can patch the agent's llm.call or inject a fake LLM that returns canned responses.
from unittest.mock import patch
def test_writer_with_mocked_llm():
with patch("crewai.llm.LLM.call", return_value="Mocked article body"):
result = Crew(agents=[writer], tasks=[write_task]).kickoff(
inputs={"topic": "testing"}
)
assert "Mocked article body" in result.raw
Also mock tools (network/DB) to avoid external dependencies.
Define metrics — accuracy, completeness, coherence, faithfulness/grounding, format compliance, latency, and cost — and measure them with automated scorers (LLM-as-judge, RAGAS for RAG) plus periodic human review. A/B test agent roles, models, and prompts. Track hallucination and guardrail-failure rates as primary quality signals.
crewai test (with a small iteration count) as a quality gate, comparing scores to a baseline.Agents: Manager (plans & delegates), Researcher (web/RAG search), Summarizer (condenses), Reviewer (checks accuracy & citations), Writer (compiles the report).
Process: Hierarchical — the manager decomposes the topic, delegates research, then routes results through summarize → review → write.
from crewai import Agent, Task, Crew, Process
from crewai_tools import SerperDevTool, ScrapeWebsiteTool
researcher = Agent(role="Researcher", goal="Find sourced facts on {topic}",
backstory="You prefer primary sources and always cite.",
tools=[SerperDevTool(), ScrapeWebsiteTool()])
summarizer = Agent(role="Summarizer", goal="Condense findings",
backstory="You distill without losing key facts.")
reviewer = Agent(role="Reviewer", goal="Verify accuracy and citations",
backstory="You reject unsupported claims.")
writer = Agent(role="Writer", goal="Write the final report",
backstory="You produce clear, well-structured reports.")
research_task = Task(description="Research {topic}.",
expected_output="Sourced bullet findings.", agent=researcher)
summary_task = Task(description="Summarize the findings.",
expected_output="A tight summary.", agent=summarizer,
context=[research_task])
review_task = Task(description="Verify the summary's claims.",
expected_output="'APPROVED' or required fixes.", agent=reviewer,
context=[summary_task])
report_task = Task(description="Write the final report with citations.",
expected_output="A markdown report.", agent=writer,
context=[review_task], output_file="report.md")
crew = Crew(agents=[researcher, summarizer, reviewer, writer],
tasks=[research_task, summary_task, review_task, report_task],
process=Process.hierarchical, manager_llm="gpt-4o", memory=True)
Agents: Intent Classifier, Knowledge Retriever (RAG over help docs), Solution Generator, Escalation Agent, Feedback Collector.
Flow over Crew: Use a Flow to route by intent and decide escalation deterministically; each branch invokes a small crew.
from crewai.flow.flow import Flow, start, router, listen
class SupportFlow(Flow):
@start()
def classify(self):
self.state.category = classify_crew.kickoff(
inputs={"msg": self.state.message}).raw
return self.state.category
@router(classify)
def route(self, category):
return "escalate" if category == "complex" else "auto_resolve"
@listen("auto_resolve")
def resolve(self):
return resolve_crew.kickoff(inputs={"msg": self.state.message}).raw
@listen("escalate")
def escalate(self):
return handoff_to_human(self.state.message)
Knowledge grounds answers; human_input=True gates account-changing actions.
Agents: Planning (requirements → tasks), Coding (implements with code execution), Testing (runs unit/integration tests), Review (quality & security), Deployment (CI/CD tools), Ops (monitoring/incidents).
Process: Hierarchical — the planner breaks features into tasks; coder implements; tester validates; reviewer enforces standards; deployment and ops run via tools (GitHub API, CI/CD).
coder = Agent(role="Engineer", goal="Implement {feature} with tests",
backstory="You write clean, tested Python.",
allow_code_execution=True)
tester = Agent(role="QA", goal="Run and report tests",
backstory="You ensure everything passes before review.")
# ...planner, reviewer, deployer, ops...
Guardrails reject code that fails tests; human_input gates production deploys.
Agents: Developer (writes code), Static Analyzer (lint/security scan tool), Reviewer (reads for quality), Tester (runs the suite), Merger (merges on pass).
Process: Sequential. Each stage gates the next; the merger only runs if review and tests pass.
review = Task(description="Review the PR diff for quality and security.",
expected_output="'APPROVE' or a list of blocking issues.",
agent=reviewer, context=[develop_task, analyze_task])
test = Task(description="Run the test suite against the PR.",
expected_output="PASS/FAIL with details.", agent=tester,
context=[develop_task])
merge = Task(description="Merge only if review is APPROVE and tests PASS.",
expected_output="Merge confirmation or a held status.",
agent=merger, context=[review, test], human_input=True)
Use GitHub API tools for diffs, comments, and merges.
Agents: Data Extraction (APIs/spreadsheets), Analysis (metrics & trends), Narrative (writes the story), Audit (verifies calculations), Presentation (formats PDF/PPTX).
Process: Sequential pipeline; the Audit agent acts as a guardrail before presentation.
analysis = Task(description="Compute KPIs and YoY trends from the data.",
expected_output="A metrics table + trend notes.",
agent=analyst, context=[extract_task], output_pydantic=Metrics)
audit = Task(description="Recompute and verify all figures.",
expected_output="'VERIFIED' or discrepancies.",
agent=auditor, context=[analysis])
present = Task(description="Format the verified report.",
expected_output="A polished report file.",
agent=presenter, context=[narrative_task, audit],
output_file="financials.md")
Tools: pandas for analysis, a charting tool, and a report generator.
Agents: Resume Parser, Skill Matcher, Shortlist Ranker, Interview Scheduler (calendar API), Feedback Collector, Offer Generator.
Process: Sequential with human gates at shortlist and offer stages.
parse = Task(description="Extract structured fields from each resume.",
expected_output="Candidate records as JSON.", agent=parser,
output_json=CandidateList)
match = Task(description="Score candidates against the job requirements.",
expected_output="Ranked candidates with scores.", agent=matcher,
context=[parse])
shortlist = Task(description="Select the top 5 for interviews.",
expected_output="A shortlist for human approval.",
agent=ranker, context=[match], human_input=True)
Tools: CV parsing, calendar API, messaging API, offer-letter templates. PII handling and guardrails are essential here.
Agents: Document Parser (segments), Clause Identifier (labels key clauses), Risk Assessor (flags risks), Summarizer, Citation Agent (attaches precedents via RAG over case law).
Process: Hierarchical — a manager assigns clauses to specialists and aggregates a risk report.
from crewai import Agent
from crewai.knowledge.source.pdf_knowledge_source import PDFKnowledgeSource
case_law = PDFKnowledgeSource(file_paths=["precedents.pdf"])
citation = Agent(role="Citation Specialist",
goal="Attach relevant legal precedents to each risk",
backstory="You ground every claim in case law.",
knowledge_sources=[case_law])
Strong grounding + human review mitigate the high cost of errors in legal contexts.
Agents: Query Understanding, Knowledge Retriever (internal docs), Answer Generator, Citation Agent, Feedback Collector, Continuous Improvement (updates the knowledge base).
Process: query → retrieve → answer → cite → feedback → update.
crew = Crew(
agents=[query_agent, retriever, answerer, citation_agent],
tasks=[understand, retrieve, answer, cite],
knowledge_sources=[internal_docs], # shared, secured by metadata filters
memory=True,
process=Process.sequential,
)
Secure retrieval (RBAC, metadata filters), audit access, and pin embeddings for consistency. Cache frequent queries to cut cost.
Agents: Query Understanding (decide if retrieval is needed), Retriever (vector DB), Responder (synthesize grounded answer), Citation Agent.
Loop: Maintain conversation context in memory; a Flow handles multi-turn routing.
class ChatFlow(Flow):
@start()
def understand(self):
self.state.needs_rag = needs_retrieval(self.state.user_msg)
@router(understand)
def route(self):
return "rag" if self.state.needs_rag else "chat"
@listen("rag")
def answer_with_rag(self):
return rag_crew.kickoff(inputs={"q": self.state.user_msg}).raw
@listen("chat")
def answer_directly(self):
return chat_crew.kickoff(inputs={"q": self.state.user_msg}).raw
Instruct the responder to answer only from retrieved context and cite sources.
kickoff_async, kickoff_for_each_async) for concurrency.max_rpm) to respect provider quotas.kickoff_for_each.token_usage to find and fix expensive agents/tasks.expected_output.crewai-tools.Set human_input=True on the high-impact task. The agent proposes the action; CrewAI pauses for a human to approve, edit, or reject before continuing. For richer control, wrap the approval in a Flow that routes to "execute" or "revise" based on the human's decision.
send_email = Task(
description="Compose the customer refund email and request approval.",
expected_output="An approved, ready-to-send email.",
agent=support_agent,
human_input=True, # pauses for human sign-off
)
Agents: Strategist (audience & angle), Researcher (facts/trends), Writer (draft), SEO Specialist (optimize), Editor (final polish).
Process: Sequential with a review loop between Writer and Editor.
strategy = Task(description="Define angle and audience for {topic}.",
expected_output="A content brief.", agent=strategist)
research = Task(description="Gather supporting facts and trends.",
expected_output="Sourced notes.", agent=researcher,
context=[strategy])
draft = Task(description="Write the article from brief + research.",
expected_output="A first draft.", agent=writer,
context=[strategy, research])
seo = Task(description="Optimize headings, keywords, meta description.",
expected_output="An SEO-optimized draft.", agent=seo_specialist,
context=[draft])
final = Task(description="Polish and finalize.",
expected_output="A publish-ready article.", agent=editor,
context=[seo], output_file="post.md", human_input=True)
Agents: Ingestion (load/clean), Analysis (compute metrics with code execution), Visualization (charts), Insight Writer (narrative), Reviewer (validates numbers).
Process: Sequential; Analysis uses code execution, Reviewer guards correctness.
from crewai import Agent
from crewai_tools import CodeInterpreterTool
analyst = Agent(role="Data Analyst",
goal="Compute metrics and trends from {dataset}",
backstory="You validate every figure by running code.",
tools=[CodeInterpreterTool()], allow_code_execution=True)
analyze = Task(description="Load {dataset}, clean it, compute KPIs.",
expected_output="A metrics table + short findings.",
agent=analyst, output_pydantic=AnalysisResult)
review = Task(description="Recompute and confirm the KPIs.",
expected_output="'VERIFIED' or discrepancies.",
agent=reviewer, context=[analyze])
output_pydantic) + guardrails to force consistency.crewai test across iterations to quantify consistency before/after fixes.CrewAI assembles the prompt for each agent step by layering several components into a single system + user message:
context=[...], plus retrieved memory and knowledge snippets.# Conceptually, the rendered prompt looks like:
# SYSTEM:
# You are {role}. {backstory} Your goal is {goal}.
# You have access to these tools: {tool_name}: {tool_description} ...
# Use this format: Thought / Action / Action Input / Observation ... Final Answer
# USER:
# Current Task: {task.description}
# Expected output: {task.expected_output}
# Context: {upstream_outputs + memory + knowledge}
Because everything is concatenated, prompt size grows with tools, context, and trace length — which is why concise backstories, focused tool lists, and summarized context matter for both cost and reliability.
Each agent runs a ReAct (Reason + Act) loop until it produces a final answer or hits max_iter:
# Simplified pseudocode of the internal loop
scratchpad = []
for step in range(agent.max_iter):
response = llm.call(build_prompt(task, tools, scratchpad))
if response.is_final_answer:
return response.final_answer
tool_result = execute_tool(response.action, response.action_input)
scratchpad.append((response.thought, response.action, tool_result))
# If we exhausted max_iter, CrewAI forces a final answer from the current state
return force_final_answer(scratchpad)
max_iter (default commonly 20–25) bounds the loop to prevent runaway reasoning or infinite tool-calling. Setting it too low truncates legitimate multi-step work; too high risks cost blowups on a confused agent.
CrewAI supports two tool-calling paths depending on the model:
Action: / Action Input: text the model emits.# Each BaseTool exposes a schema derived from its args
from crewai.tools import BaseTool
from pydantic import BaseModel, Field
class WeatherInput(BaseModel):
city: str = Field(..., description="City name")
class WeatherTool(BaseTool):
name: str = "get_weather"
description: str = "Get current weather for a city"
args_schema: type[BaseModel] = WeatherInput
def _run(self, city: str) -> str:
return f"Weather in {city}: sunny, 24°C"
Internally, CrewAI validates the LLM's arguments against args_schema (Pydantic), executes _run, captures exceptions into an Observation, and optionally caches the result so identical calls don't re-execute.
Delegation is not magic — when allow_delegation=True, CrewAI injects two synthetic tools into the agent's toolset:
# Conceptually, these are added automatically:
# Tool: "Delegate work to coworker"
# args: {task: str, context: str, coworker: str}
# Tool: "Ask question to coworker"
# args: {question: str, context: str, coworker: str}
manager = Agent(
role="Engineering Manager",
goal="Coordinate the team to ship the feature",
backstory="You delegate effectively and synthesize results.",
allow_delegation=True, # delegation tools injected here
)
When the LLM "calls" the delegate tool, CrewAI looks up the target coworker by role, spins up a sub-execution of that agent against the delegated instruction, and returns the result as the Observation. This is exactly the mechanism a hierarchical manager uses to drive workers.
In a hierarchical process, CrewAI inserts a manager agent (either your manager_agent or one auto-created from manager_llm) that owns orchestration:
from crewai import Crew, Process
crew = Crew(
agents=[researcher, writer, reviewer], # workers
tasks=[research_task, write_task, review_task],
process=Process.hierarchical,
manager_llm="gpt-4o", # auto-creates a manager, OR pass manager_agent=...
verbose=True,
)
result = crew.kickoff()
The key internal difference from sequential: task→agent binding is decided at runtime by the manager, not statically by each task's agent= field.
When memory=True, CrewAI runs a retrieval step before each agent invocation and injects the results into the prompt's context block:
from crewai import Crew
crew = Crew(
agents=[...],
tasks=[...],
memory=True, # enables short-term + long-term + entity memory
embedder={"provider": "openai", "config": {"model": "text-embedding-3-small"}},
)
Because retrieval is automatic, the agent "remembers" relevant prior facts without you manually stitching them into the prompt — but noisy or oversized memory degrades retrieval, so summarization and scoping still matter.
The Knowledge feature is purpose-built RAG that CrewAI manages for you, distinct from conversational memory:
from crewai import Agent
from crewai.knowledge.source.string_knowledge_source import StringKnowledgeSource
policy = StringKnowledgeSource(
content="Refunds are allowed within 30 days with a receipt."
)
support_agent = Agent(
role="Support Specialist",
goal="Answer policy questions accurately",
backstory="You only answer from official company policy.",
knowledge_sources=[policy], # retrieved and injected automatically
)
The distinction from memory: Knowledge is a curated, read-only grounding corpus you supply, whereas memory is the evolving record of what the crew has said and done.
Long crews can exceed the model's context window. CrewAI mitigates overflow with several mechanisms:
respect_context_window=True (default on agents) — CrewAI summarizes/trims the running context to fit the model's window instead of erroring out.context=[...] are carried forward, not every prior task.analyst = Agent(
role="Analyst",
goal="Analyze large documents",
backstory="You work with lengthy inputs.",
respect_context_window=True, # auto-handle overflow by summarizing
)
When you disable respect_context_window, an oversized prompt raises a context-length error — useful in testing to catch prompts that are silently ballooning.
CrewAI Flows carry a shared state object across @start, @listen, and @router steps. With the @persist decorator, that state is checkpointed to a backing store (SQLite by default) so a flow can be resumed:
id.from crewai.flow.flow import Flow, start, listen, persist
from pydantic import BaseModel
class ReportState(BaseModel):
topic: str = ""
draft: str = ""
@persist # checkpoints state to the backing store
class ReportFlow(Flow[ReportState]):
@start()
def gather(self):
self.state.topic = "Q3 revenue"
@listen(gather)
def write(self):
self.state.draft = f"Report on {self.state.topic}"
return self.state.draft
ReportFlow().kickoff()
This makes Flows suitable for long-running, resumable, human-in-the-loop workflows where you can't afford to recompute everything after an interruption.
CrewAI ships Process.sequential and Process.hierarchical, but you can implement custom orchestration in two practical ways:
@router, fan-out/fan-in with or_/and_, loops, and conditional execution. Flows let you call multiple crews and plain Python between steps.crew.kickoff() or agent.execute_task() to invoke based on results.from crewai.flow.flow import Flow, start, router, listen
class TriageFlow(Flow):
@start()
def classify(self):
# decide a route based on input
return "urgent" if self.state.get("priority") == "high" else "normal"
@router(classify)
def route(self, category):
return category # "urgent" or "normal"
@listen("urgent")
def handle_urgent(self):
return escalation_crew.kickoff()
@listen("normal")
def handle_normal(self):
return standard_crew.kickoff()
This pattern gives you map/reduce, conditional, and iterative-refinement topologies that the two built-in processes don't express directly — without forking the framework.
A CrewAI app is ordinary Python, so deployment follows standard service patterns plus a few CrewAI-specific concerns:
crew.kickoff(inputs=...) behind FastAPI/Flask so callers trigger runs over HTTP.requirements.txt (or crewai install) into a Docker image for reproducibility.OPENAI_API_KEY, etc.) via environment variables or a secrets manager, never in code.from fastapi import FastAPI
from my_crew import build_crew
app = FastAPI()
@app.post("/run")
def run(topic: str):
crew = build_crew()
result = crew.kickoff(inputs={"topic": topic})
return {"output": result.raw}
CrewAI also offers managed deployment (CrewAI Enterprise/AMP) if you prefer not to operate the infrastructure yourself.
There are two distinct concurrency needs — many independent runs and parallelism within one run:
kickoff_for_each for batch inputs, the async variants (kickoff_async / kickoff_for_each_async), or Flows with and_/or_ to run branches in parallel.import asyncio
# Batch the same crew over many inputs
results = crew.kickoff_for_each(inputs=[{"topic": t} for t in topics])
# Async fan-out
async def run_all(topic_list):
tasks = [crew.kickoff_async(inputs={"topic": t}) for t in topic_list]
return await asyncio.gather(*tasks)
asyncio.run(run_all(["ai", "ml", "rag"]))
Watch for provider rate limits when fanning out — add backoff/throttling so parallel runs don't trip 429s. Isolation is the golden rule: shared state across concurrent runs causes data bleed between sessions.
Caching cuts cost and latency at several layers:
cache_function on a tool to decide what is cacheable.from crewai.tools import BaseTool
class PriceTool(BaseTool):
name: str = "get_price"
description: str = "Look up a stock price by ticker"
def _run(self, ticker: str) -> str:
return fetch_price(ticker)
# Only cache successful, non-empty results
def cache_function(self, args, result):
return result is not None and "error" not in result.lower()
A cross-process cache (Redis/Memcached) is what makes caching effective in a multi-worker deployment — an in-process dict only helps a single instance.
Treat agent/task definitions and prompts as code and configuration under version control:
@CrewBase — define agents and tasks in agents.yaml / tasks.yaml so prompt changes are diffable in Git and reviewable in PRs.crewai and tool library versions; framework updates can change prompt templates and loop behavior.crewai test (or a custom eval set) on each change so prompt edits are validated before merge.# agents.yaml — versioned alongside code
researcher:
role: "Research Analyst"
goal: "Gather accurate, cited information on {topic}"
backstory: "You are meticulous and always cite reliable sources."
llm: gpt-4o-2024-08-06 # pinned snapshot, not a floating alias
The combination of config-as-code + pinned models + an eval gate is what makes prompt changes safe to ship repeatedly.
| Issue | Symptoms | Root Cause | Fix |
| --- | --- | --- | --- |
| Runaway cost / loops | High token bills, slow runs | max_iter too high; agent stuck re-calling tools | Lower max_iter; sharpen tool descriptions; add guardrails |
| Inconsistent outputs | Different result each run | High temperature; vague prompts | Set temperature low; add output_pydantic; pin model version |
| Rate-limit errors (429) | Failures under load | Too many parallel LLM/tool calls | Backoff/retry; throttle fan-out; cache responses |
| Hallucinated answers | Confident but wrong | No grounding | Add Knowledge/RAG; instruct "answer only from context"; cite sources |
| Context-length errors | Crashes on long inputs | Oversized prompt/history | Enable respect_context_window; summarize; scope context=[...] |
| Wrong tool / bad args | Tool errors, no-ops | Ambiguous tool descriptions/schemas | Clear descriptions; Pydantic args_schema; validate inputs |
| Delegation loops | Manager never finishes | Unbounded delegation in hierarchical crews | Bound max_iter; clarify roles; limit who can delegate |
| State bleed across runs | Users see others' data | Shared crew/memory across concurrent requests | Isolate crew + memory per run; don't share mutable state |
| Lost memory after restart | Crew "forgets" everything | Memory stored in ephemeral container | Persist memory store to a volume or managed DB |
| Prompt injection | Agent follows malicious retrieved text | Untrusted content treated as instructions | Sanitize/filter retrieved data; instruct agents to ignore embedded commands |
The questions and answers in this repository are a curated summary of commonly asked CrewAI interview questions, spanning fundamentals through framework internals and production operations. They cover agents, tasks, crews, processes, tools, memory, RAG and Knowledge, LLM integration, Flows, observability, security, and scenario-based design. There is no guarantee that these exact questions will appear in any given interview — the purpose is to help you rapidly review key concepts and build deep, practical understanding of the framework. Because CrewAI evolves quickly, always cross-check specific APIs and defaults against the official documentation at docs.crewai.com. Contributions and corrections are welcome.
Good luck with your interview 😊
Machine endpoints, protocol fit, contract coverage, invocation examples, and guardrails for agent-to-agent use.
Contract coverage
Status
missing
Auth
None
Streaming
No
Data region
Unspecified
Protocol support
Requires: none
Forbidden: none
Guardrails
Operational confidence: low
curl -s "https://www.xpersona.co/api/v1/agents/crewai-interviewroadmap-crewai-interview-questions/snapshot"
curl -s "https://www.xpersona.co/api/v1/agents/crewai-interviewroadmap-crewai-interview-questions/contract"
curl -s "https://www.xpersona.co/api/v1/agents/crewai-interviewroadmap-crewai-interview-questions/trust"
Trust and runtime signals, benchmark suites, failure patterns, and practical risk constraints.
Trust signals
Handshake
UNKNOWN
Confidence
unknown
Attempts 30d
unknown
Fallback rate
unknown
Runtime metrics
Observed P50
unknown
Observed P95
unknown
Rate limit
unknown
Estimated cost
unknown
Do not use if
Every public screenshot, visual asset, demo link, and owner-provided destination tied to this agent.
Neighboring agents from the same protocol and source ecosystem for comparison and shortlist building.
Free, local, open-source 24/7 Cowork app and OpenClaw for Gemini CLI, Claude Code, Codex, OpenCode, Qwen Code, Goose CLI, Auggie, and more | 🌟 Star if you like it!
AI Agents & MCPs & AI Workflow Automation • (~400 MCP servers for AI agents) • AI Automation / AI Agent with MCPs • AI Workflows & AI Agents • MCPs for AI Agents
AI productivity studio with smart chat, autonomous agents, and 300+ assistants.
The Frontend for Agents & Generative UI. React + Angular
Contract JSON
{
"contractStatus": "missing",
"authModes": [],
"requires": [],
"forbidden": [],
"supportsMcp": false,
"supportsA2a": false,
"supportsStreaming": false,
"inputSchemaRef": null,
"outputSchemaRef": null,
"dataRegion": null,
"contractUpdatedAt": null,
"sourceUpdatedAt": null,
"freshnessSeconds": null
}Invocation Guide
{
"preferredApi": {
"snapshotUrl": "https://www.xpersona.co/api/v1/agents/crewai-interviewroadmap-crewai-interview-questions/snapshot",
"contractUrl": "https://www.xpersona.co/api/v1/agents/crewai-interviewroadmap-crewai-interview-questions/contract",
"trustUrl": "https://www.xpersona.co/api/v1/agents/crewai-interviewroadmap-crewai-interview-questions/trust"
},
"curlExamples": [
"curl -s \"https://www.xpersona.co/api/v1/agents/crewai-interviewroadmap-crewai-interview-questions/snapshot\"",
"curl -s \"https://www.xpersona.co/api/v1/agents/crewai-interviewroadmap-crewai-interview-questions/contract\"",
"curl -s \"https://www.xpersona.co/api/v1/agents/crewai-interviewroadmap-crewai-interview-questions/trust\""
],
"jsonRequestTemplate": {
"query": "summarize this repo",
"constraints": {
"maxLatencyMs": 2000,
"protocolPreference": [
"OPENCLEW"
]
}
},
"jsonResponseTemplate": {
"ok": true,
"result": {
"summary": "...",
"confidence": 0.9
},
"meta": {
"source": "GITHUB_REPOS",
"generatedAt": "2026-10-10T03:51:31.604Z"
}
},
"retryPolicy": {
"maxAttempts": 3,
"backoffMs": [
500,
1500,
3500
],
"retryableConditions": [
"HTTP_429",
"HTTP_503",
"NETWORK_TIMEOUT"
]
}
}Trust JSON
{
"status": "unavailable",
"handshakeStatus": "UNKNOWN",
"verificationFreshnessHours": null,
"reputationScore": null,
"p95LatencyMs": null,
"successRate30d": null,
"fallbackRate": null,
"attempts30d": null,
"trustUpdatedAt": null,
"trustConfidence": "unknown",
"sourceUpdatedAt": null,
"freshnessSeconds": null
}Capability Matrix
{
"rows": [
{
"key": "OPENCLEW",
"type": "protocol",
"support": "unknown",
"confidenceSource": "profile",
"notes": "Listed on profile"
},
{
"key": "crewai",
"type": "capability",
"support": "supported",
"confidenceSource": "profile",
"notes": "Declared in agent profile metadata"
},
{
"key": "multi-agent",
"type": "capability",
"support": "supported",
"confidenceSource": "profile",
"notes": "Declared in agent profile metadata"
}
],
"flattenedTokens": "protocol:OPENCLEW|unknown|profile capability:crewai|supported|profile capability:multi-agent|supported|profile"
}Facts JSON
[
{
"factKey": "vendor",
"category": "vendor",
"label": "Vendor",
"value": "Interviewroadmap",
"href": "https://github.com/interviewroadmap/crewai-interview-questions",
"sourceUrl": "https://github.com/interviewroadmap/crewai-interview-questions",
"sourceType": "profile",
"confidence": "medium",
"observedAt": "2026-10-09T19:13:39.103Z",
"isPublic": true
},
{
"factKey": "protocols",
"category": "compatibility",
"label": "Protocol compatibility",
"value": "OpenClaw",
"href": "https://www.xpersona.co/api/v1/agents/crewai-interviewroadmap-crewai-interview-questions/contract",
"sourceUrl": "https://www.xpersona.co/api/v1/agents/crewai-interviewroadmap-crewai-interview-questions/contract",
"sourceType": "contract",
"confidence": "medium",
"observedAt": "2026-10-09T19:13:39.103Z",
"isPublic": true
},
{
"factKey": "traction",
"category": "adoption",
"label": "Adoption signal",
"value": "1 GitHub stars",
"href": "https://github.com/interviewroadmap/crewai-interview-questions",
"sourceUrl": "https://github.com/interviewroadmap/crewai-interview-questions",
"sourceType": "profile",
"confidence": "medium",
"observedAt": "2026-10-09T19:13:39.103Z",
"isPublic": true
},
{
"factKey": "docs_crawl",
"category": "integration",
"label": "Crawlable docs",
"value": "6 indexed pages on the official domain",
"href": "https://github.com/login?return_to=https%3A%2F%2Fgithub.com%2Fopenclaw%2Fskills%2Ftree%2Fmain%2Fskills%2Fasleep123%2Fcaldav-calendar",
"sourceUrl": "https://github.com/login?return_to=https%3A%2F%2Fgithub.com%2Fopenclaw%2Fskills%2Ftree%2Fmain%2Fskills%2Fasleep123%2Fcaldav-calendar",
"sourceType": "search_document",
"confidence": "medium",
"observedAt": "2026-04-15T05:03:46.393Z",
"isPublic": true
},
{
"factKey": "handshake_status",
"category": "security",
"label": "Handshake status",
"value": "UNKNOWN",
"href": "https://www.xpersona.co/api/v1/agents/crewai-interviewroadmap-crewai-interview-questions/trust",
"sourceUrl": "https://www.xpersona.co/api/v1/agents/crewai-interviewroadmap-crewai-interview-questions/trust",
"sourceType": "trust",
"confidence": "medium",
"observedAt": null,
"isPublic": true
}
]Change Events JSON
[
{
"eventType": "docs_update",
"title": "Docs refreshed: Sign in to GitHub · GitHub",
"description": "Fresh crawlable documentation was indexed for the official domain.",
"href": "https://github.com/login?return_to=https%3A%2F%2Fgithub.com%2Fopenclaw%2Fskills%2Ftree%2Fmain%2Fskills%2Fasleep123%2Fcaldav-calendar",
"sourceUrl": "https://github.com/login?return_to=https%3A%2F%2Fgithub.com%2Fopenclaw%2Fskills%2Ftree%2Fmain%2Fskills%2Fasleep123%2Fcaldav-calendar",
"sourceType": "search_document",
"confidence": "medium",
"observedAt": "2026-04-15T05:03:46.393Z",
"isPublic": true
}
]Sponsored
Ads related to crewai-interview-questions and adjacent AI workflows.