Перейти к содержанию
Публикация AiManual

Managed Deep Agents получили Connections: как безопасно хранить credentials и запускать действия от имени пользователя

Разбираем, как Connections в Managed Deep Agents v0.7.0+ выносят credentials из кода, .env и сборки в рабочее пространство LangSmith. На примерах Tavily, GitHub

Коротко

Что будет в материале

  1. 01

    Зачем агенту Connections

  2. 02

    Agent-owned и user-owned connections

  3. 03

    Статические секреты и OAuth-гранты

  4. 04

    Как создать connection

Connections в Managed Deep Agents v0.7.0+ выносят credentials из исходного кода, файлов .env и сборки агента в рабочее пространство LangSmith. Во время выполнения агент получает нужный секрет или OAuth-грант через connection и использует его для вызова внешнего сервиса.

Механизм решает две разные задачи. Agent-owned connection хранит общую учётную запись агента, например API-ключ Tavily. User-owned connection связывает действие с конкретным пользователем, например с его GitHub-аккаунтом. Отдельная классификация нужна для типа credentials: статический секрет работает по одной схеме, OAuth-грант требует согласия пользователя, обновления и отзыва.

Названия mda connections create и connections.get() указаны в описании механизма. Точные флаги CLI, формат параметров и доступность отдельных OAuth-возможностей нужно сверять с документацией установленной версии Managed Deep Agents. Ниже приведена практическая модель работы, которая помогает выбрать подходящую схему авторизации и не смешать общие секреты с персональными правами.

Зачем агенту Connections

Когда credentials лежат в коде или переменных окружения, секрет быстро распространяется по рабочему процессу. Он попадает в репозиторий, логи CI, дампы конфигурации, Docker-образы и резервные копии. Ротация такого секрета требует найти все места, где он использовался, заменить значение и перезапустить связанные процессы.

Connections отделяет секрет от логики агента. Код знает идентификатор подключения и запрашивает credentials во время выполнения. Секрет не требуется встраивать в prompt, передавать через инструмент вручную или хранить рядом с исходниками.

  • агентский код можно собирать и публиковать без API-ключа;
  • доступ к connection можно ограничивать на уровне рабочего пространства и среды;
  • общий секрет можно заменить без изменения логики инструмента;
  • персональный OAuth-грант можно отозвать отдельно от доступа других пользователей;
  • тип credentials становится частью архитектуры, а не случайной настройкой окружения.

Connections не отменяют контроль разрешений. Если агент получил право вызывать инструмент, он потенциально может передать этому инструменту данные из пользовательского запроса. Поэтому connection нужно связывать с минимальным набором scopes, разрешённых инструментов и понятным сценарием использования.

Общий контекст перехода от самостоятельного запуска агентов к управляемой инфраструктуре разобран в статье о managed-агентах и продакшн-разработке.

Agent-owned и user-owned connections

ТипЧья идентичность используетсяТипичный сценарийГлавный риск
agent-ownedОбщая учётная запись приложения или командыПоиск через общий API-ключ Tavily, плановая синхронизация, сервисный MCP-серверОдин секрет даёт одинаковый доступ всем запускам агента
user-ownedКонкретный пользовательРабота с личными репозиториями GitHub, календарём или персональным MCP-серверомОшибка в scope может дать агенту лишние права пользователя

Agent-owned connection

Такое подключение принадлежит агенту, проекту или рабочему пространству. Пользователь запускает действие, но внешний сервис видит одну заранее настроенную идентичность. Это подходит для задач, где результат не зависит от личных прав оператора.

Поиск публичной информации через общий API-ключ Tavily обычно относится к этой категории. Агенту нужен доступ к поисковому API, а персональная история, список репозиториев или права конкретного сотрудника не требуются.

Цена простоты очевидна: если агент получил возможность выполнять операции записи через общий connection, сервис не различит пользователей по OAuth-идентичности. Для критичных операций понадобятся отдельные роли, подтверждение действия или user-owned connection.

User-owned connection

User-owned connection создаётся после авторизации конкретного пользователя. Агент получает возможность действовать с его идентичностью, но область доступа задаётся OAuth scopes и политикой интеграции.

Сценарий с GitHub хорошо показывает разницу. Агент может читать issues пользователя, создавать pull request или работать с выбранными репозиториями, если соответствующие разрешения были выданы. Запуск от имени пользователя не означает автоматического доступа ко всем его ресурсам.

