TL;DR
Six frameworks, one decision. LangChain = compose linear LLM pipelines (LCEL chains). LangGraph = stateful graphs with branching/loops (workflows and agents). Strands = lightweight, model-driven agents with tools (AWS; great with Bedrock; "agents-as-tools" for multi-agent). AutoGen = agents that solve tasks by conversing. CrewAI = declarative role/task/process teams. OpenAI Agents SDK = minimal agents + handoffs + guardrails, provider-lean. Choose on two axes: how much control you want (low-level ↔ batteries-included) and single vs multi-agent. And keep Anthropic's principle in view: the most successful agent implementations use simple, composable patterns — not complex frameworks. Two apps in the same domain prove the point both ways: a single-agent trip-planning workflow built on LangChain/LangGraph, and a trip-planning assistant built on Strands — same domain (trip planning), two framework choices.
Simple explanation + analogy
Picture building a house:
- LangChain = a pipe-fitting kit. Snap segments together into a line (
prompt | llm | parser). Perfect for water flowing one direction. - LangGraph = the electrical blueprint with switches and loops. You draw exactly where current can branch and cycle back.
- Strands = a smart contractor with a toolbox. You hand them tools and a goal; they decide which tool to use and when (a model-driven loop), with minimal ceremony.
- AutoGen = a room of subcontractors talking it out. Emergent, conversational, self-correcting.
- CrewAI = an org chart with job tickets. Named roles, assigned tasks, a manager or an assembly line.
- OpenAI Agents SDK = a lean agent runtime — one agent that can hand off to another, with typed guardrails, and not much else in the way.
The meta-lesson (Anthropic): don't build a mansion when a shed will do. Start with the simplest pattern; add framework only when complexity earns it.
Diagram
CONTROL / TRANSPARENCY ◀───────────────────────────▶ BATTERIES / ABSTRACTION
low-level ┌───────────────┐ ┌───────────────────┐ high-level
(you own │ Direct SDK │ Strands OpenAI Agents SDK LangGraph │ LangChain (LCEL) │ (framework
the loop) │ (Anthropic: │ (thin) (thin) (explicit │ CrewAI AutoGen │ owns loop)
│ "start here")│ graph) │ │
└───────────────┘ └───────────────────┘
SINGLE-AGENT ◀──────────────────────────▶ MULTI-AGENT
LangChain chain Strands agent Strands agents-as-tools AutoGen group chat
LangGraph (1 loop) LangGraph multi-node CrewAI crew
OpenAI Agents handoffs
App A → LangChain (LCEL chat) + LangGraph (team graph) ┐
├─ same domain, two choices
App B → Strands + Bedrock (orchestrator + specialists) ┘
How it works (deep) — what each is best for
LangChain (LCEL)
Linear composition via the | operator over a uniform Runnable interface. Best for single-agent, mostly-linear flows: RAG, extraction, chat, routing. Batteries included (model connectors, prompt templates, output parsers, memory, retrievers). Ceiling: no native loops or shared mutable state → move to LangGraph.
LangGraph
Nodes + edges + shared State. Conditional edges give branching; back-edges give loops; checkpointers give durability. Builds both workflows (you write the routers — deterministic, auditable) and agents (LLM writes the routers). Best for complex, stateful, cyclic control flow and multi-step/multi-node agents. Higher learning curve; more boilerplate.
Strands (AWS)
A lightweight, model-driven agent framework: give an Agent a system prompt, a model (commonly Bedrock), and @tool-decorated functions; the model decides which tools to call in a loop. Multi-agent via "agents-as-tools" — an orchestrator agent exposes specialist agents as tools. Best when you want minimal ceremony, tight AWS/Bedrock integration, and a model-in-charge loop. Thinner and less opinionated than CrewAI; less graph control than LangGraph.
AutoGen (Microsoft)
Multi-agent as conversation: AssistantAgent + UserProxyAgent, GroupChat + GroupChatManager selecting speakers. Best for open-ended, iterative, code-executing tasks and debate/critique. Least predictable; watch O(T²) transcript growth.
CrewAI
Declarative role-based teams: agents (role/goal/backstory), tasks (expected_output), process (sequential | hierarchical). Best when you can name the roles and the workflow and want a clean, opinionated API. Standalone (not on LangChain). Also offers Flows for deterministic control.
OpenAI Agents SDK
A minimal, production-lean agent loop: an Agent with instructions + tools, handoffs to other agents, guardrails (typed input/output validation), sessions, and tracing. Provider-flexible but OpenAI-first. Best when you want a thin, typed, few-abstraction agent runtime — close in spirit to Anthropic's "just build it" advice, with a little scaffolding.
The Anthropic principle
From Building Effective Agents: across dozens of teams, the most successful implementations use simple, composable patterns rather than complex frameworks. Start with the simplest thing (often a single well-prompted LLM call, or a direct SDK loop); add a framework only when the task genuinely needs orchestration. Frameworks add abstraction layers that can hide the actual prompts/context and complicate debugging. Five patterns cover most needs without heavy machinery: prompt chaining, routing, parallelization, orchestrator-workers, evaluator-optimizer. (Anthropic: Building Effective Agents)
The comparison table
| Framework | What it's best for | Control level | Learning curve | Single vs multi-agent | Core primitive |
|---|---|---|---|---|---|
| LangChain (LCEL) | Linear pipelines: RAG, chat, extraction | Medium (some abstraction) | Low–Medium | Single-agent (chains) | Runnable + | pipe |
| LangGraph | Stateful workflows & agents; loops, branching, HITL | High (explicit graph) | Medium–High | Both (nodes/subgraphs) | Nodes + edges + State |
| Strands | Lean model-driven agents; AWS/Bedrock; tool use | Medium (model-driven loop) | Low | Both (agents-as-tools) | Agent + @tool |
| AutoGen | Open-ended, conversational, code-exec, debate | Low–Medium (emergent) | Medium | Multi-agent (conversation) | Conversable agents + GroupChat |
| CrewAI | Declarative role/task teams; pipelines & delegation | Medium (declarative) | Low | Multi-agent (crews) | Agents + Tasks + Process |
| OpenAI Agents SDK | Thin, typed agent runtime with handoffs/guardrails | Medium (few abstractions) | Low | Both (handoffs) | Agent + handoffs + guardrails |
| Direct SDK (no framework) | Simplest patterns; max transparency (Anthropic's default) | Highest (you own the loop) | Low (concept) / High (build) | Both (you wire it) | messages.create() + your loop |
Rules of thumb:
- Linear task? LangChain chain (or just a direct call).
- Needs loops / shared state / auditability? LangGraph.
- Model-in-charge agent with tools, on AWS? Strands.
- Emergent, conversational, code-heavy? AutoGen.
- Nameable roles + workflow? CrewAI.
- Thin typed agent with handoffs? OpenAI Agents SDK.
- Not sure you need any of it? Start with a direct SDK loop (Anthropic).
Real code
The same idea in two apps — same domain, two framework choices.
App B — Strands + Bedrock (multi-agent orchestrator-as-tools) (orchestrator.py). Specialist agents are wrapped as @tools the orchestrator can call:
from strands import Agent, tool
from strands.models import BedrockModel
from agents.budget_agent import budget_agent
from agents.flights_agent import flights_search_agent
from agents.hotels_agent import hotels_profile_agent
bedrock_model = BedrockModel(
model_id="anthropic.claude-3-5-sonnet-20241022-v2:0",
region_name=os.getenv("AWS_REGION", "us-east-1"),
guardrail_id=get_guardrail_id(),
)
@tool
def budget_agent_tool(query: str) -> str:
"""Handle budget and price-related queries."""
return str(budget_agent(query))
@tool
def hotels_profile_agent_tool(query: str) -> str:
"""Handle hotel matching AND preference/date filtering."""
return str(hotels_profile_agent(query))
# The orchestrator is itself an Agent; the specialists are its tools
orchestrator_agent = Agent(
model=bedrock_model,
system_prompt=ORCHESTRATOR_PROMPT, # "coordinate these specialist agents..."
tools=[budget_agent_tool, flights_search_agent_tool,
hotels_profile_agent_tool, activities_agent_tool],
conversation_manager=SummarizingConversationManager(summary_ratio=0.3),
)
def process_query(query: str) -> str:
return str(orchestrator_agent(query)) # model decides which specialist tools to call
App A — LangChain LCEL (single-agent chain) (trip_planner.py):
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_groq import ChatGroq
llm = ChatGroq(model=GROQ_MODEL, temperature=0.75, api_key=GROQ_API_KEY)
recommend_chain = _RECOMMEND_PROMPT | llm | StrOutputParser() # linear pipe
text = recommend_chain.invoke({"query": q, "context": ctx, "trip_style": style, ...})
And App A — LangGraph for the branching group-trip feature (group_trip_graph.py):
g = StateGraph(GroupTripState)
g.add_conditional_edges("classify_request", _route_after_request_type, {
"followup": "retrieve", "new_suggestion": "retrieve",
"create_task_node": "create_task_node",
})
graph = g.compile() # explicit stateful control flow
Same problem — plan trips for people. App B models it as specialists an orchestrator calls (Strands, model-driven). App A models the single-user path as a linear chain (LCEL) and the group path as an explicit graph (LangGraph). Neither is "right" — they reflect different control/structure preferences.
Real-world example (App B vs App A — the tradeoff)
Both apps plan trips. The framework choice shaped their architecture:
-
App B (Strands + Bedrock, multi-agent). Four domain specialists (budget, flights, hotels+preferences, activities) plus an orchestrator. Strands' model-driven loop lets the orchestrator decide which specialists a query needs (an activities question skips budget). Wins: clean separation of expertise, easy to add a specialist, native Bedrock + guardrails, minimal orchestration code. Costs: multiple LLM hops per query (latency/cost), and behavior depends on the orchestrator's routing judgment. Notably, the code even ships a fallback when Strands isn't installed — a reminder that a multi-agent framework is a real dependency with operational weight.
-
App A (LangChain + LangGraph, mostly single-agent). The 1:1 chat path is a single LCEL chain (parse → retrieve → recommend) — one primary LLM call, fast and cheap. Only the genuinely branching feature (group chat: suggest vs follow-up vs book) escalates to a LangGraph state machine. Wins: low latency on the common path, transparent linear flow, escalate to a graph only where branching is real. Costs: less "autonomous" — the developer wires the control flow rather than letting a model orchestrate.
The interview-ready takeaway: App B bought flexibility and separation with more moving parts and hops; App A bought speed and transparency by staying single-agent until branching forced a graph. This is exactly Anthropic's guidance in practice — don't reach for multi-agent orchestration until the task demands it. Both are defensible; the right answer depends on whether the extra autonomy pays for its latency, cost, and complexity.
Interview questions companies actually ask
1. How do you choose an agent framework? [easy] Two axes: (1) control vs abstraction — how much of the loop you want to own, and (2) single vs multi-agent. Then match the task: linear → LangChain; stateful/branching → LangGraph; model-driven tool agent → Strands; conversational → AutoGen; role-based team → CrewAI; thin typed handoffs → OpenAI Agents SDK. Start simple and escalate only when complexity earns it. (Anthropic: Building Effective Agents)
2. LangChain vs LangGraph — when each? [easy] LangChain (LCEL) for linear pipelines (RAG, extraction, chat). LangGraph when you need loops, dynamic branching, shared mutable state, checkpointing, or human-in-the-loop. You use LangChain components inside LangGraph nodes.
3. Strands vs CrewAI vs AutoGen for multi-agent — contrast them. [medium] Strands: model-driven, "agents-as-tools" (an orchestrator calls specialists as tools) — lean, AWS/Bedrock-native. CrewAI: declarative roles + tasks + process (sequential/hierarchical). AutoGen: emergent conversation with speaker selection. Structure decreases and openness increases: CrewAI (most structured) → Strands → AutoGen (most emergent).
4. What is the OpenAI Agents SDK and where does it fit? [medium]
A minimal agent runtime: Agent + tools, handoffs to other agents, guardrails (typed validation), sessions, and tracing — few abstractions, production-lean. Good when you want a thin, typed agent loop closer to direct-SDK simplicity but with handoffs and safety rails.
5. Explain the Anthropic principle that "the best agents don't rely on complex frameworks." [hard] Anthropic found that successful production agents use simple, composable patterns (prompt chaining, routing, parallelization, orchestrator-workers, evaluator-optimizer) rather than heavy frameworks, which add abstraction that hides prompts/context and complicates debugging. Start with the simplest solution — often a single LLM call or a direct SDK loop — and add orchestration only when demonstrably necessary. (Building Effective Agents)
6. Same domain, two frameworks: why might one team pick Strands and another LangChain? [hard] The Strands app wanted separated specialist expertise, Bedrock-native guardrails, and a model-orchestrated loop — accepting multiple LLM hops. The LangChain app wanted low latency and transparency on the common single-user path, escalating to LangGraph only for genuinely branching flows. The choice trades autonomy/flexibility against latency/cost/predictability.
7. What performance considerations differ across frameworks? [medium]
Latency and cost scale with the number of LLM hops: multi-agent (AutoGen, CrewAI hierarchical, Strands orchestration) makes several calls per query; a single chain makes one. Watch transcript growth (O(T²) in group chats), context accumulation in sequential crews, and manager overhead in hierarchical modes. Predictability is highest with deterministic graphs/workflows, lowest with free-form conversation.
8. How do you migrate between frameworks safely? [medium] Keep prompts, tools, and business logic decoupled from the orchestration layer. Migrate one workflow at a time behind a stable interface, snapshot inputs/outputs as regression tests (golden traces), and A/B the new orchestration against the old before cutover. Because tools and prompts are portable, the graph/chain wiring is usually the only thing that changes.
9. When would you use no framework at all? [hard]
When the task is a single call, a fixed few-step pipeline you can hand-roll, or when transparency/latency/dependency-weight matter more than convenience. A direct SDK loop (while stop_reason == "tool_use") gives full control of context and prompts — Anthropic's recommended default before adopting any framework.
10. Which framework for: a nightly research report with tool use and a fixed 4-step flow? [medium] A fixed 4-step flow with tools is a workflow, not an open-ended agent. Prefer a LangGraph workflow (or even an LCEL chain with tool-calling) for determinism and auditability, rather than a conversational AutoGen crew — the steps are known, so you don't need emergent behavior.
When to use / tradeoffs
- Latency/cost: single chain (1 hop) ≪ multi-agent (N hops). Multi-agent buys separation and flexibility at the price of more calls.
- Predictability/auditability: LangGraph workflows and CrewAI Flows are most deterministic; AutoGen conversation is least.
- Learning curve: LangChain/Strands/CrewAI/OpenAI Agents SDK are quick to start; LangGraph is heavier.
- Lock-in: Strands leans AWS/Bedrock; OpenAI Agents SDK leans OpenAI (both support other providers). LangChain/LangGraph/CrewAI/AutoGen are provider-agnostic.
- The default: per Anthropic, start with the simplest pattern (direct SDK / single call) and add a framework only when orchestration is genuinely required. More agents ≠ better; it's more failure modes, cost, and latency.
Summary + related articles
There's no universally "best" framework — only the best fit for control level and single vs multi-agent needs, tempered by Anthropic's rule that simple, composable patterns beat complex frameworks. LangChain composes linear chains; LangGraph adds stateful graphs; Strands runs lean model-driven agents (great on Bedrock); AutoGen conversates; CrewAI declares role-based teams; the OpenAI Agents SDK offers a thin typed runtime. A LangChain/LangGraph app and a Strands app solve the same problem with different tradeoffs — the clearest evidence that framework choice is an engineering decision, not a fashion.
Related articles:
- LangChain — LCEL chains and the Runnable interface.
- LangGraph — stateful graphs, conditional edges, loops.
- AutoGen — conversation-driven multi-agent.
- CrewAI — role-based crews, sequential/hierarchical processes.
- Building Effective Agents — Anthropic's simple, composable patterns.