Больше никаких «черных ящиков»: мониторим и оцениваем качество LLM-приложений с Langfuse. langfuse.. langfuse. llm.. langfuse. llm. python.. langfuse. llm. python. qa.. langfuse. llm. python. qa. Анализ и проектирование систем.. langfuse. llm. python. qa. Анализ и проектирование систем. Блог компании YADRO.. langfuse. llm. python. qa. Анализ и проектирование систем. Блог компании YADRO. искусственный интеллект.. langfuse. llm. python. qa. Анализ и проектирование систем. Блог компании YADRO. искусственный интеллект. тестирование.. langfuse. llm. python. qa. Анализ и проектирование систем. Блог компании YADRO. искусственный интеллект. тестирование. Тестирование IT-систем.

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

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

Меня зовут Александр Сесоров, я работаю инженером по тестированию в YADRO. Занимаюсь задачами автоматизации оценки производительности, точности и эффективности моделей на различных конфигурациях. Сегодня проведу краткий экскурс в инструментарий Langfuse и на примерах из практики покажу, как превратить оценку качества LLM-приложения из гадания в систематизированный и прозрачный сбор метрик на всех этапах.

Больше никаких «черных ящиков»: мониторим и оцениваем качество LLM-приложений с Langfuse - 1

Как все начиналось

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

Мы постоянно тестировали гипотезы: пробовали разные LLM, крутили версии промптов и меняли параметры. Но не получали четкого ответа, стало ли лучше. Оценивать результаты «на глаз», читая сотни саммаризаций, — путь в никуда. Нам требовался инструмент, который позволил бы наглядно тестировать и сравнивать метрики для разных моделей и промптов, и желательно с полной трассировкой по всем компонентам сервиса. 

Так мы и пришли к Langfuse. Но перед тем как перейти к обзору, давайте подсветим, какие вообще сложности могут возникнуть при оценке качества прил��жений.

Четыре главные проблемы при оценке качества LLM

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

Субъективность оценки. Трудно формализовать, какой именно ответ модели считать «хорошим», если речь не идет о простой классификации. Оценка генерации текста всегда зависит от контекста. Что лучше — краткий сухой ответ или развернутый, но с «водой»? Стандартные метрики вроде BLEU или ROUGE здесь часто бессильны: они смотрят на пересечение слов, а не на смысл. Без четких критериев качества команда рискует погрязнуть в спорах о вкусовщине вместо работы над точностью.

Приведу простой пример. Модель попросили составить список всех фильмов, снятых Тарковским, и упорядочить их по дате выхода. Вот что получилось: 

Больше никаких «черных ящиков»: мониторим и оцениваем качество LLM-приложений с Langfuse - 2

Выдача слева корректна, в нее даже вошла короткометражка, но есть ошибка с годом выхода одной из картин: «Зеркало» было снято в 1974 году, а не в 1975-м. Во втором случае (справа) модель потеряла короткометражку «Станция метро», но год выхода везде указан корректно. Какой из этих ответов в итоге лучше, зависит от контекста задачи.

Сложность отладки. Когда мы получаем неудовлетворительный результат от LLM, причина сбоя не всегда очевидна. Возможно, дело в некачественном промпте. А может, проблема возникла раньше — например, в RAG-системе, если поисковик (retriever) извлек из базы данных нерелевантный контекст, он же «мусор». Или же мы просто выбрали неудачные параметры генерации — temperature/top-p. В сложных пайплайнах, где компонентов много, найти истинный источник ошибки без трассировки — тот еще вызов.

Нестабильность. Со временем качество работы приложения может меняться, и не всегда в лучшую сторону. Это происходит после обновления самой модели провайдером, изменений в промптах или появления новых типов входных данных, к которым система не была готова. Без постоянного мониторинга мы рискуем не заметить момент деградации качества и н�� исправить ситуацию вовремя.

Основные трудности прояснили — Langfuse как раз призван решить часть из них.

Открытый исходный код и понятный интерфейс: обзор Langfuse 

Больше никаких «черных ящиков»: мониторим и оцениваем качество LLM-приложений с Langfuse - 3

Langfuse состоит из двух основных компонентов — SDK для сбора телеметрии в коде и отдельно Web UI для анализа. В нем можно посмотреть пошаговый анализ работы каждого вызова LLM-приложения, пользовательский интерфейс (UI) интуитивно понятный. Интегрируется Langfuse уже в исходные пайплайны.

