An LLM agent is a loop around a chat API: send the messages and tool schemas, run the tool the model asks for, send the result back. A framework owns that loop and charges for it in packages, cold-start imports and releases to keep up with.
LangChain's release policy keeps version 0.3 in maintenance only until December 2026, so teams still importing LLMChain face a migration either way. On October 15, 2026, we installed LangChain and seven alternatives into fresh environments on an M3 Pro MacBook Pro and ran the same one-tool agent through each. LangChain needed 44 Python packages and 41.2 MB; the OpenAI SDK alone needed 14 and 18.1 MB. What they sent the model was nearly identical, with one exception.
What LangChain 1.x Fixed, and What It Did Not
LangChain 1.0 shipped on October 17, 2025, rebuilt around create_agent, an agent loop that runs on LangGraph. Legacy chains, retrievers and the prompt hub moved to a separate langchain-classic package. The current release is langchain 1.4.6, MIT licensed, with 147,856 GitHub stars as of October 15, 2026, and the docs promise no breaking changes before 2.0.

That settled API churn. Three complaints survive. Weight: langchain requires langgraph, and langchain-core requires langsmith, the client for LangChain's commercial tracing service. LangSmith receives nothing unless you set LANGSMITH_TRACING=true, and our runs made no outbound calls, but the package ships anyway. Cadence: langchain-core published 18 stable releases in the 90 days to October 15. Direction: the homepage leads with LangSmith, whose Plus plan costs $39 per seat per month with 10,000 base traces a month.
This is the agent every section below rebuilds, in LangChain:
Pythonfrom langchain.agents import create_agent from langchain_openai import ChatOpenAI def get_weather(city: str) -> str: """Get the current weather for a US city.""" return f"72 F and sunny in {city}" model = ChatOpenAI(model="gpt-4o-mini", base_url="http://127.0.0.1:8765/v1", api_key="sk-test") agent = create_agent(model, tools=[get_weather]) result = agent.invoke({"messages": [{"role": "user", "content": "What's the weather in Austin?"}]}) print(result["messages"][-1].content)
LangChain still has the widest reach, "integrations to hundreds of LLMs and thousands of other integrations" per its docs. If you only need to leave 0.3, upgrading may cost less than switching.
What Teams Actually Install
Download counts include CI runs and transitive installs, which flatter LangChain in Python. In TypeScript, ai out-downloads langchain about nine to one. PyPI figures are from pypistats.org; npm figures cover September 13 to October 12, 2026.
| Package | Registry | Downloads, last 30 days |
|---|---|---|
| langchain | PyPI | 170.5M |
| pydantic-ai-slim | PyPI | 23.9M |
| openai-agents | PyPI | 12.4M |
| llama-index-core | PyPI | 6.6M |
| dspy | PyPI | 5.3M |
| haystack-ai | PyPI | 0.57M |
| ai (Vercel AI SDK) | npm | 126.5M |
| langchain | npm | 13.5M |
| @openai/agents | npm | 9.1M |
| @mastra/core | npm | 8.5M |
One Agent, Eight Frameworks: How We Measured
Each framework got a fresh uv environment on Python 3.13.0, or an npm project on Node 24.22.0 (arm64), holding only what an OpenAI agent needs. The script counts packages, sums their file sizes and times the agent's imports in CPU time, best of 15 interleaved runs, because other jobs on the laptop made wall-clock timings unreliable: the bare SDK's agent took anywhere from about 0.3 to more than 2 seconds.
Python# Install footprint and import cost of each framework, each in a fresh environment. # usage: python3 measure.py (needs uv and npm; installs what an OpenAI-backed agent needs) import json, shutil, subprocess from pathlib import Path PYTHON = { "openai SDK only": (["openai"], "from openai import OpenAI"), "LangChain": (["langchain", "langchain-openai"], "from langchain.agents import create_agent; from langchain_openai import ChatOpenAI"), "Pydantic AI": (["pydantic-ai-slim[openai]"], "from pydantic_ai import Agent; from pydantic_ai.models.openai import OpenAIChatModel"), "LlamaIndex": (["llama-index-core", "llama-index-llms-openai"], "from llama_index.core.agent.workflow import FunctionAgent; " "from llama_index.llms.openai import OpenAI"), "Haystack": (["haystack-ai"], "from haystack.components.agents import Agent; " "from haystack.components.generators.chat import OpenAIChatGenerator"), "DSPy": (["dspy"], "import dspy"), "OpenAI Agents SDK": (["openai-agents"], "from agents import Agent, Runner"), } NODE = { "openai SDK only (TS)": (["openai"], ["openai"]), "LangChain.js": (["langchain", "@langchain/core", "@langchain/openai"], ["langchain", "@langchain/openai"]), "Vercel AI SDK": (["ai", "@ai-sdk/openai", "zod"], ["ai", "@ai-sdk/openai"]), "Mastra": (["@mastra/core", "zod"], ["@mastra/core/agent", "@mastra/core/tools"]), "OpenAI Agents SDK (TS)": (["@openai/agents", "zod"], ["@openai/agents"]), } def run(*cmd, cwd=None): return subprocess.run(cmd, check=True, capture_output=True, text=True, cwd=cwd).stdout def size_mb(path): return sum(f.stat().st_size for f in Path(path).rglob("*") if f.is_file()) / 1e6 rows = {} # name -> [packages, size MB, import command, cwd] for name, (pkgs, imports) in PYTHON.items(): env = Path("venvs") / name.replace(" ", "-") shutil.rmtree(env, ignore_errors=True) run("uv", "venv", "-q", "--python", "3.13", str(env)) py = str(env / "bin" / "python") run("uv", "pip", "install", "-q", "--python", py, *pkgs) packages = len(json.loads(run("uv", "pip", "list", "--python", py, "--format", "json"))) code = f"import time; t = time.process_time(); {imports}; print(time.process_time() - t)" rows[name] = [packages, size_mb(env / "lib"), [py, "-c", code], None] for name, (pkgs, imports) in NODE.items(): app = Path("node") / name.replace(" ", "-").replace("(", "").replace(")", "") shutil.rmtree(app, ignore_errors=True) app.mkdir(parents=True) (app / "package.json").write_text('{"private": true, "type": "module"}') run("npm", "install", "--silent", "--no-audit", "--no-fund", *pkgs, cwd=app) packages = len(json.loads((app / "node_modules" / ".package-lock.json").read_text())["packages"]) code = ("const t = process.cpuUsage(); " + "".join(f"await import('{m}'); " for m in imports) + "const u = process.cpuUsage(t); console.log((u.user + u.system) / 1e6)") rows[name] = [packages, size_mb(app / "node_modules"), ["node", "--input-type=module", "-e", code], app] # CPU time, not wall time, and interleaved rounds: other jobs on the laptop skew single runs. cpu = {name: [] for name in rows} for _ in range(16): # round 1 is a warm-up that writes .pyc files and fills the disk cache for name, (_, _, cmd, cwd) in rows.items(): cpu[name].append(float(run(*cmd, cwd=cwd)) * 1000) print(f"{'framework':24} {'packages':>8} {'size MB':>8} {'import CPU ms':>14}") for name, (packages, mb, _, _) in rows.items(): print(f"{name:24} {packages:>8} {mb:>8.1f} {min(cpu[name][1:]):>14.0f}")
textframework packages size MB import CPU ms openai SDK only 14 18.1 201 LangChain 44 41.2 463 Pydantic AI 26 35.2 351 LlamaIndex 67 118.0 718 Haystack 42 59.6 368 DSPy 66 187.4 328 OpenAI Agents SDK 38 43.8 544 openai SDK only (TS) 1 22.7 66 LangChain.js 25 84.0 298 Vercel AI SDK 12 22.5 57 Mastra 154 116.6 263 OpenAI Agents SDK (TS) 25 66.6 187
Then each framework answered "What's the weather in Austin?" with one get_weather tool, against a local stand-in for OpenAI's Chat Completions API that logged every request: no key, no spend. Every snippet in this post is the exact code that ran; drop base_url and api_key to call OpenAI.
LangChain installs 3.1 times the packages of the bare SDK and spends 2.3 times its import CPU. On the wire the gaps shrink: every framework using native tool calling made two requests totaling 863 to 1,203 bytes, while DSPy made three totaling 6,750. Logging DNS lookups caught two frameworks calling out on their own: DSPy fetched a price map from raw.githubusercontent.com, and the OpenAI Agents SDK posted traces to api.openai.com.
Pydantic AI: Typed Agents From the Pydantic Team
The team behind Pydantic built Pydantic AI, a Python agent framework, around typed tools, typed outputs and dependency injection.

