Гайд · TNWS AI

Как зашифровать историю EncryptedSession в OpenAI Agents SDK

5 мин

Оборачиваем SQLAlchemySession в EncryptedSession, задаём ключ и TTL, проверяем чтение до срока и пропуск просроченных элементов.

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

Задача — прозрачно шифровать сохраняемые session items и автоматически исключать элементы после TTL. Результат считается готовым только при машинной проверке состояния session, RunState, interruption или event stream. Красивый ответ агента не заменяет доказательство.

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

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

  • EncryptedSession оборачивает любую совместимую session implementation.
  • Шифрование основано на Fernet.
  • Уникальные ключи сессий выводятся через HKDF.
  • TTL приводит к тихому пропуску старых элементов.
  • Один и тот же encryption_key нужен для последующего чтения; ключ нельзя хранить рядом с базой.

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

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

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

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

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

  1. Сгенерируйте и сохраните ключ в secret manager, а не в коде.
  2. Создайте underlying session и оберните её EncryptedSession с осознанным TTL.
  3. Запишите тестовый item и прочитайте тем же ключом.
  4. В тесте с управляемыми часами перейдите за TTL и подтвердите, что элемент пропущен.

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

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

import asyncio, os
from agents.extensions.memory import EncryptedSession, SQLAlchemySession

async def main():
    base=SQLAlchemySession.from_url("ticket-781",url="sqlite+aiosqlite:///secure.db",create_tables=True)
    session=EncryptedSession(session_id="ticket-781",underlying_session=base,encryption_key=os.environ["SESSION_KEY"],ttl=600)
    await session.add_items([{"role":"user","content":"Тикет T-781"}])
    items=await session.get_items()
    assert len(items)==1
    await base.engine.dispose()

asyncio.run(main())

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

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

Один обезличенный item записывается с TTL 600 секунд.

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

До TTL item читается; после искусственного сдвига времени отсутствует. Ключ в логе не появляется.

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

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

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

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

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

Проверь конфигурацию сценария «Как зашифровать историю EncryptedSession в 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 с измеримым счётчиком.

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

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

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

Комментарии

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