Pydantic AI vs smolagents
In short
Pydantic AI vs smolagents: both are coding tools on Scriptiii AI Tools. Pydantic AI pricing: Free. Free to use. (reported by the maker) smolagents pricing: Free. Free to use. (reported by the maker) Both have 0 upvotes.
- Pydantic AI
- Free. Free to use. (reported by the maker)
- smolagents
- Free. Free to use. (reported by the maker)
- Upvotes
- 0 vs 0
| Field | Pydantic AI | smolagents |
|---|---|---|
| Page | Pydantic AI | smolagents |
| Pricing (maker-reported) | Free. Free to use. | Free. Free to use. |
| Upvotes | 0 | 0 |
| Best for | ai-agents, framework, python-framework | ai-agents, framework, python-framework |
| Tagline | Python agent framework from the Pydantic team with type-safe tools and structured outputs. | Hugging Face library for building agents that think and act in code. |
| Website | Visit Pydantic AI | Visit smolagents |
Pricing and pricing details come from the maker's submission. They are not independently verified.
Pydantic AI
How Python does AI
Agents, realtime voice, image generation, embeddings. Every model, every interface, typed end to end.
Pydantic AI is the Python AI SDK: a typed, extensible agent loop with every model a string swap away, and another one to fall back to when a provider fails. The same agent runs everywhere you need it: behind a web frontend, in the terminal, on a voice call, on a durable background queue, in GitHub Actions, or as a plain object you call run() on. Image generation and embeddings come in the same box.
Pydantic AI Harness has everything an agent needs for complex, long-running work, snapped on as capabilities, from memory, guardrails, and sub-agents to planning, context management, and persistence, up to a complete coding agent.
Pydantic Evals grades an agent's final outputs and tool-call trajectories, on datasets or live production traffic, and Pydantic Graph gives you typed control flow when one agent loop is not enough. Both are separate open-source packages, and so are genai-prices, which keeps model pricing current, and Monty, the sandboxed Python interpreter that runs model-written code.
Pydantic Logfire is the AI engineering platform that sees your whole app, not just the LLM calls, and the Pydantic AI Gateway is one key for every model with real-time cost monitoring and budget control; our instrumentation is plain OpenTelemetry, so any backend you already run works.
View the complete documentation at pydantic.dev/docs/ai.
What are you building?
From simple typed data extraction to complex, long-running multi-agent collaboration, Pydantic AI and Pydantic AI Harness have got you covered.
Coding agent
A complete coding agent in your terminal: workspace-rooted file access, allowlisted shell, repo orientation, planning, and context management that survives long sessions. Here with web search and a second-opinion advisor snapped on alongside:
uv add pydantic-ai "pydantic-ai-harness[coder]"
from pydantic_ai import Agent
from pydantic_ai.capabilities import WebSearch
from pydantic_ai_harness import Advisor, Coder
agent = Agent(
'anthropic:claude-fable-5-2',
capabilities=[
Coder(), # files, shell, repo context, sub-agents, context management
WebSearch(), # look up docs and error messages on the web
Advisor('openai:gpt-6.1-sol'), # a second opinion from another model when stuck
],
)
agent.to_cli_sync()
Coder is a regular combined capability, not a black box: use it whole, or use the blocks it bundles directly; the two are equivalent:
capabilities = [
FileSystem('.'), Shell(cwd='.'), RepoContext(), SubAgents(...),
ClearToolResults(), ToolOutputLimits(), RepairToolArguments(),
]
Run the file and you're chatting with the agent in your terminal. To try it before writing any code, run the exported coder_agent with clai (the Pydantic AI CLI), via uvx:
uvx --with "pydantic-ai-harness[coder]" clai -a pydantic_ai_harness.coder:coder_agent -m anthropic:claude-fable-5-2
Build this → Coder, from the Harness
Run it on GitHub → GitHub Agentic Workflows, on issues, pull requests or a schedule
Data extraction
Give the agent an output type and tools, and every run comes back validated and typed:
uv add pydantic-ai
from typing import Literal
from pydantic import BaseModel, Field
from pydantic_ai import Agent, RunContext
class Sentiment(BaseModel):
label: Literal['positive', 'negative', 'neutral']
score: float = Field(ge=-1, le=1)
agent = Agent('openai:gpt-6.1-sol', output_type=Sentiment)
@agent.tool
def recent_reviews(ctx: RunContext, product: str) -> list[str]:
"""Fetch recent review snippets for a product."""
return ['The new release fixed everything I complained about!']
result = agent.run_sync('How are people feeling about the Extract app?')
print(result.output)
#> label='positive' score=0.9
The @agent.tool function receives a RunContext that carries your dependencies in; the rest of its signature and its docstring become the tool schema, arguments are validated before your code runs, and the run is guaranteed to return a Sentiment, so your IDE, type checker, and the LLM all agree on the returned type.
Build this → Agents, Function Tools, and Structured Output
Durable workflow
Attach TemporalDurability and the same agent runs inside a Temporal workflow under durable execution: every model and tool call becomes a durable activity, so a run working through a background queue survives restarts, failures, and long waits:
uv add "pydantic-ai[temporal]"
from temporalio import workflow
from pydantic_ai import Agent
from pydantic_ai.capabilities import WebFetch, WebSearch
from pydantic_ai.durable_exec.temporal import PydanticAIWorkflow, TemporalDurability
agent = Agent(
'openai:gpt-6.1-sol',
instructions='Research the topic and write a structured brief.',
name='researcher',
capabilities=[WebSearch(), WebFetch(), TemporalDurability()],
)
@workflow.defn
class ResearchWorkflow(PydanticAIWorkflow):
__pydantic_ai_agents__ = [agent]
@workflow.run
async def run(self, topic: str) -> str:
result = await agent.run(f'Write a brief on: {topic}')
return result.output
DBOS and Prefect attach the same way, first-party and co-maintained, with Restate, AWS Lambda, Airflow, Absurd, pgtask, and Azure Durable Task integrations besides.
Saving, resuming, and forking a run need no engine: StepPersistence from Pydantic AI Harness snapshots every settled step to a store you choose, the way a checkpointer does (see Persistence). The engine is for recovering a run that crashes partway through a step.
Build this → Durable Execution
Realtime voice
Put the same agent on a live voice session, tools and capabilities included:
uv add "pydantic-ai[openai-realtime]"
import asyncio
from pydantic_ai import Agent
from pydantic_ai.capabilities import MCP
agent = Agent(
instructions='You are a helpful voice assistant.',
capabilities=[MCP('https://internal.example.com/mcp')], # capabilities work in voice too
)
@agent.tool_plain
def order_status(order_id: str) -> str:
"""Look up the status of an order."""
return f'Order {order_id}: shipped, arriving Thursday.'
async with agent.realtime('openai:gpt-realtime-2.1').session() as session:
microphone = asyncio.create_task(session.send_audio(microphone_chunks())) # your microphone → the model
speaker = asyncio.create_task(play_audio(session.stream_audio())) # model audio → your speaker
async for part in session.stream_transcripts():
print(f'{part.speaker}: {part.transcript}')
The model calls your tools mid-conversation while it keeps talking, and every session is instrumented; voice is just another frontend, on OpenAI Realtime, Gemini Live, Azure, and xAI Grok Voice.
Build this → Realtime Voice
Image generation
Generate an image with a dedicated image model, no agent run required:
uv add pydantic-ai
from pathlib import Path
from pydantic_ai import ImageGenerator
generator = ImageGenerator('openai:gpt-image-2.5-flare')
result = generator.generate_sync('A minimalist logo for a coffee shop called Extract.')
Path('logo.png').write_bytes(result.image.data)
That standalone image API is for when your application decides; when an agent run decides, there is provider-native generation with output_type=BinaryImage for a typed image output, and the ImageGeneration capability with its fallbacks for models that generate no images of their own.
Build this → Image Generation
See your first run in Logfire
Tip: Run
uvx logfire-cli wizard --task pydantic-aionce from your project, and every model call and tool call shows up in Pydantic Logfire: it signs you in, picks or creates a project, and has your coding agent add these two lines. Logfire has a free tier that needs no credit card, and you can sign up with just a GitHub account, so you can use it while you develop even if your team uses another tool in production. The Logfire guide has the details, and any OpenTelemetry backend works instead.import logfire logfire.configure() logfire.instrument_pydantic_ai()
Why Pydantic AI
-
Any model, one Python API. Virtually every model and provider (OpenAI, Anthropic, Google, Bedrock, Azure AI Foundry, Groq, Mistral, xAI, Ollama, and dozens more), swappable with a string, or through the Pydantic AI Gateway: one key for all of them, with failover and cost monitoring built in. No flagship feature is locked to one vendor.
-
Typed end to end. Structured outputs, typed dependency injection, typed tools: your IDE, type checker, and coding agent all know what your agent returns, moving whole classes of errors from runtime to write-time. When plain control flow isn't enough, Pydantic Graph brings the same typing to graph-based workflows.
-
Measured, not vibes. OpenTelemetry-native instrumentation works with any OTel backend; run
uvx logfire-cli wizard --task pydantic-aionce to light up Pydantic Logfire for real-time debugging, tracing, and cost tracking backed by genai-prices. Pydantic Evals grades final outputs and tool-call trajectories, against datasets in code or, with online evaluation, a sample of live production traffic. -
Batteries, composably. One primitive, the capability, bundles tools, instructions, hooks, and model settings into reusable units. Core ships fundamentals like MCP and web search, the Harness ships everything else, and complete agents like Coder and Researcher are just capabilities composed: they come apart the way they went together. Or skip code entirely with YAML/JSON agent specs.
-
Every interface. One agent definition runs as a CLI, a built-in web chat, or realtime speech (OpenAI Realtime, Gemini Live, Azure, xAI Grok Voice); UI event streams (AG-UI, Vercel AI) connect it to your own frontend or anything else; ACP serves it as an editor agent; and GitHub Agentic Workflows runs it headless on issues, pull requests or a schedule.
-
Durable execution. Durable execution on nine engines: Temporal, DBOS, Prefect, Restate, AWS Lambda, Airflow, Absurd, pgtask, and Azure Durable Task, the first five co-maintained with the vendor teams. Agents survive restarts and run for days on the engine you already operate, with human-in-the-loop approval built in.
-
Coming from another framework? The comparisons show where Pydantic AI differs from LangChain, Google ADK, Microsoft Agent Framework, the Claude Agent SDK and the other frameworks people ask us about, and the migration skills let your coding agent port an existing application over.
Built by the Pydantic team: Pydantic Validation is the validation layer of the OpenAI SDK, the Anthropic SDK, the Google ADK, LangChain, and most of the AI ecosystem (and the foundation FastAPI was built on). Pydantic AI brings that same feeling to agents. Built with Pydantic AI lists open source projects and organizations that run on it.
Putting it together: a bank support agent
A typed support agent showing several features working together: dependency injection, function tools, structured output, a reusable capability bundling the customer context, and an on-demand capability the model loads only when the conversation calls for it:
from dataclasses import dataclass
from pydantic import BaseModel, Field
from pydantic_ai import Agent, Capability, RunContext
from bank_database import DatabaseConn
@dataclass
class SupportDependencies: # inject any client: DB pools, HTTP APIs, user info
customer_id: int
db: DatabaseConn
class SupportOutput(BaseModel):
support_advice: str = Field(description='Advice returned to the customer')
block_card: bool = Field(description="Whether to block the customer's card")
risk: int = Field(description='Risk level of query', ge=0, le=10)
customer_context = Capability[SupportDependencies]( # a reusable unit of tools + instructions
id='customer-context',
description="Who the customer is and what's on their account.",
)
@customer_context.instructions
async def add_customer_name(ctx: RunContext[SupportDependencies]) -> str:
customer_name = await ctx.deps.db.customer_name(id=ctx.deps.customer_id)
return f"The customer's name is {customer_name!r}"
@customer_context.tool # signature and docstring become the tool schema the LLM sees
async def customer_balance(
ctx: RunContext[SupportDependencies], include_pending: bool
) -> float:
"""Returns the customer's current account balance."""
return await ctx.deps.db.customer_balance(
id=ctx.deps.customer_id,
include_pending=include_pending,
)
refunds = Capability[SupportDependencies]( # deferred: loads on demand, like a skill
id='refunds',
description='Refund eligibility and refund status.',
defer_loading=True,
)
@refunds.tool
async def refund_status(ctx: RunContext[SupportDependencies]) -> str:
"""Look up the refund status for the customer's most recent charge."""
return await ctx.deps.db.refund_status(id=ctx.deps.customer_id)
support_agent = Agent(
'openai:gpt-6.1-sol',
deps_type=SupportDependencies,
output_type=SupportOutput, # the run returns a validated SupportOutput, typed as such
instructions=(
'You are a support agent in our bank, give the '
'customer support and judge the risk level of their query.'
),
capabilities=[customer_context, refunds],
)
... # in a real use case: more tools, longer instructions
async def main():
deps = SupportDependencies(customer_id=123, db=DatabaseConn())
result = await support_agent.run('What is my balance?', deps=deps)
print(result.output)
"""
support_advice='Hello John, your current account balance, including pending transactions, is $123.45.' block_card=False risk=1
"""
result = await support_agent.run('I just lost my card!', deps=deps)
print(result.output)
"""
support_advice="I'm sorry to hear that, John. We are temporarily blocking your card to prevent unauthorized transactions." block_card=True risk=8
"""
result = await support_agent.run( # the model loads `refunds` on demand, then answers
'Was I refunded for the duplicate charge on my last statement?', deps=deps
)
print(result.output)
"""
support_advice='Good news, John: the duplicate charge on your last statement was refunded on 2026-05-01.' block_card=False risk=1
"""
For the annotated walkthrough and Logfire tracing, see the same example in the docs.
Next Steps
- Install Pydantic AI and put your own coding agent to work: install the Pydantic AI skill, point it at the examples and the Harness index, and tell it what you'd like to build. No API key needed to start (there's a built-in
'test'model), and the Pydantic AI Gateway is one key for every model when you're ready. - See what your agent did: run
uvx logfire-cli wizard --task pydantic-aionce to set up instrumentation, and every model call and tool call shows up. It's standard OpenTelemetry: Pydantic Logfire, which has a free tier (no credit card; sign up with just a GitHub account), is the easiest way to look, and any OTLP backend works. - Ship it: Going to Production answers what teams ask before shipping an agent, from crash recovery and human approval to cost limits, tracing and deployment.
- Read the docs and the API reference.
- Give your agent its batteries: Pydantic AI Harness.
- Join Slack or file an issue on GitHub.
Part of the Pydantic Stack
Everything you need to ship production-grade AI agents:
- Pydantic AI: the type-safe AI SDK
- Pydantic AI Harness: the official capability library and harness, from single capabilities to complete agents
- Pydantic Logfire: AI-first, full-stack observability
- Pydantic AI Gateway: one key for every model, with cost monitoring and spending limits
- Pydantic Evals: evaluate any Python function, agents included, from final outputs to tool-call trajectories, on datasets or live traffic (with production evals on Logfire)
- Pydantic Graph: typed graph control flow
- genai-prices: model pricing data, kept current
- Monty: a sandboxed Python interpreter for model-written code
smolagents
Agents that think in code!
Agents that think in code!
smolagents is a library that enables you to run powerful agents in a few lines of code. It offers:
✨ Simplicity: the logic for agents fits in ~1,000 lines of code (see agents.py). We kept abstractions to their minimal shape above raw code!
🧑💻 First-class support for Code Agents. Our CodeAgent writes its actions in code (as opposed to "agents being used to write code"). To make it secure, we support executing in sandboxed environments via Blaxel, E2B, Modal, or Docker.
🤗 Hub integrations: you can share/pull tools or agents to/from the Hub for instant sharing of the most efficient agents!
🌐 Model-agnostic: smolagents supports any LLM. It can be a local transformers or ollama model, one of many providers on the Hub, or any model from OpenAI, Anthropic and many others via our LiteLLM integration.
👁️ Modality-agnostic: Agents support text, vision, video, even audio inputs! Cf this tutorial for vision.
🛠️ Tool-agnostic: you can use tools from any MCP server, from LangChain, you can even use a Hub Space as a tool.
Full documentation can be found here.
[!NOTE]
Check out our launch blog post to learn more aboutsmolagents!
Quick demo
First install the package with a default set of tools:
pip install "smolagents[toolkit]"
Then define your agent, give it the tools it needs and run it!
from smolagents import CodeAgent, WebSearchTool, InferenceClientModel
model = InferenceClientModel()
agent = CodeAgent(tools=[WebSearchTool()], model=model, stream_outputs=True)
agent.run("How many seconds would it take for a leopard at full speed to run through Pont des Arts?")
https://github.com/user-attachments/assets/84b149b4-246c-40c9-a48d-ba013b08e600
You can even share your agent to the Hub, as a Space repository:
agent.push_to_hub("m-ric/my_agent")
## agent.from_hub("m-ric/my_agent") to load an agent from Hub
Our library is LLM-agnostic: you could switch the example above to any inference provider.
InferenceClientModel, gateway for all inference providers supported on HF
from smolagents import InferenceClientModel
model = InferenceClientModel(
model_id="deepseek-ai/DeepSeek-R1",
provider="together",
)
LiteLLM to access 100+ LLMs
from smolagents import LiteLLMModel
model = LiteLLMModel(
model_id="anthropic/claude-4-sonnet-latest",
temperature=0.2,
api_key=os.environ["ANTHROPIC_API_KEY"]
)
OpenAI-compatible servers: Together AI
import os
from smolagents import OpenAIModel
model = OpenAIModel(
model_id="deepseek-ai/DeepSeek-R1",
api_base="https://api.together.xyz/v1/", # Leave this blank to query OpenAI servers.
api_key=os.environ["TOGETHER_API_KEY"], # Switch to the API key for the server you're targeting.
)
OpenAI-compatible servers: OpenRouter
import os
from smolagents import OpenAIModel
model = OpenAIModel(
model_id="openai/gpt-4o",
api_base="https://openrouter.ai/api/v1", # Leave this blank to query OpenAI servers.
api_key=os.environ["OPENROUTER_API_KEY"], # Switch to the API key for the server you're targeting.
)
Local `transformers` model
from smolagents import TransformersModel
model = TransformersModel(
model_id="Qwen/Qwen3-Next-80B-A3B-Thinking",
max_new_tokens=4096,
device_map="auto"
)
Azure models
import os
from smolagents import AzureOpenAIModel
model = AzureOpenAIModel(
model_id = os.environ.get("AZURE_OPENAI_MODEL"),
azure_endpoint=os.environ.get("AZURE_OPENAI_ENDPOINT"),
api_key=os.environ.get("AZURE_OPENAI_API_KEY"),
api_version=os.environ.get("OPENAI_API_VERSION")
)
Amazon Bedrock models
import os
from smolagents import AmazonBedrockModel
model = AmazonBedrockModel(
model_id = os.environ.get("AMAZON_BEDROCK_MODEL_ID")
)
CLI
You can run agents from CLI using two commands: smolagent and webagent.
smolagent is a generalist command to run a multi-step CodeAgent that can be equipped with various tools.
## Run with direct prompt and options
smolagent "Plan a trip to Tokyo, Kyoto and Osaka between Mar 28 and Apr 7." --model-type "InferenceClientModel" --model-id "Qwen/Qwen3-Next-80B-A3B-Thinking" --imports pandas numpy --tools web_search
## Run in interactive mode (launches setup wizard when no prompt provided)
smolagent
Interactive mode guides you through:
- Agent type selection (CodeAgent vs ToolCallingAgent)
- Tool selection from available toolbox
- Model configuration (type, ID, API settings)
- Advanced options like additional imports
- Task prompt input
Meanwhile webagent is a specific web-browsing agent using helium (read more here).
For instance:
webagent "go to xyz.com/men, get to sale section, click the first clothing item you see. Get the product details, and the price, return them. note that I'm shopping from France" --model-type "LiteLLMModel" --model-id "gpt-5"
How do Code agents work?
Our CodeAgent works mostly like classical ReAct agents - the exception being that the LLM engine writes its actions as Python code snippets.
flowchart TB
Task[User Task]
Memory[agent.memory]
Generate[Generate from agent.model]
Execute[Execute Code action - Tool calls are written as functions]
Answer[Return the argument given to 'final_answer']
Task -->|Add task to agent.memory| Memory
subgraph ReAct[ReAct loop]
Memory -->|Memory as chat messages| Generate
Generate -->|Parse output to extract code action| Execute
Execute -->|No call to 'final_answer' tool => Store execution logs in memory and keep running| Memory
end
Execute -->|Call to 'final_answer' tool| Answer
%% Styling
classDef default fill:#d4b702,stroke:#8b7701,color:#ffffff
classDef io fill:#4a5568,stroke:#2d3748,color:#ffffff
class Task,Answer io
Actions are now Python code snippets. Hence, tool calls will be performed as Python function calls. For instance, here is how the agent can perform web search over several websites in one single action:
requests_to_search = ["gulf of mexico america", "greenland denmark", "tariffs"]
for request in requests_to_search:
print(f"Here are the search results for {request}:", web_search(request))
Writing actions as code snippets is demonstrated to work better than the current industry practice of letting the LLM output a dictionary of the tools it wants to call: uses 30% fewer steps (thus 30% fewer LLM calls) and reaches higher performance on difficult benchmarks. Head to our high-level intro to agents to learn more on that.
Since code execution can be a serious security concern (arbitrary code execution!), you should run agent code in a sandbox. We support several options:
- E2B, Blaxel, Modal — managed cloud sandboxes, simplest to set up
- Docker — self-hosted container isolation
The built-in LocalPythonExecutor is not a security sandbox. It applies some restrictions but can be bypassed and must not be used as a security boundary.
Alongside CodeAgent, we also provide the standard ToolCallingAgent which writes actions as JSON/text blobs. You can pick whichever style best suits your use case.
How smol is this library?
We strived to keep abstractions to a strict minimum: the main code in agents.py has <1,000 lines of code.
Still, we implement several types of agents: CodeAgent writes its actions as Python code snippets, and the more classic ToolCallingAgent leverages built-in tool calling methods. We also have multi-agent hierarchies, import from tool collections, remote code execution, vision models...
By the way, why use a framework at all? Well, because a big part of this stuff is non-trivial. For instance, the code agent has to keep a consistent format for code throughout its system prompt, its parser, the execution. So our framework handles this complexity for you. But of course we still encourage you to hack into the source code and use only the bits that you need, to the exclusion of everything else!
How strong are open models for agentic workflows?
We've created CodeAgent instances with some leading models, and compared them on this benchmark that gathers questions from a few different benchmarks to propose a varied blend of challenges.
Find the benchmarking code here for more detail on the agentic setup used, and see a comparison of using LLMs code agents compared to vanilla (spoilers: code agents works better).
This comparison shows that open-source models can now take on the best closed models!
Security
Security is a critical consideration when working with code-executing agents. Ensure you are using one of the sandboxed execution options that provide isolation from untrusted code.
Warning: LocalPythonExecutor provides best-effort mitigations only and is not a security boundary. Do not use it to run untrusted code.
For security policies, vulnerability reporting, and more information on secure agent execution, please see our Security Policy.
Contribute
Everyone is welcome to contribute, get started with our contribution guide.
Cite smolagents
If you use smolagents in your publication, please cite it by using the following BibTeX entry.
@Misc{smolagents,
title = {`smolagents`: a smol library to build great agentic systems.},
author = {Aymeric Roucher and Albert Villanova del Moral and Thomas Wolf and Leandro von Werra and Erik Kaunismäki},
howpublished = {\url{https://github.com/huggingface/smolagents}},
year = {2025}
}
Questions
- Do Pydantic AI and smolagents list the same price?
- Both listings report Free. Free to use. Pricing is reported by the maker and is not independently verified.
- Which has more upvotes, Pydantic AI or smolagents?
- Both have 0 upvotes.
- What does each maker say Pydantic AI and smolagents are for?
- Pydantic AI: Python agent framework from the Pydantic team with type-safe tools and structured outputs. smolagents: Hugging Face library for building agents that think and act in code.
Pydantic AI alternatives·smolagents alternatives·All coding tools