CrewAI made multi-agent systems easy to start: give each agent a role, a goal and a backstory, hand them tasks, and call kickoff(). Many teams later want more control over what those agents do. This guide is for developers who use CrewAI and are weighing CrewAI alternatives. It covers the reasons people give, seven alternatives and when each fits, the same crew rebuilt in Promptise Foundry, and a map of crews, agents, tasks and flows to their equivalents.
What is the best CrewAI alternative?
There isn't one best option, because people leave CrewAI for different reasons. If you want explicit control of each step, LangGraph or Microsoft Agent Framework workflows. If you want typed outputs and strict limits, Pydantic AI. If your crew is really a triage step plus specialists, the OpenAI Agents SDK's handoffs. If you want agents built on MCP tools with approvals, budgets and deployment in one package, Promptise Foundry. And if the role-based model fits your problem and the reason you are looking is one specific issue, fixing that issue in CrewAI may be cheaper than moving.
Many crews are pipelines. A sequential crew with two agents is two model calls in order. Plain code with two agents is often easier to debug.
A hierarchical crew is a coordinator with tools. In most alternatives the manager becomes an agent that can call the other agents as tools.
Check what your limits do. CrewAI's max_iter forces a final answer when it is reached. Prefer a limit that raises an error.
Keep prompts and tools outside the framework. Join role, goal and backstory into one prompt, and serve tools over MCP, so the next move is easy.
For a feature table across seven frameworks, see Python AI agent frameworks compared.
[02]
Why do developers look for CrewAI alternatives?
These are the reasons that come up in CrewAI's GitHub issues, its community forum and developer threads. Each one has a fix or a workaround in some cases, and CrewAI ships quickly, so check the current version before you decide.
Limits that answer instead of failing. When an agent reaches max_iter, CrewAI makes one more model call that asks for a final answer without tools, and returns that answer as a normal result. The behavior is in handle_max_iterations_exceeded in agent_utils.py. Your code can't easily tell a finished task from one that ran out of steps.
Telemetry on by default. CrewAI sends anonymous usage data unless you set CREWAI_DISABLE_TELEMETRY=true. The telemetry docs list what is collected, such as versions, agent roles and tool names, and say prompts and data are not. Some companies' network policies block it, and users have asked how to turn it off (#372, #1022).
People also like CrewAI, and for good reasons. It is one of the fastest ways to get several agents working together, the role-based model is easy to explain to non-engineers, and Flows add event-driven steps with persisted state. A common view on Hacker News is to start with CrewAI and move when you reach its limits.
[03]
How CrewAI works, and what an alternative must replace
CrewAI has four building blocks. An Agent is a model with a role, a goal, a backstory and tools. A Task is a description of work, with the output you expect and the agent that does it. A Crew runs tasks with a Process: sequential, where each task gets the previous outputs as context, or hierarchical, where a manager agent assigns the work. Flows sit above crews: Python methods connected by @start, @listen and @router, with shared state that can be persisted.
kickoff(inputs)
│
▼
Task 1 ──(agent: Order analyst, tools)──▶ output 1
│ │ context
▼ ▼
Task 2 ──(agent: Support writer)──────────▶ output 2 = crew result
hierarchical: a manager agent picks which agent does each task
Flows: @start → @listen → @router … around one or more crewsAn alternative has to give you the same four things: an agent with instructions and tools, a way to pass one agent's output to the next, a way for one agent to delegate to others, and a place for long-lived state and events. Every framework below has the first. They differ in how much of the rest they give you, and in how explicit it is.
[04]
When to stay with CrewAI (and when to switch)
Stay with CrewAI when:
Your problem maps naturally to roles, and the people who maintain it think in those roles.
You use Flows for event-driven steps and persistence, and they work for you.
The issue that started your search has a fix in a newer CrewAI version or a setting.
Consider switching when:
You spend more time steering agents than building features, for example adding backstory text to stop delegation loops.
You need actions that require approval to be enforced in code, before the tool runs, for specific tools.
You need limits that raise errors, cost budgets or traces that stay on your own systems.
Most of your crews have one or two agents, so the crew abstraction adds little.
[05]
7 CrewAI alternatives and when each fits
Versions checked on 18 October 2026. Each summary comes from the project's own documentation.
Framework | Multi-agent model | Fits best when |
|---|---|---|
Promptise Foundry 1.4.1 | Agents call peer agents as tools (cross_agents); runtime with triggers and events | You want MCP tools, approvals, budgets and deployment in one package |
LangGraph 1.2.16 | Graph with subagents, handoffs and routers | You need precise control of each step and durable pauses |
OpenAI Agents SDK 0.24.0 | Handoffs (transfer_to_<agent> tools) and agents as tools | A triage agent routes to specialists, mostly on OpenAI models |
Microsoft Agent Framework 1.22.0 | Sequential, group chat, handoff and Magentic orchestrations; graph workflows | You need orchestration patterns with checkpoints on Azure or .NET |
Pydantic AI 2.57.0 | Delegation through tools, programmatic hand-off, Pydantic Graph | You want typed outputs and usage limits that roll up to the parent |
LlamaIndex AgentWorkflow (core 0.14.25) | AgentWorkflow with handoffs between agents | The agents mainly search and reason over your documents |
Google ADK 2.12.0 | Coordinator with sub-agents; sequential, parallel and loop workflow agents | You build on Gemini and Google Cloud |
Promptise Foundry
Promptise builds each agent with build_agent(), from MCP servers or LangChain tools. A sequential crew becomes agents called in order from Python. A hierarchical crew becomes a coordinator with cross_agents=: each peer appears to the coordinator as an ask_agent_<name> tool, with a delegation depth limit and loop detection. Approvals are an ApprovalPolicy checked before the tool runs, and max_agent_iterations stops a run instead of forcing an answer. For long-running teams, the Agent Runtime runs agents as processes with cron, webhook and event triggers. Promptise sends no usage telemetry, and tracing is opt-in. The trade-off: there is no role-goal-backstory abstraction, and approvals wait in the running process.
LangGraph
LangGraph models agents as a graph with shared state. Its multi-agent patterns include subagents under a supervisor, handoffs and routers. Checkpointers save state after every step, and interrupts can pause for a person and resume after a restart. More code than CrewAI, and more control. It is the framework many teams compare everything else against.
OpenAI Agents SDK
The OpenAI Agents SDK has two multi-agent tools. A handoff transfers the conversation to another agent, and Agent.as_tool() lets a specialist answer without taking over. That covers the common "triage, then specialist" crew with very little code. Tracing exports to OpenAI by default.
Microsoft Agent Framework
Microsoft Agent Framework, the successor to AutoGen and Semantic Kernel, provides orchestrations for sequential pipelines, group chats, handoffs and Magentic-style planning, plus graph workflows with checkpoints. It is a strong fit for teams on Azure, and it supports Python and .NET.
Pydantic AI
Pydantic AI does multi-agent work in plain code: an agent calls another agent inside a tool, and the usage rolls up to the parent so one limit covers both. For complex flows there is Pydantic Graph. A good fit when outputs must be validated and typed.
LlamaIndex AgentWorkflow
LlamaIndex offers AgentWorkflow, where a root agent can hand off to others it lists in can_handoff_to, and an orchestrator pattern that uses agents as tools. It fits when the agents' main job is retrieval over your data.
Google ADK
The Agent Development Kit supports a coordinator agent with sub-agents, and workflow agents that run sub-agents in sequence, in parallel or in a loop. ADK 2.0 adds graph-based workflows. It fits teams on Gemini and Google Cloud.
smolagents also supports a manager agent with managed agents, each with a name and description, and is worth a look if you want a very small library whose agents write code.
[06]
What you need to run the examples
Python 3.10 or later and an OpenAI API key. All three examples use gpt-5-mini.
Separate virtual environments for CrewAI and Promptise:
pip install "crewai==1.15.28" # CrewAI (set CREWAI_DISABLE_TELEMETRY=true)
pip install "promptise==1.4.1" # PromptiseThe example is a two-agent support crew. An order analyst looks the order up with a tool. A support writer writes the reply, and must say that refunds over 100 USD need a manager.
[07]
Step 1: Start from the CrewAI crew
This is the crew as CrewAI's docs describe it: two agents with roles, two tasks, and a sequential process where the second task gets the first one's output through context.
"""A two-agent CrewAI crew: one looks the order up, one writes the customer reply."""
from crewai import LLM, Agent, Crew, Process, Task
from crewai.tools import tool
ORDERS = {"O-1002": {"item": "Office chair", "amount": 219.00, "status": "delivered"}}
@tool("get_order")
def get_order(order_id: str) -> dict:
"""Look up an order by ID: item, amount in USD and status."""
return ORDERS.get(order_id.strip().upper(), {"error": f"No order {order_id}"})
llm = LLM(model="gpt-5-mini")
analyst = Agent(
role="Order analyst",
goal="Find the facts about the customer's order",
backstory="You check orders in the shop system and never guess.",
tools=[get_order], llm=llm, max_iter=5,
)
writer = Agent(
role="Support writer",
goal="Write a short, friendly reply to the customer",
backstory="You write replies under 60 words. Refunds over 100 USD need a manager.",
llm=llm, max_iter=3,
)
facts = Task(description="Customer message: {message}\nLook up the order it mentions.",
expected_output="The order's item, amount and status.", agent=analyst)
reply = Task(description="Write the reply to: {message}", expected_output="The reply text.",
agent=writer, context=[facts])
crew = Crew(agents=[analyst, writer], tasks=[facts, reply], process=Process.sequential)
print(crew.kickoff(inputs={"message": "My chair (order O-1002) arrived broken. I want my money back."}).raw)Sorry your Office chair (order O-1002) arrived broken. Please send photos of the damage and confirm you want a refund. Because this refund is over $100, I’ll escalate to a manager for approval once we receive the photos — we’ll respond within 2 business days. Thank you.The {message} placeholder is filled from kickoff(inputs=...). max_iter is set low for both agents, so a confused agent can't loop for long, but remember that reaching it produces a forced answer, not an error.
[08]
Step 2: Rebuild the pipeline in Promptise
A sequential crew is a pipeline, so in Promptise it is two agents and two awaits. Role, goal and backstory become one instructions string. The task description becomes the message, and context=[facts] becomes the analyst's answer pasted into the writer's message.
"""The same two-step pipeline in Promptise: two agents and two awaits."""
import asyncio
from langchain_core.tools import tool
from promptise import build_agent
ORDERS = {"O-1002": {"item": "Office chair", "amount": 219.00, "status": "delivered"}}
@tool
def get_order(order_id: str) -> dict:
"""Look up an order by ID: item, amount in USD and status."""
return ORDERS.get(order_id.strip().upper(), {"error": f"No order {order_id}"})
async def ask(agent, text: str) -> str:
result = await agent.ainvoke({"messages": [{"role": "user", "content": text}]})
return result["messages"][-1].content
async def main():
analyst = await build_agent(
model="openai:gpt-5-mini", extra_tools=[get_order], max_agent_iterations=5,
instructions="You are an order analyst. Look the order up and report its item, "
"amount and status. Never guess.")
writer = await build_agent(
model="openai:gpt-5-mini", max_agent_iterations=3,
instructions="You are a support writer. Write a short, friendly reply under 60 words. "
"Refunds over 100 USD need a manager.")
message = "My chair (order O-1002) arrived broken. I want my money back."
try:
facts = await ask(analyst, f"Customer message: {message}\nLook up the order it mentions.")
print(await ask(writer, f"Order facts: {facts}\n\nWrite the reply to: {message}"))
finally:
await analyst.shutdown()
await writer.shutdown()
asyncio.run(main())We're sorry your chair (order O-1002) arrived broken. Please send photos of the damage and confirm you'd like a refund. Because this is $219, I'll escalate to a manager for approval once we have the photos. I'll update you within 48 hours.The data flow is now ordinary Python. You can log facts, validate it, retry only the step that failed, or stop before the writer runs when the analyst found no order. That is the main gain of a move like this: the orchestration is code you can read and test. max_agent_iterations caps each agent's model calls, and a run that hits the cap while tools are pending raises GraphIterationLimitError instead of returning a forced answer.
[09]
Step 3: Replace a hierarchical crew with a coordinator
In a hierarchical crew a manager decides which agent works on what. In Promptise the manager is an agent whose tools are the other agents. CrossAgent wraps each peer, and the coordinator sees ask_agent_analyst and ask_agent_writer.
"""A hierarchical crew's manager, as a Promptise coordinator with peer agents."""
import asyncio
from langchain_core.tools import tool
from promptise import build_agent
from promptise.cross_agent import CrossAgent
ORDERS = {"O-1002": {"item": "Office chair", "amount": 219.00, "status": "delivered"}}
@tool
def get_order(order_id: str) -> dict:
"""Look up an order by ID: item, amount in USD and status."""
return ORDERS.get(order_id.strip().upper(), {"error": f"No order {order_id}"})
async def main():
analyst = await build_agent(model="openai:gpt-5-mini", extra_tools=[get_order],
instructions="Look orders up and report item, amount and status.")
writer = await build_agent(model="openai:gpt-5-mini",
instructions="Write short, friendly customer replies under 60 words.")
manager = await build_agent(
model="openai:gpt-5-mini",
instructions="You lead a support team. Get the order facts from the analyst, then have "
"the writer draft the reply. Refunds over 100 USD need a manager. "
"Return the writer's reply unchanged.",
cross_agents={
"analyst": CrossAgent(agent=analyst, description="Looks up orders"),
"writer": CrossAgent(agent=writer, description="Writes customer replies"),
},
max_agent_iterations=6,
)
try:
print("tools:", manager.tool_names)
result = await manager.ainvoke({"messages": [{"role": "user", "content":
"My chair (order O-1002) arrived broken. I want my money back."}]})
print(result["messages"][-1].content)
finally:
for a in (manager, analyst, writer):
await a.shutdown()
asyncio.run(main())tools: ['ask_agent_analyst', 'ask_agent_writer']
Sorry your chair arrived damaged. Please send photos of chair, box/label, include O-1002. Full refund or replacement? Over $100 requires manager approval; we’ll start after photos and your choice. We’ll reply in 1 business day; approval may take 2 business days. Refunds in 5–10 business days; replacements ship 1–3 days if available; restocking waived; prepaid label/pickup; secure item. Thanks.The coordinator called the analyst, then the writer, then returned the reply. Delegation is bounded: max_delegation_depth (default 3) limits nested calls, and a call back into an agent that is already working on the request is refused, which rules out the back-and-forth delegation loops some CrewAI users report. Each peer keeps its own limits and approval rules.
Look at the three outputs side by side. All of them promise response times, such as "within 2 business days" or "within 48 hours", that no prompt or tool gave them. That is the model, not the framework, and it happens in every version. Give the writer the real policy, or check replies for promises in code before they reach a customer. AI agent guardrails covers output checks.
[10]
How do you migrate from CrewAI to Promptise?
Map each CrewAI concept, then move one crew at a time.
CrewAI | Promptise equivalent | Notes |
|---|---|---|
Agent(role, goal, backstory) | build_agent(instructions=...) | Join the three fields into one prompt |
Agent(tools=[...]), @tool from crewai.tools | extra_tools=[...] (LangChain tools) or servers= (MCP) | Port each tool to @tool from langchain_core.tools, or serve it over MCP |
| | MCP is built in |
Agent(llm=LLM(...)) | model="provider:model" or a LangChain chat model | |
max_iter | max_agent_iterations | Raises instead of forcing a final answer |
Task(description, expected_output) | The message you send, plus a format rule in the instructions | |
| Pass the earlier answer in the next message | Plain Python |
Task(output_pydantic=Model) | Validate the answer with Pydantic, or use PromptNode(output_schema=Model) in a custom graph | build_agent()'s default loop returns text |
Process.sequential | await the agents in order | Or a static PromptGraph |
Process.hierarchical, manager_llm | A coordinator with cross_agents={"name": CrossAgent(agent=..., description=...)} | Bounded by max_delegation_depth |
allow_delegation=True | cross_agents= on that agent | |
| An f-string or a prompt template | |
human_input=True on a task | Ask in your code before the next step; ApprovalPolicy for tool calls | |
before_tool_call hook | ApprovalPolicy(tools=[...], handler=...), or guardrails | Runs before the tool; denied calls return DENIED |
memory=True | memory= provider (InMemoryProvider, ChromaProvider, Mem0Provider) | |
Flows: @start, @listen, @router | Async Python functions; the Agent Runtime for cron, webhook and event triggers | |
Flows: @persist | conversation_store= for history; runtime journal for process state | |
agents.yaml, tasks.yaml | .superagent YAML files | See the YAML config guide |
Telemetry (CREWAI_DISABLE_TELEMETRY) | None sent; tracing is opt-in with observe= |
A safe order for the migration:
1. Write evals for the crew you have. Record which tools it calls, what it must never do and which facts the result must contain. How to evaluate AI agents in Python shows how. 2. Port the tools. Move them to an MCP server if more than one framework will use them. Build a production MCP server in Python shows how. 3. Collapse single-agent crews first. A crew with one agent and one task is one build_agent() call. 4. Turn sequential crews into code. One agent per role, called in order. 5. Turn hierarchical crews into a coordinator with cross_agents, and keep the delegation depth low. 6. Move hooks to approval policies, and test that a refused call never reaches the tool. 7. Compare eval results for both versions before you switch traffic.
[11]
Running it in production
Cost
Multi-agent setups multiply model calls: every delegation is at least one more agent run. Count calls per request in your traces, cap each agent with max_agent_iterations, and give the coordinator a smaller limit than you think it needs. AI agent cost control shows budgets.
Approvals
Put approval rules on the agent that owns the tool, not on the coordinator. Then the rule holds no matter which agent asked. Promptise's handler runs before the tool and can ask a person; human-in-the-loop approval covers the patterns.
Visibility
When three agents work on one request, you need to see who did what. Build each agent with observe=True, or with an ObservabilityConfig that exports to your own OTLP collector. Multi-agent systems in Python covers coordination and tracing in more depth.
[12]
Common problems and fixes
Symptom | Cause | Fix |
|---|---|---|
A CrewAI task "finishes" with a vague or wrong answer | max_iter was reached and a final answer was forced | Raise the limit or check the output; in Promptise, catch GraphIterationLimitError |
CrewAI apps hang or log export errors behind a firewall | Telemetry export is blocked | Set CREWAI_DISABLE_TELEMETRY=true (and OTEL_SDK_DISABLED=true) |
The coordinator answers without asking a peer | Peer descriptions are vague | Write a clear description= for each CrossAgent and say in the instructions when to use it |
Delegation is refused with DelegationError | Depth limit reached, or a peer was asked to call back into its caller | Flatten the team, or raise max_delegation_depth deliberately |
The ported agent ignores the role | Role, goal and backstory were dropped | Join all three into instructions |
Replies promise things no tool did | The model fills gaps in the policy | Put the real policy in the prompt and check outputs in code |
A CrewAI tool doesn't work in Promptise | It is a CrewAI BaseTool | Rewrite it with LangChain's @tool, or serve it over MCP |
[13]
Limitations
This is not a benchmark. It compares documented features and shows one example. With the same model and tools, answers depend mostly on the model.
Promptise has no role abstraction. If your team values role, goal and backstory as a design language, CrewAI expresses it more directly.
Approvals in Promptise are in-process. A pending approval doesn't survive a restart. LangGraph and Microsoft Agent Framework offer checkpointed pauses.
Flows have no one-to-one equivalent. Simple flows become Python; event-driven ones map to the Agent Runtime, which works differently from CrewAI's decorators.
We make Promptise. We checked every competitor claim against its docs, source or issues, and said where CrewAI is the better fit.
[14]
Frequently asked questions
What is the best alternative to CrewAI?
It depends on why you are moving. For explicit control and durable pauses, LangGraph. For typed outputs and usage limits, Pydantic AI. For triage-and-specialist setups on OpenAI models, the OpenAI Agents SDK. For orchestration on Azure, Microsoft Agent Framework. For MCP tools, approvals, budgets and deployment in one package, Promptise Foundry. For retrieval-heavy agents, LlamaIndex.
Is CrewAI good for production?
Many teams run it in production, and its Flows add persistence and event-driven control. Before you do, check a few things: set CREWAI_DISABLE_TELEMETRY=true if your policy requires it, handle the forced final answer that max_iter produces, enforce risky actions with a hook rather than a prompt, and test hierarchical delegation with evals.
How do I disable CrewAI telemetry?
Set the environment variable CREWAI_DISABLE_TELEMETRY=true before the process starts. OTEL_SDK_DISABLED=true also disables it, along with other OpenTelemetry exports in the process. CrewAI's telemetry docs say it collects anonymous usage data, such as versions, agent roles and tool names, but not prompts, task descriptions or your data.
How do I convert a CrewAI crew to plain agents?
Give each CrewAI agent its own agent, with role, goal and backstory joined into one system prompt. For a sequential crew, call the agents in order and pass each answer into the next message. For a hierarchical crew, make the manager an agent that can call the others as tools. Port the tools to LangChain's @tool or to an MCP server.
Is LangGraph better than CrewAI?
Neither is better in general. LangGraph gives low-level control: a graph with persisted state, interrupts that survive restarts and precise limits. CrewAI gives a higher-level model of agents with roles working through tasks, which is faster to set up. Choose LangGraph when you need control and durability, and CrewAI when the role-based model fits and speed matters most.
Can Promptise agents delegate to each other like a CrewAI manager?
Yes. Pass cross_agents={"name": CrossAgent(agent=peer, description=...)} to build_agent(), and the agent gets an ask_agent_<name> tool for each peer. Delegation is bounded by max_delegation_depth, which defaults to 3, and a request that would loop back into a busy peer is refused. Each peer keeps its own tools, limits and approval rules.
[15]
Next steps
Compare seven frameworks feature by feature: Python AI agent frameworks compared.
Design teams of agents: multi-agent systems in Python.
Test the crew before and after you move it: how to evaluate AI agents in Python.
Enforce approval rules in code: human-in-the-loop approval for AI agents.
Configure agents in YAML: AI agent YAML config file.
Reference: multi-agent coordination and cross-agent delegation in the Promptise docs.