Article

AI Agent Frameworks

Nine agent frameworks: versions from each project's docs, a two-axis map, and the same task in LangGraph, OpenAI Agents SDK, Claude Agent SDK, and Google ADK.

Most comparisons of AI agent frameworks are wrong in the same two ways. They compare tools that sit at different layers of the stack, and they copy stability labels from ranking blogs rather than from the projects themselves. The first produces a category error. The second produces a table that was inaccurate the week it was published.

This page is an attempt at the opposite: a maintained reference. Every version below comes from PyPI or npm, every stability claim comes from the vendor’s own documentation, and the four code samples were built against the exact versions shown. It is re-verified quarterly.

Last verified: Oct 2026 (2026-10-13). Next scheduled re-verification: January 2027.

TL;DR

The layer distinction is real, and LangChain’s own docs now make it for you: they separate agent frameworks (LangChain, Vercel AI SDK, CrewAI, OpenAI Agents SDK, Google ADK), agent runtimes (LangGraph), and agent harnesses (Deep Agents), noting that “agent frameworks are generally higher level and run on agent runtimes” (Runtimes, frameworks, and harnesses). Comparing LangGraph to CrewAI is comparing a runtime to a framework.

On stability, the rechecked answer is less tidy than the usual table suggests. Of the nine projects here, exactly one uses the letters “GA” anywhere on its documentation home page. Two ship pre-1.0 packages while describing themselves as production-ready, and one of those two still carries the Development Status :: 3 - Alpha classifier in its own package metadata. A fourth is stable in one language, prerelease in a second, and public preview in a third. Read the stability column before you read anything else.

The Layer Problem Is Not a Matter of Opinion

The old version of this article argued that LangGraph vs CrewAI vs OpenAI Agents SDK is a malformed comparison. That argument has since been adopted by one of the vendors. LangChain’s concepts page distinguishes three things:

Two other vendors have converged on the same vocabulary from different directions. AWS organises the Strands docs around exactly that split: the Strands Harness SDK is “for building an agent harness from the ground up”, and it sits beside a separately documented Strands harness that the site describes as “fully assembled”. And Anthropic’s Agent SDK overview defines itself by what harness it hands you: “the same tools, agent loop, and context management that power Claude Code, programmable in Python and TypeScript”.

So the useful first question is still not which framework is winning. It is which layer am I buying, and the follow-up is how much of the harness do I want to write myself. That is what the map below plots.

The Map

Nine agent frameworks placed by flow explicitness and harness completeness A scatter plot. The horizontal axis runs from the model deciding the path on the left to the developer declaring the path on the right. The vertical axis runs from assembling the harness yourself at the bottom to the harness arriving assembled at the top. Bottom left holds smolagents and the Vercel AI SDK. Bottom right holds LangGraph alone, as the most explicit flow with the least harness. The middle holds the OpenAI Agents SDK and Google ADK. Upper right holds the Microsoft Agent Framework. Upper left holds CrewAI, the Claude Agent SDK, and the Strands harness. HARNESS ARRIVES ASSEMBLED HOW EXPLICIT IS THE FLOW? model decides the path you declare the path you assemble the harness smolagents Vercel AI SDK LangGraph OpenAI Agents SDK Google ADK Microsoft Agent Framework CrewAI Claude Agent SDK Strands harness code-agent loop ToolLoopAgent graph + checkpoints handoffs, guardrails agents + graph workflows agents + workflows crews + flows Claude Code as a library fully assembled
Two axes, not one. The bottom-right corner is nearly empty because a runtime that gives you total control over the path is, by construction, not also handing you a finished harness. Positions reflect each project's own framing of itself, not benchmark results.

The bottom-right outlier is the point of the diagram. LangGraph is the only one of the nine whose docs open by telling you it is “very low-level, and focused entirely on agent orchestration”, and recommend you look at a higher-level option if you are just getting started (LangGraph overview). The top-left cluster is the opposite bet: Claude Code’s harness, or Strands’ assembled one, with the model choosing the path inside it.

The Comparison Table

Two tables over the same nine rows, because one table with nine columns is unreadable on a phone. Every cell that makes a claim links to the page that proves it.

Release and stability

