.agents/skills/adk-style/references/pydantic.md
ADK models use Pydantic v2. This guide covers the key patterns used throughout the codebase.
Field() for validation, defaults, and descriptions.PrivateAttr() for internal state that shouldn't be serialized.model_post_init() instead of __init__ for setup logic.model_dump() over dict() (Pydantic v2).| Need | Pattern |
|---|---|
| Simple numeric/string bounds | Field(ge=0, le=100) |
| Single-field business logic | @field_validator('field', mode='after') |
| Cross-field consistency | @model_validator(mode='after') |
| Field deprecation/migration | @model_validator(mode='before') |
| Internal mutable state | PrivateAttr(default_factory=...) |
| Post-construction setup | model_post_init() |
Field() with ConstraintsUse Field() constraints for declarative validation directly on the field definition. This keeps validation close to the data declaration and avoids custom validator boilerplate.
field_validator — Single-Field ValidationUse @field_validator for validation logic that goes beyond simple constraints. This is heavily used in ADK (36+ instances). Always use mode='after' unless you need to intercept raw input before Pydantic coercion.
Rules:
@field_validator(...). While @classmethod is automatically applied by Pydantic v2, adding it is recommended in ADK for explicit visibility.ValueError with a descriptive message on failure.mode='after' (validates after Pydantic's own parsing/coercion).model_validator — Cross-Field and Migration ValidationUse @model_validator when validation depends on multiple fields, or when handling deprecation/migration of field names.
mode='before' — Deprecation and Field Migrationmode='after' — Cross-Field ConsistencyRules:
mode='before': receives raw data (usually dict). Use for field renaming, deprecation, and input normalization. Must return the (modified) data.mode='after': receives the fully constructed model instance (self). Use for cross-field consistency checks. Must return self.mode='before' validators with isinstance(data, dict) since data could also come as an existing model instance.