Гайд · TNWS AI
Как извлечь поля заявки из русского письма через Pydantic AI и output_type
Пошаговое извлечение темы и номера заявки в Pydantic AI: схема BaseModel, конкретное письмо, проверка полей и ошибки, которые не исправит одна валидация.
Что решаем и кому подходит
Поисковый вопрос: «как извлечь структурированную заявку из письма через Pydantic AI». Получить объект с двумя строго названными полями из письма в поддержку, а не свободный пересказ. В официальном руководстве Pydantic AI для этого используется аргумент output_type с моделью Pydantic. result.output после удачного прогона — экземпляр заданного класса. Возможность модели создавать структурированный вывод зависит от выбранного провайдера и режима; не обещайте одинакового поведения всех моделей. Инструкция опирается на актуальную официальную документацию Pydantic AI, проверенную 20 сентября 2026 года. Примеры предназначены для Python 3.10+ с пакетом pydantic-ai. Используйте модель и учётные данные, доступные именно вашему аккаунту; пример идентификатора из документации не является обещанием доступа. Демонстрационные коды, статусы и суммы вымышлены.
Порядок действий
- Создайте схему заявки с номером и темой, определите допустимый формат номера в своей предметной области.
- Создайте Agent с проверенным идентификатором модели, инструкцией и
output_type=Ticket; ключ провайдера храните в окружении. - Передайте одно вымышленное письмо через
run_sync; результатом используйтеresult.output, а не произвольный текст ответа. - Проверьте тип объекта, извлечённые значения и отдельно соответствие исходному письму; негативным тестом сделайте письмо без номера.
До сетевого запуска установите pydantic-ai и настройте ключ провайдера предусмотренным им способом. Примеры не содержат действующих секретов. Для воспроизводимого теста зафиксируйте версии Python, пакета и выбранной модели; после обновления снова выполните как удачный, так и отрицательный сценарий. Вызов run_sync использован для наглядного скрипта вне уже работающего асинхронного цикла. Там, где проект асинхронный, применяйте документированный await agent.run(...) и управляйте ресурсами на стороне приложения.
Готовый шаблон для запуска
from pydantic import BaseModel, Field
from pydantic_ai import Agent
class Ticket(BaseModel):
number: str = Field(description="Номер обращения из письма")
topic: str = Field(description="Краткая тема письма")
agent = Agent("openai:gpt-5.2", output_type=Ticket,
instructions="Извлеки только прямо указанные данные. Не придумывай номер.")
letter = "Тема: доставка. Здравствуйте! По обращению A-204 не пришла посылка."
result = agent.run_sync(letter)
assert isinstance(result.output, Ticket)
print(result.output.model_dump())
Конкретный вход и ожидаемый результат
Вход: «Тема: доставка. Здравствуйте! По обращению A-204 не пришла посылка». Предметно ожидаются number="A-204" и тема о задержке доставки; словесная формулировка темы может отличаться. Второй вход «Где моя посылка?» не содержит номера: для него нельзя считать успехом аккуратный JSON с выдуманным идентификатором. Выберите политику отсутствующих значений — отдельное поле None, запрос на уточнение или отказ от автоматической записи — до запуска, а не после получения ответа.
Почему этот способ работает
BaseModel устанавливает форму, а не истинность извлечённых фактов. Модель может вернуть синтаксически правильную строку A-240 вместо A-204; схема это пропустит. Для номера заявки добавьте постпроверку по регулярному выражению и сопоставление с буквальным фрагментом входа. Если письмо содержит два разных номера, не выбирайте первый без правила: обозначьте, что главный номер — тот, который связан с текущим запросом, и сохраните неоднозначность для оператора. В рабочем конвейере не отправляйте ответ сразу в CRM после одной лишь проверки типа. Отдельно тестируйте русские буквы, дефисы, пробелы и сообщения с цитатой старой переписки.
Пограничный случай и предметная проверка
Полезный регрессионный набор содержит пять писем: одно стандартное, одно с двумя номерами, одно без номера, одно с кириллическим номером и одно с длинной цитатой предыдущего ответа. Для каждого заранее запишите ожидаемый номер либо явный признак неоднозначности. Проверяйте не буквальное совпадение темы, а наличие заданного смысла и отсутствие неподтверждённых обещаний. Если формат входа изменился после обновления почтового шаблона, запустите этот набор повторно. Точное имя модели в примере взято из документации и не является утверждением о том, что она подключена у каждого читателя.
Критерии приёмки
- Вывод имеет тип
Ticket, а ключи в сериализации названыnumberиtopic. - Номер
A-204взят из сообщения без перестановки цифр; смысл темы соответствует задержке. - На письме без номера автоматическая обработка не выдаёт несуществующий номер: предусмотрено явное решение оператора.
Проверка успешного выполнения Python-программы не равна проверке верности ответа нейросети. Сопоставьте результат с входом и с доверенным источником данных, затем повторите тест на отрицательном примере. Формулировка текста может отличаться от образца; условия приёмки описывают наблюдаемое поведение, которое действительно нужно пользователю. Если один критерий не соблюдён, не скрывайте сбой повтором без ограничения: сохраните минимальный безопасный воспроизводимый пример и исправьте соответствующий слой — данные, схему, инструмент, инструкцию или обработку ошибки.
Частые ошибки и чего не делать
- Не подменяйте
output_typeпросьбой «напиши JSON»: текст может оказаться невалидным или содержать лишние поля. - Не считайте прохождение Pydantic-валидации доказательством правильности всех фактов.
- Не записывайте реальные клиентские письма и ключи API в открытые примеры и журналы.
Вопросы и ответы
Можно ли сразу сохранить result.output?
Сначала проверьте предметные правила и затем сериализуйте через model_dump().
Нужен ли номер в каждом письме?
Если номер отсутствует, запросите уточнение или проектируйте необязательное поле; не выдумывайте его.
Одинаково ли работают все модели?
Нет. Поддержку режима вывода проверяют на конкретной модели и провайдере.
Официальные источники
Частые вопросы
Можно ли сразу сохранить `result.output`?
Сначала проверьте предметные правила и затем сериализуйте через `model_dump()`.
Нужен ли номер в каждом письме?
Если номер отсутствует, запросите уточнение или проектируйте необязательное поле; не выдумывайте его.
Одинаково ли работают все модели?
Нет. Поддержку режима вывода проверяют на конкретной модели и провайдере.
Читайте также
Как дать агенту Pydantic AI инструмент чтения справки без права записи
Инструмент tool_plain для чтения вымышленной справки: минимальные полномочия, пример вопроса, проверка вызова и защита от ложных ответов.
Как ограничить число обращений агента Pydantic AI к модели через request_limit
Ограничение числа модельных шагов Pydantic AI: UsageLimits(request_limit), обработка исключения и тест на цикл инструмента.
Как отклонить фактически неверный ответ Pydantic AI через output_validator
Выходной валидатор Pydantic AI на примере суммы заказа: проверка суммы по каталогу, ModelRetry, границы повторов и критерий приёмки.
Комментарии
Пока тихо. Скажите первое слово