Self-hosted Langfuse: установка и настройка на VPS
Руководство по развертыванию Langfuse на своем сервере. Узнайте, как настроить ClickHouse для экономии диска, зафиксировать версии образов и настроить TLS для защиты данных.
Зачем вообще отслеживать работу AI-агента
Вы разворачиваете Langfuse на собственном сервере, чтобы видеть, что именно агент делал во время выполнения. Langfuse — это инструмент с открытым исходным кодом для обеспечения наблюдаемости LLM (больших языковых моделей). Он записывает каждый промпт, каждый ответ модели, каждый вызов инструментов и каждый токен, а затем группирует их в единую трассировку (trace), которую можно открыть и изучить. Запуск на собственном VPS означает, что эти промпты никогда не покидают сервер, который вы контролируете.
Причина, по которой стоит этим заниматься, очевидна. Вы не можете исправить проблему с затратами или качеством, если не видите её источник. Счет от провайдера показывает, что во вторник расходы были в 4 раза выше, чем в понедельник. Трассировка показывает, какой именно запуск агента стал причиной, какой промпт разросся до 40,000 токенов и какой цикл повторных попыток сработал 9 раз, прежде чем завершиться неудачей. Счет дает вам цифру. Трассировка дает вам код, который её породил.
В этом руководстве используются три термина. Трассировка (trace) — это один полный цикл выполнения вашего агента от начала до конца. Наблюдение (observation) — это один шаг внутри этого цикла: span для обычного кода или generation для вызова модели. Оценка (score) — это числовое значение, присвоенное трассировке на основе проверки человеком или автоматическим оценщиком. Langfuse поддерживает OpenTelemetry (OTel), независимый от вендоров стандарт распределенной трассировки, поэтому уже имеющиеся у вас средства инструментирования могут быть направлены на него.
Что на самом деле запускается при self-hosting Langfuse
Langfuse v4 — это не один контейнер. Система состоит из двух контейнеров приложений и четырех сервисов хранения данных, и на одном VPS все шесть работают на вашем узле.
langfuse-webобслуживает веб-интерфейс и API для приема данных.langfuse-workerобрабатывает очередь в фоновом режиме. Он разбирает пакеты входящих данных, рассчитывает стоимость и выполняет ежедневную задачу по очистке данных (retention job).- Postgres хранит транзакционные данные, такие как пользователи, организации, проекты, API-ключи и промпты.
- ClickHouse хранит сами данные трассировки, то есть наблюдения и оценки. Это колоночная СУБД, созданная для аналитических запросов, поэтому дашборд быстро отвечает даже при ста миллионах строк.
- Redis выступает в роли очереди и кэша между веб-интерфейсом и воркером.
- MinIO предоставляет S3-совместимое объектное хранилище на вашем сервере. В нем хранятся все необработанные входящие события и любые прикрепленные медиафайлы.
Langfuse публикует минимальные требования к ресурсам для каждого компонента. В таблице ниже представлены три компонента, выполняющие основную работу.
Данные, на которых построен график
[
{
"label": "ClickHouse",
"cpu_cores": 2,
"memory_gib": 8
},
{
"label": "Langfuse web",
"cpu_cores": 2,
"memory_gib": 4
},
{
"label": "Langfuse worker",
"cpu_cores": 2,
"memory_gib": 4
}
]Только для ClickHouse требуется 8 GiB оперативной памяти. Веб-контейнер и воркер требуют по 4 GiB каждый. Это опубликованные минимальные значения для 3 компонентов в таблице. На той же странице указано, что Postgres требует 4 GiB, Redis или Valkey — 1.5 GiB, а MinIO — 4 GiB, поэтому сумма минимумов для всех шести компонентов составляет 25.5 GiB. Официальное руководство по Docker Compose для этого проекта рекомендует как минимум 4 ядра, 16 GiB оперативной памяти и около 100 GiB дискового пространства для одной машины. Это меньше, чем сумма минимальных требований компонентов, поэтому рассматривайте 16 GiB как абсолютный минимум для общего сервера с Compose, а не как запас по ресурсам.
Не пытайтесь запускать это на тарифе с 2 GiB памяти. ClickHouse запустится, некоторое время будет принимать записи, а затем завершится с ошибкой во время фонового слияния (merge), так как слияние загружает большие части таблицы в оперативную память. Вы увидите, что docker compose ps сообщает о статусе контейнера clickhouse как restarting, dmesg содержит строку вида Out of memory: Killed process 1234 (clickhouse-serv), а все дашборды Langfuse возвращают ошибку 500. При меньшей нагрузке ClickHouse просто отклоняет запрос и записывает в лог DB::Exception: Memory limit (total) exceeded. Ориентируйтесь на 16 GiB. Если на этом же VPS должны работать другие сервисы, выделите для них ресурсы отдельно, так как даже относительно легкий стек, такой как self-hosted рабочее пространство AFFiNE, требует своих гигабайтов памяти, а ClickHouse не освободит занятую память.
Развертывание Langfuse с помощью Docker Compose
Клонируйте репозиторий. Стек, связи между компонентами и конфигурация по умолчанию находятся в файле docker-compose.yml.
git clone https://github.com/langfuse/langfuse.git
cd langfuseВсе значения, которые необходимо изменить, отмечены в этом файле как # CHANGEME. Сначала сгенерируйте три секрета приложения.
openssl rand -base64 32 # NEXTAUTH_SECRET
openssl rand -base64 32 # SALT
openssl rand -hex 32 # ENCRYPTION_KEYЗначение ENCRYPTION_KEY должно представлять собой 256 бит, записанных как 64 шестнадцатеричных символа; именно это выводит команда openssl rand -hex 32. Этот ключ шифрует конфиденциальные данные в состоянии покоя, включая ключи провайдеров LLM, которые вы храните в экземпляре. Изменение ключа после появления данных приведет к невозможности их расшифровки, поэтому считайте его постоянным с момента первого запуска. Значение SALT используется для хеширования ваших API-ключей Langfuse, поэтому его изменение сделает недействительными все ключи, которые уже используют ваши агенты.
Затем установите POSTGRES_PASSWORD, CLICKHOUSE_PASSWORD, REDIS_AUTH и MINIO_ROOT_PASSWORD. Пароль MinIO указывается в четырех местах: один раз как MINIO_ROOT_PASSWORD, а затем как LANGFUSE_S3_EVENT_UPLOAD_SECRET_ACCESS_KEY, LANGFUSE_S3_MEDIA_UPLOAD_SECRET_ACCESS_KEY и LANGFUSE_S3_BATCH_EXPORT_SECRET_ACCESS_KEY. Если пропустить хотя бы одно, MinIO отклонит клиент с ошибкой SignatureDoesNotMatch, которая попадет в лог воркера, в то время как веб-интерфейс будет выглядеть работоспособным. Хранение этих значений в файле окружения вместо отслеживаемого файла compose — это стандартный подход, описанный в файлы окружения и секреты Docker Compose.
Закрепление тегов образов перед запуском
В поставляемом файле используются docker.langfuse.com/langfuse/langfuse:4 и docker.langfuse.com/langfuse/langfuse-worker:4. Эти теги динамические. Langfuse автоматически выполняет миграции Postgres и ClickHouse при запуске, поэтому обычная команда docker compose pull спустя несколько месяцев может привести к незапланированной миграции схемы базы данных, которую вы не успели забэкапить утром того же дня. Закрепите обе версии в файле docker-compose.override.yml, который Compose объединяет с основным файлом, чтобы последующая команда git pull не конфликтовала с вашими правками. Те же образы публикуются на Docker Hub, откуда их и забирает приведенный ниже переопределяющий файл.
services:
langfuse-web:
image: docker.io/langfuse/langfuse:4.72.0
langfuse-worker:
image: docker.io/langfuse/langfuse-worker:4.72.0Версия 4.3.1 была актуальным релизом 4.3 по состоянию на август 2026 года. С тех пор релизы выходят часто, и v4.56.0 была последней на GitHub по состоянию на 11 октября 2026 года. В переопределении выше используется v4.72.0 — последняя версия на GitHub по состоянию на 31 октября 2026 года. Проверьте страницу релизов проекта на GitHub, закрепите версию, актуальную на день развертывания, а затем обновляйте её осознанно. Некоторые образы хранилищ в поставляемом файле требуют такого же подхода, так как их теги также меняются. postgres:17 (значение по умолчанию для переменной POSTGRES_VERSION) и redis:7 следуют за мажорной версией. Сейчас в поставляемом файле используется точный тег версии для docker.io/clickhouse/clickhouse-server, фиксирующий конкретную версию ClickHouse. Это правило применимо не только к Langfuse: трекер тренировок openGym использует лишь часть этого стека, но всё равно требует указания git-тега, так как любой сервис, выполняющий миграцию базы данных при старте, может превратить обычное обновление в изменение схемы.
Запустите стек.
docker compose up -d
docker compose ps
docker compose logs -f langfuse-workerПри первом запуске выполняются миграции, поэтому подождите две-три минуты, прежде чем ожидать ответа от сервисов. Веб-контейнер записывает в лог Ready, когда он готов. Команда docker compose ps должна показать шесть сервисов в состоянии running. Если контейнер перезапускается в цикле, причина указана в его логе. Миграции ClickHouse применяются при запуске веб-контейнера, поэтому ошибка в CLICKHOUSE_MIGRATION_URL будет видна в docker compose logs langfuse-web, а не в логе воркера, который вы отслеживаете. Эта переменная использует собственный протокол ClickHouse на порту 9000, а не HTTP-порт 8123; указание порта 8123 нарушит работу миграций при запуске веб-контейнера. Воркер выполняет более медленные фоновые миграции, поэтому отчеты о них попадают в его лог.
Проверьте работоспособность изнутри системы.
curl -s "http://localhost:3000/api/public/health?failIfDatabaseUnavailable=true"
curl -s -o /dev/null -w '%{http_code}\n' http://localhost:3000/api/public/readyОбычный вызов /api/public/health лишь подтверждает, что процесс API запущен, так как по умолчанию он не проверяет базу данных. Форма failIfDatabaseUnavailable=true — это то, на что стоит настроить мониторинг; она возвращает 503, если база данных недоступна. /api/public/ready возвращает 200, когда веб-контейнер готов принимать трафик, и 500, если получена команда на завершение работы. Оба варианта — это обычные HTTP-проверки, поэтому страница статуса Uptime Kuma может отслеживать их и сообщить вам, что стек не работает, раньше, чем это заметят ваши агенты.
Настройте TLS и закройте лишние порты
Поставляемый файл compose публикует 3000:3000 для веб-контейнера и 9090:9000 для MinIO. Оба привязываются ко всем сетевым интерфейсам. На публичном IP это означает, что любой, кто просканирует порт 3000, попадет на вашу страницу регистрации, а любой, кто просканирует 9090, получит доступ к бакету с вашими необработанными промптами.
Правила брандмауэра сами по себе не закрывают эти порты. Docker записывает собственные правила DNAT в таблицу nat, которые обрабатываются до того, как пакеты попадут в правила фильтрации ufw, поэтому ufw deny 3000 оставляет опубликованный порт открытым. Эта проблема встречается настолько часто, что для неё есть отдельное руководство: почему опубликованные порты Docker обходят ufw. Вместо этого используйте привязку к loopback в вашем файле переопределения. Используйте !override в Docker Compose версии 2.24.4 или новее, чтобы заменить опубликованные порты; обычный список будет объединен с исходными привязками.
services:
langfuse-web:
ports: !override
- "127.0.0.1:3000:3000"
environment:
NEXTAUTH_URL: https://langfuse.example.com
minio:
ports: !override
- "127.0.0.1:9090:9000"
- "127.0.0.1:9091:9001"NEXTAUTH_URL должен содержать точный публичный адрес, включая схему, так как процесс входа в систему формирует URL обратного вызова на основе этого значения. Если оставить его как http://localhost:3000 за HTTPS-прокси, то при попытке входа браузер будет перенаправлен туда, куда не сможет подключиться.
Теперь направьте reverse proxy на 127.0.0.1:3000 и позвольте ему управлять сертификатом. Для Traefik в том же проекте Compose настройте маршрутизацию на langfuse-web:3000 через сеть Compose, используя метки, описанные в запуск нескольких приложений за одним reverse proxy Traefik. Caddy выполняет ту же задачу в две строки, если Langfuse — единственный сервис на сервере. Проверьте работу с помощью curl -sI https://langfuse.example.com/api/public/ready, а затем убедитесь с другого компьютера, что curl http://YOUR_IP:3000 недоступен.
Важное замечание по MinIO. Langfuse выдает подписанные URL (presigned URLs), указывающие на этот S3-эндпоинт, как для SDK, загружающих медиафайлы, так и для вашего браузера, который их отображает. Поэтому, если вы используете мультимодальные трейсы с изображениями или аудио, привязка MinIO только к loopback приведет к тому, что эти вложения не будут загружаться с других машин или отображаться в браузере. Прочитайте страницу настройки хранилища объектов перед тем, как проксировать его, так как эндпоинт, записываемый в подписанный URL, LANGFUSE_S3_MEDIA_UPLOAD_ENDPOINT, должен совпадать с тем, который вы публикуете. На текстовые трейсы это не влияет.
Создайте свою учетную запись при первом посещении, а затем ограничьте доступ к инстансу. Установите AUTH_DISABLE_SIGNUP=true после того, как ваша учетная запись будет создана, чтобы посторонние лица, попавшие на страницу, не могли зарегистрироваться. В Langfuse также есть LANGFUSE_ALLOWED_ORGANIZATION_CREATORS, который ограничивает круг лиц, способных создавать организации, но это функция Enterprise Edition, требующая лицензионного ключа. Если вы уже используете Authentik в качестве собственного провайдера идентификации, Langfuse поддерживает стандартное OIDC-подключение, поэтому учетные записи будут управляться централизованно вместе с остальными вашими приложениями, а не храниться в списке паролей, известном только этому серверу.
Отправка первой трассировки
Создайте проект в веб-интерфейсе и скопируйте публичный и секретный ключи из настроек проекта. Python SDK считывает три переменные окружения.
export LANGFUSE_PUBLIC_KEY="pk-lf-..."
export LANGFUSE_SECRET_KEY="sk-lf-..."
export LANGFUSE_BASE_URL="https://langfuse.example.com"LANGFUSE_BASE_URL — это имя переменной в SDK v4, выпущенном в марте 2026 года. В старом коде и руководствах используется LANGFUSE_HOST. Если ваши трассировки попадают в Langfuse Cloud вместо вашего сервера, значит, не задан базовый URL: по умолчанию SDK обращается к облачному экземпляру.
Текущая версия Python SDK v5 требует Python 3.11 или новее и self-hosted Langfuse v4.59.0 или новее, что соответствует требованиям сервера, указанного выше.
pip install langfuse opentelemetry-instrumentation-anthropic anthropicimport os
from anthropic import Anthropic
from langfuse import get_client, observe
from opentelemetry.instrumentation.anthropic import AnthropicInstrumentor
AnthropicInstrumentor().instrument()
langfuse = get_client()
client = Anthropic(api_key=os.environ["ANTHROPIC_API_KEY"])
@observe(as_type="tool")
def lookup_order(order_id: str) -> str:
return f"order {order_id}: shipped"
@observe()
def handle_request(question: str) -> str:
context = lookup_order("A-1042")
message = client.messages.create(
model="claude-haiku-4-5",
max_tokens=512,
messages=[{"role": "user", "content": f"{context}\n\n{question}"}],
)
return message.content[0].text
if __name__ == "__main__":
assert langfuse.auth_check()
print(handle_request("Where is my order?"))
langfuse.flush()Декоратор @observe открывает наблюдение вокруг функции, захватывает её аргументы и возвращаемое значение, а также вкладывает его в уже активное наблюдение. AnthropicInstrumentor — это инструментарий OpenTelemetry для клиента Anthropic; он превращает каждый вызов messages.create в генерацию, содержащую имя модели, количество токенов и задержку, без внесения изменений в место вызова.
Два вызова выполняют проверку за вас. langfuse.auth_check() возвращает False при неверных ключах или неправильном базовом URL, что быстрее, чем выяснение причин пустой панели мониторинга. langfuse.flush() блокирует выполнение до тех пор, пока не будут отправлены поставленные в очередь спаны; это необходимо для короткоживущих процессов, так как SDK выполняет пакетную обработку в фоновом режиме, и скрипт, завершающийся немедленно, прерывает отправку пакета. Если трассировки отправляет вся команда, а не один скрипт, задайте эти три переменные один раз в шлюзе, через который проходят агенты всех пользователей, вместо того чтобы настраивать их в оболочке каждого сотрудника. Именно так инструментарий OneCLI для self-hosted установки обеспечивает сбор данных о запусках у всех коллег, сохраняя ключи в одном месте.
Почему ClickHouse продолжает расти?
Трейсы — это наиболее быстрорастущий тип данных, который пользователи обычно размещают на собственных серверах. Каждый запуск агента записывает одну строку на каждый шаг, а входные и выходные данные сохраняются полностью. В результате «разговорчивый» агент с длинными промптами генерирует гораздо больше байтов в день, чем само приложение, за которым он наблюдает. Если оставить всё как есть, ClickHouse заполнит диск, а переполнение диска приводит к остановке приема данных, а не к замедлению процесса.
Здесь растут два разных типа данных, и для них требуются два разных решения.
Первый тип — ваши собственные данные трейсов, и решение заключается в настройке периода хранения (retention). На self-hosted инстансе управление периодом хранения данных является функцией Enterprise Edition и требует лицензионного ключа. Без него Langfuse хранит трейсы, наблюдения (observations), оценки (scores) и медиафайлы бессрочно. Рассчитывайте объем диска исходя из этого и полагайтесь на оповещение о заполнении диска в конце этого раздела. При наличии лицензии владельцы проектов и администраторы могут открыть настройки проекта и задать период хранения данных в днях. Langfuse поддерживает минимум 3 дня. Ночное задание выбирает трейсы, наблюдения, оценки и медиаактивы, которые старше этого периода, и удаляет их из ClickHouse и из объектного хранилища (blob storage), за исключением медиафайлов, связанных с сохраненными элементами наборов данных (datasets). Заданию требуются права DeleteObject на бакет, которые уже есть у root-учетных данных MinIO в стандартном файле compose. Удаление является необратимым, поэтому сначала настройте экспорт в объектное хранилище, если вам нужна долгосрочная история. Не прописывайте вручную условия TTL для таблиц Langfuse: задание по очистке данных обеспечивает синхронизацию ClickHouse и бакета, а ручное задание TTL удалит данные только в одном месте.
Выберите период, исходя из реальных потребностей. Анализ стоимости и качества проводится на данных, которым несколько дней, а не месяцев. 30 дней — разумный срок для небольшой команды, а 14 дней достаточно, если вы открываете трейс только в случае сбоя.
Второй тип — системные таблицы логов самого ClickHouse. Это часто становится сюрпризом, так как диск продолжает расти даже после настройки периода хранения данных. ClickHouse записывает trace_log, text_log, opentelemetry_span_log, metric_log, asynchronous_metric_log и latency_log для собственной диагностики, они поставляются без TTL, и Langfuse их никогда не читает. Сначала выясните, куда именно уходит место на диске.
SELECT table, formatReadableSize(size) AS size, rows FROM (
SELECT table, database, sum(bytes) AS size, sum(rows) AS rows
FROM system.parts
WHERE active
GROUP BY table, database
ORDER BY size DESC
)Запустите его с docker compose exec clickhouse clickhouse-client --password "$CLICKHOUSE_PASSWORD". Если системные таблицы занимают верхние строчки, отключите их с помощью конфигурационного оверлея, так как ClickHouse при запуске объединяет каждый файл в /etc/clickhouse-server/config.d/ со своей основной конфигурацией.
<clickhouse>
<trace_log remove="1"/>
<text_log remove="1"/>
<opentelemetry_span_log remove="1"/>
<asynchronous_metric_log remove="1"/>
<metric_log remove="1"/>
<latency_log remove="1"/>
</clickhouse>Примонтируйте его и перезапустите ClickHouse.
services:
clickhouse:
volumes:
- ./clickhouse-config.d/system-logs.xml:/etc/clickhouse-server/config.d/system-logs.xml:roЭто остановит новые записи. Строки, которые уже находятся на диске, останутся там, поэтому освободите место явно с помощью DROP TABLE IF EXISTS system.trace_log и повторите то же самое для каждой удаленной таблицы. Если вы хотите сохранить диагностику, альтернативой является агрессивный TTL для каждой таблицы вместо remove="1", что подробно описано в документации Langfuse по масштабированию. Эти директивы TTL применяются только при первом создании системной таблицы, поэтому в существующей инсталляции та же документация поможет вам добавить их задним числом.
Стоит знать еще об одной таблице. blob_storage_file_log отслеживает файлы событий, загруженные в ваш бакет. Если вы также настраиваете политику жизненного цикла (lifecycle policy) для бакета, задайте для этой таблицы соответствующий TTL, чтобы они не рассинхронизировались.
ALTER TABLE blob_storage_file_log MODIFY TTL created_at + INTERVAL 30 DAY DELETE;Также настройте простое оповещение df -h для диска с данными. Трейсы не растут равномерно. Они растут в тот день, когда вы выпускаете нового агента, и первым признаком этого не должен быть отказ в приеме данных.
Резервное копирование Postgres и ClickHouse
Резервная копия Langfuse состоит из трех частей. В Postgres хранятся пользователи, организации, проекты и API-ключи. В ClickHouse хранятся трассировки. В MinIO хранятся необработанные события. Если восстановить только Postgres, вы получите работающий вход в систему без истории. Если восстановить только ClickHouse, вы получите историю, которую никто не сможет просмотреть. Такое разделение характерно не только для Langfuse; система поддержки Chatwoot при self-hosted установке имеет ту же структуру: дамп Postgres, сделанный без директории с загрузками, восстанавливает переписки, в которых отсутствуют все вложения.
Postgres представляет собой обычный pg_dump, который и используется в документации по резервному копированию Langfuse для Docker-инсталляций.
docker compose exec -T postgres pg_dump -U postgres postgres \
| gzip > langfuse-pg-$(date +%F).sql.gzС ClickHouse требуется больше внимания, так как директория с данными, скопированная во время выполнения операций слияния (merges), не является консистентной резервной копией. Простой подход для одного сервера — остановить контейнер и архивировать том.
docker compose stop clickhouse
docker volume ls | grep clickhouse
docker run --rm -v langfuse_langfuse_clickhouse_data:/data -v "$PWD":/backup alpine \
tar czf /backup/langfuse-ch-$(date +%F).tar.gz -C /data .
docker compose start clickhouseИспользуйте имя тома, которое выводит docker volume ls, а не то, что указано в YAML-файле. В файле объявлен langfuse_clickhouse_data, но Compose добавляет к нему префикс с именем проекта, поэтому клон в директории с именем langfuse создаст langfuse_langfuse_clickhouse_data. Если ошибиться, docker run создаст новый пустой том без предупреждений, и ваш архив окажется пустым.
Langfuse загружает необработанные данные событий в бакет при каждом запросе на прием данных и повторно считывает их для перезапуска неудачных заданий, поэтому кратковременная остановка ClickHouse в основном означает, что воркеры выполнят повторные попытки позже. Выполняйте это в часы низкой нагрузки и старайтесь сократить время простоя. Для более нагруженных инстансов инструкция BACKUP DATABASE default TO S3(...) в самом ClickHouse позволяет создать консистентную резервную копию без остановки сервера. MinIO — это третья часть, и mc mirror или репликация MinIO во внешний бакет решают эту задачу. Что бы вы ни создали, выносите данные с сервера, для чего и предназначены зашифрованные резервные копии restic на VPS.
В Redis хранятся очередь и кэш. Потеря этих данных приведет к удалению заданий из очереди, даже если файлы необработанных событий останутся в бакете.
Предостережение о консистентности реально и требует четкого понимания. Дампы Postgres и ClickHouse создаются в разные моменты времени, поэтому после восстановления может оказаться, что запись о проекте существует без трассировок или трассировки принадлежат проекту, которого больше нет. Langfuse допускает такие ситуации, но старайтесь делать оба дампа с минимальным интервалом и в периоды низкой активности. Бакет с событиями является основной страховкой, так как Langfuse загружает туда необработанные данные при каждом запросе на прием.
Хотя бы раз выполните восстановление в тестовой среде. Именно так вы узнаете о неверном имени тома сейчас, а не во время аварии.
На что смотреть в первую очередь
Четыре показателя заслуживают внимания в первую неделю.
- Стоимость трассировки. Langfuse вычисляет стоимость на основе имени модели и количества использованных токенов. Отсортируйте трассировки по стоимости и изучите самую дорогую от начала до конца. Обычно причина кроется в разросшемся промпте: в контекст вставлен целый документ или история диалога, которую никто не сокращает. Как только вы это увидите, контроль расходов на AI-агента превратится из догадок в инженерную задачу.
- Разделение токенов на входные и выходные. Входных токенов много, и они дешевы; выходных мало, и они дороги, а кэшированные входные данные стоят еще меньше. Тот же принцип учета описан в том, как считается использование токенов в Claude Code, и он применим к любому агенту, который вы пишете самостоятельно.
- Перцентили задержки. Медиана скрывает проблему. В p95 и p99 скрываются тайм-ауты, а внутри цикла агента медленный вызов инструмента на уровне p95 умножается на количество итераций.
- Неудачные вызовы инструментов. Отфильтруйте наблюдения по уровню
ERROR. Инструмент, который дает сбой в 5% случаев, незаметен в общей статистике успеха, но очень хорошо виден в трассировках, где вы наблюдаете, как модель пытается повторить запрос и тратит токены на обходные пути.
Установите период хранения данных и выберите дашборд, который будете проверять еженедельно в тот же день, когда выполняете деплой. Инструмент наблюдаемости, который никто не открывает — это база данных, которая просто заполняет диск.
FAQ
Сколько оперативной памяти требуется для self-hosted Langfuse?
Планируйте использование 4 ядер CPU и 16 GiB оперативной памяти — это рекомендуемые параметры для одной виртуальной машины согласно руководству Langfuse Docker Compose, плюс около 100 GiB дискового пространства. Опубликованные минимальные требования для компонентов составляют 8 GiB для ClickHouse и 4 GiB для каждого из контейнеров web и worker. На той же странице указаны 4 GiB для Postgres, 1.5 GiB для Redis и 4 GiB для MinIO. Суммарно для всех шести компонентов требуется 25.5 GiB, что превышает рекомендацию в 16 GiB для Compose.
Почему диск ClickHouse продолжает заполняться после настройки хранения данных?
Настройка периода хранения (retention) распространяется только на собственные данные Langfuse. ClickHouse отдельно записывает данные в свои диагностические таблицы trace_log, text_log, opentelemetry_span_log, metric_log, asynchronous_metric_log и latency_log, для которых по умолчанию не задан TTL. Выполните запрос system.parts с группировкой по таблицам, чтобы определить самую большую из них, затем отключите неиспользуемые таблицы с помощью записи remove="1" в файле конфигурации в директории /etc/clickhouse-server/config.d/, перезапустите ClickHouse и удалите существующие таблицы, чтобы освободить занятое место.
Какой минимальный срок хранения данных в Langfuse?
Три дня. Период хранения настраивается для каждого проекта в настройках проекта или через Organization Management API. Ночное задание удаляет трассировки, наблюдения, оценки и медиафайлы, срок хранения которых истек, как из ClickHouse, так и из объектного хранилища (за исключением медиафайлов, связанных с сохраненными элементами наборов данных). В self-hosted инсталляции эта функция является частью Enterprise Edition и требует лицензионного ключа. Без ключа данные хранятся бессрочно. Удаление необратимо, поэтому сначала настройте экспорт в объектное хранилище, если вам требуется история за пределами этого окна.
Нужно ли делать резервные копии и Postgres, и ClickHouse?
Да, так как они хранят разные данные. В Postgres находятся пользователи, организации, проекты и API-ключи, а в ClickHouse — сами данные трассировок. Восстановление только из Postgres даст вам пустой экземпляр, в который можно войти, но в котором ничего нет. Также делайте резервную копию бакета MinIO, так как там хранятся необработанные события, которые Langfuse сохраняет при поступлении; это наиболее близкий к «источнику истины» компонент в стеке.
Можно ли подключить существующую настройку OpenTelemetry к self-hosted Langfuse?
Да. Langfuse v4 и текущие SDK построены на базе OpenTelemetry, а инструменты Anthropic и OpenAI OTel экспортируют данные напрямую в него. В Python выполните pip install langfuse opentelemetry-instrumentation-anthropic, вызовите AnthropicInstrumentor().instrument() один раз при запуске и установите LANGFUSE_PUBLIC_KEY, LANGFUSE_SECRET_KEY и LANGFUSE_BASE_URL на ваш хост. Проверьте результат с помощью langfuse.auth_check(), прежде чем искать причину отсутствия данных на дашборде.