Структурированный вывод: главная суперсила
Как заставить модель возвращать не «примерно то», а ровно то, что нужно приложению.
Идея
Вместо «попроси модель ответить в JSON и надейся» ты описываешь результат как модель данных — список полей с типами. Параметр output_type агента делает эту структуру обязательной: Pydantic AI сам объяснит её модели, проверит ответ и автоматически попросит модель переделать, если та ошиблась.
from pydantic import BaseModel
from pydantic_ai import Agent
class CityLocation(BaseModel):
city: str
country: str
agent = Agent('google:gemini-3-flash-preview', output_type=CityLocation)
result = agent.run_sync('Где проходила Олимпиада 2012 года?')
print(result.output) # city='London' country='United Kingdom'
Пример из официальной документации. result.output — готовый объект: result.output.city вернёт строку, всегда.
Что можно требовать на выходе
- Простые типы:
bool(«спам или нет»),int,str; - Pydantic-модели — структуры с полями любой вложенности;
- списки:
list[str]— например, «10 тем для эфиров»; - варианты:
output_type=[Lead, Failed]— «либо заявка, либо честное "не смог"»; - даже функции — модель обязана вызвать одну из них с правильными аргументами.
Вариант «результат или Failed» — практичный приём: агент не выдумывает данные, когда их нет, а явно возвращает отказ, и твой код это видит через обычный if.
Валидация с ограничениями
Поля могут иметь правила — и они реально проверяются:
from pydantic import BaseModel, Field
from typing import Literal
class SeatPreference(BaseModel):
row: int = Field(ge=1, le=30) # ряд строго от 1 до 30
seat: Literal['A', 'B', 'C', 'D', 'E', 'F'] # только эти буквы
Если модель вернёт ряд 42 — Pydantic AI не пропустит ответ, а отправит модели ошибку и попросит исправить. Это и есть механизм retries: количество попыток настраивается, по умолчанию одна дополнительная.
Своя проверка: output_validator
Когда правил «в полях» мало, добавляется своя функция-проверка. Классика — агент пишет SQL-запрос, а валидатор проверяет его на настоящей базе:
from pydantic_ai import ModelRetry
@agent.output_validator
async def validate_sql(ctx, output: Success) -> Success:
if not is_valid_query(output.sql_query):
raise ModelRetry('Запрос некорректен, исправь') # модель попробует снова
return output
ModelRetry — ключевое слово этого урока. Это способ сказать модели «не годится, попробуй ещё раз» — автоматически, без участия человека. Так строится самоисправляющийся цикл.
Три режима под капотом
Знать глубоко не обязательно, но полезно понимать, что фреймворк умеет добиваться структуры тремя способами и выбирает совместимый с твоей моделью:
| Режим | Как работает |
|---|---|
| Tool Output (по умолчанию) | Структура подаётся модели как «инструмент», который она обязана вызвать. Работает почти со всеми моделями. |
| Native Output | Используется встроенный режим structured outputs провайдера (например, у OpenAI). |
| Prompted Output | Схема вставляется в промпт — запасной вариант для простых моделей. |
Зачем это твоим проектам
- Умные формы: из диалога — объект заявки с полями и флагом качества лида. Ни одного «сломанного JSON» в CRM.
- Школа: из транскрипта эфира — структура «темы, тайм-коды, обещания участникам, задания». Дальше она автоматически раскладывается в GetCourse.
- Аналитика продаж: из вопроса «что с выручкой?» — готовый объект-запрос к базе с датами и фильтрами.