← Блог
Технологии4 сентября 2026 · 9 мин чтения

Погодный ИИ-агент на DeepSeek и Pydantic AI: тот же агент, другой SDK

Та же задача, что в прошлой статье, но на фреймворке команды Pydantic: нативный провайдер DeepSeek из коробки и контракт ответа, который фреймворк валидирует сам. Сравниваем с OpenAI Agents SDK на живом прогоне.

Команда Digital Paragonразработка ИИ-агентов
Иллюстрация к статье «Погодный ИИ-агент на DeepSeek и Pydantic AI»

В прошлой статье мы собрали погодного консультанта на OpenAI Agents SDK и наткнулись на грабли: DeepSeek не принимает response_format типа json_schema, поэтому контракт ответа пришлось валидировать вручную. Сегодня собираем ровно того же агента — тот же инструмент с Gismeteo, тот же контракт — но на фреймворке команды Pydantic, и посмотрим, сколько кода исчезнет.

Стек и установка

Pydantic AI — агентный фреймворк от команды, которая делает сам Pydantic: типизация и валидация здесь первоклассные граждане. Версия на момент написания (сентябрь 2026): 2.32.0 — код в статье проверен именно на ней.

pip install pydantic-ai

Ключ, как и раньше, выпускается в кабинете platform.deepseek.com и кладётся в переменную окружения DEEPSEEK_API_KEY — провайдер подхватит её сам.

Модель и контракт: одна строка провайдера

Никакого клиента AsyncOpenAI с base_url: у Pydantic AI есть нативный провайдер для DeepSeek, модель задаётся строкой «провайдер:модель». Контракт — та же Pydantic-модель, что в прошлой статье, передаётся параметром output_type. Главное отличие: JSON из ответа модели фреймворк парсит и валидирует сам, при ошибке — повторяет попытку, ручной разбор текста не нужен.

from pydantic import BaseModel, Field
from pydantic_ai import Agent

class WeatherReport(BaseModel):
    city: str = Field(description="Город, для которого составлен отчёт")
    temperature_c: int = Field(description="Текущая температура, °C")
    feels_like_c: int = Field(description="Ощущаемая температура, °C")
    advice: str = Field(description="Практичная рекомендация: что надеть и взять с собой")

agent = Agent(
    "deepseek:deepseek-v4-flash",  # нативный провайдер: ключ берётся из DEEPSEEK_API_KEY
    output_type=WeatherReport,      # контракт ответа, фреймворк валидирует его сам
    system_prompt=(
        "Ты — консультант по погоде. По вопросу пользователя определи город, "
        "вызови get_gismeteo_weather и составь короткий практичный отчёт. "
        "Температуры — ровно те, что вернул инструмент, без выдумок."
    ),
)

Грабли версии: фреймворк быстро едет

Честно о первых минутах переноса: в актуальной версии 2.32 параметр называется output_type, а не result_type, как в старых туториалах, а ключ не передаётся в конструктор агента — он берётся из окружения либо через явный провайдер. Оба раза мы получили TypeError и поправили код; если будете повторять по старым примерам — не удивляйтесь. Плюс фреймворка в том, что ошибки громкие и мгновенные: контракт не съезжает в тихий мусор.

Инструмент: та же живая погода с Gismeteo

Инструмент регистрируется декоратором @agent.tool; первым аргументом идёт контекст запуска, дальше — обычные аннотированные параметры. Логика парсинга — ровно та же, что в прошлой статье.

import re
import httpx
from pydantic_ai import RunContext

CITY_SLUGS = {
    "москва": "weather-moscow-4368",
    "санкт-петербург": "weather-sankt-peterburg-4079",
    "казань": "weather-kazan-4364",
}

@agent.tool
async def get_gismeteo_weather(ctx: RunContext[None], city: str) -> str:
    """Текущая температура и «ощущается как» со страницы города на Gismeteo."""
    slug = CITY_SLUGS.get(city.strip().lower())
    if slug is None:
        return "Город не найден. Доступны: " + ", ".join(sorted(CITY_SLUGS))
    url = f"https://www.gismeteo.ru/{slug}/"
    async with httpx.AsyncClient(timeout=15, headers={"User-Agent": "Mozilla/5.0"}) as http:
        page = (await http.get(url)).text
    temps = re.findall(r'<temperature-value[^>]*value="(-?\d+)"[^>]*from-unit="c"', page)
    if len(temps) < 2:
        return "Не удалось разобрать погоду на странице Gismeteo."
    return f"{city}: сейчас {temps[0]}°C, ощущается как {temps[1]}°C (данные Gismeteo, {url})"

Запуск

import asyncio

async def main() -> None:
    result = await agent.run("Сейчас в Москве тепло? Что надеть на прогулку?")
    report = result.output  # уже провалидированная Pydantic-модель
    print(f"{report.city}: {report.temperature_c}°C, ощущается {report.feels_like_c}°C")
    print("Совет:", report.advice)

asyncio.run(main())

Реальный прогон (deepseek-v4-flash, 4 сентября 2026):

Москва: 17°C, ощущается 16°C
Совет: На улице прохладно, но не холодно — одевайтесь в несколько слоёв. Подойдут
лёгкая куртка или джинсовка, свитер или лонгслив, удобные кроссовки. Возьмите
с собой ветровку или лёгкий шарф на случай ветра.

Тот же город, те же температуры с Gismeteo, тот же по смыслу совет — но в коде нет ни строчки ручного парсинга JSON. Сравните с прошлой статьёй: там контракт держался на нашей функции разбора с повтором, здесь он — ответственность фреймворка.

Какой SDK выбрать

  • OpenAI Agents SDK берите, если вы в экосистеме OpenAI и вам нужны трассировка, эскалации-хендоффы между агентами. На DeepSeek учтите грабли из прошлой статьи: структурированный вывод через output_type там не работает, контракт придётся закрывать вручную.
  • Pydantic AI берите, если хотите меньше кода и валидацию вывода из коробки: нативный провайдер «провайдер:модель», контракт в одну строку, ретраи при ошибках валидации. Цена — молодой фреймворк с быстрыми переименованиями.

Обе реализации мы прогнали вживую на одной задаче: цифры погоды совпали, контракт выполнен в обоих случаях. Выбор — вопрос вкуса команды, а не возможностей.

Что улучшить дальше

  • retries — параметр конструктора агента: сколько раз повторять попытку при ошибке валидации ответа.
  • deps_type — типизированные зависимости (конфиг, клиенты), которые инструменты получают через тот же контекст.
  • Стриминг и Logfire — потоковый ответ и наблюдаемость от той же команды разработчиков.
  • Кэш погоды и больше городов — точно так же, как в прошлой статье: архитектура это позволяет без изменений.

Итог пары статей: простой агент — это модель, факты и контракт. Фреймворк можно взять любой из двух; главное, чтобы контракт проверялся кодом, а данные приходили из инструмента.

Читайте также
Погодный ИИ-агент на DeepSeek: OpenAI Agents SDK + Pydantic 4 сен 2026 · 10 мин RAG или дообучение: что выбрать для базы знаний 14 авг 2026 · 9 мин Пилот ИИ-агента за две недели: что реально успеть 28 авг 2026 · 9 мин

Нужен такой агент в вашем процессе?

Обсудить задачу