ПРАКТИЧЕСКОЕ СРАВНЕНИЕ

Langfuse, Phoenix или Opik: сравниваем три инструмента наблюдаемости AI-агента

Уровень: средний Время: 120 минут Результат: сравнительная таблица на одном сценарии агента

Список функций почти не помогает выбрать инструмент: у всех трёх есть трассы, метрики и интерфейс, но это ещё не означает, что в них одинаково легко найти лишний вызов, отделить задержку модели от задержки инструмента и подтвердить стоимость запуска. В этой лаборатории один и тот же AI-агент последовательно отправит одинаковые события в Langfuse, Phoenix и Opik. Мы не будем доверять демонстрационным графикам: подготовим контролируемую ошибку, сверим дерево выполнения с локальным журналом и заполним собственную оценочную таблицу.

Короткий вывод до лаборатории

Все три решения относятся к области наблюдаемости приложений с моделями. Выбирать следует не по числу пунктов на странице продукта, а по тому, насколько быстро конкретная команда отвечает на пять операционных вопросов:

  1. На каком шаге агент ошибся?
  2. Какой вход получил проблемный шаг?
  3. Где возникла задержка: в модели, инструменте или коде оркестрации?
  4. Из каких обращений сложилась стоимость запуска?
  5. Можно ли воспроизвести расследование локально и передать его другому разработчику?

Langfuse

Разумная отправная точка, когда нужен общий продуктовый контур: трассы, сессии, пользовательская обратная связь, оценки, промпты и расходы в одном интерфейсе.

Phoenix

Особенно удобен для локального исследования трасс и моделей, когда команда уже использует OpenTelemetry или хочет быстро открыть отладочный интерфейс рядом с ноутбуком.

Opik

Стоит проверить, когда трассировку нужно тесно связать с экспериментами, наборами примеров и оценкой изменений приложения.

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

Что именно мы сравниваем

AgentOps в этой статье означает практику эксплуатации агентов: сбор истории запусков, диагностику ошибок, измерение задержек, контроль расходов и проверку изменений. Мы оцениваем не весь продуктовый каталог, а пять свойств, указанных в задаче.

Критерий Что проверяем Плохой результат Хороший результат
Настройка Установка, подключение приложения, количество обязательных переменных и изменений в коде Непонятно, какой компонент не готов; ошибки появляются только после запуска агента Есть проверка здоровья, тестовая отправка и ясная ошибка конфигурации
Трассировка Связь запуска, модельного шага, вызовов инструментов, повторов и ошибок Плоский список несвязанных запросов Полное дерево с длительностью, статусом, входом и выходом каждого шага
Метрики Токены, стоимость, длительность, ошибки, число вызовов и фильтрация по сценарию Есть только общая сумма без возможности открыть исходный запуск Агрегат связан с конкретными трассами и проверяется по сырым данным
Локальный запуск Подъём без внешнего аккаунта, сохранение данных, повторный старт, экспорт «Локальный» интерфейс всё равно требует внешней передачи трасс Приложение и хранилище работают на машине, маршрут данных понятен
Отладка Сколько действий нужно, чтобы найти корневой шаг заданной ошибки Приходится сопоставлять события по времени вручную Ошибка находится через фильтр и раскрывается до проблемного дочернего шага

Сценарий: агент разбирает заявку

Тестовый агент получает заявку, просит LLM определить категорию, вызывает локальный инструмент поиска ответственного и затем формирует краткий итог. Внешние системы не нужны: инструмент читает маленький JSON-файл, а модельный ответ можно сначала имитировать детерминированной функцией.

запуск агента
├── classify_request       модельный шаг
├── lookup_owner           локальный инструмент
├── draft_answer           модельный шаг
└── save_result            запись JSONL

Трасса должна соответствовать одному запуску агента. Каждый дочерний спан представляет отдельный шаг. Такой контракт важнее конкретного SDK: если три системы получают разные деревья, сравнение интерфейсов теряет смысл.

Контролируемые варианты

Case ID Поведение Что должно появиться в трассе
CASE-OK Категория известна, владелец найден Четыре успешных шага и итоговый статус ok
CASE-SLOW Инструмент ждёт заданное время перед ответом Увеличена длительность только lookup_owner
CASE-RETRY Первый модельный вызов завершается временной ошибкой, второй успешен Две попытки внутри одного логического шага
CASE-FAIL Инструмент не знает категорию и возвращает контролируемую ошибку Ошибка инструмента, пропущенный финальный шаг и ошибочный статус корневой трассы
CASE-USAGE-NULL Модельный адаптер не сообщает расход input_tokens=null, output_tokens=null, cost=null, а не нули

