Back to Adk Python

Pydantic Patterns

.agents/skills/adk-style/references/pydantic.md

2.0.0b12.3 KB
Original Source

Pydantic Patterns

ADK models use Pydantic v2. This guide covers the key patterns used throughout the codebase.

Basic Model Structure

  • Use Field() for validation, defaults, and descriptions.
  • Use PrivateAttr() for internal state that shouldn't be serialized.
  • Use model_post_init() instead of __init__ for setup logic.
  • Prefer model_dump() over dict() (Pydantic v2).

Summary of When to Use Each

NeedPattern
Simple numeric/string boundsField(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 statePrivateAttr(default_factory=...)
Post-construction setupmodel_post_init()

Field() with Constraints

Use 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 Validation

Use @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:

  • Decorate with @field_validator(...). While @classmethod is automatically applied by Pydantic v2, adding it is recommended in ADK for explicit visibility.
  • Return the (possibly transformed) value.
  • Raise ValueError with a descriptive message on failure.
  • Prefer mode='after' (validates after Pydantic's own parsing/coercion).

model_validator — Cross-Field and Migration Validation

Use @model_validator when validation depends on multiple fields, or when handling deprecation/migration of field names.

mode='before' — Deprecation and Field Migration

mode='after' — Cross-Field Consistency

Rules:

  • 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.
  • Always guard mode='before' validators with isinstance(data, dict) since data could also come as an existing model instance.