Гайд · TNWS AI

Как скрыть чувствительные данные в tracing OpenAI Agents SDK

6 мин

Отключаем запись входов и выходов модели и tools через trace_include_sensitive_data, сохраняя техническую трассировку выполнения.

Конкретная задача и применимость

Здесь настраивается диагностировать агентный workflow без сохранения пользовательского текста и результатов tools с помощью точного интерфейса RunConfig(trace_include_sensitive_data=False). Это материал для Python-сервиса на OpenAI Agents SDK, где одного факта «tracing включён» недостаточно: нужна наблюдаемая и проверяемая семантика. Общая трассировка включена SDK по умолчанию, но конкретная операция из этого гайда меняет корреляцию, состав данных или способ экспорта.

Документация проверена 12 сентября 2026 года. Фактическая основа — официальное руководство по tracing и официальный API reference. по умолчанию чувствительные данные включаются; при False generation и function spans не сохраняют ввод и вывод, а официальный Responses endpoint может оставить response_id как корреляционные metadata. Цены, квоты и номера версий не приводятся: для этой операции они не нужны, а версия библиотеки должна фиксироваться lock-файлом проекта.

Результат, который будем доказывать

Готовность определяется не отсутствием исключения. Нужен проверяемый признак: конкретное поле trace, событие processor, отсутствие секретного маркера или завершённый экспорт. Сначала запускайте пример на staging-проекте. В metadata не помещайте prompt, email, телефон, токены и ответы tools. Для корреляции используйте внутренний непрямой ID.

До изменения сохраните контрольную trace со стандартной конфигурацией и запишите её структуру: trace_id, имена spans, parent_id и число событий. Это baseline. После изменения сравнивайте именно ожидаемую разницу. Если одновременно обновить SDK, exporter и конфигурацию, причину изменения определить будет трудно.

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

  1. Создайте виртуальное окружение, установите openai-agents и зафиксируйте разрешённую версию в lock-файле.
  2. Настройте ключи через переменные окружения или secret manager. Не вставляйте рабочий ключ в код, trace metadata и тестовый отчёт.
  3. Скопируйте пример ниже в отдельный интеграционный тест. Имена workflow и атрибуты замените на значения вашей предметной области.
  4. Выполните один контрольный запуск и сохраните только технические идентификаторы. Текст сообщения нужен лишь локальному assert и не должен попадать в общий лог.
  5. Проверьте позитивный критерий из раздела примера. Для processor считайте callbacks; для редактирования сериализуйте событие в тестовый sink; для flush проверяйте порядок закрытия контекста.
  6. Выполните негативный сценарий. Он должен отличать ошибочную конфигурацию от временной задержки backend.
  7. Запустите два параллельных trace. Их trace_id должны различаться, parent_id не должны пересекать workflows, а общий group_id допускается только если это один диалог.
  8. Добавьте cleanup: flush для критичного короткого job, shutdown для собственного processor и очистку тестовых данных по политике проекта.

Готовый пример

import asyncio
from agents import Agent, RunConfig, Runner, function_tool

@function_tool
def get_status(order_id: int) -> str:
    return "packed"

async def main():
    agent=Agent(name="Support",tools=[get_status])
    cfg=RunConfig(trace_include_sensitive_data=False)
    result=await Runner.run(agent,"Проверь заказ 481",run_config=cfg)
    print(result.final_output)

asyncio.run(main())

В примере нет универсального «попробуйте посмотреть dashboard»: состояние проверяется программно. Для реального exporter дополните тест контролируемым sink, потому что появление записи в веб-интерфейсе может быть отложено фоновой пакетной отправкой. Не делайте сетевой запрос внутри синхронного callback processor — складывайте событие в очередь.

Реалистичный вход и ожидаемый результат

Вход: Запрос содержит номер заказа 481, tool возвращает packed.

Ожидаемый результат: Структура trace и факт вызова сохраняются, но тексты model input/output и function input/output не должны присутствовать в соответствующих spans.

Зафиксируйте expected как автоматический критерий. Если сравнивается trace_id, проверяйте формат и уникальность, но не жёстко заданное случайное значение. Если сравнивается набор spans, используйте тип и имя, а не время выполнения: длительность зависит от среды и сети. Если проверяется отсутствие данных, ищите уникальные маркеры во всём сериализованном событии, включая error и metadata.

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