Главное правило эксперимента: не подменяйте неизвестные значения нулями. Ноль означает подтверждённое отсутствие расхода, а null — отсутствие данных. Это различие напрямую влияет на финансовые отчёты.

Шаг 1. Подготовьте отдельный каталог

Не проводите сравнение внутри рабочего агента. Создайте изолированную лабораторию и храните в ней версии, сценарии и доказательства:

mkdir agentops-compare
cd agentops-compare
python3 -m venv .venv
. .venv/bin/activate
python -m pip install --upgrade pip

mkdir -p app adapters evidence exports
touch requirements.txt run-log.jsonl scorecard.csv versions.txt

На Windows активация окружения обычно выполняется командой:

.venv\Scripts\activate

Запишите исходные версии среды:

python --version > versions.txt
docker --version >> versions.txt
docker compose version >> versions.txt
git --version >> versions.txt

Если Docker не используется, зафиксируйте способ запуска каждого сервиса отдельно. Не смешивайте локальную установку одного инструмента с облачной версией другого: это уже два критерия одновременно.

Шаг 2. Зафиксируйте единый формат события

Локальный журнал нужен как контрольная точка. Он не заменяет платформу наблюдаемости, но позволяет проверить, не потерялся ли запуск при отправке. Одна строка соответствует одному завершённому шагу:

{
  "run_id": "RUN-001",
  "case_id": "CASE-OK",
  "trace_name": "lead_triage",
  "span_name": "classify_request",
  "parent_span": "lead_triage",
  "attempt": 1,
  "started_at": "2026-01-01T10:00:00.000Z",
  "finished_at": "2026-01-01T10:00:00.250Z",
  "duration_ms": 250,
  "status": "ok",
  "model": "configured-model-or-null",
  "input_tokens": null,
  "output_tokens": null,
  "cost": null,
  "currency": null,
  "error_type": null
}

В реальном запуске даты и числа создаются программой. Значения выше показывают только схему и не являются результатом теста.

Токены записывайте из структурированного поля ответа провайдера. Если провайдер сообщает только общее количество, не угадывайте разделение на вход и выход. Стоимость рассчитывайте лишь при наличии тарифа, единицы измерения и точного идентификатора модели.

input_cost =
  input_tokens / price_unit_tokens * input_price

output_cost =
  output_tokens / price_unit_tokens * output_price

run_cost =
  сумма подтверждённых input_cost и output_cost
  для всех попыток внутри run_id

Тариф не следует зашивать в код без даты действия. Храните его в отдельном файле конфигурации:

{
  "model_id": "exact-provider-model-id",
  "currency": "configured-currency",
  "price_unit_tokens": 1000000,
  "input_price": null,
  "output_price": null,
  "verified_at": null,
  "source_note": "Заполнить по действующему тарифу перед тестом"
}

Шаг 3. Реализуйте нейтральный агент

Агент должен одинаково работать без любой из трёх платформ. Наблюдаемость подключается адаптером, а бизнес-логика не меняется.

OWNERS = {
    "billing": "finance-queue",
    "access": "security-queue",
    "technical": "support-queue",
}

def classify_request(text, case_id):
    if case_id == "CASE-RETRY":
        # Первая попытка управляемо завершается временной ошибкой.
        # Счётчик попыток хранится в контексте конкретного запуска.
        pass
    return deterministic_category(text)

def lookup_owner(category, case_id):
    if case_id == "CASE-SLOW":
        controlled_delay_ms = 1200
        sleep(controlled_delay_ms / 1000)

    if case_id == "CASE-FAIL":
        raise LookupError("owner_not_found")

    return OWNERS[category]

def draft_answer(category, owner):
    return {
        "category": category,
        "owner": owner,
        "message": "Заявка принята и направлена ответственному."
    }

Задержка в CASE-SLOW задаётся вами заранее и записывается в паспорт теста. Не используйте случайную паузу: тогда нельзя понять, корректно ли интерфейс показал длительность.

Интерфейс адаптера

Каждый интеграционный модуль должен реализовать одинаковые операции:

