Туториалы

LLM Observability с Langfuse: зачем нужно и как настроить

Что такое LLM observability?

LLM observability — это практика мониторинга, трейсинга и оценки вызовов языковых моделей в production по четырём направлениям: трейсинг запросов, контроль стоимости, версионирование промптов и оценка качества выходов. В отличие от традиционного APM, она учитывает недетерминированность ответов и стоимость каждого вызова — то, что стандартные метрики вроде HTTP-статусов не отражают.

TL;DR

  • -Langfuse — MIT-лицензия, self-hosted без ограничений по трейсам, 22 000+ звёзд на GitHub, 23 млн установок SDK в месяц
  • -Один неудачный промпт против хорошего может стоить сотни долларов в месяц при 1000 активных пользователях — трекинг затрат обязателен
  • -Self-hosted разворачивается за 15 минут через Docker Compose; минимальные требования — Docker и 2 ГБ RAM
  • -SDK v3 построен на OpenTelemetry — нативная совместимость с любой OTEL-инструментацией, без vendor lock-in
  • -Покрывает все четыре столпа LLM observability: трейсинг, трекинг стоимости, управление промптами и оценку качества

LLM-вызовы в production нужно трейсить, промпты — версионировать, расходы — контролировать. Стандартные APM-инструменты здесь не помогут: ответы недетерминированы, каждый вызов стоит денег, а 200 OK ничего не говорит о качестве результата. Это отдельная категория observability.

Langfuse — open-source платформа (MIT) для LLM observability. Self-hosted без ограничений, 22 000+ звёзд на GitHub, 23 миллиона установок SDK в месяц. В этом руководстве — установка, трейсинг, prompt management, cost tracking и evaluations.

LLM Observability: четыре компонента

Если вы работали с APM (Application Performance Monitoring), LLM observability покажется знакомой. Но есть три важных отличия:

Недетерминизм. Один и тот же промпт при temperature > 0 даёт разные ответы. Нельзя просто сравнить expected vs actual — качество приходится оценивать статистически.

Стоимость за вызов. HTTP-запрос к собственному API стоит доли цента. Один вызов GPT-4o с контекстом на 10 000 токенов — 3-5 центов. При 1 000 пользователей в день разница между хорошим и плохим промптом — сотни долларов в месяц.

Качество вывода. 200 OK ничего не говорит о качестве ответа. Модель может вернуть грамматически правильный, но фактически бесполезный текст. Нужны метрики качества, а не только метрики доступности.

Четыре компонента LLM observability:

┌─────────────────────────────────────────────────────┐
│                  LLM Observability                   │
├──────────┬──────────┬──────────────┬────────────────┤
│ Tracing  │   Cost   │   Prompt     │  Evaluation    │
│          │ Tracking │  Management  │                │
├──────────┼──────────┼──────────────┼────────────────┤
│ Что      │ Сколько  │ Какой промпт │ Насколько      │
│ произошло│ стоило   │ в продакшене │ хороший ответ  │
└──────────┴──────────┴──────────────┴────────────────┘

Langfuse покрывает все четыре. Можно начать с одного (обычно tracing) и добавлять остальные по мере роста.

Почему Langfuse

На рынке LLM observability пять-шесть платформ. Вот чем выделяется Langfuse:

Open-source (MIT). Код на GitHub, self-hosted версия без ограничений. Нет vendor lock-in — исходники и данные всегда у вас.

Self-hosted бесплатно. Никаких лимитов на количество трейсов. Для небольших и средних команд self-hosted на одной VM — дешевле любого SaaS.

Не привязан к фреймворку. LangSmith заточен под LangChain — с другими стеками работать сложнее. Langfuse работает с любым LLM-провайдером: OpenAI, Anthropic, open-source модели через LiteLLM, Vercel AI SDK.

Активно развивается. За последний год: SDK v3 на OpenTelemetry (нативная совместимость с любой OTEL-инструментацией), встроенный MCP-сервер (управление промптами прямо из IDE), observation-level evaluations, dataset versioning. Рост с 10 000 до 22 000 звёзд за 10 месяцев.

Сравнение (кратко):

LangfuseLangSmithHelicone
Open-sourceMITНетApache 2.0
Self-hostedБесплатно, без лимитовEnterprise onlyДа
Framework lock-inНетLangChainOpenAI-first
Prompt managementДа + MCPДаДа (beta)
Free tier (cloud)50k obs/мес5k traces/мес100k req/мес

Установка за 15 минут: self-hosted

Минимальные требования: Docker и 2 ГБ RAM. Langfuse упаковывает всё в один docker-compose.

