Суть
После того как структура гарантирована, остаётся бизнес-логика: даты, диапазоны, кратности, межполевые инварианты. Их проверяют валидаторы; при провале поднимается ModelRetry, и модель видит свой прошлый ответ + причину ошибки.
Зачем это нужно
Технически валидный JSON может быть бизнес-неверным: дата конца раньше даты начала, priority=critical без флага requires_human, сумма не сходится. Кейс юр.документов: добавление output-валидаторов снизило логические ошибки с 4.7% до 0.0%, исправление с первой попытки в 94% случаев.
Как работает
Три независимых уровня проверки:
- JSON Schema / типы — автоматически (тип поля, обязательность, enum, диапазоны).
@field_validator— правило для конкретного поля и нормализация (строку"$1,200.50"→1200.50).@agent.output_validator— последний рубеж: бизнес-логика, в т.ч. обращение к БД/API черезctx.deps(Agent Deps).
При провале — raise ModelRetry("поле X провалило проверку Y по причине Z"). Защита от бесконечного цикла: retries=3 на агенте, после исчерпания — UnexpectedModelBehavior (связь с лимитами в Agent CostControl).
agent = Agent('openai:gpt-4o-mini', output_type=TicketClassification,
deps_type=TicketDeps, retries=3)
@agent.output_validator
async def validate_output(ctx: RunContext[TicketDeps],
output: TicketClassification) -> TicketClassification:
if output.priority == "critical" and not output.requires_human:
raise ModelRetry("priority=critical обязывает requires_human=True")
if output.estimated_minutes % 15 != 0:
raise ModelRetry(f"{output.estimated_minutes} не кратно 15")
return output
# число потраченных retry: result.usage().requests - 1
Связано с
- PydanticAI — где реализованы валидаторы и ModelRetry
- Structured Output — типовая валидация, поверх которой идёт бизнес-проверка
- Agent CostControl —
retries=3и стоп приUnexpectedModelBehavior
Открытые вопросы
- оптимальный лимит retries vs стоимость (
retry_overhead_tokens) - что делать при исчерпании попыток: fallback-ответ vs алерт vs отказ