Why this matters
The agent framework landscape is noisy. Every few months a new library claims to solve multi-agent orchestration forever. As an AI engineer, your job is to cut through the hype and make framework choices that will hold up six months into production — not just in a demo. This lesson gives you a structured way to compare frameworks on criteria that actually matter, so you can make and defend the right call for your team and use case.
Core concepts
The frameworks
Anthropic tool_use (bare SDK)
The foundation. You define tools as JSON schemas, call the API, execute tool calls your code, return results. Full control, zero abstraction, maximum debuggability. Every other framework builds on this pattern.
import anthropic
client = anthropic.Anthropic()
tools = [{
"name": "web_search",
"description": "Search the web for current information",
"input_schema": {
"type": "object",
"properties": {"query": {"type": "string"}},
"required": ["query"],
},
}]
def run_agent(user_message: str, max_steps: int = 5) -> str:
messages = [{"role": "user", "content": user_message}]
for _ in range(max_steps):
response = client.messages.create(
model="claude-3-5-sonnet-20241022",
max_tokens=1024,
tools=tools,
messages=messages,
)
if response.stop_reason == "end_turn":
return next(b.text for b in response.content if hasattr(b, "text"))
# Handle tool calls
messages.append({"role": "assistant", "content": response.content})
tool_results = []
for block in response.content:
if block.type == "tool_use":
result = execute_tool(block.name, block.input)
tool_results.append({
"type": "tool_result",
"tool_use_id": block.id,
"content": result,
})
messages.append({"role": "user", "content": tool_results})
return "Max steps reached"
LangGraph
Graph-based orchestration. Best when you need: conditional routing, parallel branches, checkpointing, human-in-the-loop, or multiple distinct agent roles. The graph makes control flow explicit and testable. Overhead: learning curve, added dependency, more boilerplate for simple cases.
CrewAI
Role-based multi-agent framework. You define agents with roles, goals, and backstories, then assign tasks. Good for demos and quick prototypes where the "agent team" metaphor maps well to the problem. Weakness: less control over execution flow, harder to debug when something goes wrong, role metaphor breaks down for technical tasks.
from crewai import Agent, Task, Crew
researcher = Agent(
role="Research Analyst",
goal="Find accurate information on any topic",
backstory="Expert at synthesizing information from multiple sources",
verbose=False,
)
writer = Agent(
role="Technical Writer",
goal="Produce clear, accurate summaries",
backstory="Turns complex research into readable prose",
verbose=False,
)
research_task = Task(
description="Research the current state of vector databases",
expected_output="A bullet-point summary of key developments",
agent=researcher,
)
write_task = Task(
description="Write a 3-paragraph summary of the research",
expected_output="A polished 3-paragraph summary",
agent=writer,
context=[research_task],
)
crew = Crew(agents=[researcher, writer], tasks=[research_task, write_task])
result = crew.kickoff()
AutoGen
Microsoft's multi-agent conversation framework. Agents converse with each other via message passing. Strong for code generation workflows (has a built-in CodeExecutorAgent). Weakness: conversation-as-orchestration can be unpredictable for complex tasks; harder to add deterministic routing.
When each framework shines
| Use case | Best fit |
|---|---|
| Single-provider, simple tool use | Bare Anthropic SDK |
| Complex routing, human approval gates | LangGraph |
| Multi-step research + writing pipeline | LangGraph or CrewAI |
| Code generation with execution | AutoGen |
| Rapid prototyping, demo | CrewAI |
| Production service with observability | LangGraph + callbacks |
| Switching between providers | LangChain + LangGraph |
Migration patterns between frameworks
From bare SDK to LangGraph:
- Identify the implicit states in your loop (e.g., "waiting for tool result", "writing final answer")
- Make each state a node
- Replace
if/elifbranching with conditional edges - Wrap your existing tool execution logic in a node function
From CrewAI to LangGraph:
- Map each CrewAI agent to a LangGraph node
- Map task dependencies to edges
- Replace CrewAI's implicit orchestration with explicit routing functions
- Add checkpointing for long-running workflows
From LangGraph to bare SDK:
Usually not worth it unless you need to eliminate the dependency. LangGraph adds ~30% more code in the graph definition but saves that and more in debugging overhead for complex workflows.
Decision matrix
Score each criterion 1-3 (1 = poor, 3 = excellent) for your situation:
| Criterion | Bare SDK | LangGraph | CrewAI | AutoGen |
|---|---|---|---|---|
| Debuggability | 3 | 2 | 1 | 1 |
| Control over flow | 3 | 3 | 1 | 2 |
| Speed to first demo | 2 | 2 | 3 | 2 |
| Multi-agent support | 1 | 3 | 3 | 3 |
| Human-in-the-loop | 1 | 3 | 1 | 2 |
| Checkpointing | 1 | 3 | 1 | 1 |
| Production observability | 2 | 3 | 1 | 1 |
| Dependency footprint | 3 | 2 | 1 | 1 |
Rule of thumb: Start with the bare SDK. Add LangGraph when your loop needs explicit state, routing, or checkpointing. Reach for CrewAI only if the "team of specialists" metaphor genuinely fits your use case and you do not need production reliability.
Common mistakes
Choosing a framework for its ecosystem, not its fit. LangGraph has more GitHub stars than your current loop needs. That is not a reason to add it. Add it when you are fighting the loop.
Mixing framework abstractions. Using CrewAI's Agent class inside a LangGraph node creates two layers of agent abstraction that are nearly impossible to debug. Pick one framework per workflow.
Assuming the framework handles retries and rate limits. None of these frameworks implement exponential backoff by default. Add retry logic at the HTTP client layer, not the orchestration layer.
Not writing tests before adding orchestration complexity. If you cannot write a unit test for a bare-SDK agent, you will not be able to test it inside LangGraph either. Get the tool execution logic working and tested first, then add the orchestration layer.
Try it yourself
Implement the same research + writing workflow in two frameworks: CrewAI and LangGraph. Both should: take a user query, search for information (mock the search tool), and return a written summary. Compare the two implementations on: lines of code, time to implement, ease of adding a human review step, and how you would add a retry if the writing step produces fewer than 100 words. Write a paragraph on which you would choose for a production feature and why.