AWS Builder Center
Picking an AI Agent Framework in 2026

Picking an AI Agent Framework in 2026

A hands-on comparison of nine Python frameworks — with code, data, and no marketing spin.

Why I wrote this

I've spent the last year and half building POC or production AI agents. I've shipped pipelines that run inside real business workflows, I've thrown away prototypes that looked great in a notebook and fell apart under load, and I've argued with colleagues about whether we even need a framework at all. This post is the reference I kept wishing existed: honest, grounded in actual use, with real code samples and no agenda.
I'm going to cover nine Python frameworks as of March 2026. Not because these are the only options, but because they're the ones showing up in architecture discussions, job postings, and production repositories.
Note on methodology: All GitHub star counts and growth data were collected in March 2026 via GitHub's API and the OSS Insight API. Code samples are functional as of this writing. My opinions are my own — I work in the AWS ecosystem and I'll call that out where it's relevant.

The Landscape at a Glance

Here's the raw data before I get into opinions. Absolute star counts are a popularity contest, not a quality signal. The six-month growth column tells a more useful story — it shows which frameworks developers are actively discovering and adopting right now.
FrameworkStarsAge6-month GrowthBest For
AutoGen55.4K31 mo+1,982Conversational multi-agent teams
CrewAI45.7K28 mo+2,540Role-based collaborative workflows
LlamaIndex47.6K40 mo+1,183RAG pipelines & data retrieval
LangGraph26.1K31 mo+2,351Complex stateful graphs
Smolagents25.9K15 mo+1,018Lightweight code-first agents
OpenAI SDK19.7K12 mo+1,554Simple OpenAI-first agents
Google ADK18.3K11 mo+1,900Google Cloud ecosystem
Pydantic AI15.4K21 mo+996Structured, validated outputs
Strands Agents5.3K10 mo+618Model-driven, AWS-native
GitHub data collected March 2026. 'Age' measured from first stargazer event.
A few things jump out. CrewAI and LangGraph are still pulling the most new interest in absolute terms. Google ADK is remarkable for something less than a year old. Strands has the smallest community but it grew through AWS product adoption rather than viral open-source traction — it's already running inside Amazon Q, Kiro, and AWS Glue.
Also worth noting: almost every framework shows the same pattern in monthly star activity. A massive launch spike, then convergence to a steady trickle of 200–600 new stars per month. The hype fades. What you see afterward is genuine, organic adoption. On that measure, the field is far more level than the headline numbers suggest.

Different Philosophies, Different Trade-offs

These aren't interchangeable tools. They reflect genuinely different ideas about how agents should be built.

Scaffold-heavy

LangGraph and AutoGen give you explicit control over execution flow. You define graphs, nodes, edges, and state transitions. You get predictability at the cost of boilerplate. These frameworks assume you don't fully trust the model to decide what comes next, and they're often right.

Model-driven

Strands Agents and Smolagents take the opposite stance. Give the model tools, give it a goal, get out of the way. Less scaffolding, more trust in the model's reasoning. This approach has become more viable because the models themselves have gotten dramatically better at tool use and multi-step planning.

Role-based

CrewAI models the problem as a team of specialists with defined roles, backstories, and goals. Intuitive for business workflows — a researcher, a writer, an editor working in sequence. Can feel constraining when you need fine-grained execution control.

Type-safe

Pydantic AI focuses on structured, validated outputs. Less about orchestration, more about guaranteeing that the LLM returns exactly what your code expects. I use this one constantly as a layer inside larger pipelines.

Vendor-optimized

OpenAI Agents SDK and Google ADK are tuned for their respective ecosystems but generally work with other providers. The depth of integration with their native platform is noticeably smoother than going cross-provider.

The Same Thing, Nine Ways

The fastest way to understand a framework is to see the same minimal example written in each. Here's the pattern: create an agent with one tool, run it. The tool rolls a dice. The differences are immediately visible.

Strands Agents

Three imports, a decorated function, two lines to run. The @tool decorator pulls schema from the docstring and type hints. Sensible defaults, no ceremony.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
from strands import Agent, tool
import random

@tool
def roll_dice(sides: int) -> str:
"""Roll a dice with the given number of sides.
Args:
sides: Number of sides on the dice
"""

return f"You rolled a {random.randint(1, sides)}"

agent = Agent(tools=[roll_dice])
response = agent("Roll a 20-sided dice for me")
print(response)

LangGraph

The prebuilt create_react_agent keeps simple cases manageable. Real power — and real complexity — shows up when you build custom graphs with nodes and edges, which is what most production teams end up doing.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
from langchain.chat_models import init_chat_model
from langgraph.prebuilt import create_react_agent
import random