Если сравнивать с аналогами, одно из преимуществ Langfuse — полностью открытый исходный код. Его можно бесплатно развернуть на своих серверах, в своем контуре и при необходимости настроить под себя.

Под капотом Langfuse несколько ключевых компонентов. Основа всего — трейсы (traces).

Больше никаких «черных ящиков»: мониторим и оцениваем качество LLM-приложений с Langfuse - 4

Каждый трейс состоит из отдельных шагов — наблюдений (observation). В Langfuse их всего три типа:

  • генерация (generation) — вызов языковой модели;

  • спан (span) — любая другая функциональность вроде вызова API и обращения к базе данных;

  • события (events)— моментальное дебажное текстовое сообщение, как лог, чтобы зафиксировать что-то важное в определенный момент времени работы приложения.

Следующий ключевой компонент — метрики. Langfuse автоматически собирает базовые показатели Performance для каждой генерации. Это и время задержки, и расходы на вызов API модели, и объем токенов. 

Но главное, мы можем добавлять собственные кастомные метрики. Поддерживаются:

  • числовые — например, оценка качества ответа условно по шкале от одного до десяти;

  • булевые, то есть прошел ли ответ проверку;

  • категориальные, текстовые оценки — например, тема разговора или текстовые градации точности ответа «полностью корректный», «частично корректный» и так далее.

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

Больше никаких «черных ящиков»: мониторим и оцениваем качество LLM-приложений с Langfuse - 5

Для системного улучшения приложений в Langfuse есть датасеты и эксперименты. Датасет — это коллекция тестовых примеров, они задаются через UI или код. Каждый пример — это входные данные и эталонный ответ для сравнения, но он есть не всегда. Эксперимент — это запуск определенной версии приложения, например с новым промптом или моделью на примерах из датасета. Langfuse записывает и логирует все результаты, чтобы на одном датасете можно было сравнить разные версии моделей и промптов и выбрать лучшую.

Больше никаких «черных ящиков»: мониторим и оцениваем качество LLM-приложений с Langfuse - 6

Еще в Langfuse есть инструментарий для создания шаблонов промптов прямо в UI. В них вы можете задать переменные, которые потом определите уже в коде, чтобы не делать множество промптов с плюс-минус одинаковыми входными данными. Между шаблонами легко переключаться, можно сравнивать версии и метрики для них.

Чтобы видеть картину в целом, в Langfuse предусмотрены дашборды. Тут сразу отмечу, что в версии, которая развернута сейчас в контуре компании YADRO, они не поддерживаются. Поэтому мы и перешли к использованию Superset, об этом расскажу ниже. Но в последних версиях дашборды уже добавлены, они кастомизируются, на них можно вывести ключевые показатели приложений, метрики качества и не только, поэтому сказать о них важно.

Больше никаких «черных ящиков»: мониторим и оцениваем качество LLM-приложений с Langfuse - 7

Как интегрировать в проекты

Чтобы создать новый проект, достаточно нажать кнопку New Project и задать название. Дальше мы получаем API-ключи и секретный публичный ключ, который будем использовать в пайплайне нашего приложения, чтобы логировать метрики.

Ключи, которые выдаются на этапе создания проекта, можно использовать для инициализации в Langfuse. Прямо в UI есть подсказка, как это сделать в чистом Python или отдельных библиотеках — Lang Chain, LLM Index и других. При необходимости можете создать дополнительные ключи. Пригодится, если нужно разграничить права доступа: ключ для администратора, только для чтения и так далее.

Дальше покажу, как мы размечаем код для логирования данных в Langfuse. В первую очередь создаем родительский трейс для всей операции с помощью функции Langfuse trace — он будет основным для всего пайплайна. Можно задать ему имя и юзера и любые полезные данные, которые хотим видеть в дашборде. Поддерживаются все типы данных, которые есть в Python. 

trace = langfuse.trace(

    name="summarization",

    user_id="username",

    metadata={"environment": "dev"}

)

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

span = trace.span(

    name="transcription",

    input={"audio_path": path},

    metadata={"some": "useful data"}

)

transcription = transcribe(audio_path=path)

span.end(output={"transcription": transcription})