Among the Python options that still feel like a framework, it has the leanest install: 26 packages and 35.2 MB. Tool schemas come straight from type hints and docstrings. Durable execution plugs into Temporal, DBOS, Prefect or Restate.
Pythonfrom pydantic_ai import Agent from pydantic_ai.models.openai import OpenAIChatModel from pydantic_ai.providers.openai import OpenAIProvider provider = OpenAIProvider(base_url="http://127.0.0.1:8765/v1", api_key="sk-test") agent = Agent(OpenAIChatModel("gpt-4o-mini", provider=provider)) @agent.tool_plain def get_weather(city: str) -> str: """Get the current weather for a US city.""" return f"72 F and sunny in {city}" print(agent.run_sync("What's the weather in Austin?").output)
The catch is pace. Version 2.0 shipped June 23, 2026, about nine and a half months after 1.0. In 90 days, pydantic-ai-slim published 56 stable releases, more than three times langchain-core's pace. Our run also printed a banner for Pydantic Logfire, the company's commercial observability service; set PYDANTIC_AI_NO_BANNER=1 to hide it.
License and version: MIT · 20,629 GitHub stars · v2.56.0 released October 13, 2026 · Python 3.11+.
OpenAI Agents SDK: Few Primitives, Tracing On by Default
The OpenAI Agents SDK is OpenAI's production upgrade of its Swarm experiment: agents, handoffs and guardrails, plus sessions for memory, in Python and TypeScript.