При отзыве гранта в GitHub действие должно перестать работать для этого пользователя, даже если сам агент продолжает обслуживать остальных. Такой уровень изоляции недостижим, когда вся команда использует один API-ключ.

Статические секреты и OAuth-гранты

МодельКак проходит авторизацияКогда подходитЧто контролировать
Статический секретАгент отправляет API-ключ или другой заранее созданный секретОбщий сервисный доступ, автоматические задачи, API без пользовательского согласияХранение, ротацию, срок действия, лимиты и отзыв ключа
OAuth-грантПользователь подтверждает доступ, после чего агент использует выданный грантПерсональные аккаунты, пользовательские ресурсы и действия с индивидуальной историейScopes, срок действия, refresh, отзыв и повторную авторизацию

Статический секрет проще запустить в планировщике или серверном процессе. У него нет интерактивного согласия пользователя, зато любой процесс с доступом к connection получает одну и ту же идентичность.

OAuth-грант требует более сложного жизненного цикла. Пользователь проходит авторизацию, сервис сохраняет выданные данные, агент получает их при вызове инструмента, а после истечения срока действия запускается обновление или повторное согласие.

Один тип credentials нельзя механически заменить другим. Для общего поиска OAuth добавит лишнюю зависимость от пользователя. Для изменения личного репозитория общий API-ключ создаст слишком широкую и плохо контролируемую модель доступа.

Как создать connection

Базовая точка входа, указанная для Managed Deep Agents, выглядит так:

mda connections create

Команда должна привести к созданию connection в выбранном рабочем пространстве. В зависимости от версии и провайдера понадобятся имя подключения, тип credentials, владелец, данные OAuth или статический секрет. Точный набор флагов нельзя безопасно восстановить без CLI reference, поэтому не стоит переносить параметры из примера в продакшен вслепую.

Перед созданием подключения зафиксируйте четыре решения:

  1. Владелец. Выберите agent-owned для общей сервисной идентичности или user-owned для действий конкретного пользователя.
  2. Тип credentials. Укажите статический секрет, OAuth-грант или другой тип, который поддерживает провайдер.
  3. Область доступа. Составьте минимальный набор scopes и разрешённых операций.
  4. Среда. Разделите рабочие, тестовые и локальные подключения, чтобы эксперименты не использовали боевой секрет.

Логическая модель connection может выглядеть так:

name: github-personal
owner: user-owned
credential_type: oauth
scopes: repository-read

Это схема для проектирования, а не гарантированный payload API. Реальные имена полей и допустимые значения нужно проверить в интерфейсе конкретной версии.

Как агент получает credentials

В описании механизма для чтения credentials используется вызов connections.get(). На уровне логики агент сначала получает connection, затем передаёт результат нужному инструменту:

credentials = connections.get(connection_name)
result = tool.call(credentials=credentials)

Код инструмента не должен просить пользователя вставить API-ключ в prompt. Агент получает ссылку на подключение, а рантайм разрешает доступ к credentials во время выполнения.

Такой вызов нужно окружить защитными правилами:

  • не выводить объект credentials в логи и трассировки;
  • не добавлять секрет в сообщение модели;
  • не возвращать его пользователю в тексте ответа;
  • не сохранять результат вызова в долговременной памяти агента;
  • проверять, что connection соответствует конкретному инструменту и среде.

Полезно отделять идентификатор подключения от названия внешнего сервиса. Например, github-personal-read лучше описывает назначение, чем общее имя github. Такая схема уменьшает риск случайно выдать инструменту connection с правами записи.

Пример с Tavily: общий API-ключ агента

Сценарий с Tavily подходит для agent-owned connection, если все пользователи должны выполнять поиск через одну сервисную учётную запись. Агент получает общий API-ключ и передаёт его поисковому инструменту во время вызова.

  1. Создайте отдельное подключение для поискового API.
  2. Назначьте ему владельца агента или проекта.
  3. Ограничьте connection только инструментом поиска.
  4. Проверьте лимиты и расходы на стороне провайдера.
  5. Заранее определите процедуру замены ключа.

В таком сценарии Tavily не получает идентичность конечного пользователя. Сервис видит общий ключ, а различать пользователей можно только через собственные журналы запуска агента и правила доступа платформы.