Чтобы вызвать LLM, используем trace generation. Передаем все самое важное, касающееся генерации, — саму модель, промпт, а после выполнения логируем полученный ответ и данные об использованных токенах. Для разных подходов и библиотек применяются разные способы подсчета токенов, поэтому мой код тут только для примера:

generation = trace.generation(

    name="summary-generation",

    input=transcription,

    model=model_name,

    prompt=prompt

)


 answer = generate_summary(transcription, model_name, prompt)

usage = {"promptTokens": 25, "completionTokens": 15, "totalTokens": 40}
 generation.end(output=answer, usage=usage)

Добавить оценку так же просто, как и создать отдельные трейсы и шаги. С помощью функции langfuse score мы привязываем какую-либо метрику ко всему трейсу.

langfuse.score(

    trace_id=trace.id,

    name="faithfulness",

    value=0.95,

    comment="Reason from DeepEval"

)

Для конкретной генерации можно взять отдельно метрику с помощью generation score. В моем примере это bertscore:

generation.score(

    name=“bertscore",

    value=0.8,

	data_type="NUMERIC"

)

Так же можно добавить оценку для любого шага, а потом в UI Langfuse посмотреть пошаговые оценки для каждого компонента пайплайна.

С датасетами мы тоже работаем через код. Создаем их в Langfuse, загружаем необходимые данные, указываем input и output, если они есть, — с ними можно будет сравнить ответ. Потом во время эксперимента получаем датасет и вызываем приложение для каждого элемента.

Загрузка локального датасета в Langfuse:

langfuse.create_dataset(name="dataset_name");

for item in local_items:

    langfuse.create_dataset_item(

        dataset_name="dataset_name",

        input=item["input"],

        expected_output=item["expected_output"]

    )

Оборачивая запуск в RAM, мы автоматически связываем каждый прогон с соответствующим элементом. Затем в UI можно будет перейти во вкладку Datasets и для каждого элемента посмотреть, какие были запуски, метрики и так далее. Это сильно упрощает анализ.

Использование загруженного датасета в экспериментах:

dataset = langfuse.get_dataset("dataset_name")

for item in dataset.items:

    with item.run(run_name="experiment_name") as root_span:

        output = run_my_custom_llm_app(item.input, prompt)

        root_span.score_trace(name="sentence_bertscore", value=0.7)

Напоследок ��ще пример с управлением промптами. В интерфейсе Langfuse мы можем создать шаблон с переменными. Тут у меня в фигурных скобках указан language:

«Твоя задача — строго на основании данных из стенограммы подготовить связное и подробное саммари на {{language}} языке».

В коде мы запрашиваем нужный промпт по имени, можем выбрать определенную версию или найти по тегу — в моем примере это latest. Дальше компилируем, подставляя нужные значения в заданные переменные. Готово, можно брать и работать!

prompt = langfuse.get_prompt("summarization_demo", label="latest", version=19)

compiled_prompt = prompt.compile(language="русском")

Из Langfuse в Superset

Выше я уже писал, что с нашей версией мы не могли создавать кастомные дашборды. Решение было таким — интегрировать аналитику данных, которую собирали в Langfuse, в Superset. С PostgreSQL сделать это было просто.

Мы создали несколько дашбордов. Например, в Nightly попадают ежедневные замеры из триггера для отслеживания флуктуаций в метриках. Тут есть фильтрация по версиям моделей репозитория приложений саммаризации или промпта. На любой трейс из nightly-запуска можно перейти из Superset в Langfuse, для этого есть ссылки.

Больше никаких «черных ящиков»: мониторим и оцениваем качество LLM-приложений с Langfuse - 8

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

Больше никаких «черных ящиков»: мониторим и оцениваем качество LLM-приложений с Langfuse - 9
Больше никаких «черных ящиков»: мониторим и оцениваем качество LLM-приложений с Langfuse - 10

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

Больше никаких «черных ящиков»: мониторим и оцениваем качество LLM-приложений с Langfuse - 11

Что в итоге

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

С экскурсом в Langfuse у меня на сегодня все. Если у вас есть вопросы или хотите подробнее узнать об интеграции в приложение, оставляйте комментарии или приходите в личку — помогу чем смогу. А пока спасибо за внимание!

Автор: Salexoid

Источник

Rambler's Top100