# docker-compose.yml
services:
  langfuse:
    image: langfuse/langfuse:2
    ports:
      - "3000:3000"
    environment:
      DATABASE_URL: postgresql://postgres:postgres@db:5432/langfuse
      NEXTAUTH_SECRET: your-secret-key-change-me
      SALT: your-salt-change-me
      NEXTAUTH_URL: http://localhost:3000
    depends_on:
      - db

  db:
    image: postgres:16
    environment:
      POSTGRES_PASSWORD: postgres
      POSTGRES_DB: langfuse
    volumes:
      - langfuse_data:/var/lib/postgresql/data

volumes:
  langfuse_data:
docker compose up -d

Через минуту Langfuse доступен на localhost:3000. Создайте аккаунт, проект, скопируйте API-ключи.

Первые трейсы через Python SDK

pip install langfuse
from langfuse import Langfuse

langfuse = Langfuse(
    public_key="pk-lf-...",
    secret_key="sk-lf-...",
    host="http://localhost:3000"  # ваш self-hosted URL
)

# Создаём трейс
trace = langfuse.trace(name="chat-response", user_id="user-123")

# Логируем LLM-вызов
generation = trace.generation(
    name="gpt-4o-response",
    model="gpt-4o",
    input=[{"role": "user", "content": "Порекомендуй кафе в Москве"}],
    output="Вот несколько вариантов...",
    usage={"input": 42, "output": 128},
)

langfuse.flush()

Откройте Langfuse UI — трейс появится в списке с данными о модели, токенах и latency.

Автоматическая инструментация через LiteLLM

Ручное логирование — для понимания механики. В продакшене лучше автоматизировать. Если вы используете LiteLLM как прокси к LLM-провайдерам, Langfuse подключается одной строкой:

import litellm
litellm.success_callback = ["langfuse"]

# Каждый вызов автоматически попадёт в Langfuse
response = litellm.completion(
    model="gpt-4o",
    messages=[{"role": "user", "content": "Привет"}],
    metadata={
        "trace_name": "chat-response",
        "trace_user_id": "user-123",
        "generation_name": "greeting",
        "tags": ["production", "chat"],
    }
)

LiteLLM сам отправит в Langfuse: модель, токены, стоимость, latency, input/output. Вы пишете обычный LLM-вызов, Langfuse заполняется автоматически.

Для OpenAI SDK есть drop-in replacement:

from langfuse.openai import openai

# Используйте как обычный OpenAI SDK
# Все вызовы автоматически трейсятся
client = openai.OpenAI()
response = client.chat.completions.create(
    model="gpt-4o",
    messages=[{"role": "user", "content": "Привет"}],
)

Трейсинг: что внутри LLM-вызова

Трейс в Langfuse — это дерево операций. На верхнем уровне — trace (один запрос пользователя). Внутри — generations (LLM-вызовы) и spans (промежуточные шаги: retrieval, preprocessing, postprocessing).

Trace: "generate-itinerary"

├── Span: "validate-input" (12ms)

├── Generation: "analyze-request" (GPT-4o, 340 tokens, $0.003)

├── Span: "search-places" (Foursquare API, 800ms)

├── Generation: "build-itinerary" (GPT-4o, 2100 tokens, $0.018)

└── Generation: "validate-result" (GPT-4o-mini, 450 tokens, $0.001)

Что видно в UI для каждой generation:

  • Input/Output — полный промпт и ответ
  • Model — какая модель использовалась
  • Tokens — input, output, total
  • Cost — стоимость в долларах (автоматически по модели)
  • Latency — время ответа
  • Metadata — произвольные поля (user ID, feature, session)

Три вещи, которые трейсинг показывает сразу:

Паттерн 1: скрытые повторные вызовы. Retry-логика в коде может вызывать модель 2-3 раза на один запрос пользователя. Без трейсинга вы видите только финальный ответ. С трейсингом — каждый вызов со стоимостью.

Паттерн 2: model mismatch. Предполагается GPT-4o-mini для быстрых ответов, но один эндпоинт тянет GPT-4o. В трейсинге модель видна по каждому вызову — фильтр по полю model сразу покажет, где что-то не так.

Паттерн 3: latency bottleneck. В цепочке из четырёх LLM-вызовов один занимает 80% времени. Без spans вы знаете только общее время. С ними — точно видно, куда оптимизировать.

Prompt Management: версионирование без деплоя

Стандартный подход: промпт зашит в код. Изменение требует PR → code review → merge → deploy. A/B тест двух промптов — два деплоя.

Langfuse выносит промпты из кода: код загружает их по имени через API. Изменение промпта в UI применяется к следующему запросу без деплоя.

# Загрузка промпта из Langfuse
prompt = langfuse.get_prompt("travel-assistant")

# Компиляция с переменными
compiled = prompt.compile(
    destination="Москва",
    preferences="вегетарианская кухня"
)