FrameworkLatest package (verified 2026-10-13)LanguagesLicenseStability, per its own docs
LangGraphlanggraph 1.2.15 (2026-10-12); @langchain/langgraph 1.5.0 (2026-10-12)Python, JS/TSMITNo “GA” wording. Lists “production-ready deployment” as a core benefit and ships a backward-compatibility policy for in-flight runs. PyPI classifies it Development Status :: 5 - Production/Stable.
OpenAI Agents SDKopenai-agents 0.23.1 (2026-10-02); @openai/agents 0.20.0 (2026-10-08)Python, TSMITPre-1.0, but the docs call it “a production-ready upgrade of our previous experimentation for agents, Swarm”.
Google ADKgoogle-adk 2.11.0 (2026-10-02)Python, TS, Go, Java, KotlinApache-2.0The only explicit GA label in this table: the docs home banner reads “ADK TypeScript 2.0 GA is now available with graph workflows support”.
Claude Agent SDKclaude-agent-sdk 0.2.165 (2026-10-08); @anthropic-ai/claude-agent-sdk 0.3.296 (2026-10-09)Python, TSMIT package; docs say use is “governed by Anthropic’s Commercial Terms of Service”No stability label. Pre-1.0 in both languages, and the Python package still carries the Development Status :: 3 - Alpha classifier. The docs nav lists a removed TypeScript V2.
Microsoft Agent Frameworkagent-framework 1.21.0 (2026-10-08)Python, .NET, GoMITPer-language. Python installs plainly; the .NET quickstart installs with --prerelease; “the Agent Framework for Go is in public preview”.
CrewAIcrewai 1.15.27 (2026-10-09)PythonMITNo formal label. Docs home claims “production ready from day one”.
Vercel AI SDKai 7.0.138 (2026-10-12)TSApache-2.0No stability label on the agents docs; a 7.x release line with documented migration guides.
AWS Strands Agentsstrands-agents 1.60.0 (2026-10-12)Python, TSApache-2.0The clearest policy of the nine: semver 2.0.0, breaking changes reserved for majors, experimental features explicitly outside the guarantee. Strands Box is separately marked “in preview”.
smolagentssmolagents 1.26.0 (2026-05-29)PythonApache-2.0No stability label. Note the release date: the slowest cadence here by several months.

Capabilities

FrameworkState / persistenceHITL / interruptsTracingMCPMulti-agent primitive
LangGraphCheckpointers and stores; fault toleranceinterrupt() and time travelLangSmithVia the framework layer above it, not the runtimeSubgraphs
OpenAI Agents SDKSessionsHuman in the loopBuilt inYesHandoffs and agents-as-tools
Google ADKSessionsTool confirmationObservabilityYesMulti-agent systems
Claude Agent SDKSessions, resumable and forkablePermissions and approvalsOpenTelemetryYesSubagents
Microsoft Agent FrameworkAgent sessionTool approvalObservabilityHosted and localGraph workflows
CrewAIMemoryVia FlowsObservabilityYesCrews
Vercel AI SDKMemoryTool approvalsVia the host appYesSubagents
AWS Strands AgentsSession managementInterruptsOpenTelemetry tracesYesSwarm and graph
smolagentsAgent memoryInteractive plan reviewOpenTelemetryYesManaged agents

Three notes on reading this table. The tracing column is the one where a blank is most misleading: “via the host app” means the SDK does not ship its own tracer, not that your agent is unobservable, and Tracing and Observability for Agent Systems applies either way. The MCP column is close to uniformly “yes” in late 2026, which makes it a poor differentiator — MCP in Practice covers what the protocol actually buys you. And the multi-agent column names a primitive, not a capability: every one of these can run several agents, but a swarm, a handoff, a crew, and a subgraph commit you to different control structures, which is the subject of Supervisor, Router, and Planner-Executor Patterns.

What Rechecking the Stability Labels Turned Up

The labels in circulation are mostly inherited from blog posts. Checked against each project’s own docs and package metadata on 2026-10-13, three of the common ones do not survive — and a fourth, which this article previously asserted without a source, turns out to be exactly right.

“LangGraph 1.x is GA” is an inference, not a claim. Nothing on the LangGraph overview says GA. What the project actually offers is a 1.x line on PyPI classified Production/Stable, plus a backward-compatibility page that is unusually candid about the real risk: unlike workflow engines that pin a run to the code version it started under, “LangGraph applies the latest graph immediately to every thread”, so every deploy is a compatibility question against persisted checkpoints. That is more useful than a GA badge, and it is a reason to read the page before shipping.

The Claude Agent SDK’s own package metadata says alpha. The docs promise “production AI agents”, the versions are 0.2.165 and 0.3.296, and the Python distribution still ships Development Status :: 3 - Alpha. The nav also lists a removed TypeScript V2, which tells you how fast the API surface has moved. None of that means it is unusable — it means pin the version and read the changelog before upgrading.

The Microsoft Agent Framework’s stability is per-language. Python installs with a bare pip install agent-framework at 1.21.0; the .NET quickstart on the same page installs with --prerelease; and a callout states that Go “is in public preview”, with declarative agents, RAG, CodeAct, and functional workflows “not yet available”. A single row in anyone’s table cannot be right about all three.