There is little to learn. @function_tool turns any Python function into a tool, and tracing and MCP tool calling come in one 38-package install.
Pythonfrom agents import (Agent, Runner, function_tool, set_default_openai_api, set_default_openai_client, set_tracing_disabled) from openai import AsyncOpenAI set_default_openai_client(AsyncOpenAI(base_url="http://127.0.0.1:8765/v1", api_key="sk-test")) set_default_openai_api("chat_completions") set_tracing_disabled(True) # tracing exports to OpenAI's backend by default @function_tool def get_weather(city: str) -> str: """Get the current weather for a US city.""" return f"72 F and sunny in {city}" agent = Agent(name="Assistant", model="gpt-4o-mini", tools=[get_weather]) print(Runner.run_sync(agent, "What's the weather in Austin?").final_output)
Expect two rough edges. It is still pre-1.0, sitting at 0.24.0 after 88 stable releases in a year. And tracing is on by default: without set_tracing_disabled(True), our run posted traces to api.openai.com. Other providers go through OpenAI-compatible Chat Completions endpoints or the beta Any-LLM and LiteLLM adapters.
License and version: MIT · 30,051 GitHub stars · openai-agents 0.24.0 released October 15, 2026 · @openai/agents 0.20.0 for TypeScript.
LlamaIndex: Retrieval First, Python Only Now
LlamaIndex calls its framework "our original open-source toolkit for RAG and agents"; the company now leads with LlamaParse, its hosted document parser.

It is not small. This agent pulled in 67 packages and 118 MB, NLTK and NumPy included, and had the slowest Python import here, 718 ms. TypeScript is off the table: LlamaIndex.TS was archived on April 30, 2026, and the core is still pre-1.0.
Pythonimport asyncio from llama_index.core.agent.workflow import FunctionAgent from llama_index.llms.openai import OpenAI def get_weather(city: str) -> str: """Get the current weather for a US city.""" return f"72 F and sunny in {city}" llm = OpenAI(model="gpt-4o-mini", api_base="http://127.0.0.1:8765/v1", api_key="sk-test") agent = FunctionAgent(tools=[get_weather], llm=llm) async def main(): print(await agent.run("What's the weather in Austin?")) asyncio.run(main())
In return you get the data side. Connectors, indexes, query engines and event-driven Workflows are first-party, and LlamaParse output drops straight into an index the agent can query.
License and version: MIT · 52,507 GitHub stars · llama-index-core 0.14.25 released September 21, 2026.
Haystack: Pipelines You Can Read and Serialize
Haystack from deepset builds applications from explicit pipelines: components with typed inputs and outputs, wired into a graph you can save as YAML and load back.

