Гайд · TNWS AI

Как записать ручной вызов функции через function_span Agents SDK

6 мин

Инструментируем функцию function_span, записываем JSON-вход и выход и проверяем отсутствие секретов в трассировке.

Задача и область применения

Практическая задача — увидеть аргументы и результат внутренней функции рядом с автоматическими tool spans. Для неё используется точный интерфейс function_span(name, input, output). Ручной span нужен, когда операция выполняется вне стандартной обвязки Runner или когда требуется отдельный типизированный участок внутри общей трассы. Если SDK уже автоматически создаёт нужный span, второй такой же вручную добавлять нельзя: получите дубликаты и неверную картину длительности.

Факты проверены 12 сентября 2026 года по официальному руководству OpenAI Agents SDK по tracing и официальному API reference tracing. function_span принимает строковые input и output; без контекстного менеджера span требуется запускать и завершать вручную. Здесь нет цен, тарифов или неподтверждённых лимитов: они не влияют на контракт helper. Версию пакета фиксируйте lock-файлом и перепроверяйте сигнатуру при обновлении.

Что должно получиться

Результат — завершённый span с ожидаемым типом и полями, вложенный в корректную trace. Проверка должна читать span_data или события тестового processor, а не полагаться только на внешний dashboard. Идентификаторы генерируются SDK; жёстко заданные span_id нужны только при интеграции с системой, которая уже выдала корректный ID.

Перед началом создайте staging-проект и безопасные тестовые данные. Не используйте реальный prompt, аудиозапись клиента, токен, email или ответ внутренней системы. Поля input/output некоторых spans специально способны хранить содержимое операции, поэтому политика чувствительных данных важнее удобства отладки.

Пошаговые действия

  1. Установите пакет openai-agents в отдельное окружение и зафиксируйте версию в lock-файле.
  2. Создайте общую trace через context manager. Он гарантирует правильные start и finish даже при исключении.
  3. Внутри trace откройте нужный helper span также через with. Передайте только поля, подтверждённые API reference.
  4. Выполните целевую операцию. Не подменяйте её искусственной задержкой в production; тестовый stub допустим только в воспроизводимом примере.
  5. Проверьте span_data и бизнес-результат assert-ами. Проверка одного span_id недостаточна: она доказывает создание объекта, но не корректность данных.
  6. Запустите негативный сценарий из отдельного раздела. Ошибка операции должна быть отличима от пустого успешного результата.
  7. Подключите тестовый TracingProcessor, если нужно проверить полный экспорт. Его callbacks должны быть быстрыми и потокобезопасными.
  8. Перед релизом выполните два параллельных workflow и подтвердите, что trace_id и parent_id не смешиваются.

Готовый код

import json
from agents import function_span, trace

def lookup_order(order_id): return {"status":"packed"}

with trace("order_workflow"):
    safe_input=json.dumps({"order_id":481})
    with function_span("lookup_order",input=safe_input) as span:
        result=lookup_order(481)
        span.span_data.output=json.dumps(result)
        assert result["status"]=="packed"
        print(span.span_id,result)

Пример можно копировать в unit или integration test. Если он содержит заглушку ответа, замените её реальным объектом только после того, как минимальный контракт пройдёт локально. Не печатайте весь export span в общем CI-логе: там могут быть input/output. Для проверки извлекайте только разрешённые поля.

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

Вход: Функция lookup_order получает order_id 481 и возвращает status=packed.

Ожидаемый результат: Завершённый function span содержит имя lookup_order, безопасный JSON-вход и JSON-выход packed.

Для автоматической проверки сравнивайте тип span, поле span_data, trace_id, parent_id и факт завершения. Время выполнения нельзя сравнивать с придуманным нормативом: сеть и среда различаются. Если нужны SLO, сформируйте их по собственной статистике, а не по примеру из статьи.

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

Добавьте тестовый маркер SECRET-DO-NOT-EXPORT в локальный объект, но не в input/output span. Сериализованная трасса не должна содержать этот маркер.

Смысл негативного теста — доказать границу ответственности helper. Tracing описывает случившееся, но не валидирует бизнес-маршрут, существование tool, корректность usage и безопасность данных автоматически. Эти инварианты обеспечивает приложение до передачи значений в span.

Как встроить в production

Создайте небольшой слой observability с функциями предметной области: record_order_lookup, record_route, record_audio_stage. Внутри они вызывают официальный helper и фильтруют разрешённые поля. Тогда разработчик не сможет случайно положить полный объект пользователя в data. Список разрешённых ключей храните рядом с политикой логирования.

Не создавайте второй ручной span поверх автоматического одноимённого span Runner. Сначала посмотрите baseline trace. Ручная инструментализация оправдана для собственного adapter, запроса к базе, внешней очереди или нестандартного этапа. Имена spans должны быть стабильными: динамический order_id в имени раздувает кардинальность; его место — в безопасных metadata или внутренней корреляции.

При исключении используйте context manager и set_error там, где нужна дополнительная классификация. После фиксации ошибки не проглатывайте исключение без явной бизнес-логики. Для чувствительных generation, function и audio spans используйте настройки исключения чувствительных данных; ручное маскирование одной строки не защищает соседние поля.

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

Тип span: function_span(name, input, output)
Почему автоматического span недостаточно: <причина>
Родительская trace/span: <имя>
Разрешённые поля span_data: <список>
Тестовый вход: <без PII и секретов>
Ожидаемые поля: <точные значения>
Негативный сценарий: <ошибка или пустой результат>
Поведение исключения: <повторно выбрасывается/обработано>
Маркер чувствительных данных отсутствует в export: <да>
Параллельный тест parent_id: <пройден>
Ссылка на официальный API reference: https://openai.github.io/openai-agents-python/ref/tracing/

Шаблон отделяет телеметрию от бизнес-операции и делает ревью проверяемым.

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

  • Helper и его параметры сверены с документацией 12 сентября 2026 года.
  • Span открыт внутри ожидаемой trace или parent span.
  • Context manager гарантирует завершение при исключении.
  • span_data содержит только разрешённые поля.
  • В input/output нет ключей, токенов и реальных PII.
  • Позитивный результат проверяется assert.
  • Негативный тест отличает ошибку от пустого успеха.
  • Не создаётся дубликат автоматического Runner span.
  • Имена spans не содержат динамические идентификаторы.
  • Параллельные traces не смешивают parent_id.
  • Ошибка tracing не ломает основной workflow.
  • Версия зависимости зафиксирована в lock-файле.

FAQ

Нужно ли вручную вызывать start и finish?

Нет, если helper используется через context manager with. При ручном управлении оба вызова обязательны; context manager проще и надёжнее закрывает span при исключении.

Когда передавать parent явно?

Когда span создаётся вне текущего context или нужно привязать его к конкретному trace/span. В обычном вложенном коде helper использует текущий контекст автоматически.

Можно ли записывать полный input и output?

Технически некоторые helpers это поддерживают, но решение принимает политика данных. В production лучше сохранять минимальные технические поля и отключать чувствительное содержимое там, где оно не требуется.

Почему dashboard недостаточен для теста?

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

Доступен ли tracing для ZDR-организаций?

Официальное руководство сообщает, что tracing недоступен организациям с политикой Zero Data Retention для API OpenAI. Уточните политику своего проекта до внедрения.

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

Комментарии

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