Microsoft’s successor claim is real and quotable. The previous version of this article paraphrased it without a link. The overview page says it outright: Semantic Kernel and AutoGen “pioneered the concepts of AI agents and multi-agent orchestration. The Agent Framework is the direct successor, created by the same teams,” and it ships migration guides from both.

One more correction worth recording, because it is the kind of thing a dated conference talk will mislead you about. At Cloud Next in April 2025, Google launched ADK as “a brand new open source project” that was Python-first, with “Java… coming soon” (Introducing Agent Development Kit, 3:46). Eighteen months later the docs carry five language tabs — Python, TypeScript, Go, Java, and Kotlin. Take the design philosophy from the talk and the language list from the docs.

The Same Task, Four Times

One task, deliberately trivial: call a get_weather tool, then answer in one sentence. The point is not what the agent does, it is how much structure each surface asks you to declare before it will do it.

Each sample was built against the pinned version shown on 2026-10-13. Verification means the graph compiles, the agent and tool construct, and the generated tool schema is what the snippet implies — not that a model was called, which would prove only that an API key works.

LangGraph 1.2.15

The runtime gives you nodes and edges and nothing else, so the loop is visible in the source. Note what is not imported: langgraph.prebuilt.create_react_agent still exists but is deprecated in favour of langchain.agents.create_agent, and at today’s versions you cannot have both — langchain 1.2.5 pins langgraph>=1.0.2,<1.1.0, which excludes langgraph 1.2.15. Writing the graph yourself sidesteps the pin entirely.

# pip install "langgraph==1.2.15" "langchain-openai==1.7.1"
from langchain_core.tools import tool
from langchain_openai import ChatOpenAI
from langgraph.graph import START, MessagesState, StateGraph
from langgraph.prebuilt import ToolNode, tools_condition

SYSTEM = "Call get_weather, then answer in exactly one sentence."

@tool
def get_weather(city: str) -> str:
    """Return the current weather for one city."""
    return f"{city}: 18C, light rain"

model = ChatOpenAI(model="gpt-5.4-mini").bind_tools([get_weather])

def call_model(state: MessagesState) -> dict:
    return {"messages": [model.invoke([("system", SYSTEM), *state["messages"]])]}

builder = StateGraph(MessagesState)
builder.add_node(call_model)
builder.add_node("tools", ToolNode([get_weather]))
builder.add_edge(START, "call_model")
builder.add_conditional_edges("call_model", tools_condition)
builder.add_edge("tools", "call_model")
graph = builder.compile()

result = graph.invoke({"messages": [("user", "What is the weather in Lisbon?")]})
print(result["messages"][-1].content)

Add checkpointer=InMemorySaver() to compile() and this becomes resumable; that one argument is most of what the runtime layer is for.

OpenAI Agents SDK 0.23.1

The same task with the loop supplied. @function_tool derives the JSON schema from the type hints and docstring, and Runner owns the turn.

# pip install "openai-agents==0.23.1"
from agents import Agent, Runner, function_tool

@function_tool
def get_weather(city: str) -> str:
    """Return the current weather for one city."""
    return f"{city}: 18C, light rain"

agent = Agent(
    name="Weather",
    instructions="Call get_weather, then answer in exactly one sentence.",
    tools=[get_weather],
)

print(Runner.run_sync(agent, "What is the weather in Lisbon?").final_output)

The docs draw the layer boundary explicitly rather than leaving it to you: use the Responses API directly “when you want to own the loop, tool dispatch, and state handling yourself”, and the Agents SDK “when you want the runtime to manage turns, tool execution, guardrails, handoffs, or sessions”.

Claude Agent SDK 0.2.165

Longest of the four, and the extra length is informative. There is no plain function-tool path — a custom tool is registered as an in-process MCP server and then allow-listed by its fully qualified mcp__server__tool name. The permission surface is not an add-on here; it is how you wire a tool up at all.

# pip install "claude-agent-sdk==0.2.165"   (also needs the Claude Code CLI on PATH)
import anyio
from claude_agent_sdk import (AssistantMessage, ClaudeAgentOptions, TextBlock,
                              create_sdk_mcp_server, query, tool)

@tool("get_weather", "Return the current weather for one city", {"city": str})
async def get_weather(args):
    return {"content": [{"type": "text", "text": f"{args['city']}: 18C, light rain"}]}

options = ClaudeAgentOptions(
    mcp_servers={"weather": create_sdk_mcp_server("weather", tools=[get_weather])},
    allowed_tools=["mcp__weather__get_weather"],
    system_prompt="Call get_weather, then answer in exactly one sentence.",
)

async def main():
    async for message in query(prompt="What is the weather in Lisbon?", options=options):
        if isinstance(message, AssistantMessage):
            for block in message.content:
                if isinstance(block, TextBlock):
                    print(block.text)

