Choosing an Agent Framework in Late 2026: 10 Frameworks Compared by Use Case

TL;DR
Ten agent frameworks, one decision guide: a capability matrix built from official docs and a flowchart that picks by language, durability and team.
There is no single best agent framework in late 2026. Three things decide the right one: your language, how long a single run has to survive, and which model vendor you are tied to. As defaults, pick the Vercel AI SDK or Mastra for TypeScript apps, Pydantic AI or LangGraph for Python backends, the vendor's own SDK (OpenAI Agents SDK, Claude Agent SDK, Google ADK) when you are committed to that vendor, and Microsoft Agent Framework for .NET and Azure shops.
Last updated: October 17, 2026
This guide covers ten projects: LangChain/LangGraph, Mastra, the Vercel AI SDK, the OpenAI Agents SDK, the Claude Agent SDK, Google ADK, LlamaIndex, Pydantic AI, CrewAI and Microsoft Agent Framework (MAF). Every row in the matrix comes from the project's own docs or release notes. When a doc did not state something, the cell says so instead of guessing. Every TypeScript block was type-checked and every Python block was compiled and import-checked against the versions listed; the Pydantic AI approval flow was also run end to end against its offline test model. No API calls were made.
The short answer by situation#
- TypeScript app: the Vercel AI SDK if you want an agent loop (
ToolLoopAgent) that plugs into your UI, withWorkflowAgentwhen it has to survive restarts. Pick Mastra when you also want workflows, memory, a local Studio and storage-backed suspend/resume in one framework. - Python backend: Pydantic AI for a typed agent loop where "every model [is] a string swap away", or LangGraph when deterministic and LLM-driven steps have to live in one explicit graph.
- Durable, long-running workflows: LangGraph checkpointers, Mastra workflow snapshots, AI SDK
WorkflowAgentand MAF superstep checkpoints all ship durability in the framework itself. Pydantic AI integrates with nine durable engines, and the OpenAI Agents SDK has Temporal, DBOS, Restate and Dapr integrations. - Multi-agent systems: MAF documents five named orchestration patterns (sequential, concurrent, handoff, group chat, Magentic-One). CrewAI is built around role-playing agent teams. Google ADK has prebuilt workflow agents plus experimental A2A support.
- Enterprise and regulated environments: MAF 1.0 ships stable APIs with long-term support for .NET and Python. ADK deploys to Agent Runtime, Cloud Run or GKE. The Claude Agent SDK authenticates through Amazon Bedrock, Claude Platform on AWS, Google Cloud's Agent Platform and Microsoft Foundry.
None of these is a ranking. Each pick follows from a constraint, not from a feature count.
Three layers people all call "a framework"#
Feature-list comparisons mislead because these projects sit at different layers. Some are model toolkits, some are orchestration runtimes, and some are complete agent harnesses that give you a working loop with tools, context management and permissions already set up. Many span two layers. If you are unsure what a harness is, start with what an agent harness is.
%% title: Three layers people call a framework
flowchart LR
subgraph Harness[Agent harness]
H1[Claude Agent SDK]
H2[LangChain Deep Agents]
H3[Pydantic AI Harness]
H4[MAF Harness Agent]
H5[AI SDK HarnessAgent]
end
subgraph Orchestrator[Orchestration runtime]
O1[LangGraph]
O2[Mastra workflows]
O3[MAF workflows]
O4[ADK graph workflows]
O5[CrewAI Flows]
O6[LlamaIndex Workflows]
end
subgraph Toolkit[Model toolkit]
T1[AI SDK core]
T2[Pydantic AI core]
end
Harness --> Orchestrator --> ToolkitLangChain's docs describe this split for their own stack. Deep Agents is an agent harness (planning, subagents, filesystem tools, context management) built on LangGraph. create_agent is a minimal, configurable harness that you extend with middleware. LangGraph is the orchestration runtime underneath both. Other projects are converging on the same shape: MAF now lists a Harness Agent next to Agents and Workflows, Pydantic AI has a Harness that adds memory, guardrails, sub-agents and planning as capabilities, and the AI SDK's HarnessAgent runs an existing harness (the docs name Claude Code, Codex and Pi) and streams the output into AI SDK UI primitives.
The practical consequence is that you can mix layers. An AI SDK frontend over a LangGraph or Mastra backend is a reasonable combination, not a compromise.
Capability matrix (documented features only)#
| Framework | Languages | Core abstraction | Deterministic workflows | Durable resume | Approval / HITL API | Multi-agent | Models | Version (2026-10-17) |
|---|---|---|---|---|---|---|---|---|
| LangGraph | Python, JS | StateGraph nodes and edges | Yes, the graph is the workflow | Checkpointers per super-step; durability exit, async, sync | interrupt() + Command(resume=...) | Subgraphs | Any (LangChain integrations or your own client) | 1.2.16 py, 1.5.1 js |
LangChain create_agent | Python, JS | Harness with middleware, built on LangGraph | Via LangGraph | Via LangGraph checkpointers | HumanInTheLoopMiddleware | Deep Agents subagents | Model strings via LangChain integrations | 1.4.6 py, 1.5.18 js |
| Mastra | TypeScript | Agent + workflows | Workflows | suspend() snapshots in storage (libSQL default; Upstash, PostgreSQL, OracleDB); durable agents beta | suspend() / run.resume() with resumeSchema; agent HITL approval | Supervisor agents | Model router, provider/model strings | 1.78.0 |
| Vercel AI SDK | TypeScript | ToolLoopAgent, WorkflowAgent | Via Workflow ('use workflow', 'use step') | WorkflowAgent persists state; 'use step' tools retry (3 attempts default) | needsApproval per tool, toolApproval on the agent or call | Not stated in cited docs | Provider packages or provider/model strings | 7.0.143 |
| OpenAI Agents SDK | Python, TS | Agents, handoffs, guardrails | Orchestrate in code | Serializable RunState at interruptions; Temporal, DBOS, Restate, Dapr integrations | needs_approval + RunState.approve() | Handoffs, agents as tools | OpenAI by default (Responses API); ModelProvider; beta Any-LLM and LiteLLM adapters | 0.24.0 py, 0.20.0 js |
| Claude Agent SDK | Python, TS | Claude Code agent loop as a library | No graph; hooks and subagents | Sessions: continue, resume, fork | Permissions + hooks | Subagents | Claude via Anthropic API, Bedrock, Claude Platform on AWS, Agent Platform (Vertex), Foundry | 0.2.168 py, 0.3.302 ts |
| Google ADK | Python, TS, Go, Java, Kotlin | LlmAgent + workflow agents | Graph workflows (ADK 2.0: Py, TS, Go); Sequential, Parallel, Loop agents | Session and State services | FunctionTool(require_confirmation=...), LongRunningFunctionTool | Hierarchical agents, AgentTool, A2A (experimental) | Optimized for Gemini; others via BaseLlm | 2.12.0 py, 2.3.0 ts |
| LlamaIndex | Python | FunctionAgent, ReActAgent, CodeActAgent + Workflows | Event-driven Workflows | Not stated in cited docs | Human-in-the-loop review in Workflows | AgentWorkflow | Unified LLM interface; OpenAI, Anthropic, Hugging Face and more via integration packages (e.g. llama-index-llms-openai) | core 0.14.25 |
| Pydantic AI | Python 3.11+ | Typed Agent + capabilities | Pydantic Graph (separate package) | 9 engines: Temporal, DBOS, Prefect, Restate, AWS Lambda, Kitaru, Airflow, Absurd, pgtask | Deferred tools (requires_approval=True) | Harness sub-agents | Any model by string | 2.57.0 |
| CrewAI | Python 3.10 to 3.13 | Crews + Flows | Flows (@start, @listen, @router) | @persist (SQLite default), restore_from_state_id | @human_feedback (1.8.0+) | Crews of role-playing agents | provider/model-id strings; native SDKs for OpenAI, Anthropic, Gemini, Azure, Bedrock, Snowflake Cortex; other providers via LiteLLM | 1.15.28 |
| Microsoft Agent Framework | .NET, Python, Go (preview) | Agents, Harness Agent, Workflows | Graph workflows (all SDKs); Python functional @workflow (experimental) | Checkpoints at superstep boundaries | ctx.request_info(), RequestInfoExecutor; tool approval_mode | Sequential, concurrent, handoff, group chat, Magentic-One; A2A, MCP | Foundry, Azure OpenAI, OpenAI, Anthropic, Bedrock, Gemini, Ollama | 1.22.0 py |
How to read it: "Not stated in cited docs" means the pages listed under Sources did not document it. It does not mean the feature is missing. Versions come from the npm registry and PyPI on October 17, 2026. The LlamaIndex and CrewAI model cells come from each project's LLM configuration page. The ADK approval cell comes from the google-adk 2.12.0 package itself (both classes construct and import cleanly). The MAF approval_mode value comes from agent-framework-core 1.22.0.
Decision flowchart#
%% title: Pick an agent framework by situation
flowchart TD
A[Start] --> B{Biggest constraint?}
B -->|TypeScript app| C{Need a full backend layer?}
C -->|No, UI plus agent loop| D[Vercel AI SDK]
C -->|Yes, workflows and memory| E[Mastra]
C -->|Explicit graph control| F[LangGraph.js]
B -->|Python backend| G{What dominates the work?}
G -->|Typed outputs, swap models| H[Pydantic AI]
G -->|Retrieval over your documents| I[LlamaIndex]
G -->|Role-based agent teams| J[CrewAI]
G -->|Deterministic plus agentic steps| K[LangGraph]
B -->|.NET or Azure shop| L[Microsoft Agent Framework]
B -->|Committed to one model vendor| M{Which vendor?}
M -->|OpenAI| N[OpenAI Agents SDK]
M -->|Anthropic, agent works on files and shell| O[Claude Agent SDK]
M -->|Gemini or Google Cloud| P[Google ADK]Use the flowchart as a starting point, not a verdict. Real systems often combine branches. A TypeScript team can put AI SDK UI over a Mastra or LangGraph backend. A Python team can run Pydantic AI agents inside a durable engine and keep LlamaIndex for the retrieval layer. A team that has standardized on Azure can still use Anthropic or Gemini models through MAF's connectors.
Framework by framework#
LangChain and LangGraph#
LangGraph calls itself "a low-level orchestration framework and runtime for building, managing, and deploying long-running, stateful agents". Its strength is mixing hand-coded deterministic steps with LLM-driven steps in one graph, with checkpointing, streaming and human-in-the-loop built in. LangChain's create_agent and Deep Agents run on top of it, so they inherit that persistence, and LangSmith adds tracing, evals and deployment across frameworks.
Tradeoff: LangGraph is low-level by design, and LangChain's docs recommend starting with create_agent or Deep Agents and dropping down only when you need explicit graph control. On resume after interrupt(), the node restarts from the beginning, so side-effecting nodes need idempotency.
pip install langchain langgraph langchain-openai # or: npm i langchain @langchain/core @langchain/langgraph
Mastra#
Mastra is "a TypeScript framework for building AI agents and applications". Its agent docs cover memory, structured output, human-in-the-loop approval, supervisor agents, processors, guardrails, scorers, voice and channels (Slack, Discord, Telegram). Workflows persist suspend() snapshots to storage and resume with a typed resumeSchema. A local Studio runs at localhost:4111, and integration guides cover Next.js, React + Vite, Astro, Express, SvelteKit and Hono.
Tradeoff: createDurableAgent() (added in @mastra/core 1.45.0) is still labelled beta. For predetermined multi-step processes, the docs point to workflows rather than agents.
npm create mastra@latest
Vercel AI SDK#
The AI SDK's recommended agent class is ToolLoopAgent, which manages the loop, context and stopping conditions. runtimeContext carries shared state, and toolsContext gives each tool only its own typed context. AI SDK 7 (released June 25, 2026) added WorkflowAgent, which runs the same loop inside a workflow with automatic state persistence. It replaces the Workflow DevKit's DurableAgent.
Tradeoff: ToolLoopAgent is in-memory, and the docs say its progress is lost on a crash. Durability means adopting Workflow (@ai-sdk/workflow with workflow@5) and its compiler directives. Note also that WorkflowAgent.stream() has no default step limit (generate() caps at 20), so set stopWhen to bound cost.
npm install ai zod # durable: npm i @ai-sdk/workflow ai workflow@5OpenAI Agents SDK#
The OpenAI Agents SDK is built on a small set of primitives: agents, handoffs or agents as tools, and guardrails, with tracing built in. It also ships sandbox agents with resumable sessions, realtime and voice agents, MCP tool calling, sessions and human-in-the-loop. Approvals serialize into a RunState, and the Temporal integration has been GA for Python since March 23, 2026.
Tradeoff: OpenAI models via the Responses API are the default. Other models go through ModelProvider or set_default_openai_client, and the docs label the Any-LLM adapter beta and best-effort. The OpenAI Agents SDK vs Claude Agent SDK comparison covers handoffs vs subagents and guardrails vs hooks in depth.
pip install openai-agents # or: npm i @openai/agents zod
Claude Agent SDK#
The Claude Agent SDK gives you "the same tools, agent loop, and context management that power Claude Code, programmable in Python and TypeScript". You get built-in tools to read, write and edit files and run commands, plus hooks, subagents, MCP, permissions, sessions (continue, resume, fork) and skills, commands and memory loaded from .claude/. Custom tools run as in-process MCP servers (type-checked against @anthropic-ai/claude-agent-sdk@0.3.302):
import { query, tool, createSdkMcpServer } from '@anthropic-ai/claude-agent-sdk';
import { z } from 'zod';
const orders = createSdkMcpServer({
name: 'orders',
version: '1.0.0',
tools: [
tool('lookup_order', 'Look up an order by id', { orderId: z.string() }, async ({ orderId }) => ({
content: [{ type: 'text', text: JSON.stringify({ orderId, status: 'shipped' }) }],
})),
],
});
for await (const message of query({
prompt: 'Where is order A-1001?',
options: { mcpServers: { orders }, allowedTools: ['mcp__orders__lookup_order'] },
})) {
if (message.type === 'result') console.log(message.session_id, message.subtype);
}
Tradeoff: it runs Claude models only, and it is a library that runs the Claude Code binary under the hood, so that binary is part of your deployment. Use is governed by Anthropic's Commercial Terms, and the docs say third-party products may not offer claude.ai login unless approved. Anthropic's hosted alternative is Managed Agents.
npm install @anthropic-ai/claude-agent-sdk # or: pip install claude-agent-sdk (Node 18+ / Python 3.10+)Google ADK#
ADK is available in Python, TypeScript, Go, Java and Kotlin, which is the widest language spread here. ADK 2.0 added graph workflows (Python, TypeScript and Go) alongside dynamic workflows written in your own code and the prebuilt SequentialAgent, ParallelAgent and LoopAgent. It ships a CLI, a developer UI, evaluation with multi-turn eval sets and criteria, and bidirectional streaming for live voice and video agents. This agent was compiled and import-checked against google-adk==2.12.0:
from google.adk import Agent
def lookup_order(order_id: str) -> dict:
"""Look up an order by id."""
return {"order_id": order_id, "status": "shipped"}
root_agent = Agent(
name="support_agent",
model="gemini-flash-latest",
instruction="You answer order questions with the lookup_order tool.",
tools=[lookup_order],
)
Tradeoff: ADK is optimized for Gemini, and other models plug in through BaseLlm. A2A support is marked Experimental, and the docs note that some third-party integrations may not work with graph workflows.
pip install google-adk # Python 3.11+; or: npm i @google/adk
LlamaIndex#
LlamaIndex describes itself as "a Python toolkit for building LLM-powered agents over your data". Its data connectors, indexes, vector stores and query engines sit next to prebuilt agents (FunctionAgent, ReActAgent, CodeActAgent), AgentWorkflow for multiple agents, and event-driven Workflows with branching, retries and human review that deploy as services. Models plug in through one LLM interface, with integrations for OpenAI, Anthropic, Hugging Face and more. It is MIT-licensed.
Tradeoff: its center of gravity is data and retrieval. If your agent barely touches documents, a lighter loop may fit better. If retrieval quality is the product, it is the only project here whose docs are organized around connectors, indexes and query engines.
pip install llama-index-core llama-index-llms-openai
Pydantic AI#
Pydantic AI calls itself "the Python AI SDK: a typed, extensible agent loop with every model a string swap away". Its capability primitive bundles tools, instructions, hooks and settings. Instrumentation is OpenTelemetry-native, and UI event streams support AG-UI and the Vercel AI protocol. It also offers the most durable-engine options here: nine, five of them co-maintained with the vendor teams.
Tradeoff: it requires Python 3.11+, and durability comes from an external engine rather than a built-in checkpointer. Pydantic Graph and Pydantic Evals are separate packages.
pip install pydantic-ai # slim install used here: pydantic-ai-slim[openai]
CrewAI#
CrewAI combines Crews (role-playing agents that collaborate on tasks) with Flows (event-driven workflows with state, conditional logic, loops and branching). For production apps the docs say to "start with a Flow" and use a Crew inside a Flow step when you need autonomy. That mirrors the deterministic-first pattern that LangChain, Mastra and MAF docs also describe. Models are named as provider/model-id strings, with native SDK integrations for six providers and LiteLLM for the rest.
Tradeoff: @persist uses SQLiteFlowPersistence unless you supply a custom FlowPersistence backend, so plan that before running multiple workers. The package requires Python 3.10 to 3.13.
pip install crewai
Microsoft Agent Framework#
MAF 1.0 shipped on April 3, 2026 for .NET and Python with stable APIs and long-term support. It unifies Semantic Kernel and AutoGen, with migration assistants for both (per Microsoft's 1.0 announcement). Every orchestration pattern (sequential, concurrent, handoff, group chat, Magentic-One) supports checkpointing, approvals and pause/resume. It also has declarative YAML agents and workflows, A2A and MCP, and a Harness Agent with planning, context compaction, file access, memory and tool approval. Our Microsoft Agent Framework guide covers migration from AutoGen and Semantic Kernel.
Tradeoff: the Go SDK is in public preview, and declarative agents, RAG, CodeAct and functional workflows are not available in Go yet. The Python functional @workflow API is experimental. In our check, pip install agent-framework==1.22.0 would not resolve without allowing pre-releases because of an Azure pre-release dependency, while agent-framework-core plus agent-framework-openai installed cleanly.
pip install agent-framework-core agent-framework-openai
Pick by use case#
TypeScript app#
Choose between three shapes. The AI SDK keeps the agent close to your UI and model calls, and you add WorkflowAgent when you need durability. Mastra gives you an opinionated backend layer (agents, workflows, memory, storage, Studio). LangGraph.js gives you explicit graph control and the LangSmith tooling. Here is the same lookupOrder tool in the first two, type-checked against ai@7.0.143 and @mastra/core@1.78.0:
// AI SDK
import { ToolLoopAgent, tool, isStepCount } from 'ai';
import { z } from 'zod';
const lookupOrder = tool({
description: 'Look up an order by id',
inputSchema: z.object({ orderId: z.string() }),
execute: async ({ orderId }) => ({ orderId, status: 'shipped' }),
});
export const supportAgent = new ToolLoopAgent({
model: 'openai/gpt-5.5',
instructions: 'You handle order questions.',
tools: { lookupOrder },
stopWhen: isStepCount(10),
});
// Mastra
import { Agent } from '@mastra/core/agent';
import { createTool } from '@mastra/core/tools';
import { z } from 'zod';
const lookupOrder = createTool({
id: 'lookup-order',
description: 'Look up an order by id',
inputSchema: z.object({ orderId: z.string() }),
execute: async ({ orderId }) => ({ orderId, status: 'shipped' }),
});
export const supportAgent = new Agent({
id: 'support-agent',
name: 'Support Agent',
instructions: 'You handle order questions.',
model: 'openai/gpt-5.5',
tools: { lookupOrder },
});
They are close at this size. The difference shows up around them: where state lives, how a run resumes, and whether you want a framework-owned dev server. The TypeScript AI agent stack post goes deeper on this choice.
Python backend#
- Pydantic AI fits teams that already think in Pydantic models and want typed dependencies and outputs, plus a choice of durable engine.
- LangGraph fits workflows where the order of steps matters and some steps are plain code. The graph makes that explicit and checkpointable.
- LlamaIndex fits when the hard part is ingesting, indexing and querying your own documents.
None of these blocks the others. Pydantic AI and LangGraph agents can both call a LlamaIndex query engine as a tool.
Durable workflows#
The short version: LangGraph and Mastra checkpoint into your own database and re-execute the interrupted step. AI SDK WorkflowAgent turns 'use step' tools into retried durable steps. Pydantic AI and the OpenAI Agents SDK hand the run to an engine such as Temporal or DBOS. The mechanics differ in the one place that matters, whether a side effect can run twice after a crash, and our durable AI agent frameworks comparison walks through that with a real crash test.
Multi-agent#
Each project documents a different multi-agent model:
- MAF: named orchestrations (sequential, concurrent, handoff, group chat, Magentic-One), all checkpointable.
- Google ADK: hierarchical agents,
AgentTool, prebuilt Sequential/Parallel/Loop agents, and experimental A2A for cross-process agents in Python, Go and Java. - CrewAI: Crews of role-playing agents, wrapped in a Flow for control.
- OpenAI Agents SDK: handoffs and agents as tools.
- Claude Agent SDK: subagents inside one Claude Code style loop.
- LangGraph: subgraphs, with Deep Agents subagents one layer up.
- Mastra: supervisor agents. LlamaIndex:
AgentWorkflow.
If you cannot say why one agent is not enough, start with one agent and a deterministic workflow around it. CrewAI's and Mastra's docs nudge in that direction too.
Enterprise#
- MAF is positioned by Microsoft as the long-term-support path for .NET and Python teams, with Foundry, Azure OpenAI and five other model connectors.
- Google ADK deploys to your own containers or to Google Cloud through Agent Runtime, Cloud Run or GKE.
- LangGraph pairs with LangSmith for tracing, evals and deployment.
- Claude Agent SDK authenticates through Amazon Bedrock (
CLAUDE_CODE_USE_BEDROCK=1), Claude Platform on AWS (CLAUDE_CODE_USE_ANTHROPIC_AWS=1plusANTHROPIC_AWS_WORKSPACE_ID), Google Cloud's Agent Platform (CLAUDE_CODE_USE_VERTEX=1) and Microsoft Foundry (CLAUDE_CODE_USE_FOUNDRY=1), so model usage can run through an existing cloud account.
The same approval gate, five frameworks#
A refund tool that must not run without a human "yes" is a typical gate in production agents. Here it is five ways. All of them follow the same shape:
%% title: Approval pause and resume, common shape
sequenceDiagram
participant U as User
participant A as Agent loop
participant S as State store
participant R as Human reviewer
U->>A: Refund order A-1001
A->>A: Model calls issue_refund
A->>S: Save run state and pending call
A-->>U: Paused, awaiting approval
R->>S: Approve or reject
S->>A: Load state with decision
A->>A: Run issue_refund if approved
A-->>U: Final answerPydantic AI (checked against pydantic-ai-slim[openai]==2.57.0; with the model string swapped to Pydantic AI's built-in offline "test" model, this exact flow paused, accepted the approval and then ran the tool, with no API calls):
from pydantic_ai import Agent, DeferredToolRequests, DeferredToolResults
agent = Agent(
"openai:gpt-5.5",
instructions="You handle refunds.",
output_type=[str, DeferredToolRequests],
)
@agent.tool_plain(requires_approval=True)
def issue_refund(order_id: str, amount_usd: float) -> str:
return f"Refunded {amount_usd} USD on {order_id}"
result = agent.run_sync("Refund order A-1001 for 42 USD")
if isinstance(result.output, DeferredToolRequests):
approvals = {call.tool_call_id: True for call in result.output.approvals}
result = agent.run_sync(
message_history=result.all_messages(),
deferred_tool_results=DeferredToolResults(approvals=approvals),
)
OpenAI Agents SDK (compiled and import-checked against openai-agents==0.24.0):
from agents import Agent, Runner, function_tool
@function_tool(needs_approval=True)
def issue_refund(order_id: str, amount_usd: float) -> str:
"""Refund an order."""
return f"Refunded {amount_usd} USD on {order_id}"
agent = Agent(name="Support", instructions="Handle refunds.", tools=[issue_refund])
async def main() -> None:
result = await Runner.run(agent, "Refund order A-1001 for 42 USD")
while result.interruptions:
state = result.to_state() # serializable; store it while a human decides
for item in result.interruptions:
state.approve(item)
result = await Runner.run(agent, state)
LangChain create_agent (compiled against langchain==1.4.6, langgraph==1.2.16 and langchain-openai==1.7.2; the import check built the agent with a placeholder key and stopped before the two invoke() calls, which need a live model):
from langchain.agents import create_agent
from langchain.agents.middleware import HumanInTheLoopMiddleware
from langchain.tools import tool
from langgraph.checkpoint.memory import InMemorySaver
from langgraph.types import Command
@tool
def issue_refund(order_id: str, amount_usd: float) -> str:
"""Refund an order."""
return f"Refunded {amount_usd} USD on {order_id}"
agent = create_agent(
model="openai:gpt-5.5",
tools=[issue_refund],
middleware=[HumanInTheLoopMiddleware(interrupt_on={"issue_refund": True})],
checkpointer=InMemorySaver(),
)
config = {"configurable": {"thread_id": "refund-A-1001"}}
agent.invoke({"messages": [{"role": "user", "content": "Refund A-1001 for 42 USD"}]}, config)
agent.invoke(Command(resume={"decisions": [{"type": "approve"}]}), config)
Swap InMemorySaver for a database checkpointer in production, because an in-memory saver loses the paused run on restart. The openai: model string needs the langchain-openai package installed.
AI SDK WorkflowAgent (type-checked against @ai-sdk/workflow@2.0.75, ai@7.0.143 and workflow@5.2.2):
import { WorkflowAgent, type ModelCallStreamPart } from '@ai-sdk/workflow';
import { getWritable } from 'workflow';
import { z } from 'zod';
async function issueRefund({ orderId, amountUsd }: { orderId: string; amountUsd: number }) {
'use step';
return { orderId, refundedUsd: amountUsd };
}
export async function refundWorkflow(orderId: string) {
'use workflow';
const agent = new WorkflowAgent({
model: 'anthropic/claude-opus-5.5',
instructions: 'You handle refunds.',
tools: {
issueRefund: {
description: 'Refund an order',
inputSchema: z.object({ orderId: z.string(), amountUsd: z.number() }),
needsApproval: true,
execute: issueRefund,
},
},
});
const result = await agent.stream({
messages: [{ role: 'user', content: `Refund order ${orderId}` }],
writable: getWritable<ModelCallStreamPart>(),
});
return result.messages;
}
When the model calls issueRefund, the agent pauses and emits the approval request to that writable stream, which is how the request reaches your client, and the workflow suspends until the user approves or denies. The docs' tool approval section covers resuming, including signed approvals for sensitive tools. The type checker only proves the shapes. The 'use workflow' and 'use step' directives take effect only when the Workflow toolchain compiles the file, and that is what makes the approval survive restarts, as the docs describe.
CrewAI Flows (compiled and import-checked against crewai==1.15.28):
from crewai.flow import Flow, human_feedback, listen, persist, start
@persist()
class RefundFlow(Flow):
@start()
@human_feedback(
message="Approve this refund?",
emit=["approved", "rejected"],
llm="openai/gpt-5.4-mini",
)
def propose_refund(self):
return {"order_id": "A-1001", "amount_usd": 42}
@listen("approved")
def issue_refund(self):
return "refund issued"
@listen("rejected")
def notify_customer(self):
return "refund declined"
CrewAI's gate sits at the Flow step level instead of the tool level. The llm turns free-text feedback into one of the emit outcomes, which then routes to a listener.
Two more for completeness, both import-checked: MAF marks a tool with @tool(approval_mode="always_require"), and ADK wraps one as FunctionTool(issue_refund, require_confirmation=True). The Claude Agent SDK handles the same need through permissions and hooks rather than a per-tool flag.
How to run a one-day spike before committing#
Feature tables only get you to a shortlist of two. Then build the same small agent in both and look for where each one breaks:
- Build a 3-tool agent (one read tool, one write tool, one tool behind an approval gate) in each of your top two candidates.
- Give both the same model, so you are comparing frameworks and not models.
- Kill the process in the middle of a write tool call. Then check whether the tool ran once, twice or not at all after resume.
- Pause on the approval gate, deploy twice, then approve. Confirm the run picks up where it stopped, with the original arguments.
- Compare the traces. Can you see every model call, tool input and tool output without adding custom logging?
- Install both in your real dependency set, not a fresh venv. During verification for this post,
crewai==1.15.28andpydantic-ai-slim[openai]==2.57.0could not be installed together, because they pin incompatible ranges of theopenaiSDK (<3versus>=3.26.0). Conflicts like that one show up on day one or in month three. - Write down what you had to build yourself: storage, retries, idempotency keys, UI streaming.
Whichever candidate needed less code to get through steps 3 and 4 is a good default choice.
FAQ#
What is the best AI agent framework in 2026?#
There is no single best one. Answer three questions first: which language your team ships in, how long one run must survive (seconds, or days with a human approval in the middle), and whether you are committed to one model vendor. Those answers narrow ten options to two, and a one-day spike picks between them.
Is LangChain still worth using, or should I use LangGraph directly?#
LangChain's create_agent is built on LangGraph, so you get LangGraph's durable execution, human-in-the-loop and persistence either way. LangChain's docs recommend starting at the higher level (create_agent or Deep Agents) and dropping to raw LangGraph when you need explicit control over the graph.
Can I use the OpenAI Agents SDK or Claude Agent SDK with other models?#
The OpenAI Agents SDK supports non-OpenAI models through set_default_openai_client, ModelProvider and Agent.model, plus Any-LLM and LiteLLM adapters that the docs label beta. The Claude Agent SDK runs Claude models, reached through the Anthropic API, Amazon Bedrock, Claude Platform on AWS, Google Cloud's Agent Platform or Microsoft Foundry.
Which frameworks support durable, resumable agents out of the box?#
LangGraph (checkpointers), Mastra (workflow snapshots, with durable agents in beta), AI SDK WorkflowAgent, Microsoft Agent Framework (superstep checkpoints) and CrewAI (@persist) ship durability in the framework. Pydantic AI and the OpenAI Agents SDK get it from integrations with engines such as Temporal and DBOS.
Sources#
- LangGraph overview: https://docs.langchain.com/oss/python/langgraph/overview
- LangChain overview: https://docs.langchain.com/oss/python/langchain/overview
- LangGraph persistence: https://docs.langchain.com/oss/python/langgraph/persistence
- LangGraph interrupts: https://docs.langchain.com/oss/python/langgraph/interrupts
- Mastra docs: https://mastra.ai/docs
- Mastra agents overview: https://mastra.ai/docs/agents/overview
- Mastra workflow snapshots: https://mastra.ai/docs/workflows/snapshots
- Mastra suspend and resume: https://mastra.ai/docs/workflows/suspend-and-resume
- Mastra durable agents: https://mastra.ai/docs/harness/durable-agents
- AI SDK introduction (names Claude Code, Codex and Pi as
HarnessAgentharnesses): https://ai-sdk.dev/docs/introduction - AI SDK agents overview: https://ai-sdk.dev/docs/agents/overview
- AI SDK WorkflowAgent: https://ai-sdk.dev/docs/agents/workflow-agent
- AI SDK WorkflowAgent tool approval: https://ai-sdk.dev/docs/agents/workflow-agent#tool-approval
- AI SDK HarnessAgent: https://ai-sdk.dev/docs/ai-sdk-harnesses/harness-agent
- AI SDK 7 announcement: https://vercel.com/blog/ai-sdk-7
- AI SDK 7 changelog: https://vercel.com/changelog/ai-sdk-7
- AI SDK release history (
ai@7.0.0published June 25, 2026): https://www.npmjs.com/package/ai?activeTab=versions - OpenAI Agents SDK (Python): https://openai.github.io/openai-agents-python/
- OpenAI Agents SDK models: https://openai.github.io/openai-agents-python/models/
- OpenAI Agents SDK human-in-the-loop: https://openai.github.io/openai-agents-python/human_in_the_loop/
- OpenAI Agents SDK running agents: https://openai.github.io/openai-agents-python/running_agents/
- Temporal and OpenAI Agents SDK integration: https://temporal.io/blog/announcing-openai-agents-sdk-integration
- Claude Agent SDK overview: https://code.claude.com/docs/en/agent-sdk/overview
- Claude Agent SDK quickstart: https://code.claude.com/docs/en/agent-sdk/quickstart
- Claude Agent SDK sessions: https://code.claude.com/docs/en/agent-sdk/sessions
- Google ADK: https://adk.dev/
- Google ADK graph workflows: https://adk.dev/graphs/
- Google ADK concepts: https://adk.dev/get-started/about/
- Google ADK A2A: https://adk.dev/a2a/
- Google ADK evaluation: https://adk.dev/evaluate/
- Google ADK live and voice agents (bidirectional streaming): https://adk.dev/live/
- LlamaIndex framework: https://developers.llamaindex.ai/python/framework/
- LlamaIndex agents: https://developers.llamaindex.ai/python/framework/understanding/agent/
- LlamaIndex LLMs: https://developers.llamaindex.ai/python/framework/module_guides/models/llms/
- Pydantic AI overview: https://pydantic.dev/docs/ai/overview/
- Pydantic AI Harness: https://pydantic.dev/docs/ai/harness/
- CrewAI introduction: https://docs.crewai.com/en/introduction
- CrewAI Flows: https://docs.crewai.com/en/concepts/flows
- CrewAI LLMs: https://docs.crewai.com/en/concepts/llms
- Microsoft Agent Framework 1.0: https://devblogs.microsoft.com/agent-framework/microsoft-agent-framework-version-1-0/
- Microsoft Agent Framework overview: https://learn.microsoft.com/en-us/agent-framework/overview/
- Microsoft Agent Framework workflows: https://learn.microsoft.com/en-us/agent-framework/concepts/workflows/
- Microsoft Agent Framework Harness Agent: https://learn.microsoft.com/en-us/agent-framework/concepts/harness
- npm packages: https://www.npmjs.com/package/ai , https://www.npmjs.com/package/@mastra/core , https://www.npmjs.com/package/@openai/agents , https://www.npmjs.com/package/@anthropic-ai/claude-agent-sdk , https://www.npmjs.com/package/@langchain/langgraph , https://www.npmjs.com/package/@google/adk , https://www.npmjs.com/package/@ai-sdk/workflow , https://www.npmjs.com/package/workflow
- PyPI packages: https://pypi.org/project/langgraph/ , https://pypi.org/project/langchain/ , https://pypi.org/project/langchain-openai/ , https://pypi.org/project/openai-agents/ , https://pypi.org/project/claude-agent-sdk/ , https://pypi.org/project/google-adk/ , https://pypi.org/project/llama-index-core/ , https://pypi.org/project/pydantic-ai/ , https://pypi.org/project/crewai/ , https://pypi.org/project/agent-framework/
Continue Reading#
Get the next comparison like this in your inbox
One email a week on AI Agents and the rest of the AI dev stack. Free.
Read next on AI coding tools
Durable AI Agent Frameworks Compared: One Run, Four Stacks
One agent run crashes mid tool call, waits two days for approval, then retries a charge. How LangGraph, Mastra, Pydantic AI and OpenAI Agents SDK handle it.
14 min readThe TypeScript AI Agent Stack in Mid-2026: Mastra vs Vercel AI SDK vs OpenAI Agents SDK vs LangGraph.js
The TypeScript AI agent stack compared - Mastra, Vercel AI SDK, OpenAI Agents SDK and LangGraph.js, which layer each covers, and how to pick or combine them.
10 min readOpenAI Agents SDK vs Claude Agent SDK: Building Agents on the Two Big Platforms
OpenAI Agents SDK vs Claude Agent SDK compared - handoffs vs subagents, guardrails vs hooks, sandboxing, MCP support and how to choose a platform for your team.
9 min readNew here? Start with
Technical content at the intersection of AI and development. Building with AI agents, Claude Code, and modern dev tools - then showing you exactly how it works.








