Гайд · TNWS AI

Как объединить аудиоэтапы через speech_group_span Agents SDK

5 мин

Создаём speech_group_span для одного голосового ответа, вкладываем speech_span и проверяем общую родительскую связь.

Практическая задача

В этом гайде решается задача: объединить подготовку текста и синтез речи в один наблюдаемый голосовой этап. Используется официальный интерфейс speech_group_span(input). Материал нужен, когда стандартной автоматической трассировки Runner недостаточно или требуется строго проверить tracing context. Если обычный Runner уже создаёт тот же span, ручное дублирование запрещено: оно искажает дерево и длительность.

Факты проверены 12 сентября 2026 года (проверены сигнатура, параметры, контекстный жизненный цикл и экспорт; при обновлении зависимости контракт нужно проверить повторно) по руководству OpenAI Agents SDK по tracing и официальному API reference. speech_group_span принимает исходный текст и создаёт родительский span для связанных аудиоопераций. Изменяемые цены, тарифы и неподтверждённые лимиты не используются. Версию пакета берите из lock-файла своего проекта.

Проверяемый результат

Критерий готовности — конкретное поле, parent_id, состояние contextvar, результат export или событие processor. Внешний dashboard полезен для просмотра, но не заменяет assert. Перед внедрением создайте baseline trace и сохраните только технические идентификаторы и типы spans.

Для примеров используйте staging и искусственные данные. Не помещайте в metadata, input, output и имя span реальные персональные данные, токены или полный ответ внутренней системы. Динамический ID клиента не должен становиться именем span: высокая кардинальность ухудшает анализ.

Пошаговая реализация

  1. Создайте виртуальное окружение, установите openai-agents и зафиксируйте зависимость.
  2. Откройте верхнеуровневую trace через context manager либо подготовьте ручной lifecycle с обязательным finally.
  3. Создайте нужный span/helper только в той области, которую он должен измерять.
  4. Передайте параметры строго по API reference. Не придумывайте дополнительные поля в типизированном helper.
  5. Выполните операцию и проверьте бизнес-результат независимо от tracing.
  6. Проверьте tracing-контракт: trace_id, span_id, parent_id, span_data или export.
  7. Запустите негативный сценарий и убедитесь, что он даёт отличимый результат.
  8. Проверьте два параллельных workflow: их текущие контексты не должны смешиваться.
  9. Для собственного processor добавьте force_flush и shutdown в жизненный цикл worker.
  10. Перед релизом выполните поиск тестового секретного маркера по сериализованным событиям.

Готовый код

import base64
from agents import speech_group_span, speech_span, trace

audio=base64.b64encode(b"test-pcm").decode()
with trace("voice_reply"):
    with speech_group_span(input="Заказ собран") as group:
        with speech_span(
            model="tts-test", input="Заказ собран",
            output=audio, output_format="pcm",
        ) as child:
            assert child.parent_id==group.span_id
            print(group.span_id,child.span_id)

Код содержит машинно проверяемые утверждения. В CI не заменяйте assert печатью. Если пример использует ConsoleSpanExporter, оставляйте его только в тестовой среде: вывод всей trace может содержать больше данных, чем разрешает production-политика.

Пример входа и ожидаемого результата

Вход: Фраза «Заказ собран» и безопасный тестовый PCM-маркер в base64.

Ожидаемый результат: Speech span вложен в speech_group_span: child.parent_id полностью совпадает с group.span_id.

Проверяйте структуру, а не случайные значения или длительность. Для ID важны формат, уникальность и сохранение связи; для context helper — тот же объект внутри области и None снаружи; для очереди — факт flush и отдельный учёт отброшенных элементов.

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

Создайте speech_span после выхода из group. Parent ID не должен совпасть; такой тест обнаруживает неверную область context manager.

Негативный тест показывает границу API: helper не проверяет бизнес-маршрут, монотонность turn или безопасность данных за приложение. Ошибка tracing не должна подменять основной результат, но нарушение обязательной политики конфигурации должно останавливать деплой.

Встраивание в production

Сосредоточьте tracing-настройки в одном bootstrap-модуле. Глобальные processors нельзя регистрировать на каждом HTTP-запросе. Локальные trace и spans создавайте рядом с операцией, но через небольшую обёртку предметной области, которая фильтрует разрешённые поля.

Contextvars автоматически помогают с async concurrency, однако новый поток или задача, созданная особым способом, требует отдельного теста переноса контекста. Не храните current trace в глобальной переменной. Всегда обрабатывайте None: функция может быть вызвана вне instrumented workflow или tracing может быть отключён.

Для ручного start/finish применяйте try/finally. Для processor задайте bounded queue, быстрые callbacks и явные метрики delivered, retried, dropped. Не объявляйте «потерь нет», если измеряется только число успешных экспортов. Для сериализации оставляйте include_tracing_api_key=False.

Копируемый шаблон ревью

Операция: speech_group_span(input)
Причина ручной настройки: <конкретная причина>
Ожидаемый parent: <trace/span>
Проверяемые поля: <список>
Вход без PII: <значение>
Ожидаемый результат: <точная структура>
Негативный тест: <сценарий>
Поведение при исключении: <finish/reset/shutdown>
Результат вне контекста: <None или другое>
Секретный маркер отсутствует в export: <да>
Параллельная изоляция: <пройдена>
Источник: https://openai.github.io/openai-agents-python/ref/tracing/

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

  • Сигнатура сверена с документацией 12 сентября 2026 года (проверены сигнатура, параметры, контекстный жизненный цикл и экспорт; при обновлении зависимости контракт нужно проверить повторно).
  • Нет дубликата автоматического span Runner.
  • Context manager или finally гарантирует завершение.
  • parent_id соответствует ожидаемому родителю.
  • ID создан официальным helper или самим SDK.
  • Имена стабильны и не содержат пользовательские ID.
  • Input/output не раскрывают секреты и реальные PII.
  • Позитивный критерий проверяется assert.
  • Негативный сценарий отличим от успеха.
  • Вне контекста корректно обрабатывается None.
  • Параллельные workflow изолированы.
  • Flush и shutdown включены там, где нужны.

FAQ

Почему лучше использовать with?

Context manager автоматически выполняет start и finish и корректно восстанавливает текущий контекст при исключении. Ручной lifecycle нужен только при реальной callback-границе.

Можно ли передавать собственный span_id?

Да, параметр предусмотрен, но используйте gen_span_id, чтобы получить корректный формат. Произвольный внешний ID предварительно валидируйте.

Что возвращают get_current_trace и get_current_span вне контекста?

Они возвращают None. Это нормальное состояние, а не исключение; вызывающий код обязан его обработать.

Нужно ли вызывать flush после каждого запроса?

Нет. BatchTraceProcessor экспортирует в фоне. Flush нужен, когда короткоживущая задача требует немедленной доставки перед завершением процесса или job.

Можно ли хранить tracing API key в to_json?

Метод имеет специальный флаг, но по умолчанию ключ исключён именно для защиты от случайного сохранения. Для обычного транспорта оставляйте значение False.

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

Комментарии

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