class ObservabilityAdapter:
    def start_trace(self, run_id, case_id, input_data): ...
    def start_span(self, name, kind, attributes): ...
    def end_span(self, output_data, usage, status): ...
    def record_error(self, error_type, message): ...
    def end_trace(self, output_data, status): ...
    def flush(self): ...

Для шага модели используйте тип generation или его ближайший эквивалент. Для вызова инструмента — тип tool. Названия типов могут различаться между SDK, но имена трасс, шагов и пользовательские атрибуты должны оставаться одинаковыми.

Обязательные атрибуты

run.id
case.id
agent.name
agent.version
environment
step.name
step.kind
attempt.number
model.id
usage.input_tokens
usage.output_tokens
cost.total
cost.currency
error.type

Не помещайте секреты, ключи, полные персональные данные или системный промпт в атрибуты только ради удобства поиска. Для лаборатории используйте искусственные заявки.

Шаг 4. Поднимите инструменты по одному

Одновременный запуск трёх платформ экономит время, но повышает риск перепутать порты, базы и переменные. Сначала доведите до конца один прогон, экспортируйте доказательства, остановите сервис и только потом меняйте адаптер.

Перед установкой: выберите конкретный выпуск, прочитайте его файл примера переменных и выполните команду справки. Команды запуска могут меняться между версиями. Не используйте плавающую ветку или тег latest для итогового сравнения.

Langfuse

Для локального теста удобно использовать официальный Compose-комплект из закреплённого выпуска:

export LANGFUSE_VERSION="<проверенный-тег>"

git clone \
  --branch "$LANGFUSE_VERSION" \
  --depth 1 \
  https://github.com/langfuse/langfuse.git \
  vendor-langfuse

cd vendor-langfuse
docker compose config
docker compose up -d
docker compose ps
cd ..

Скопируйте предоставленный выпуском пример переменных, задайте собственные локальные секреты и не публикуйте файл. После открытия интерфейса создайте отдельный проект agentops-compare и получите ключи только для этого проекта.

export OBS_BACKEND="langfuse"
export LANGFUSE_PUBLIC_KEY="<локальный-project-key>"
export LANGFUSE_SECRET_KEY="<локальный-secret-key>"
export LANGFUSE_HOST="<локальный-адрес>"

В адаптере Langfuse свяжите корневое наблюдение с run.id, модельные шаги пометьте как генерации и передайте usage только из фактического ответа. Перед завершением процесса вызовите доступный в закреплённой версии метод flush.

Phoenix

Phoenix можно проверить отдельным Python-окружением. Не смешивайте его зависимости с приложением, если разрешение пакетов создаёт конфликт:

python3 -m venv .venv-phoenix
. .venv-phoenix/bin/activate
python -m pip install --upgrade pip
python -m pip install arize-phoenix
python -m pip freeze > evidence/phoenix-packages.txt

phoenix serve

В другом терминале активируйте окружение агента и настройте экспорт на локальный приёмник, указанный запущенной версией Phoenix:

export OBS_BACKEND="phoenix"
export PHOENIX_PROJECT_NAME="agentops-compare"
export PHOENIX_COLLECTOR_ENDPOINT="<адрес-локального-коллектора>"

Если используется OpenTelemetry, проверьте, какой протокол принимает конкретный выпуск: HTTP или gRPC. Несовпадение протокола часто выглядит как успешная работа агента без единой трассы в интерфейсе.

Opik

Для локального варианта закрепите тег официального репозитория и сначала изучите справку установочного сценария:

export OPIK_VERSION="<проверенный-тег>"

git clone \
  --branch "$OPIK_VERSION" \
  --depth 1 \
  https://github.com/comet-ml/opik.git \
  vendor-opik

cd vendor-opik
./opik.sh --help
./opik.sh
cd ..

Если выбранный выпуск предлагает Compose-команду вместо сценария, используйте именно способ из закреплённого выпуска и сохраните вывод docker compose config.

export OBS_BACKEND="opik"
export OPIK_PROJECT_NAME="agentops-compare"
export OPIK_URL_OVERRIDE="<локальный-адрес>"

В адаптере создавайте один trace на запуск и дочерние spans для шагов. После выполнения дождитесь отправки очереди SDK. Если процесс завершается сразу, буфер телеметрии может не успеть выгрузиться.