anyio.run(main)

It is also the only one of the four that will not run from the package alone: the SDK drives the Claude Code binary. In the Anthropic workshop, Thariq Shihipar explains that as the origin rather than an implementation detail — “the Claude Agent SDK is actually built on top of Claude Code… we kept rebuilding the same parts over and over again” (3:57). You are adopting the harness, which is why it sits top-left on the map.

Google ADK 2.11.0

A plain Python function is a tool; the ceremony is in the runner, which wants an app, a user, and a session before it will take a message.

# pip install "google-adk==2.11.0"
import asyncio
from google.adk.agents import Agent
from google.adk.runners import InMemoryRunner
from google.genai import types

def get_weather(city: str) -> str:
    """Return the current weather for one city."""
    return f"{city}: 18C, light rain"

agent = Agent(
    name="weather",
    model="gemini-2.5-flash",
    instruction="Call get_weather, then answer in exactly one sentence.",
    tools=[get_weather],
)

async def main():
    runner = InMemoryRunner(agent)
    session = await runner.session_service.create_session(app_name=runner.app_name, user_id="u")
    message = types.Content(role="user", parts=[types.Part(text="What is the weather in Lisbon?")])
    async for event in runner.run_async(user_id="u", session_id=session.id, new_message=message):
        if event.is_final_response():
            print(event.content.parts[0].text)

asyncio.run(main())

Swap InMemoryRunner for a persistent session service and the same agent is deployable; that is the “deployment agnostic” design the ADK team led with at launch — “model agnostic, it’s deployment agnostic, and built for interoperability” (1:03).

What the four samples show

Line counts are not the lesson. The ordering of what you must decide first is. LangGraph makes you name the edges before it will run anything. The OpenAI Agents SDK makes you name nothing. The Claude Agent SDK makes you name the permission. ADK makes you name the session. Each of those is the layer’s actual opinion, visible in under 25 lines.

Choosing Without Fooling Yourself

Start at the runtime layer when the failure modes are operational. Long-running work, approvals, resumption after a crash. Harrison Chase’s argument for this is the honest one: agents are long-running and “flaky… you want to have human in the loop… you need some statefulness” (Interrupt 2025 Keynote, 20:23). You will write more code and you will understand your system better.

Start at the framework layer when the task is bounded and the team is new to this. A tool loop with handoffs and built-in tracing gets you to a working system faster, and the defaults are defaults you can inspect. The risk is inheriting an abstraction you cannot see past later.

Take the harness when you want the harness. The Claude Agent SDK and the Strands harness are not thin layers and are not pretending to be. Shihipar’s list of what a harness contains — tools, prompts, “the file system is a way of context engineering”, skills, sub-agents, web search, compacting, hooks, memory (4:59) — is a list of things you would otherwise build. Adopting it is a reasonable trade, as long as you know you made it.

Let autonomy level pick the layer, not the other way round. Andrew Ng’s framing is that there are “degrees to which something is agentic” (State of AI Agents, 2:42), and the degree you need should drive the choice. He is also specific about where teams actually lose: evaluations and tracing individual steps (5:50) — which no framework choice fixes for you. See Error Analysis.

Skip the framework if plain workflow code is enough. Microsoft’s own overview says it plainly: “if you can write a function to handle the task, do that instead of using an AI agent”. When to Use a Workflow Instead of an Agent is the longer version. For the coding-agent case specifically, the platform question is usually more decisive than the framework one — see OpenAI Codex as a Coding-Agent Platform.

FAQ

Which framework is best?

Unanswerable as asked, and the tables above are the reason. The answerable version is: which layer, and how much harness. Once you fix those two, the shortlist is usually two or three projects rather than nine.

Is a pre-1.0 version a reason not to use something?

Not on its own, but it is a reason to pin. Two of the most widely used surfaces here — the OpenAI Agents SDK and the Claude Agent SDK — are pre-1.0 and under rapid change. Pin the exact version, read the changelog before upgrading, and keep your integration surface small.

Do all of these support MCP?

Effectively yes, as of late 2026, which is why it is near the bottom of this page rather than the top. What differs is where MCP sits: a first-class tool source in most, and the only way to register a custom tool in the Claude Agent SDK.

How current is this page?

Last verified 2026-10-13 against each project’s own docs and the PyPI and npm release metadata. Version numbers in this category change weekly; if you are reading this more than a quarter after that date, treat the version column as a starting point and re-check the two or three projects you actually care about.

Further watching

Timestamps link to the moment the claim appears. Checked 2026-10-13.

Primary Sources

Every one of these returned HTTP 200 on 2026-10-13, and every stability and capability claim above comes from one of them.