Langfuse: трейсы LLM-вызовов
Зачем отдельный инструмент для LLM, self-hosting в compose, интеграция SDK, что смотреть и как связать с evals
Langfuse: трейсы LLM-вызовов
Обычный трейс говорит: «вызов модели занял 4.2 секунды, HTTP 200». Этого достаточно для инфраструктуры и бесполезно для качества — потому что главные вопросы AI-продукта звучат иначе: какой промпт ушёл, что вернулось, сколько стоило, стало ли хуже после вчерашней правки промпта.
Langfuse — открытая (MIT) платформа, которая закрывает именно это. В курсе она стоит в контуре с лабы 3 и работает на роль AI Engineer и роль Quality одновременно.
Что даёт
- Трейс каждого вызова: промпт целиком, ответ, модель, параметры, токены на вход и выход, стоимость, задержка.
- Вложенность. Цепочка «ретривер → промпт → модель → парсер» видна деревом: понятно, какой шаг сожрал время и на каком испортились данные.
- Версии промптов. Промпт хранится и версионируется в Langfuse, приложение тянет нужную версию — правка промпта перестаёт быть деплоем кода, а изменения качества привязываются к версии.
- Датасеты и эксперименты. Реальные трейсы отправляются в датасет, на нём прогоняются прогоны при смене промпта или модели — сравнение «было/стало» на одних и тех же входах.
- Оценки. Оценка человеком, кодом или моделью-судьёй пишется прямо на трейс, и её видно в общей статистике.
Поднять у себя
Langfuse ставится в тот же compose-контур, что и продукт. Учти, что это не один контейнер: web, воркер, PostgreSQL для метаданных, ClickHouse для аналитики трейсов, Redis для очереди и S3-совместимое хранилище для сырых событий.
git clone https://github.com/langfuse/langfuse.git
cd langfuse
docker compose up -d # UI на http://localhost:3000Дальше в UI создаётся проект и пара ключей (LANGFUSE_PUBLIC_KEY,
LANGFUSE_SECRET_KEY) — они уезжают в .env продукта, как любые
другие секреты. На слабой машине честнее взять облачный бесплатный
тариф: шесть контейнеров рядом с вашим стеком заметно греют ноутбук.
Подключить к коду
Минимальный вариант — декоратор поверх функции и обёртка над клиентом модели:
from langfuse import observe, get_client
langfuse = get_client()
@observe()
def answer_question(question: str, trace_id: str) -> str:
langfuse.update_current_trace(
session_id=trace_id, # тот же id, что в логах и метриках
tags=["uc-02", "questions"], # какой use case обслуживаем
)
...Две строчки, которые превращают инструмент из красивого в полезный:
- Общий идентификатор с логами и метриками — иначе Langfuse живёт отдельной жизнью и три столпа не сходятся.
- Тег use case на трейсе. Тогда качество считается не «в среднем по продукту», а по каждому UC отдельно — и сразу видно, какой сценарий тянет статистику вниз.
Что смотреть каждую неделю
- Стоимость на пользователя и на UC — растёт ли, и за счёт чего: длины промпта, числа ретраев, выбранной модели.
- P95 задержки вызова модели — отдельно от задержки API.
- Доля вызовов с ошибкой формата — сколько раз ответ не прошёл валидацию структуры.
- Оценки по свежим трейсам — берётся выборка реального трафика и прогоняется через evals; расхождение с результатами на golden-наборе означает, что набор устарел.
Связь с лабами прямая: golden dataset из лабы 2 живёт в CI, а Langfuse показывает, что происходит на настоящем трафике. Evals ловят регрессию до деплоя, Langfuse — деградацию после. Нужны оба: набор из 30–50 примеров никогда не покроет того, что придумают живые пользователи.