def roll_dice(sides: int) -> str:
"""Roll a dice with the given number of sides."""
return f"You rolled a {random.randint(1, sides)}"

model = init_chat_model("anthropic:claude-sonnet-4-20250514")
agent = create_react_agent(model, tools=[roll_dice])
result = agent.invoke(
{"messages": [{"role": "user", "content": "Roll a 20-sided dice for me"}]}
)
print(result["messages"][-1].content)

CrewAI

More ceremony. You define an agent with a role, backstory, and goal, then wrap the interaction in a Task and a Crew. This overhead starts making sense when you have multiple specialized agents. For a single tool call, it feels like a lot.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from crewai import Agent, Task, Crew
from crewai.tools import tool
import random

@tool
def roll_dice(sides: int) -> str:
"""Roll a dice with the given number of sides."""
return f"You rolled a {random.randint(1, sides)}"

roller = Agent(
role="Dice Roller",
goal="Roll dice accurately when asked",
backstory="You are a tabletop gaming assistant",
tools=[roll_dice],
)
task = Task(
description="Roll a 20-sided dice for me",
expected_output="A dice roll result",
agent=roller,
)
crew = Crew(agents=[roller], tasks=[task])
result = crew.kickoff()
print(result)

OpenAI Agents SDK

Dead simple. @function_tool, an Agent definition, Runner.run_sync. Built-in tracing and session persistence (SQLite) are nice extras you don't have to configure.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from agents import Agent, Runner, function_tool
import random

@function_tool
def roll_dice(sides: int) -> str:
"""Roll a dice with the given number of sides."""
return f"You rolled a {random.randint(1, sides)}"

agent = Agent(
name="Dice Agent",
instructions="You help roll dice when asked.",
tools=[roll_dice],
)
result = Runner.run_sync(agent, "Roll a 20-sided dice for me")
print(result.final_output)

Google ADK

More verbose for basic cases, but the multi-agent composition primitives — SequentialAgent, ParallelAgent, LoopAgent — are clean and explicit. The dev UI (adk web) is genuinely excellent for testing before you ship.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from google.adk.agents import Agent
from google.adk.runners import InMemoryRunner
from google.genai.types import Content, Part
import random

def roll_dice(sides: int) -> str:
"""Roll a dice with the given number of sides."""
return f"You rolled a {random.randint(1, sides)}"

root_agent = Agent(
name="dice_agent",
model="gemini-2.5-flash",
instruction="You help roll dice when asked.",
tools=[roll_dice],
)
runner = InMemoryRunner(agent=root_agent, app_name="dice_app")
session = await runner.session_service.create_session(app_name="dice_app", user_id="user1")
response = runner.run(user_id="user1", session_id=session.id,
new_message=Content(parts=[Part(text="Roll a 20-sided dice for me")]))
async for event in response:
if event.content and event.content.parts:
print(event.content.parts[0].text)

Pydantic AI

Where this framework shines is structured output. Define a Pydantic model as the return type and the framework guarantees the LLM's response validates against it, retrying with error context if it doesn't. This eliminates an entire class of production bugs.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from pydantic_ai import Agent
import random

agent = Agent(
"openai:gpt-4o",
system_prompt="You help roll dice when asked.",
)

@agent.tool_plain
def roll_dice(sides: int) -> str:
"""Roll a dice with the given number of sides."""
return f"You rolled a {random.randint(1, sides)}"

result = agent.run_sync("Roll a 20-sided dice for me")
print(result.output)

Smolagents

The CodeAgent writes Python code to orchestrate tool calls instead of using JSON. More token-efficient in some scenarios, and lets the agent compose operations in ways JSON tool calls can't easily express. Be aware of CVE-2025-9959 — it's patched in 1.21.0+, but code-executing agents need serious sandboxing.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
from smolagents import CodeAgent, InferenceClientModel, tool
import random

@tool
def roll_dice(sides: int) -> str:
"""Roll a dice with the given number of sides.
Args:
sides: Number of sides on the dice
"""

return f"You rolled a {random.randint(1, sides)}"

model = InferenceClientModel()
agent = CodeAgent(tools=[roll_dice], model=model)
agent.run("Roll a 20-sided dice for me")

AutoGen

Async-first and event-driven. The Team abstraction is where it gets interesting. Worth noting: there was a major 0.2-to-0.4 rewrite that left a lot of outdated tutorials floating around online — if you're debugging, check the version of the example you're reading.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from autogen_agentchat.agents import AssistantAgent
from autogen_agentchat.ui import Console
from autogen_ext.models.openai import OpenAIChatCompletionClient
import random

