building-pydantic-ai-a…
Build AI agents with Pydantic AI — tools, capabilities (including on-demand loading), workspaces, structured output, streaming,…
Pydantic is a Python data validation and serialization library, based on type hints. Use this skill whenever you need to do relatively complex data modeling using Pydantic, e.g. when adding constraints, defining a model hierarchy with subclasses, etc.
$ npx -y skills add pydantic/skills --skill pydantic --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/pydanticContext preview
The summary Claude sees to decide when to auto-load this skill.
Pydantic is a Python data validation and serialization library, based on type hints. Use this skill whenever you need to do relatively complex data modeling using Pydantic, e.g. when adding constraints, defining a model hierarchy with subclasses, etc.
name: pydantic description: Pydantic is a Python data validation and serialization library, based on type hints. Use this skill whenever you need to do relatively complex data modeling using Pydantic, e.g. when adding constraints, defining a model hierarchy with subclasses, etc.
In a nutshell, Pydantic is dataclasses with runtime validation. It leverages type hints to understand how validation (and serialization) should be performed. It is mostly useful when dealing with external untrusted data, for example when defining an HTTP API.
It is generally *not* recommended to use Pydantic to define classes that are instantiated within the user code. By doing so, you will lose flexibility (e.g. you cannot use types not supported by Pydantic, and it is harder to perform post-init changes). It is usually better to use vanilla classes (or standard library dataclasses) in this case, as a static type checker will already catch type mismatches.
Here is a simple example of using a Pydantic model:
from datetime import date
from pydantic import BaseModel, Field
class Person(BaseModel):
name: str
age: int = Field(description='The age of the person')
birthdate: date | None = None
p = Person(name='John', age=20, birthdate='1970-01-01')Pydantic coerces compatible input: the ISO date string `'1970-01-01'` is parsed into a `date`.
The `Field()` function is used to provide metadata and constraints. You need to distinguish two types of metadata:
have meaning when attached to a field.
and also metadata that affects the JSON Schema (e.g. `description`, `title`).
Model fields are declared with `Field()` using the assignment form:
from pydantic import BaseModel, Field
class User(BaseModel):
first_name: str = Field(alias='name')or using the annotated pattern:
from typing import Annotated
from pydantic import BaseModel, Field
class Model(BaseModel):
value: Annotated[int, Field(deprecated=True)] = 1The annotated pattern has some advantages:
has a default value, while in reality the field is still required.
the `Field()` function only supports a limited set of constraints/metadata, and you may have to use different Pydantic utilities such as `WithJsonSchema` in some cases.
But note that:
is to do the following:
from typing import Annotated
from pydantic import BaseModel, Field
class Model(BaseModel):
field_bad: Annotated[int, Field(deprecated=True)] | None = None
field_ok: Annotated[int | None, Field(deprecated=True)] = None*field specific* metadata should apply to the whole union in this example.
As much as possible, use the "built-in" validation constraints, instead of defining custom validators:
from typing import Annotated
from annotated_types import Gt # annotated_types is an alternative to the `Field()` function.
from pydantic import BaseModel, field_validator
class Model(BaseModel):
constrained_int_ok: Annotated[int, Gt(1)] # This is good
constrained_int_bad: int
@field_validator('constrained_int_bad') # This is bad
@classmethod
def validate(cls, v: int) -> int:
if not v > 1:
raise ValueError('Value is not greater than 1')
return vSometimes, constraints can't be expressed using the `Field()` function. For example, string constraints such as `strip_whitespace`, `to_upper`, `to_lower` and `ascii_only` can only be specified using `pydantic.StringConstraints`:
from typing import Annotated
from pydantic import BaseModel, StringConstraints
class Model(BaseModel):
# Do this instead of a validator calling s.strip():
a: Annotated[str, StringConstraints(strip_whitespace=True)]<https://pydantic.dev/docs/validation/latest/api/pydantic/standard_library_types/> is the canonical documentation for all supported standard library types and their constraints.
In some cases, you may have to use custom validators. As much as possible, use *after* validators. Because they run after Pydantic validation, the value is already the field's type. If you use *before* validators, the input data can literally be anything, so it is more error-prone (especially for model validators, the input isn't necessarily a dict, it can also be an arbitrary object).
If possible, prefer using the annotated pattern for validators:
from typing import Annotated
from pydantic import AfterValidator, BaseModel, field_validator
def is_even(value: int) -> int:
if value % 2 == 1:
raise ValueError(f'{value} is not an even number')
return value
class Model(BaseModel):
# Prefer this form: the validator is right next to the field, making it easy to understand
even: Annotated[int, AfterValidator(is_even)]
odd: int
# If you define a validator as decorator, make sure to define it as classmethod.
@field_validator('odd', mode='after')
@classmethod
def is_odd(cls, value: int) -> int:
if value % 2 == 0:
raise ValueError(f'{value} is not an odd number')
return valueUsing the decorator pattern can lead to unclear behavior, especially regarding the order in which validators run (in particular on subclasses).
Logfire, Pydantic AI, and Pydantic plugins for Claude Code, Codex, and Cursor. Instrument your code with Logfire, query and export the resulting telemetry, build LLM agents with Pydantic AI, and validate data with Pydantic.
Build AI agents with Pydantic AI — tools, capabilities (including on-demand loading), workspaces, structured output, streaming,…
Migrate Python Agno applications to Pydantic AI and, only when needed, Pydantic AI Harness. Use when source code imports `agno`…
Migrate Python applications from the Claude Agent SDK to Pydantic AI and, only when needed, Pydantic AI Harness. Use when source…
Migrate Python Google Agent Development Kit (ADK) applications to Pydantic AI. Use for `LlmAgent`, `Runner`, sessions, state,…
Migrate Python LangChain, LangGraph, or Deep Agents applications to Pydantic AI and, when the source uses harness features,…
Migrate TypeScript Mastra applications to Python with Pydantic AI and, only when needed, Pydantic AI Harness. Use when source…