Шаг 5. Проверяйте готовность до запуска агента

Для каждого инструмента выполните четыре проверки:

  1. Контейнеры или процесс находятся в состоянии ready.
  2. Интерфейс открывается по ожидаемому локальному адресу.
  3. Хранилище доступно для записи.
  4. Минимальное тестовое событие появляется в отдельном проекте.
docker compose ps
docker compose logs --tail=100

curl -fsS "<health-endpoint-из-вашего-выпуска>"
python -m app.send_probe --backend "$OBS_BACKEND"

Не переходите к сценарию агента, пока probe не появился. Иначе при пустом интерфейсе придётся одновременно проверять бизнес-логику, SDK, сеть, авторизацию и сервер.

Шаг 6. Запустите одинаковую матрицу

Для каждого backend выполните сценарии в одном порядке. Идентификаторы запуска должны быть уникальными, но предсказуемыми:

python -m app.run --backend langfuse --case CASE-OK         --run-id LF-001
python -m app.run --backend langfuse --case CASE-SLOW       --run-id LF-002
python -m app.run --backend langfuse --case CASE-RETRY      --run-id LF-003
python -m app.run --backend langfuse --case CASE-FAIL       --run-id LF-004
python -m app.run --backend langfuse --case CASE-USAGE-NULL --run-id LF-005

Затем повторите команды с phoenix и префиксом PX, после этого — с opik и префиксом OP. Не меняйте текст заявок, задержку, правила повторов и структуру агента.

После каждого запуска:

Как проверять трассировку

Красивое дерево ещё не доказывает полноту данных. Для каждого run.id пройдите чек-лист:

Проверка дерева для повтора

lead_triage / CASE-RETRY
├── classify_request
│   ├── attempt 1 / temporary_error
│   └── attempt 2 / ok
├── lookup_owner / ok
├── draft_answer / ok
└── save_result / ok

Если две попытки оказались двумя независимыми корневыми трассами, платформа не сможет корректно показать стоимость логической задачи без дополнительной группировки.

Как проверять задержки

Сравнивайте не только общую длительность. Для одного запуска должно выполняться приближённое равенство:

total_latency
≈ orchestration_time
+ classify_latency
+ lookup_latency
+ draft_latency
+ save_latency
+ retry_backoff

Дочерние шаги могут выполняться параллельно, поэтому их длительности нельзя всегда просто складывать. В нашем сценарии шаги последовательны, что упрощает проверку.

Для CASE-SLOW сравните три значения:

Ожидается не точное равенство, а понятная разница, включающая накладные расходы вызова и измерения. Если замедлилась модельная генерация вместо инструмента, проверьте родительские связи и момент начала спана.

Как проверять токены и стоимость

Платформа может показать стоимость тремя способами:

  1. получить готовую сумму от приложения;
  2. получить usage и применить собственную таблицу цен;
  3. показать только токены, оставив стоимость неизвестной.

Во время сравнения запишите, какой путь использован. Одинаковые цифры в интерфейсе и локальном файле ничего не доказывают, если приложение само отправило готовую сумму в оба места.

Проверка Контрольный источник Допустимый результат Ошибка
Входные токены Структурированный usage ответа модели То же значение или документированная агрегация Оценка по символам представлена как факт
Выходные токены Структурированный usage ответа модели То же значение Включены токены другого запуска
Повторная попытка Две записи запросов В расход включены обе принятые провайдером попытки Показана только успешная попытка
Неизвестный usage null в адаптере N/A, unknown или пустое значение Отображается подтверждённый ноль
Стоимость Тариф с датой и точным model ID Формула воспроизводится Нет валюты, единицы или версии тарифа

Фактура провайдера остаётся окончательным финансовым источником. Трасса нужна для распределения расхода по агентам и этапам, но может не учитывать скидки, кэширование, налоги, пакетные тарифы или округление.

Как измерить удобство отладки

Не ставьте оценку «понравился интерфейс». Выполните одну и ту же задачу: найти причину CASE-FAIL, начиная с главной страницы проекта.

Записывайте:

Таймер запускайте после появления трассы в системе. Время доставки телеметрии измеряйте отдельно: это другая характеристика.

Единая шкала оценивания

Каждый критерий получает от 0 до 5 баллов. Не используйте половинные значения: они создают ложную точность.