Автотест экспортера ищет маркеры «481» и «packed» в сериализованных spans. При безопасной конфигурации оба маркера отсутствуют.

Негативный тест важен, потому что tracing не должен ломать основной ответ агента. Сбой дополнительного exporter следует журналировать технически и обрабатывать внутри processor. При этом тест конфигурации обязан падать, если ожидаемая защита данных отключена или события отправляются не в тот проект. Разделяйте доступность observability и корректность бизнес-операции.

Производственная интеграция

Инициализируйте глобальные processors один раз при старте процесса. Повторная регистрация после каждого HTTP-запроса создаёт дубликаты. Конфигурацию отдельного run передавайте через RunConfig, когда поведение действительно относится только к нему. Глобальные set-функции меняют процесс целиком и требуют явного владельца в bootstrap-коде.

Собирайте минимальные metadata: environment, тип workflow, версия схемы, непрямой tenant ID. Полный пользовательский ввод остаётся в бизнес-системе с её правилами доступа. Для расследования связывайте записи по trace_id и внутреннему request_id, а не копируйте содержимое запроса во все системы.

Callback собственного processor должен быть потокобезопасным и быстрым. Правильная архитектура — bounded queue, фоновый exporter, счётчик отброшенных событий и ограниченное время shutdown. Не выдумывайте метрику успешности: считайте доставленные, повторённые и отброшенные записи отдельно. Ошибка очереди не должна зависать внутри Runner.

Шаблон проверки для pull request

Сценарий tracing: RunConfig(trace_include_sensitive_data=False)
Workflow: <стабильное имя>
Trace/group/request ID: <непрямые ID без PII>
Ожидаемые spans/callbacks: <точный список>
Проверяемое изменение относительно baseline: <одно изменение>
Маркер чувствительных данных: <тестовая строка>
Есть ли маркер в экспортированном событии: <да/нет по политике>
Поведение при недоступном exporter: <ожидаемая ошибка/очередь>
Порядок flush/shutdown: <описание>
Повторная инициализация не дублирует processor: <проверено>
Ссылка на trace в staging: <внутренняя ссылка>

Этот шаблон можно копировать без изменения структуры. Он заставляет указать одно проверяемое изменение, границы данных и поведение отказа.

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

  • Название workflow стабильно и понятно команде.
  • trace_id генерируется корректным helper или самим SDK.
  • group_id используется только для связанных запусков.
  • Metadata не содержат PII, prompt, tool output и секреты.
  • Позитивный критерий проверен кодом.
  • Негативный сценарий даёт ожидаемое отличие.
  • Глобальная конфигурация применяется один раз при старте.
  • Callback processor не выполняет долгий сетевой I/O.
  • Для короткой задачи определена политика flush.
  • Повторный запуск не создаёт дубликаты событий.
  • Отказ tracing не подменяет результат агента.
  • Источники повторно проверены 12 сентября 2026 года.

FAQ

Tracing включён автоматически?

Да, SDK включает его по умолчанию и создаёт spans для Runner, агента, генерации, tools, guardrails и handoffs. Но конкретные поля, sensitive data и processors всё равно требуют явной политики приложения.

Почему trace может появиться не сразу?

Стандартный BatchTraceProcessor отправляет данные фоновыми пачками. Если требуется гарантия сразу после job, завершите контекст trace и вызовите flush_traces. Для обычного долгоживущего процесса фоновая задержка допустима.

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

Технически поле принимает строку, но так делать не следует. Используйте непрямой ID диалога, который раскрывается до пользователя только в вашей системе с контролем доступа.

Что произойдёт при set_trace_processors?

Текущий список processors будет заменён. Стандартный экспорт в OpenAI исчезнет, если вы явно не сохранили processor, который его выполняет. Для добавочного приёмника используйте add_trace_processor.

Доступен ли tracing при Zero Data Retention?

Официальное руководство указывает, что tracing недоступен организациям, использующим API OpenAI по политике ZDR. Не обещайте доступность, пока это не подтверждено настройками вашей организации.

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

Комментарии

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