def roll_dice(sides: int) -> str:
"""Roll a dice with the given number of sides."""
return f"You rolled a {random.randint(1, sides)}"

model = OpenAIChatCompletionClient(model="gpt-4o")
agent = AssistantAgent("dice_agent", model_client=model, tools=[roll_dice])

async def main():
await Console(agent.run_stream(task="Roll a 20-sided dice for me"))

import asyncio
asyncio.run(main())

LlamaIndex

The agent loop itself is not LlamaIndex's main event. What you're really buying is 160+ data connectors, the RAG pipeline, and evaluation modules. The agent is the orchestration layer on top of serious retrieval infrastructure.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from llama_index.core.agent.workflow import FunctionAgent
from llama_index.core.tools import FunctionTool
from llama_index.llms.openai import OpenAI
import random

def roll_dice(sides: int) -> str:
"""Roll a dice with the given number of sides."""
return f"You rolled a {random.randint(1, sides)}"

tool = FunctionTool.from_defaults(fn=roll_dice)
agent = FunctionAgent(
tools=[tool],
llm=OpenAI(model="gpt-4o"),
system_prompt="You help roll dice when asked.",
)

async def main():
response = await agent.run("Roll a 20-sided dice for me")
print(response.response.content)

import asyncio
asyncio.run(main())

What Actually Matters When Choosing

Model lock-in

The single most important architectural decision. Do you want to be free to swap providers in 12 months?
  • Model-agnostic (no friction): Strands, LangGraph, Smolagents, Pydantic AI, LlamaIndex
  • Provider-first but open: Google ADK, OpenAI Agents SDK, CrewAI
  • No framework is truly locked, but integration depth varies enormously. Strands on Bedrock and ADK on Vertex are each smoother in their native cloud than they are fighting against the grain.

MCP support

Model Context Protocol has become the standard for connecting agents to external tools and data sources. Where things stand today:
  • First-class native: Strands Agents, CrewAI, Smolagents, Pydantic AI
  • Built-in via integrations: LangGraph (added in 1.0), OpenAI Agents SDK, Google ADK
  • Built-in: AutoGen
  • Emerging/partial: LlamaIndex

Deployment story

This is where the field really splits. Some frameworks are Python libraries that stop at the process boundary. Others have a real answer for getting your agent into production at scale.
  • Full deployment story: Strands (Bedrock AgentCore, Lambda, Fargate), LangGraph (LangGraph Cloud), Google ADK (Cloud Run, Vertex AI)
  • SDK + guidance: Pydantic AI, CrewAI (optional Agent Management Platform), OpenAI Agents SDK
  • SDK only: Smolagents, AutoGen, LlamaIndex — deployment is your responsibility

Observability

You cannot debug what you cannot see, and agents are notoriously hard to debug. LangGraph with LangSmith is the most mature story. Pydantic AI with Logfire is good. OpenAI Agents SDK has built-in tracing. Strands uses OpenTelemetry, which plugs into AWS X-Ray and CloudWatch cleanly. For the others, you're bringing your own stack.

The Honest Take on Each

LangGraph

The good: Swiss Army knife. Broad integrations, mature tooling, LangSmith observability, durable execution for long-running agents. Battle-tested in production.
The honest: Heavy. Abstraction layers on abstraction layers. Documentation is extensive but scattered, and it's not always clear which version you're reading. The pricing for LangGraph Cloud can surprise you at scale. There's a vocal developer backlash around over-abstraction and API churn — worth reading before you commit.
Use it if: You need durable execution, complex stateful workflows, and you're willing to invest in learning the ecosystem.

CrewAI

The good: Fastest path from idea to multi-agent prototype. The role/backstory/goal pattern clicks immediately. Massive, active community. MCP and A2A support are first-class.
The honest: The abstraction can fight you when you need fine-grained control. Multiple teams report hitting a ceiling at 6–12 months and rewriting to LangGraph or custom code. Infinite loops and limited built-in observability are recurring complaints.
Use it if: You're building collaborative multi-agent workflows and want fast prototyping. The crew metaphor should fit your problem.

OpenAI Agents SDK

The good: Zero to working agent in under an hour. Built-in tracing, guardrails, session persistence. Massive PyPI download numbers suggest broad real-world adoption.
The honest: Works best with OpenAI models. Limited semantic memory layer. The handoff pattern for multi-agent is simple but not as powerful as graph-based approaches.
Use it if: You're an OpenAI shop and want the path of least resistance.

Google ADK