# Использование в LLM-вызове
response = litellm.completion(
    model="gpt-4o",
    messages=compiled,
    metadata={"langfuse_prompt_name": "travel-assistant"}
)

Каждое изменение промпта — новая версия. Langfuse хранит всю историю: кто, когда, что изменил. Можно откатить одним кликом.

Fallback-паттерн

Langfuse — внешний сервис. Он может быть недоступен. Промпт нужен всегда.

try:
    prompt = langfuse.get_prompt("travel-assistant", label="production")
    messages = prompt.compile(destination=city)
except Exception:
    # Если Langfuse недоступен — fallback на хардкод
    messages = [
        {"role": "system", "content": FALLBACK_SYSTEM_PROMPT},
        {"role": "user", "content": f"Порекомендуй кафе в {city}"},
    ]

Для production этот паттерн обязателен. Langfuse ускоряет итерацию над промптами, но не должен быть single point of failure.

MCP-сервер: промпты из IDE

С ноября 2025 Langfuse поддерживает MCP (Model Context Protocol). Подключив MCP-сервер к Claude Code, Cursor или другому AI-ассистенту, вы можете читать и редактировать промпты прямо из IDE.

{
  "mcpServers": {
    "langfuse": {
      "type": "http",
      "url": "https://your-langfuse.com/api/public/mcp",
      "headers": {
        "Authorization": "Basic base64(publicKey:secretKey)"
      }
    }
  }
}

Зачем: вместо переключения между IDE и браузером, AI-ассистент видит текущие промпты, предлагает изменения и может применить их через MCP — всё в одном рабочем потоке.

Cost Tracking: сколько стоит каждая фича

Langfuse автоматически считает стоимость каждого LLM-вызова по модели и количеству токенов. Встроенная таблица pricing обновляется с каждым релизом (GPT-5.2, Claude Opus 4 — поддержка в день выхода).

В дашборде вы видите:

  • Total cost за период
  • Cost per trace — средняя стоимость одного запроса
  • Cost per user — сколько тратит конкретный пользователь
  • Cost per model — распределение расходов между моделями

Паттерн: per-feature cost tracking

Добавляя теги или metadata к трейсам, вы группируете расходы по фичам:

trace = langfuse.trace(
    name="itinerary-generation",
    tags=["feature:itinerary", "tier:premium"],
    user_id="user-123",
)

Фильтр по тегу feature:itinerary в дашборде покажет, сколько стоит именно генерация маршрутов. Отдельно — чат, отдельно — рекомендации, отдельно — саммаризация.

Паттерн: синхронизация расходов в свою БД

Langfuse API позволяет программно получить стоимость:

# Получить все трейсы пользователя
traces = langfuse.fetch_traces(user_id="user-123")

# Суммировать стоимость
total_cost = sum(t.total_cost or 0 for t in traces.data)

# Записать в свою БД для лимитов, биллинга, аналитики
db.update_user_spending(user_id="user-123", amount=total_cost)

Это нужно, если у вас есть лимиты на LLM-расходы per user (freemium, credits) или вы хотите показывать пользователю его потребление.

Evaluations: качество ответов в числах

Трейсинг показывает, что произошло. Evaluations показывают, насколько хорошо.

LLM-as-a-Judge

Автоматическая оценка через LLM: одна модель оценивает ответы другой. Langfuse поддерживает это из коробки.

Настраивается в UI: выбираете evaluator template (relevance, helpfulness, toxicity), целевой набор трейсов — Langfuse прогоняет оценку по каждому. Результат — score от 0 до 1, привязанный к трейсу.

Observation-Level Evaluations (новинка 2026)

Раньше оценка привязывалась только к trace целиком. Но в цепочке из четырёх LLM-вызовов проблема может быть в одном конкретном шаге. С февраля 2026 можно оценивать каждый observation (generation, span) отдельно.

Пример: в pipeline “analyze → search → generate → validate” evaluator для generate проверяет фактическую корректность, а для validate — соответствие формату. Разные evaluators для разных шагов.

Datasets: регрессионное тестирование промптов

Dataset в Langfuse — набор пар input/expected_output. Изменили промпт — прогоняете dataset, сравниваете scores с предыдущей версией. Если качество упало — откатываете.

С декабря 2025 поддерживается версионирование datasets: каждое изменение (добавление, удаление, обновление item) создаёт новую версию. Можно запустить эксперимент на конкретной исторической версии для воспроизводимости.

# Создаём или обновляем dataset
langfuse.create_dataset(name="travel-queries")

langfuse.create_dataset_item(
    dataset_name="travel-queries",
    input={"query": "Кафе в центре Москвы"},
    expected_output="Список из 5+ кафе с адресами",
)