Балл Интерпретация
0Проверку выполнить не удалось.
1Данные отсутствуют либо доступны только через ручное сопоставление внешних логов.
2Основной путь работает, но критичная часть неполна или требует обходного решения.
3Задача выполняется штатно, хотя требует заметной ручной настройки.
4Задача выполняется быстро, данные связаны и проверяемы.
5Есть удобный штатный путь, проверка воспроизводится другим человеком и не требует скрытого знания.

Сохраняйте рядом с баллом короткое доказательство. Запись «4 — хороший UI» бесполезна. Запись «4 — ошибка найдена фильтром по case.id, до дочернего шага три действия, ссылка сохраняет фильтр» позволяет повторить оценку.

Сравнительная таблица

Первая таблица — предварительная карта выбора по типичному фокусу инструментов. Она помогает решить, с чего начать тест, но не заменяет измерения на вашей версии и вашем стеке.

Критерий Langfuse Phoenix Opik
Основной практический фокус Продуктовая наблюдаемость LLM-приложений, трассы, сессии, оценки, промпты и расходы Исследование и отладка трасс, моделей и retrieval-пайплайнов с сильной опорой на открытые стандарты телеметрии Трассировка вместе с экспериментами, наборами данных и оценкой вариантов приложения
Первый локальный тест Обычно требует нескольких сервисов и внимательной настройки Compose Можно начать с отдельного локального Python-процесса Обычно используется локальный комплект сервисов или установочный сценарий
Модель данных для агента Trace с наблюдениями и специализированными генерациями OpenTelemetry/OpenInference-трассы и spans Trace со spans, моделями, метаданными и оценками
Контроль токенов и стоимости Проверить автоматическое распознавание model ID, пользовательские цены и повторы Проверить полноту semantic attributes и способ расчёта стоимости в выбранном выпуске Проверить передачу usage, сопоставление модели с тарифом и агрегацию экспериментов
Сильный сценарий проверки Путь от пользовательской сессии до конкретной дорогой или ошибочной генерации Локальный разбор структуры трассы и технических причин задержки Сравнение трасс до и после изменения агента на одном наборе задач
Что особенно проверить Объём локальной инфраструктуры, редактирование данных и правила расчёта цены Маршрут OTLP, семантические атрибуты, долговременное хранение и командный доступ Ресурсы локального комплекта, экспорт, редактирование чувствительных полей и связь trace с experiment

Вторую таблицу заполните только после теста. Она и будет честным результатом лаборатории:

Критерий Вес Langfuse, 0–5 Phoenix, 0–5 Opik, 0–5 Доказательство
Настройка20%Команды, время, число обязательных параметров
Трассировка25%Экспорт дерева для пяти case ID
Метрики и стоимость20%Сверка usage и формулы цены
Локальный запуск15%Версии, процессы, тома, сетевой маршрут
Удобство отладки20%Время и действия до причины CASE-FAIL
Итого 100% Σ(балл × вес) Σ(балл × вес) Σ(балл × вес) Решение с учётом обязательных требований

Сохраните её как CSV:

criterion,weight,langfuse,phoenix,opik,evidence
setup,0.20,,,,
tracing,0.25,,,,
metrics_cost,0.20,,,,
local_run,0.15,,,,
debugging,0.20,,,,

Максимальный итог не должен автоматически определять выбор. Если локальное хранение обязательно, инструмент, не прошедший этот порог в вашей конфигурации, исключается независимо от суммы.

Быстрый выбор по ситуации

Ситуация С чего начать проверку Почему
Нужны трассы, сессии, обратная связь пользователей, управление промптами и расходы в одном продукте Langfuse Его продуктовая модель естественно связывает пользовательский запуск, генерации и оценки
Главная задача — локально открыть трассы и быстро исследовать задержку или качество retrieval Phoenix Удобная стартовая точка для технического исследования и стандартной телеметрии
Команда регулярно сравнивает версии агента на наборах примеров Opik Стоит проверить связку трасс, экспериментов и оценок как единый рабочий цикл
Уже существует OpenTelemetry-контур Phoenix, затем остальные Сначала проверяется нативный для команды маршрут, затем стоимость адаптации других платформ
Строгие требования к локальному хранению Все три на изолированном хосте Заявления о self-hosting недостаточно: нужно проверить DNS, исходящий трафик, тома, резервное копирование и удаление данных

Типовые неисправности

