
Pydantic AI: Produktionsguiden (Ud over Hello World)
Rå LLM-outputs ødelægger apps. Du beder om JSON, men får markdown. Du beder om et tal mellem 1 og 10, men får "Selvfølgelig! Her er et tal: syv." Hvis du har bygget noget realistisk med LLM-API'er, har du skrevet defensiv parser-kode, der får dig til at betvivle dine karrierevalg. Pydantic AI løser dette problem. Det er et typesikkert agent-framework bygget af samme team bag Pydantic og FastAPI. Tænk på det som "FastAPI for AI-agenter": du definerer, hvad du vil have, med Python-typehints, og frameworket håndterer validering, genforsøg og funktionskald.
Denne Pydantic AI-guide er til udviklere, der allerede har kørt deres første LLM-kald og nu søger produktionsmønstre: strukturerede outputs, der ikke bryder sammen, dependency injection til testbare agenter og værktøjer til den virkelige verden ud over vejr-API'er. I slutningen vil du have fungerende agenter med værktøjer, DI, streaming og tests.
<!-- IMAGE: Pydantic AI agentarkitektur, Agent modtager prompt, kalder værktøjer via RunContext, validerer output gennem Pydantic-model -->Pydantic AI ved første øjekast
| Attribut | Detaljer |
|---|---|
| Hvad det er | Typesikkert AI-agent-framework til Python |
| Udviklet af | Pydantic-teamet (Samuel Colvin m.fl.) |
| Filosofi | "FastAPI for AI-agenter", typehints driver alt |
| Licens | MIT (open source) |
| Nuværende version | v1.74.0 (marts 2026) |
| Python-version | 3.9+ |
| Understøttede modeller | OpenAI, Anthropic, Google Gemini, Groq, Mistral, Ollama og flere |
| Nøglefunktioner | Strukturerede outputs, funktionskald, dependency injection, streaming, TestModel |
| GitHub-stjerner | 16.000+ |
| Produktionsklar | Ja, v1.0 udkom september 2025 |
| Observability | NatLogfire-integration (baseret på OpenTelemetry) |
| Lerningskurve | Lav, hvis du kender Pydantic/FastAPI; moderat ellers |
De mest fremtrædende funktioner er strukturerede outputs (valideret med Pydantic-modeller), dependency injection (ligesom FastAPI's Depends) og TestModel (mock-LLM til test uden API-kald). Hvis du kommer fra LangChain og undrer dig over "findes der noget renere?", så er dette sandsynligvis svaret.
Installation og første agent
# Install with OpenAI support (swap openai for anthropic, google, etc.)
pip install "pydantic-ai[openai]"
# Set your API key
export OPENAI_API_KEY="sk-..."Din første agent på 5 linjer:
from pydantic_ai import Agent
agent = Agent("openai:gpt-4o", system_prompt="You are a helpful assistant.")
result = agent.run_sync("What's the capital of France?")
print(result.output) # "Paris"Det var det. Agent omslutter modellen, run_sync sender en prompt og returnerer et resultat. result.output er her en almindelig streng, men det er lige ved at ændre sig.
Strukturerede outputs – derfor findes Pydantic AI
Dette er kernefunktionen. I stedet for at få en streng tilbage fra LLM'en og håbe, at det er gyldig JSON, definerer du en Pydantic-model, og agenten returnerer et valideret Python-objekt.
Før: Råt LLM-output
# The old way -- hope for the best
from openai import OpenAI
client = OpenAI()
response = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": "Review the movie Inception. Return JSON with title, rating (1-10), summary."}]
)
# response.choices[0].message.content is a string
# Maybe it's JSON. Maybe it has markdown code fences. Maybe rating is "eight".
# You're on your own.Efter: Struktureret med Pydantic AI
from pydantic import BaseModel
from pydantic_ai import Agent
class MovieReview(BaseModel):
title: str
rating: int # Guaranteed to be an int, not "eight"
summary: str
recommended: bool
agent = Agent("openai:gpt-4o", result_type=MovieReview)
result = agent.run_sync("Review the movie Inception")
review = result.output # This is a MovieReview instance, not a string
print(f"{review.title}: {review.rating}/10")
print(f"Recommended: {review.recommended}")
print(review.summary)Forskellen er som nat og dag. result.output er et rigtigt MovieReview-objekt. Hvis LLM'en returnerer rating: "eight" i stedet for rating: 8, fanger Pydantics validering det. For et dybere kig på, hvordan dette fungerer på tværs af forskellige udbydere, se vores guide om strukturerede outputs på tværs af LLM-udbydere.
Hvad sker der, når valideringen fejler?
Her er den del, som ingen anden tutorial viser: hvad sker der, når LLM'en laver fejl?
from pydantic import BaseModel, Field
from pydantic_ai import Agent
class StrictReview(BaseModel):
title: str
rating: int = Field(ge=1, le=10) # Must be 1-10
pros: list[str] = Field(min_length=2) # At least 2 pros
agent = Agent("openai:gpt-4o", result_type=StrictReview)
# If the LLM returns rating=15 or only 1 pro:
# 1. Pydantic validation fails
# 2. The error message is sent BACK to the LLM
# 3. The LLM tries again with the corrected output
# 4. This repeats up to the retry limit
result = agent.run_sync("Review the movie Inception")Denne loop med genforsøg og feedback er Pydantic AIs killer-feature. LLM'en lærer af sine egne valideringsfejl. Du behøver ikke skrive logik for genforsøg; frameworket håndterer det.
Dom: Strukturerede outputs er den enkelt bedste grund til at bruge Pydantic AI frem for rå API-kald. Hvis du manuelt parser LLM-JSON, så stop.
Værktøjer og funktionskald
Værktøjer lader din agent kalde Python-funktioner for at hente rigtige data. I stedet for at LLM'en hallucinerer fakta, kan den query'e din database, søge i dine dokumenter eller kalde et API.
Registrering af et værktøj
from pydantic_ai import Agent
agent = Agent("openai:gpt-4o")
@agent.tool
async def search_docs(query: str) -> str:
"""Search the documentation for relevant articles."""
# Your actual search logic here
results = await doc_search_engine.search(query, limit=5)
return "\n".join(r.title + ": " + r.snippet for r in results)Dekoratoren @agent.tool registrerer funktionen. Pydantic AI læser funktionens typehints og docstring for at fortælle LLM'en, hvad værktøjet gør, hvilke argumenter det tager, og hvad det returnerer. Ingen manuel schema-skrivning – dine typehints ER schemaet. For baggrundsinformation om hvordan LLM-funktionskald fungerer under motorhjelmen, har vi en dedikeret guide.
RunContext: Videregivelse af data til værktøjer
Her adskiller Pydantic AI sig fra andre frameworks. RunContext lader dig videregive runtime-data (databaseforbindelser, brugerinfo, API-klienter) til dine værktøjer uden global state.
from dataclasses import dataclass
from pydantic_ai import Agent, RunContext
@dataclass
class SupportDeps:
customer_id: str
db_connection: DatabaseConnection
agent = Agent("openai:gpt-4o", deps_type=SupportDeps)
@agent.tool
async def get_order_history(ctx: RunContext[SupportDeps], limit: int = 5) -> str:
"""Fetch recent orders for the current customer."""
orders = await ctx.deps.db_connection.query(
"SELECT * FROM orders WHERE customer_id = $1 ORDER BY date DESC LIMIT $2",
ctx.deps.customer_id, limit
)
return format_orders(orders)ctx.deps giver værktøjet adgang til hvad som helst, du har sendt med ved runtime. Værktøjet importerer ikke en global databaseforbindelse; det modtager én. Dette er dependency injection, og det er dét, der gør dine agenter testbare.
Et eksempel på et værktøj fra den virkelige verden
@agent.tool
async def run_sql_query(ctx: RunContext[SupportDeps], sql: str) -> str:
"""Run a read-only SQL query against the analytics database.
Only SELECT queries are allowed."""
if not sql.strip().upper().startswith("SELECT"):
return "Error: only SELECT queries are allowed"
results = await ctx.deps.db_connection.fetch(sql)
return json.dumps(results, default=str)Dom: Funktionskald i Pydantic AI er renere end i ethvert andet framework takket være typehints, der løfter tungten. Du skriver normale Python-funktioner med typeannoteringer. Frameworket finder ud af resten.
Dependency injection – funktionen LangGraph wished it had
Hvis du har brugt FastAPI's Depends, forstår du allerede Pydantic AIs DI-system. Hvis du ikke har, er her den korte version: i stedet for at din agent rækker ud for at grabbe det, den har brug for (globale databaseforbindelser, API-klienter, konfiguration), giver du den alt ved runtime.
Definition af dependencies
from dataclasses import dataclass
from pydantic_ai import Agent
@dataclass
class AppDeps:
db: AsyncDatabasePool
search_client: SearchAPIClient
current_user: User
agent = Agent(
"openai:gpt-4o",
deps_type=AppDeps,
system_prompt="You are a customer support agent."
)Brug af dependencies i værktøjer
@agent.tool
async def lookup_account(ctx: RunContext[AppDeps]) -> str:
"""Look up the current user's account details."""
account = await ctx.deps.db.fetchrow(
"SELECT * FROM accounts WHERE user_id = $1",
ctx.deps.current_user.id
)
return json.dumps(account, default=str)
# Run with real dependencies
result = await agent.run(
"What's my account status?",
deps=AppDeps(db=real_db, search_client=real_search, current_user=user)
)Hvorfor DI gør dine agenter testbare
Dette er den egentlige gevinst. I LangChain ville du sende kontekst gennem chain kwargs eller closures; der er intet standardmønster. I Pydantic AI er det trivielt at bytte rigtige dependencies ud med test-doubles:
# In your test file
from pydantic_ai import Agent
from your_app import agent, AppDeps
async def test_account_lookup():
mock_deps = AppDeps(
db=MockDatabase({"user_123": {"status": "active", "plan": "pro"}}),
search_client=MockSearch(),
current_user=User(id="user_123")
)
result = await agent.run("What's my account status?", deps=mock_deps)
assert "active" in result.output
assert "pro" in result.outputIngen monkey-patching. Ingen mocking af globale imports. Du sender bare forskellige deps.
Dom: Dependency injection er grunden til, at erfarne Python-udviklere foretrækker Pydantic AI. Det er FastAPI-indflydelsen, der viser sig.
Modeludbydere: OpenAI, Anthropic, Gemini, Ollama
Pydantic AI er model-agnostisk. At skifte udbyder er en ændring på én linje:
# OpenAI
agent = Agent("openai:gpt-4o")
# Anthropic
agent = Agent("anthropic:claude-sonnet-4-20250514")
# Google Gemini
agent = Agent("google-gla:gemini-2.0-flash")
# Local Ollama
agent = Agent("ollama:llama3.1")Alt andet – værktøjer, strukturerede outputs, DI – forbliver identisk. Din forretningslogik ændres ikke, når du skifter modeller.
| Udbyder | Modeller | Gratis niveau | Opsætningskompleksitet |
|---|---|---|---|
| OpenAI | GPT-4o, GPT-4o mini, o1 | $5 kredit (nye konti) | Lav, kun API-nøgle |
| Anthropic | Claude Sonnet, Haiku, Opus | Intet gratis niveau | Lav, kun API-nøgle |
| Google Gemini | Gemini 2.0 Flash, Pro | Generøst gratis niveau | Medium, projektopsætning |
| Groq | Llama, Mixtral | Gratis niveau tilgængeligt | Lav, kun API-nøgle |
| Ollama (lokal) | Llama, Mistral, Phi osv. | Helt gratis | Medium, installer Ollama |
Dom: Model-agnostisk design betyder, at du aldrig er låst fast til én udbyder. Start med OpenAI for bekvemmelighed, benchmarke med Anthropic, og brug Ollama til lokal udvikling.
Streaming-respons
Til chat-UI'er og realtidsapplikationer er streaming essentielt. Pydantic AI understøtter det, samtidig med at typesikkerheden bevares:
from pydantic_ai import Agent
from pydantic import BaseModel
class AnalysisResult(BaseModel):
summary: str
sentiment: str
confidence: float
agent = Agent("openai:gpt-4o", result_type=AnalysisResult)
async def stream_analysis(text: str):
async with agent.run_stream(f"Analyze this text: {text}") as stream:
async for partial in stream.stream_structured():
# partial is a partially-validated AnalysisResult
print(f"Streaming: {partial}")
# Final result is fully validated
result = await stream.get_output()
print(f"Final: {result.summary} ({result.confidence:.0%} confident)")Dette fungerer smukt sammen med FastAPI's StreamingResponse – samme økosystem, samme mønstre. Pydantic AI agents docs dækker avancerede streaming-muligheder, herunder tekst-only streaming med stream_text().
Pydantic AI vs LangGraph vs OpenAI Agents SDK
Du er her, så du spørger sandsynligvis: "skal jeg bruge Pydantic AI eller LangGraph?" Ærligt svar: de løser forskellige problemer, og du kan måske bruge begge.
Sammenligningstabel over funktioner
| Funktion | Pydantic AI | LangGraph | OpenAI Agents SDK |
|---|---|---|---|
| Typesikkerhed | Fuld (Pydantic-modeller) | Delvis (TypedDict) | Minimal |
| Dependency Injection | Indbygget (FastAPI-stil) | Ingen | Ingen |
| Strukturerede outputs | Naturlig med genforsøg | Via output parsers | Via JSON-mode |
| Funktionskald | @agent.tool decorator | @tool decorator | funktionsdefinitioner |
| Multi-Agent | Grundlæggende handoffs | Avanceret (state machines) | Handoffs + guardrails |
| Streaming | Typed streaming | Streaming events | Streaming |
| Modelsupport | 10+ udbydere | Primært LangChain-modeller | Kun OpenAI |
| Test | TestModel indbygget | Ingen indbygget test | Ingen indbygget test |
| Lerningskurve | Lav (hvis du kender Pydantic) | Høj (grafkoncepter) | Lav (simpelt API) |
| Community-størrelse | Voksende (16K stjerner) | Stor (LangChain-økosystem) | Voksende (OpenAI-backing) |
| Bedst til | Rene, testbare agenter | Komplekse state-workflows | Kun OpenAI-projekter |
Hvornår skal du bruge hvad?
Vælg Pydantic AI, når du vil have ren, typesikker agentkode. Det er ideelt til single-agent-opgaver med værktøjer (kundeservice-bots, dataekstraktion, code review-agenter) og situationer, hvor testbarhed betyder noget. Hvis dit team allerede bruger FastAPI og Pydantic, er lerningskurven næsten flad.
Vælg LangGraph, når du har brug for komplekse multi-step workflows med betinget grening, godkendelse med menneskelig involvering (human-in-the-loop) og sofistikeret state-management. LangGraph excellerer i orkestrering af flere trin, ikke i kvaliteten af individuelle agenter. For et dybt dyk, se vores fulde sammenligning af LangGraph vs CrewAI vs OpenAI Agents SDK.
Vælg OpenAI Agents SDK, når du er 100% på OpenAI, ønsker den simplest mulige opsætning og ikke har brug for support til flere udbydere eller DI.
Kombinationsmønsteret
Her er hvad erfarne teams faktisk gør: brug Pydantic AI til individuelle agenter (ren kode, testbar, typede outputs) og LangGraph til orkestrering mellem agenter (routing, state machines, betinget logik). De konkurrerer ikke; de er komplementære lag.
# Pydantic AI agent -- clean, testable, type-safe
support_agent = Agent("openai:gpt-4o", result_type=SupportResponse, deps_type=SupportDeps)
# LangGraph graph -- orchestrates when to call which agent
graph = StateGraph(SupportState)
graph.add_node("classify", classify_intent)
graph.add_node("support", lambda state: support_agent.run_sync(state["query"]))
graph.add_node("escalate", escalate_to_human)Dom: Vælg Pydantic AI for ren, testbar agentkode. Vælg LangGraph for komplekse multi-step workflows. De er ikke gensidigt eksklusive.
Test af dine agenter med TestModel
Dette er afsnittet, der adskiller en begynderguide fra en produktionsguide. Alle rigtige codebases har brug for tests, og test af agenter er berygtet svært. LLM-kald er langsomme, dyre og ikke-deterministiske. Pydantic AI leverer en løsning: TestModel.
from pydantic_ai import Agent
from pydantic_ai.models.test import TestModel
from pydantic import BaseModel
class SupportResponse(BaseModel):
answer: str
confidence: float
escalate: bool
agent = Agent("openai:gpt-4o", result_type=SupportResponse)
# In tests: swap the real model for TestModel
def test_support_agent():
with agent.override(model=TestModel()):
result = agent.run_sync("I need help with billing")
# TestModel returns valid structured data matching your result_type
assert isinstance(result.output, SupportResponse)
assert isinstance(result.output.confidence, float)
assert isinstance(result.output.escalate, bool)TestModel genererer gyldige data, der matcher din result_type, uden at foretage nogen API-kald. Nul omkostninger, deterministisk, hurtigt. Pydantic AI testing docs dækker avancerede mønstre som FunctionModel til brugerdefinerede respons og capture_run_messages til inspektion af værktøjskald.
Test af værktøjer og DI sammen
def test_order_lookup_tool():
# Mock dependencies
mock_deps = SupportDeps(
customer_id="test-123",
db_connection=MockDB(orders=[{"id": "ord-1", "status": "shipped"}])
)
with agent.override(model=TestModel()):
result = agent.run_sync(
"Where is my order?",
deps=mock_deps
)
assert isinstance(result.output, SupportResponse)Ingen API-kald. Ingen ustabile tests. Ingen omkostninger. Kør dette i CI/CD sammen med resten af din test-suite.
Dette er det #1 indholdshul på hele SERP. Ingen anden Pydantic AI-guide dækker test. Hvis du bygger agenter til produktion, er det dette, du har brug for.
Observability: Logfire-integration på 5 minutter
Produktionsagenter har brug for AI observability. Du vil se hvert eneste LLM-kald, værktøjsinvokation, latens, token-antal og omkostninger. Pydantic AI integrerer naturligt med Logfire, Pydantic-teamets observability-platform (bygget på OpenTelemetry).
import logfire
from pydantic_ai import Agent
logfire.configure() # Uses LOGFIRE_TOKEN env var
logfire.instrument_pydantic_ai()
agent = Agent("openai:gpt-4o", result_type=MovieReview)
# Every run is now traced automatically
result = agent.run_sync("Review Inception")Tre linjer. Du får fulde traces, der viser: sendt prompt, modelrespons, værktøjskald (hvis nogen), validerings-success/failure, genforsøg, latens og estimerede omkostninger. Hvis Logfire ikke er noget for dig, er Langfuse et solidt open source-alternativ med understøttelse af context engineering til sporing af, hvordan dine prompts udvikler sig.
FAQ
Hvad er Pydantic AI, og hvordan adskiller det sig fra LangChain?
Pydantic AI er et typesikkert agent-framework, hvor Python-typehints driver validering, værktøjsschemaer og dependency injection. LangChain er et større framework fokuseret på at kæde LLM-kald sammen. Den vigtigste forskel: Pydantic AI validerer outputs på framework-niveau og giver indbygget dependency injection for testbarhed; det gør LangChain ikke som standard.
Hvordan bygger jeg en typesikker AI-agent med Pydantic AI?
Definer en Pydantic BaseModel til dit output, send det som result_type til Agent, og kald run_sync() eller run(). Agenten returnerer en valideret instans af din model, ikke en rå streng. Se afsnittet om strukturerede outputs for komplette eksempler.
Skal jeg bruge Pydantic AI eller LangGraph til produktionsagenter?
Brug Pydantic AI til individuelle agenter, hvor typesikkerhed, testbarhed og ren kode betyder noget. Brug LangGraph til orkestrering af komplekse multi-step workflows med betinget routing. Mange teams bruger begge dele: Pydantic AI-agenter inde i et LangGraph-orkestreringslag.
Hvordan håndterer Pydantic AI funktionskald og dependency injection?
Dekorér en funktion med @agent.tool, så læser Pydantic AI dens typehints for at generere værktøjsschemaet. Til DI skal du sætte deps_type på Agent og acceptere RunContext[DineDeps] i værktøjer. Runtime-dependencies (DB-forbindelser, API-klienter) flyder igennem uden global state.
Hvordan tilføjer jeg streaming til en Pydantic AI-agent?
Brug agent.run_stream() i stedet for agent.run(). Det returnerer en async context manager, der yielder delvise resultater via stream_structured() eller stream_text(). Det endelige resultat er stadig fuldt valideret mod din result_type.
Er Pydantic AI produktionsklar i 2026?
Ja. Version 1.0 udkom i september 2025 med et løfte om API-stabilitet. Det er bakket op af Pydantic-teamet (det mest downloadede Python-bibliotek til datavalidering) og er aktuelt på v1.74.0 med regelmæssige opdateringer.
Kan jeg bruge Pydantic AI med Ollama og lokale modeller?
Ja. Brug Agent("ollama:llama3.1") og sørg for, at Ollama kører lokalt. Installer ollama-provider-extrat: pip install "pydantic-ai[ollama]". Strukturerede outputs og værktøjer fungerer på samme måde som med cloud-udbydere.
Hvordan tester jeg Pydantic AI-agenter?
Brug TestModel, en mock-model, der genererer gyldige strukturerede data, der matcher din result_type, uden API-kald. Omslut din test med agent.override(model=TestModel()) og kør assertions på outputtet. Se afsnittet om test for komplette pytest-eksempler.
Fungerer Pydantic AI med FastAPI?
Perfekt. De deler samme filosofi omkring dependency injection og er bygget af samme team. Du kan bruge Pydantic AI-agenter inde i FastAPI-endpoints, dele dependency-typer mellem dem og streame agent-respons gennem StreamingResponse.
Hvad er forskellen mellem Pydantic AI og OpenAI Agents SDK?
Pydantic AI er model-agnostisk (fungerer med OpenAI, Anthropic, Gemini, Ollama osv.), har dependency injection, TestModel til test og Pydantic-validering. OpenAI Agents SDK er simplere, men låst til OpenAI-modeller og mangler DI og indbygget test. Vælg Pydantic AI for fleksibilitet; vælg OpenAI Agents SDK for den simplest mulige kun-OpenAI-opsætning.
Vigtigste pointer og næste skridt
| Koncept | Vigtig indsigt | Næste skridt |
|---|---|---|
| Strukturerede outputs | Din result_type valideres og genforsøges automatisk | Definer Pydantic-modeller for alle agent-outputs |
| Værktøjer | Typehints ER schemaet, ingen manuelle definitioner | Byg værktøjer med @agent.tool og RunContext |
| Dependency Injection | Send runtime-deps eksplicit for testbarhed | Definer en deps_type dataclass for hver agent |
| Test | TestModel eliminerer API-omkostninger i CI/CD | Tilføj agent.override(model=TestModel()) til din test-suite |
| Modeludbydere | Skift model på én linje, ingen kodeændringer | Start med OpenAI, benchmarke alternativer senere |
| Observability | 3-linjers Logfire-opsætning for fulde traces | Tilføj logfire.instrument_pydantic_ai() til produktion |
Start med en lille agent, der har strukturerede outputs. Tilføj et værktøj. Tilføj dependencies. Skriv en test med TestModel. Det er vejen til produktion, og du har nu alt, hvad du behøver for at gå den.
De officielle Pydantic AI docs og GitHub-repositoriet er fremragende til at gå dybere. Frameworket bevæger sig hurtigt, så bogmærk changeloggen.