Haystack aims at predictable production RAG. A serialized pipeline stores API keys as environment variable names rather than values, and Hayhooks serves a pipeline as a REST endpoint or MCP server. The install is 42 packages and 59.6 MB.
Pythonfrom haystack.components.agents import Agent from haystack.components.generators.chat import OpenAIChatGenerator from haystack.dataclasses import ChatMessage from haystack.tools import tool from haystack.utils import Secret @tool def get_weather(city: str) -> str: """Get the current weather for a US city.""" return f"72 F and sunny in {city}" llm = OpenAIChatGenerator(model="gpt-4o-mini", api_base_url="http://127.0.0.1:8765/v1", api_key=Secret.from_token("sk-test")) agent = Agent(chat_generator=llm, tools=[get_weather]) result = agent.run(messages=[ChatMessage.from_user("What's the weather in Austin?")]) print(result["last_message"].text)
Major versions still mean migrations. Haystack 3.0, released July 20, 2026, removed ToolInvoker and the legacy generators. On telemetry, the docs say anonymous usage statistics are collected unless HAYSTACK_TELEMETRY_ENABLED=False. Our agent run made no outbound calls.
License and version: Apache-2.0 · 26,745 GitHub stars · v3.4.0 released October 15, 2026 · Python 3.11+.
DSPy: Signatures Instead of Prompt Strings
DSPy from Stanford NLP describes itself as a framework for programming language models rather than prompting them. You declare inputs and outputs as signatures, and optimizers such as GEPA and MIPROv2 tune prompts against a metric you define.

No other framework here attempts what DSPy is for. Give it labeled examples and a metric, and it rewrites the prompts and few-shot demos for you.
Pythonimport dspy def get_weather(city: str) -> str: """Get the current weather for a US city.""" return f"72 F and sunny in {city}" dspy.configure(lm=dspy.LM("openai/gpt-4o-mini", api_base="http://127.0.0.1:8765/v1", api_key="sk-test", cache=False)) agent = dspy.ReAct("question -> answer", tools=[get_weather]) print(agent(question="What's the weather in Austin?").answer)
It is heavy, and chatty on the wire. DSPy was the biggest install by size, 187.4 MB across 66 packages. Its default ChatAdapter sets use_native_function_calling=False, so ReAct wrote its own field protocol into the prompt. The first call also downloads LiteLLM's model price map unless LITELLM_LOCAL_MODEL_COST_MAP=True is set.
License and version: MIT · 38,644 GitHub stars · v3.4.1 released October 12, 2026.
Vercel AI SDK: The Lightest Framework We Measured
The Vercel AI SDK is "the TypeScript toolkit for building AI applications and agents": generateText, a ToolLoopAgent class, providers as separate packages, and UI hooks such as useChat.

This one costs almost nothing to add. Twelve packages, 22.5 MB and a 57 ms import put it level with the bare openai package, yet it still runs the tool loop for you.
JavaScriptimport { generateText, stepCountIs, tool } from "ai"; import { createOpenAI } from "@ai-sdk/openai"; import { z } from "zod"; const openai = createOpenAI({ baseURL: "http://127.0.0.1:8765/v1", apiKey: "sk-test" }); const { text } = await generateText({ model: openai.chat("gpt-4o-mini"), tools: { get_weather: tool({ description: "Get the current weather for a US city.", inputSchema: z.object({ city: z.string() }), execute: async ({ city }) => `72 F and sunny in ${city}`, }), }, stopWhen: stepCountIs(5), prompt: "What's the weather in Austin?", }); console.log(text);
Where it costs you is API churn. Version 5.0 shipped July 31, 2025, 6.0 on December 22, 2025, and 7.0 on June 25, 2026. Each came with a migration guide and codemods (npx @ai-sdk/codemod v7 for the latest). Durable workflows need the separate @ai-sdk/workflow package, and memory and evals are left to you.
License and version: Apache-2.0 · 27,327 GitHub stars · ai 7.0.141 published October 15, 2026.
Mastra: Agents, Workflows and Memory in One TypeScript Framework
Mastra is a TypeScript framework for agents, suspendable workflows, memory and evals, with a local Studio UI for testing them.