Для поиска это часто приемлемо. Для операций, где нужно знать автора изменения, общий ключ становится слабым местом. Изменение записи, отправка сообщения или публикация результата требуют user-owned connection либо отдельного механизма подтверждения.

Пример с GitHub: действие от имени пользователя

Персональная авторизация в GitHub требует user-owned connection. Пользователь проходит OAuth-согласие, после чего агент получает грант с ограниченными разрешениями.

Перед подключением определите, какое действие действительно нужно:

  • чтение репозитория и issues;
  • создание ветки или pull request;
  • комментирование issue;
  • изменение файлов;
  • администрирование настроек репозитория.

Каждый пункт несёт разный риск. Если агенту нужен анализ кода, права записи не требуются. Если задача включает подготовку pull request, разрешение на публикацию нужно отделить от права на слияние изменений.

Действие от имени пользователя должно оставлять понятный след: какой пользователь выдал грант, какой connection использовался, какой инструмент был вызван и какой ресурс изменился. При отзыве доступа агент должен получить ошибку авторизации, а не перейти на общий ключ с более широкими правами.

MCP-серверы и Connections

MCP-сервер часто выступает промежуточным слоем между агентом и внешним API. Он предоставляет инструменты, а credentials нужны уже на границе с конкретным сервисом. Connections помогает вынести секреты из конфигурации агента и MCP-инструментов, но не заменяет проверку доверия к самому серверу.

Об архитектуре MCP, инструментах и рисках подключения можно прочитать в разборе Model Context Protocol для AI-агентов.

Для MCP возможны две базовые схемы:

СценарийConnectionИдентичность
Командный MCP-сервер с общим сервисным API-ключомAgent-owned, статический секретОдна сервисная учётная запись
Персональный MCP-сервер или пользовательский аккаунтUser-owned, OAuth-грантКонкретный пользователь
Сервер с разными ролями для разных средОтдельные connections для dev, staging и productionИдентичность зависит от среды

Перед подключением MCP-сервера проверьте список инструментов, операции записи, сетевые направления и способ передачи credentials. Инструмент с именем search может быть относительно безопасным, а инструмент с возможностью выполнить произвольный запрос к API требует отдельного контроля.

Как автоматизировать OAuth-флоу

OAuth нельзя свести к созданию одного секрета. У него есть последовательность состояний:

  1. Агент или приложение запрашивает авторизацию для нужного connection.
  2. Пользователь подтверждает провайдера, аккаунт и запрошенные scopes.
  3. Сервис обменивает результат авторизации на грант.
  4. Грант связывается с user-owned connection конкретного пользователя.
  5. При вызове инструмента рантайм получает действующие credentials.
  6. После истечения срока действия запускается обновление или повторная авторизация.

Автоматический сценарий должен корректно обрабатывать отказ пользователя, отмену окна согласия, истечение grant и отзыв доступа у провайдера. Нельзя считать успешным подключением ситуацию, когда интерфейс сохранил идентификатор, но проверочный вызов не прошёл.

Для фоновых задач нужен отдельный вопрос: может ли refresh выполняться без присутствия пользователя. Если провайдер требует интерактивного согласия после каждого истечения срока, ночной запуск агента остановится до повторной авторизации. Это ограничение нужно учитывать при выборе user-owned модели.

Автоматизация не должна имитировать согласие пользователя и не должна получать более широкие scopes, чем требует инструмент. Для чувствительных действий полезно разделить чтение данных и операции записи на разные connections.

Ротация и отзыв секретов

СобытиеДействие для статического секретаДействие для OAuth-гранта
Плановая ротацияСоздать новый ключ, заменить значение в connection, выполнить проверочный вызов, отозвать старый ключПроверить срок действия и работу обновления гранта
КомпрометацияНемедленно отозвать ключ у провайдера и заблокировать connectionОтозвать грант пользователя и создать новый после проверки
Увольнение сотрудникаПроверить, не использовал ли сотрудник общий connectionОтозвать user-owned connection конкретного пользователя
Изменение ролиПересмотреть доступ сервисной учётной записиУдалить лишние scopes и повторить согласие

Ротация должна включать проверку после замены. Простое обновление значения без тестового вызова оставляет риск обнаружить проблему только во время пользовательской задачи.

