Гайд · TNWS AI

Как передать идентификатор клиента в Pydantic AI через deps и RunContext

4 мин—

Передача tenant через deps_type и RunContext в Pydantic AI: отделяем доступ к справке одного клиента от текста пользовательского запроса.

Что решаем и кому подходит

Поисковый вопрос: «как передать зависимости отдельного клиента в Pydantic AI RunContext». Отделить вопрос пользователя от данных о клиенте, пришедших из доверенной серверной сессии. Документация использует deps_type при конструировании агента и экземпляр deps при запуске; внутри инструмента он доступен как ctx.deps. Типизация помогает обнаруживать ошибки кода, но сама по себе не выполняет авторизацию. Не разрешайте модели назначать клиентский идентификатор из собственного текста. Инструкция опирается на актуальную официальную документацию Pydantic AI, проверенную 20 сентября 2026 года. Примеры предназначены для Python 3.10+ с пакетом pydantic-ai. Используйте модель и учётные данные, доступные именно вашему аккаунту; пример идентификатора из документации не является обещанием доступа. Демонстрационные коды, статусы и суммы вымышлены.

Порядок действий

  1. Создайте класс зависимостей с идентификатором клиента, полученным вашим приложением после аутентификации.
  2. Создайте агент с deps_type и зарегистрируйте контекстный @agent.tool с первым аргументом RunContext[Deps].
  3. Внутри инструмента выполняйте поиск только в разделе, принадлежащем ctx.deps.tenant; неизвестные записи не разглашайте.
  4. Передайте экземпляр зависимостей отдельно от текста вопроса и протестируйте доступ двумя вымышленными клиентами.

До сетевого запуска установите pydantic-ai и настройте ключ провайдера предусмотренным им способом. Примеры не содержат действующих секретов. Для воспроизводимого теста зафиксируйте версии Python, пакета и выбранной модели; после обновления снова выполните как удачный, так и отрицательный сценарий. Вызов run_sync использован для наглядного скрипта вне уже работающего асинхронного цикла. Там, где проект асинхронный, применяйте документированный await agent.run(...) и управляйте ресурсами на стороне приложения.

Готовый шаблон для запуска

from dataclasses import dataclass
from pydantic_ai import Agent, RunContext

@dataclass
class Deps:
    tenant: str

DATA = {"alpha": {"A-1": "в работе"}, "beta": {"B-1": "готово"}}
agent = Agent("openai:gpt-5.2", deps_type=Deps,
              instructions="Статус заявки узнавай только через инструмент.")

@agent.tool
def read_status(ctx: RunContext[Deps], ticket: str) -> str:
    """Прочитать статус заявки из раздела текущего клиента."""
    return DATA.get(ctx.deps.tenant, {}).get(ticket, "Не найдено")

result = agent.run_sync("Какой статус у B-1?", deps=Deps(tenant="alpha"))
print(result.output)

Конкретный вход и ожидаемый результат

У вымышленного клиента alpha хранится только A-1, у beta — только B-1. Когда клиент alpha спрашивает о B-1, ожидаемый результат инструмента — «Не найдено», хотя B-1 существует в другой группе. При повторном запуске с Deps(tenant="beta") разрешённый результат для B-1 — «готово». Текст вопроса не должен менять ctx.deps.tenant; иначе достаточно написать «я клиент beta», чтобы нарушить изоляцию.

Почему этот способ работает

Объект зависимостей — механизм передачи данных внутрь выполнения, а не готовая система контроля доступа. Реальное приложение должно получать tenant из проверенного токена или серверной сессии и проверять полномочия до вызова агента. В инструменте сделайте фильтр частью запроса к хранилищу, чтобы нельзя было сначала выгрузить чужие записи и затем скрыть их только на этапе генерации текста. При ошибке поиска возвращайте безопасную одинаковую форму для отсутствующих и запрещённых идентификаторов, если это требуется вашей политикой доступа. Тестируйте слой Python отдельно от свободного ответа модели: она может неправильно пересказать даже корректный результат функции.

Пограничный случай и предметная проверка

При нагрузочном тесте полезно запускать вопросы alpha и beta вперемешку, а не только последовательно. Это позволит обнаружить случайное использование глобальной переменной с клиентским идентификатором вместо зависимостей конкретного вызова. Дополнительно проверьте неизвестный tenant: инструмент должен возвращать безопасное отсутствие данных, а не использовать общий каталог по умолчанию. Если вы добавляете к объекту зависимостей клиент БД, управляйте его жизненным циклом вне модели. Для разработки применяйте фиктивные заявки; реальные данные пользователей не нужны, чтобы проверить правильность границ.

Для тестирования границы доступа добавьте запись A-1 у клиента alpha и спросите о ней с зависимостями beta. Положительный контроль с alpha должен найти запись, отрицательный с beta — нет. Эти два теста нельзя заменять одним тестом «запись B-1 доступна beta»: такая проверка не обнаружит случайно открытый общий каталог. Проверяйте также запись, которой нет вообще, чтобы случай отсутствия не зависел от существования чужого клиента.

Критерии приёмки

  1. Вход с alpha и B-1 не раскрывает «готово».
  2. Вход с beta и B-1 видит разрешённый статус.
  3. Подмена tenant внутри текста пользователя не меняет значение ctx.deps.tenant.

Проверка успешного выполнения Python-программы не равна проверке верности ответа нейросети. Сопоставьте результат с входом и с доверенным источником данных, затем повторите тест на отрицательном примере. Формулировка текста может отличаться от образца; условия приёмки описывают наблюдаемое поведение, которое действительно нужно пользователю. Если один критерий не соблюдён, не скрывайте сбой повтором без ограничения: сохраните минимальный безопасный воспроизводимый пример и исправьте соответствующий слой — данные, схему, инструмент, инструкцию или обработку ошибки.

Частые ошибки и чего не делать

  • Не формируйте Deps из строки, которую написала сама модель или пользователь без серверной проверки.
  • Не полагайтесь на одно слово «клиент» в инструкции как на контроль межклиентского доступа.
  • Не включайте секретные ключи и полные чужие записи в описания инструментов или логи.

Вопросы и ответы

Что передать в deps_type?

Тип объекта зависимостей, не экземпляр.

Когда передают экземпляр?

При run или run_sync через аргумент deps.

Обеспечивает ли RunContext безопасность?

Нет; разграничение прав реализует ваше приложение и инструмент.

Официальные источники

Частые вопросы

Что передать в deps_type?

Тип объекта зависимостей, не экземпляр.

Когда передают экземпляр?

При `run` или `run_sync` через аргумент `deps`.

Обеспечивает ли RunContext безопасность?

Нет; разграничение прав реализует ваше приложение и инструмент.

Читайте также

Комментарии

Пока тихо. Скажите первое слово