# Запуск эксперимента
dataset = langfuse.get_dataset("travel-queries")
for item in dataset.items:
    response = run_my_pipeline(item.input)
    item.link(
        trace_id=response.trace_id,
        run_name="prompt-v3-test",
    )

В UI Langfuse вы увидите сравнение run’ов: prompt v2 vs v3, с scores по каждому item.

Production Checklist

Self-hosted vs Cloud

КритерийSelf-hostedCloud
СтоимостьТолько инфраструктура (~$10-20/мес VPS)От $59/мес (Pro)
ДанныеОстаются у васНа серверах Langfuse
ОбслуживаниеВы обновляете, бекапите, мониторитеВсё включено
ЛимитыНет50k obs/мес (бесплатно), далее по тарифу
Подходит дляКоманды с DevOps, compliance-требованияБыстрый старт, маленькие команды

Для большинства production-проектов self-hosted выгоднее: $15/мес за VPS vs $59+/мес за cloud. Но self-hosted = ваша ответственность за uptime и бекапы.

Мониторинг самого Langfuse

Langfuse — внешняя зависимость для ваших LLM-вызовов (prompt management). Если он падает — промпты не грузятся. Два паттерна:

  1. Health check. /api/public/health возвращает статус. Добавьте в мониторинг (Zabbix, Uptime Robot, Grafana).
  2. Fallback промпты. Каждый get_prompt() обёрнут в try/catch с fallback на хардкод. Langfuse может лежать — приложение продолжает работать.

Retention и cleanup

Трейсы занимают место в PostgreSQL. 1 000 трейсов в день — ~1 ГБ в месяц (зависит от размера промптов и ответов). Настройте автоматическое удаление старых трейсов:

-- Удалять трейсы старше 90 дней
DELETE FROM traces WHERE created_at < NOW() - INTERVAL '90 days';

Или используйте встроенные настройки retention в Langfuse Cloud.

Минимальный production-сетап

┌─────────────────────────────────────────┐
│            Ваше приложение               │
│                                          │
│  LLM-вызов → LiteLLM → OpenAI/Anthropic │
│       │                                  │
│       │ metadata (trace_name,            │
│       │  user_id, tags)                  │
│       ▼                                  │
│  LiteLLM callback → Langfuse            │
└─────────────────────────────────────────┘


┌──────────────────┐
│ Langfuse (Docker) │
│                   │
│ • Трейсы          │  ← автоматически
│ • Стоимость       │  ← автоматически
│ • Промпты         │  ← управление в UI
│ • Evaluations     │  ← настройка в UI
└──────────────────┘

Промпты загружаются из Langfuse при каждом вызове (с кешем). Трейсы отправляются асинхронно — не блокируют основной поток. Стоимость считается автоматически по модели и токенам.

Итог

Langfuse закрывает четыре задачи одним инструментом: трейсинг, cost tracking, prompt management и evaluations. Self-hosted версия бесплатна и разворачивается за 15 минут. Интеграция через LiteLLM или OpenAI drop-in — одна строка кода.

Минимальный путь: подключить трейсинг к одному endpoint, посмотреть данные за неделю. Этого достаточно, чтобы оценить полезность инструмента для конкретного проекта.

Ссылки:

FAQ

Какой реальный объём хранилища занимают трейсы в PostgreSQL при долгосрочном хранении?

Один трейс с промптом на 1 000 токенов и ответом на 500 токенов занимает примерно 8–12 КБ в PostgreSQL с учётом индексов. При 1 000 трейсов в день это около 300–400 МБ в месяц. Официальная рекомендация по retention — 90 дней, устойчивое состояние хранилища около 1–1.5 ГБ — без проблем помещается на VPS за $15/мес. При больших контекстах (RAG с длинными документами) умножайте на 3–5x и планируйте заранее.

Поддерживает ли Langfuse мультитенантные сценарии с изолированными данными разных команд?

Да. Langfuse использует иерархию Organizations → Projects. У каждого проекта свои API-ключи, пространство имён промптов и датасетов. Один self-hosted инстанс обслуживает несколько команд с полной изоляцией данных на уровне проекта. RBAC доступен в облачном тарифе Pro и в Enterprise-версии self-hosted.

Как параметр cache_ttl_seconds взаимодействует с провайдерским кешированием промптов?

cache_ttl_seconds управляет клиентским кешированием объекта промпта в памяти — он предотвращает лишние запросы к серверу Langfuse при каждом LLM-вызове. Это не влияет на провайдерское кеширование промптов (Anthropic или OpenAI). Два механизма независимы: можно иметь TTL кеша Langfuse 5 минут и при этом использовать кеширование Anthropic для самого LLM-вызова, если приложение передаёт нужные cache-control заголовки дальше по цепочке.