При отзыве сначала заблокируйте использование connection в агенте, затем отзовите ключ или OAuth-грант у внешнего провайдера. После этого проверьте журналы запусков и удалите остаточные копии из временных файлов, кэшей и систем трассировки.

Локальная разработка

Локальный запуск требует отдельного решения о том, откуда рантайм получает connection. Если локальная среда не умеет обращаться к рабочему пространству LangSmith, нужно использовать поддерживаемый dev-механизм, а не копировать production credentials в .env.

Практичная схема для разработки выглядит так:

  • отдельное рабочее пространство или проект для тестов;
  • отдельный API-ключ с низкими лимитами;
  • отдельный OAuth-аккаунт или тестовый пользователь;
  • минимальные scopes;
  • короткий срок действия локальных секретов;
  • проверка, что логи и трассировки не содержат credentials.

Если локальный рантайм поддерживает тот же вызов connections.get(), проверьте поведение при недоступном рабочем пространстве, истёкшем гранте и отсутствии connection. Эти ошибки должны появляться до вызова внешнего инструмента, иначе агент может сформировать неполный или вводящий в заблуждение ответ.

Scopes и защита от опасных действий

Минимальный scope снижает последствия ошибки в prompt, неправильного выбора инструмента и компрометации процесса. Агенту для чтения документа не нужен доступ на удаление, а агенту для подготовки отчёта не требуется право публиковать изменения.

Для каждого connection зафиксируйте:

  • разрешённые инструменты;
  • допустимые внешние сервисы;
  • операции чтения и записи;
  • пользователя или сервисную роль;
  • условия подтверждения опасной операции;
  • срок действия и порядок отзыва.

Prompt injection особенно опасен там, где агент одновременно читает недоверенный текст и имеет право записи во внешний сервис. Текст из issue или документа может попытаться изменить поведение агента. Изоляция connection, allowlist инструментов и подтверждение операции перед записью ограничивают такой сценарий.

Практики governance для управляемых AI-агентов, включая разделение доступа и контроль действий, разобраны в материале об enterprise-контроле AI-агентов.

Как выбрать модель авторизации

ЗадачаПодходящий connectionПочему
Общий поиск через TavilyAgent-owned, статический API-ключРезультат не связан с личными правами пользователя
Чтение личных репозиториев GitHubUser-owned, OAuth-грантСервис должен видеть конкретного пользователя и его scopes
Ночная синхронизация командного сервисаAgent-owned, отдельный сервисный секретЗадача выполняется без интерактивного пользователя
Изменение пользовательских данных через MCPUser-owned, OAuth-грантНужно связать действие с владельцем данных
Тестирование нового инструментаОтдельный dev connectionОшибка не затрагивает рабочие ресурсы

Главный критерий выбора прост: если внешний сервис должен знать, кто инициировал действие, используйте user-owned модель. Если агент работает как самостоятельный сервис с общей ролью, подойдёт agent-owned connection. Тип credentials выбирайте после определения жизненного цикла: статический секрет удобен для фоновых задач, OAuth нужен для персонального доступа и пользовательского согласия.

Проверочный список перед запуском

  • Connection не хранится в исходном коде, сборке и prompt.
  • Определён владелец: agent-owned или user-owned.
  • Для каждого инструмента назначены минимальные scopes.
  • Чтение и запись разделены там, где это возможно.
  • Локальная, тестовая и рабочая среды используют разные подключения.
  • Секреты исключены из логов, трассировок и долговременной памяти.
  • Есть процедура ротации статических ключей.
  • Есть процедура отзыва OAuth-грантов.
  • Проверены ошибки при истёкшем или недоступном connection.
  • Опасные действия требуют отдельного подтверждения.

Connections полезны, когда credentials становятся управляемым ресурсом с владельцем, scope и жизненным циклом. Общий API-ключ Tavily можно оставить agent-owned, персональный GitHub-доступ привязать к user-owned OAuth-гранту, а для MCP выбрать модель после проверки того, чью идентичность должен видеть внешний сервис.

Перед публикацией интеграции проверьте точные параметры mda connections create, сигнатуру connections.get(), поддержку OAuth и поведение локального рантайма в документации своей версии Managed Deep Agents. Это особенно важно для v0.7.0+, где интерфейс и доступные провайдеры могут зависеть от конкретной сборки.

Подписаться на канал