Pydantic AI · курс Глоссарий
Урок 4 из 6 · ~12 минут

Инструменты и зависимости: руки агента

Модель умеет только писать текст. Инструменты дают ей возможность действовать: искать, считать, работать с базой.

Что такое инструмент

Инструмент (tool) — обычная Python-функция, которую ты «показываешь» агенту. Модель сама решает, когда её вызвать и с какими аргументами, получает результат и продолжает рассуждать. Так агент из «говорилки» превращается в исполнителя.

Регистрация — просто пометка над функцией:

import random
from pydantic_ai import Agent, RunContext

agent = Agent('google:gemini-3-flash-preview', deps_type=str)

@agent.tool_plain          # простой инструмент, контекст не нужен
def roll_dice() -> str:
    """Бросить шестигранный кубик."""
    return str(random.randint(1, 6))

@agent.tool                # инструмент с доступом к контексту запуска
def get_player_name(ctx: RunContext[str]) -> str:
    """Узнать имя игрока."""
    return ctx.deps

Пример из документации по tools. Два декоратора: @agent.tool_plain — без контекста, @agent.tool — с контекстом.

Откуда модель знает, как пользоваться функцией

Pydantic AI автоматически собирает «паспорт» инструмента из самого кода: имена и типы аргументов берутся из сигнатуры функции, а описания — из docstring (комментария-описания). Модель получает аккуратную схему и понимает, что делает функция и что ей передавать.

Практический вывод: понятные имена функций и внятные описания — это не «красота кода», а буквально качество работы агента. Модель читает их как инструкцию.

Зависимости: как агент получает доступ к твоей системе

Инструментам почти всегда нужно что-то внешнее: API-ключ, подключение к базе, id текущего пользователя. Передавать это через глобальные переменные — путь к хаосу. Pydantic AI предлагает зависимости (dependencies): аккуратный контейнер, который отдаётся агенту при каждом запуске.

from dataclasses import dataclass
import httpx
from pydantic_ai import Agent, RunContext

@dataclass
class MyDeps:
    api_key: str
    http_client: httpx.AsyncClient

agent = Agent('openai:gpt-5.2', deps_type=MyDeps)

@agent.tool
async def get_joke_material(ctx: RunContext[MyDeps], subject: str) -> str:
    response = await ctx.deps.http_client.get(
        'https://example.com#jokes',
        headers={'Authorization': f'Bearer {ctx.deps.api_key}'},
    )
    return response.text

# при запуске передаём реальные объекты:
result = await agent.run('Расскажи шутку', deps=MyDeps(key, client))

Внутри любого инструмента контекст ctx.deps — это твой контейнер. Пример из документации по dependencies.

Зачем такие сложности? Ради тестов

Главный выигрыш зависимостей — их можно подменить. В тестах вместо боевой базы подставляется заглушка, и вся логика агента проверяется бесплатно и безопасно:

with joke_agent.override(deps=test_deps):   # подменяем на время теста
    result = await application_code('Tell me a joke.')

В связке с TestModel из урока 2 получается полноценный автотест агента: ни одного реального вызова нейросети и базы, а логика проверена.

Картина целиком

Один запуск агента с инструментами выглядит так:

  1. Твой код запускает агента с вопросом и зависимостями.
  2. Модель читает инструкции и список инструментов.
  3. Решает: «мне нужно проверить базу» — вызывает инструмент.
  4. Инструмент выполняет настоящий код и возвращает результат модели.
  5. Шаги 3–4 повторяются, пока модель не соберёт всё нужное.
  6. Модель формирует финальный ответ в формате output_type — Pydantic AI его валидирует.

Весь этот цикл фреймворк ведёт сам. Ты пишешь только функции и структуру результата.

💬 Спроси агента в Claude Code: «какие инструменты понадобились бы агенту-куратору моей школы?» — интересное упражнение на проектирование.
← Урок 3. Структурированный вывод Урок 5. Мультиагентные системы →