The good: Clean multi-agent composition primitives. Excellent dev UI. Multi-language support (Python, TypeScript, Go, Java) — more language breadth than any other framework here.
The honest: Gemini-first. Other providers work but aren't as polished. Google's reputation for sunsetting products makes some developers cautious about deep investment.
Use it if: You're in the Google ecosystem or the SequentialAgent/ParallelAgent composition model fits your architecture.

AutoGen

The good: Strong academic backing. Interesting Team abstraction for conversational multi-agent. Built-in code execution. Well-designed event-driven architecture.
The honest: The 0.2-to-0.4 rewrite created a documentation minefield. Microsoft is steering investment toward Semantic Kernel. Token consumption and circular conversation loops are persistent community complaints.
Use it if: You need conversational multi-agent systems or code execution as a core capability.

Strands Agents

The good: Minimal boilerplate, broad provider support (12+ providers), first-class MCP integration, three distinct multi-agent patterns (Graph, Swarm, Workflow), A2A protocol support. The @tool decorator is dead simple. The deepest AWS deployment story via Bedrock AgentCore. 14 million downloads — it's not a side project.
The honest: Newer than most frameworks here. Smaller community. Some features are still experimental. Lambda deployments don't support streaming — you need AgentCore Runtime or Fargate for that. If you're not on AWS, you miss the main deployment advantage, though the SDK works with any provider.
Use it if: You want model-driven agents with minimal scaffolding. You're on AWS or plan to be. You want to go from prototype to production without switching frameworks.

Pydantic AI

The good: Nothing else comes close for structured output. Type-safe approach catches errors that would otherwise surface in production. Logfire integration is solid. Low lock-in.
The honest: Often used as a validation layer alongside other frameworks rather than standalone. The multi-agent graph is newer and less battle-tested than LangGraph.
Use it if: Output structure is critical to your application or you're building API-driven agents with strict contracts.

Smolagents

The good: True to its name. The CodeAgent pattern is genuinely interesting for token-efficient tool orchestration. Model-agnostic. Push-to-Hub makes sharing agents easy.
The honest: CVE-2025-9959 was a sandbox escape (patched in 1.21.0+). More experimental than production-hardened. Deployment requires careful sandboxing configuration.
Use it if: You want a small, code-first library for research or prototyping.

LlamaIndex

The good: Unmatched retrieval infrastructure. 160+ data connectors, evaluation modules, a mature RAG pipeline. If your agent's primary job is querying documents and data sources, this is the most complete solution.
The honest: The agent loop is less sophisticated than dedicated agent frameworks. You're buying the retrieval stack and getting an agent as the orchestration layer on top.
Use it if: Your agent is fundamentally a retrieval/RAG system that also needs to reason and act.

The Cheat Sheet

If you need…Use
Complex, stateful workflows with maximum controlLangGraph
A multi-agent crew for content/research pipelinesCrewAI
The simplest possible thing that worksOpenAI Agents SDK
Structured, validated outputsPydantic AI
Document and data source queryingLlamaIndex
Google Cloud ecosystemGoogle ADK
Code-generating agents for researchSmolagents
Conversational multi-agent teamsAutoGen
Model-driven agents with minimal scaffoldingStrands Agents
Something in production on AWS next monthStrands + Bedrock AgentCore

Where This Is All Going

A year ago the question was which framework to learn. Now I hear a different question more often: do I even need a framework?
That's not a fringe view. There's a growing movement of developers who stripped out the frameworks and went back to raw Python loops against the provider API. The models have gotten good enough at tool use that a direct approach can get you surprisingly far. Vendor lock-in anxiety is real — major players formed the Agentic AI Foundation (AAIF) to promote interoperability and open standards. Watch that space.
The frameworks that will survive are the ones providing genuine value beyond what you'd write yourself: durable execution, managed deployment, observability, multi-agent coordination, structured outputs. These are hard problems worth depending on a library to solve. Everything else is scaffolding around a model that's increasingly capable of scaffolding itself.
The direction is clear. Less framework, more model. The best frameworks on this list know that. They're getting thinner, not thicker. They trust the model more and engineer the prompt less. Strands calls it model-driven. Smolagents calls it barebones. Pydantic AI calls it the Pydantic way. The label doesn't matter. The direction does.
Pick the framework that fits your cloud, your team, and your problem. Don't pick the one with the most stars.

"inspired by the conversation around agentic frameworks"
Any opinions in this article are those of the individual author and may not reflect the opinions of AWS.
Enjoyed reading this content? Let the author know!

Your likes, comments, shares, and saves help creators reach more builders.

Loading recommendations

Loading article