Первый агент: устройство и запуск
Разбираем агента на детали: из чего он состоит и какими способами запускается.
Агент — это контейнер
В Pydantic AI агент — не что-то мистическое. Это объект-контейнер, в котором собрано всё нужное для общения с моделью: инструкции, выбранная модель, инструменты и описание результата. Документация называет его первичным интерфейсом работы с LLM.
Хорошая аналогия — сотрудник с должностной инструкцией. Один агент отвечает за один участок работы: «квалификатор лидов», «составитель конспектов», «проверяющий квизов». В приложении агентов может быть несколько, и создают их обычно один раз, глобально — а потом много раз запускают.
Из чего состоит агент
- Модель — строка вида
'провайдер:модель', например'openai:gpt-5.2'. - Инструкции (
instructions) — «должностная инструкция»: кто он и как себя вести. - Тип результата (
output_type) — что агент обязан вернуть (текст, число, структура). Подробно — в уроке 3. - Инструменты (
tools) — функции, которые модель может вызывать. Разберём в уроке 4. - Зависимости (
deps_type) — данные и сервисы, которые агент получает при запуске: ключи, клиент базы данных, id пользователя. - Настройки модели — температура, лимит токенов и т.п.
instructions или system_prompt?
В коде встречаются оба параметра, и они похожи. Разница тонкая: system_prompt сохраняется в истории сообщений и «едет» дальше, если ты передашь историю другому агенту; instructions действуют только на текущий запрос. Документация рекомендует по умолчанию использовать instructions.
Пример: агент с инструментом
from pydantic_ai import Agent, RunContext
roulette_agent = Agent(
'openai:gpt-5.2',
deps_type=int, # агенту при запуске дадут число
output_type=bool, # агент обязан вернуть да/нет
system_prompt='Через функцию roulette_wheel проверь, выиграл ли клиент.',
)
@roulette_agent.tool
async def roulette_wheel(ctx: RunContext[int], square: int) -> str:
"""Проверить, выигрышная ли клетка."""
return 'winner' if square == ctx.deps else 'loser'
result = roulette_agent.run_sync('Ставлю на 18', deps=18)
print(result.output) # True
Обрати внимание: результат — настоящий True/False, а не строка «да, поздравляю!». С этим можно работать дальше в коде без парсинга.
Способы запуска
| Метод | Что делает | Когда нужен |
|---|---|---|
run_sync() | Запускает и ждёт полный ответ | Скрипты, простые сценарии |
run() | То же, но асинхронно (await) | Веб-приложения, боты — почти весь продакшн |
run_stream() | Отдаёт ответ по кусочкам | Чтобы текст «печатался» в чате на глазах у пользователя |
run_stream_events() | Поток всех событий: вызовы инструментов, статусы | Показать «агент ищет в базе…» в интерфейсе |
Диалог с памятью
Сам агент не хранит историю — она передаётся явно, и это удобно: историю ты кладёшь в свою базу и полностью контролируешь.
result1 = agent.run_sync('Кто такой Эйнштейн?')
result2 = agent.run_sync(
'Какое его самое известное уравнение?',
message_history=result1.new_messages(), # передаём контекст
)
Тестовая модель — запуск без ключей
Укажи модель 'test' — и агент отработает без единого запроса к нейросети и без затрат. Незаменимо для проверки логики и автотестов:
agent = Agent('test')
result = agent.run_sync('Любой вопрос') # мгновенный ответ-заглушка
Страховка от перерасхода: при запуске можно задать usage_limits — жёсткий лимит запросов и токенов на один запуск. Агент физически не сможет уйти в бесконечный цикл и сжечь бюджет.