All of that is heavy. @mastra/core pulled in 154 packages and 116.6 MB, the largest TypeScript install here. Nor is all of it open: code in ee/ directories needs a Mastra Enterprise License in production. The hosted Teams plan costs $250 a month.
JavaScriptimport { Agent } from "@mastra/core/agent"; import { createTool } from "@mastra/core/tools"; import { z } from "zod"; const getWeather = createTool({ id: "get_weather", description: "Get the current weather for a US city.", inputSchema: z.object({ city: z.string() }), execute: async ({ city }) => `72 F and sunny in ${city}`, }); const agent = new Agent({ id: "weather-agent", name: "Weather Agent", instructions: "You are a helpful assistant.", model: { id: "openai/gpt-4o-mini", url: "http://127.0.0.1:8765/v1", apiKey: "sk-test", api: "chat" }, tools: { getWeather }, }); const result = await agent.generate("What's the weather in Austin?"); console.log(result.text);
In exchange you get what the AI SDK leaves out. Its model router takes a string ID for any of more than 8,200 models from 218 providers, and mastra dev starts Studio locally.
License and version: Apache-2.0 core plus Mastra Enterprise License · 28,831 GitHub stars · @mastra/core 1.77.0 published October 14, 2026.
Side by Side
| Framework | Language | Version | License | Packages | Install size | Import CPU | Bytes sent |
|---|---|---|---|---|---|---|---|
| OpenAI SDK only | Python | 3.31.0 | Apache-2.0 | 14 | 18.1 MB | 201 ms | 863 |
| LangChain | Python | 1.4.6 | MIT | 44 | 41.2 MB | 463 ms | 893 |
| Pydantic AI | Python | 2.56.0 | MIT | 26 | 35.2 MB | 351 ms | 1,021 |
| OpenAI Agents SDK | Python | 0.24.0 | MIT | 38 | 43.8 MB | 544 ms | 1,033 |
| LlamaIndex | Python | 0.14.25 | MIT | 67 | 118.0 MB | 718 ms | 1,203 |
| Haystack | Python | 3.4.0 | Apache-2.0 | 42 | 59.6 MB | 368 ms | 890 |
| DSPy | Python | 3.4.1 | MIT | 66 | 187.4 MB | 328 ms | 6,750 |
| LangChain.js | TypeScript | 1.5.16 | MIT | 25 | 84.0 MB | 298 ms | 1,098 |
| Vercel AI SDK | TypeScript | 7.0.141 | Apache-2.0 | 12 | 22.5 MB | 57 ms | 1,066 |
| Mastra | TypeScript | 1.77.0 | Apache-2.0 + EE | 154 | 116.6 MB | 263 ms | 1,181 |
Measured October 15, 2026 on one M3 Pro laptop. Bytes sent totals every request for the Austin question.
How to Choose Without Migrating Twice
- Grep for what you actually use. If
langchain.chainsandLLMChaindominate, you owe a migration before December 2026 either way; if you only use chat models and tools, any framework here is a short port. - Run the script on your real dependency list. Add your vector store and providers, then compare import time where cold starts matter, such as AWS Lambda in
us-east-1. - Decide where traces go first. LangSmith, Pydantic Logfire and OpenAI's trace viewer each pull you toward a vendor; check every default that calls out.
- Budget for churn everywhere. Pydantic AI and the AI SDK both released more often than LangChain this year. Pin exact versions.
- Port one agent first. Rebuild your smallest real agent behind a logging proxy and compare requests and bytes before porting the rest.
Which One Should You Actually Use?
Python, typed outputs, fewer layers: Pydantic AI, pinned to an exact version.
OpenAI models only: the OpenAI Agents SDK, with tracing off if data cannot leave.
Mostly retrieval over messy documents: LlamaIndex.
Pipelines reviewed like code before production: Haystack.
Labeled examples and a metric: DSPy.
TypeScript and Next.js: the Vercel AI SDK, or Mastra when you want workflows, memory and a local UI included.
Just leaving 0.3: stay on LangChain and upgrade to 1.x.
Conclusion
LangChain 1.0 fixed its API churn, then made the smallest agent depend on LangGraph and the LangSmith client. Apart from DSPy, the alternatives send the model roughly the same request. Where they differ is what they install, what they call home to and how often they break. Run the script on your own stack before you port.
Related DevToolLab Tools
- PyPI Package Inspector - check a framework's dependencies and release history before adding it.
- NPM Package Size Checker - estimate what
aior@mastra/coreadds to a bundle. - Semver Range Tester - see which releases a range like
^1.4pulls in from a fast-moving framework. - JSON to Zod - turn a sample tool payload into the Zod schema AI SDK and Mastra tools expect.
Related Guides
- Best AI Agent Frameworks - the wider field, including Google ADK and AWS Strands.
- LangGraph vs CrewAI vs AutoGen - for teams staying in the LangChain family.
- Best LLM Observability Tools - tracing options after you leave LangSmith.
- Best RAG Platforms and Tools - frameworks versus managed retrieval services.