Агент завершился, но трассы нет

Диагностика:

date -Iseconds
docker compose ps
docker compose logs --tail=200
env | grep -E 'LANGFUSE|PHOENIX|OPIK|OTEL'
python -m app.send_probe --backend "$OBS_BACKEND"

Перед публикацией доказательств удалите значения секретов из вывода переменных.

Трасса есть, но шаги плоские

Обычно дочерний контекст не передан в функцию инструмента или потерян при переходе между потоками. Проверьте, что span создаётся внутри активного trace, а фоновая задача получает контекст явно.

Ошибка видна только в дочернем шаге

После перехвата исключения приложение могло завершить корневую трассу как успешную. Запишите ошибку в дочерний span, установите его статус, затем пометьте корневой запуск как error или partial. Не скрывайте ошибку успешным запасным ответом.

Стоимость равна нулю

Проверьте точный model ID, наличие usage, единицу тарифа и поддержку выбранной модели платформой. Если одно из значений неизвестно, правильный результат — N/A. Не заменяйте отсутствие тарифной записи нулевой ценой.

Общая задержка меньше суммы шагов

Это нормально для параллельных spans. В последовательном тесте проверьте временные зоны, единицы измерения и правильность родительских связей. Не сравнивайте серверные миллисекунды с клиентскими наносекундами без преобразования.

После перезапуска локальные данные пропали

Скорее всего, база или объектное хранилище находились в временном контейнере без постоянного тома. До повторного теста определите явные volumes и проверьте восстановление на искусственном проекте.

Интерфейс стал медленным после нескольких прогонов

Проверьте число spans, размер входов и выходов, состояние диска и фоновые процессы индексации. Один агентный запуск способен создать десятки событий. Не отправляйте большие документы целиком, если для расследования достаточно идентификатора и безопасного фрагмента.

Проверка локальности

Self-hosted не означает автоматически изолированный. Проверьте каждый слой:

Если модель внешняя, её запрос всё равно покидает машину. Корректно разделяйте локальную платформу наблюдаемости, локальную модель и локальный инструмент.

Безопасность трасс

Трасса часто содержит больше чувствительной информации, чем обычный лог: вход пользователя, инструкции, документы, аргументы инструмента и полный ответ. Для production заранее определите:

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

Проверка изменений

После выбора инструмента превратите пять лабораторных случаев в маленький бенчмарк. Запускайте его при обновлении SDK, модели, промпта или платформы наблюдаемости.

Проверки релиза:
1. Все пять run_id доставлены.
2. Дерево каждого запуска полно.
3. Ошибки не помечены успешными.
4. Повторы остаются внутри одного логического запуска.
5. Unknown usage не превращается в ноль.
6. Стоимость воспроизводится по закреплённому тарифу.
7. Фильтры по agent.version и case.id работают.
8. В трассах нет запрещённых полей.
9. Перезапуск не удаляет историю.
10. Экспорт открывается без интерфейса платформы.

Перед обновлением локального экземпляра подготовьте откат: резервную копию томов, закреплённые образы, копию конфигурации без секретов и проверенную команду восстановления.

Ограничения сравнения

Итоговый комплект

После двух часов работы у вас должен остаться не список впечатлений, а воспроизводимый пакет:

закреплённые версии трёх платформ
+ один неизменный сценарий агента
+ пять контролируемых case ID
+ одинаковый контракт трассы
+ локальный JSONL как контрольный журнал
+ экспорт или безопасные снимки каждого запуска
+ сверка задержек по шагам
+ подтверждённый usage либо явный null
+ воспроизводимая формула стоимости
+ замер поиска CASE-FAIL
+ проверка сохранности после перезапуска
+ таблица с баллами и доказательствами
+ список обязательных требований
+ решение и причина выбора

Практический выбор обычно становится очевидным после первой контролируемой ошибки. Langfuse стоит начинать первым, если нужен единый продуктовый контур вокруг запусков, оценок и стоимости. Phoenix — если приоритетом является локальное техническое исследование трасс и стандартная телеметрия. Opik — если трассы должны сразу участвовать в экспериментах и сравнении версий агента. Но окончательный победитель — тот инструмент, в котором ваша команда быстрее и надёжнее находит заранее известную причину ошибки, а не тот, у которого длиннее перечень функций.

← Все практические инструкции · Лабораторный словарь →