Гайд · TNWS AI

Как настроить sticky approval через always_approve в OpenAI Agents SDK

5 мин

Одобряем tool identity на остаток текущего run, проверяем повторные вызовы без новой паузы и границы решения для Hosted MCP.

Задача и критерий готовности

Задача — однократно подтвердить доверенный tool и не запрашивать approval повторно для той же identity в пределах текущего run. Результат считается готовым только при машинной проверке состояния session, RunState, interruption или event stream. Красивый ответ агента не заменяет доказательство.

Методы и поведение сверены 12 сентября 2026 года по официальной документации OpenAI Agents SDK. В статье нет выдуманных цен, квот и метрик.

Подтверждённый контракт

  • Per-call approval по умолчанию относится к конкретному call ID.
  • always_approve=True сохраняет решение для будущих вызовов той же tool identity в текущем run.
  • always_reject=True аналогично кеширует отказ.
  • Sticky decision хранится в RunState и переживает сериализацию.
  • Для HostedMCPTool identity образуют server_label и tool name; оба должны быть непустыми.

Каждый пункт проверяется отдельно. Не объединяйте доступность backend, корректность истории и качество ответа в один флаг success: это независимые слои.

Что подготовить

  • отдельную тестовую базу, Redis database или временный файл;
  • уникальный session_id, не совпадающий с ID реального пользователя;
  • fake tool и provider stub для контроля вызовов;
  • переменные окружения для ключей и строк подключения;
  • журнал безопасных агрегатов и версий без содержимого переписки.

Прежде чем запускать код, определите владельца соединения и cleanup. Для hosted storage проверьте, где фактически лежат данные. Для durable state считайте payload чувствительным: он включает app context и runtime metadata.

Пошаговая настройка

  1. Поставьте run на pause при первом вызове fake tool.
  2. Одобрите interruption с always_approve=True.
  3. Настройте тест так, чтобы модель запросила ту же tool identity повторно.
  4. Проверьте отсутствие второй паузы и ровно два исполнения; затем протестируйте другое имя tool.

После каждого шага записывайте наблюдаемый признак: число items, конкретный exception, наличие interruption, счётчик tool или факт завершения async iterator. Комментарий в коде не является проверкой.

Копируемый пример

state=paused.to_state()
first=paused.interruptions[0]
state.approve(first,always_approve=True)
resumed=Runner.run_sync(original_agent,state)
# Тестовый агент должен запросить тот же tool второй раз.
assert not resumed.interruptions
assert fake_tool_counter.value==2

Запускайте пример в отдельном virtualenv. Все ключи и URL берите из окружения; тестовые localhost-адреса не превращайте в production-конфигурацию автоматически. Заполнители paused, original_agent и fake counters должны быть определены вашим воспроизводимым fixture.

Реалистичный вход

Первый вызов lookup_account одобряется sticky, второй вызов того же tool возникает позже в run.

Ожидаемый результат

Второй вызов не создаёт interruption; другое tool name всё ещё требует отдельного решения.

Перенесите ожидание в assert. Для недетерминированного текста проверяйте сохранённый факт через model stub либо напрямую session items. Для approval проверяйте и interruptions, и execution counter.

Негативный тест

Используйте обычный approve без флага: второй вызов должен снова остановить run.

Негативная проверка меняет одно условие. Ошибка подключения не равна пустой истории, новый run не равен resume, другой session_id не является потерей данных, а отсутствие второй паузы допустимо только при подтверждённом sticky decision.

Готовый prompt для ревью

Проверь конфигурацию сценария «Как настроить sticky approval через always_approve в OpenAI Agents SDK». Для каждого факта найди исполняемое доказательство. Проверь ownership соединений, cleanup, секреты, session_id, число model/tool вызовов и негативный тест. Верни таблицу PASS/FAIL; если доказательства нет, ставь FAIL.

Prompt используйте после приложения кода и очищенного лога. Он не заменяет исполнение: языковая модель может назвать комментарий гарантией или пропустить неверный cleanup.

Независимая проверка

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

Считайте отдельно model calls, tool executions, session writes и approval interruptions. Один счётчик не описывает весь run. Для async cleanup добавьте fixture, который проверяет закрытие даже после исключения.

В CI сохраняйте версии пакета, exit code и агрегаты. Не сохраняйте encryption key, DATABASE_URL, Redis URL с паролем, сериализованный RunState или полный dialog в открытых artifacts.

Частые ошибки

Неправильное владение ресурсом

from_url может создать клиент или engine, который нужно закрыть. Если ресурс передан извне, его жизненный цикл может принадлежать приложению. Зафиксируйте это в одном месте.

Пустое значение считают успехом

Пустая история может означать новый ID, истёкший TTL, ошибку ключа или отсутствие записи. Тест должен различать причины и не возвращать универсальное «готово».

Approval смешивают с авторизацией

Решение оператора разрешает конкретный workflow SDK, но backend всё равно обязан проверить права пользователя и допустимость операции.

Cleanup выполняется только при успехе

Соединения закрывают в finally или lifecycle hook. Отдельно моделируйте исключение Runner и убеждайтесь, что dispose/close всё равно выполнен.

Чек-лист финальной проверки

  • Уникальный session_id не содержит PII.
  • Версия SDK зафиксирована.
  • Названия методов сверены 12 сентября 2026 года.
  • Секреты приходят только из окружения.
  • Есть штатный и негативный assert.
  • Model calls и tool executions считаются отдельно.
  • Cleanup работает после исключения.
  • Resume использует RunState, а не новый prompt.
  • Serialized state защищён как чувствительные данные.
  • Старые items не удаляются случайно retrieval-limitом.

Ограничения

Гайд проверяет технический контракт, но не соответствие нормативным требованиям, стоимость backend, качество модели и производительность. TTL, limit и схема retention выбираются по политике проекта; нельзя объявлять пример универсальным.

Шифрование session не отменяет управление ключами. Redis не даёт durable backup автоматически. SQLite branching не заменяет production database. Sticky approval действует в границах run и не должен превращаться в бессрочное разрешение.

FAQ

Нужно ли логировать всю историю?

Нет. Сохраняйте безопасные агрегаты и идентификаторы. Полная история и RunState требуют отдельного защищённого хранилища.

Почему недостаточно финального ответа?

Он не показывает, откуда взялась память, сколько раз выполнился tool и был ли run действительно возобновлён.

Что проверять после обновления SDK?

Импорты, constructor arguments, lifecycle close/dispose, сериализацию state и порядок approval.

Можно ли использовать реальные операции в тесте?

Нет. Approval, retry и cancellation сначала проверяются fake tool с измеримым счётчиком.

Первоисточник

Материал написан самостоятельно; тестовые идентификаторы не относятся к реальным пользователям.

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

Комментарии

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