AlignEval: Building an App to Make Evals Easy, Fun, and Automated
Юджин Ян представляет AlignEval — приложение, которое упрощает и автоматизирует создание LLM-оценщиков (LLM-evaluators) и сводит процесс к четырём шагам: загрузить CSV с входами и выходами, разметить примеры как pass/fail, задать критерии и запустить оценщик, а затем оптимизировать его на dev/test-разбиении. Ключевая идея в том, что мало выровнять ИИ под человеческие предпочтения — нужно ещё калибровать человеческие критерии по реальным выходам модели, то есть сначала смотреть на данные, а не придумывать критерии заранее. Приложение использует самые маленькие модели крупных лабораторий (gpt-4o-mini и claude-3-haiku), бэкенд на Python + FastAPI и фронтенд на Next.js (первый TypeScript-проект автора), а хостинг — на Railway. В качестве примера приводится датасет Factual Inconsistency Benchmark из 50 новостных статей с парами «согласованное/несогласованное» резюме. Автор делится тем, что оптимизация делит данные на dev и test, прогоняет n испытаний для улучшения F1 (в примере F1 растёт с 0,571 до 0,722 на dev и 0,727 на test), и предупреждает о риске переобучения при малой выборке. Код проекта открыт на GitHub, а статью завершают благодарности и рекомендации по дальнейшему чтению про оценку LLM.
AlignEval: создаём приложение, которое делает оценки простыми, увлекательными и автоматизированными
Зайдите на aligneval.com, чтобы начать создавать собственный LLM-оценщик; примеры данных прилагаются.
Обновление: теперь интегрировано с LangSmith и упомянуто на VentureBeat! 🎉
Любому продукту на базе ИИ нужны оценки. Но признаем честно — их мучительно строить, трудно масштабировать, и большинство команд делает их неправильно. В результате многие ИИ-продукты упираются в оценки как в узкое место, иногда задерживая запуски на недели или даже месяцы.
Примерно последний год я бьюсь над оценками, специфичными для продукта и задачи. Я пробовал разные способы обнаруживать галлюцинации, дообучать оценщиков и оценивать сами LLM-оценщики. Были тупики. Были кроличьи норы. Но я понял, что работает, а что нет.
Именно поэтому я рад представить AlignEval — приложение, которое делает оценки простыми и… увлекательными? (Ладно, я согласен хотя бы на «менее мучительными».) Оно также пытается частично автоматизировать процесс. AlignEval сводит создание LLM-оценщиков к четырём простым шагам:
Загрузите CSV-файл со столбцами для входа и выхода. Посмотрите на данные и разметьте примеры как pass или fail. Задайте критерии оценки, запустите LLM-оценщик, проверьте результаты. Оптимизируйте LLM-оценщик на разбиении dev-test.
Кстати, если вы хотите больше узнать об оценках, мои друзья Hamel и Shreya в июле проводят последний поток курса «AI Evals for Engineers and PMs». Вот промокод на скидку 35%.
Выравнивайте ИИ под человека. Калибруйте человека под ИИ. Повторяйте.
Ключевая мысль в том, что выравнивание ИИ под человеческие предпочтения — это лишь половина дела. Чтобы построить эффективные оценки, нужно ещё калибровать человеческие критерии по выходам ИИ.
Многие команды совершают ошибку, разрабатывая изощрённые критерии оценки, не посмотрев сначала на данные. Это всё равно что теоретизировать о пользовательском опыте и дефектах из башни из слоновой кости, не делая разбор ошибок. Из работы Who Validates the Validators: «Невозможно полностью определить критерии оценки до того, как человек оценит выходы LLM.»
Это ведёт к двум типам плохих критериев. Во-первых, нерелевантные критерии — пустая трата времени, например общие метрики (скажем, полезность) или дефекты с очень низкой вероятностью (например, грамматика, орфография). Во-вторых, нереалистичные, недостижимые критерии, к которым технология ещё не готова, — например, автономные агенты ещё в 2023 году. В любом случае команды растрачивают усилия, которые лучше было бы вложить в оценку настоящих дефектов, встречающихся с умеренной частотой.
(Я думаю, готовые «из коробки» решения для оценки подпитывают эту проблему, навязывая общие критерии, которые легко подключить, но которые игнорируют особенности вашего домена, продукта и данных.)
Способ решить это — и построить полезные оценки — двигаться от данных назад. Именно это и пытается делать AlignEval, ставя на первое место данные и метрики, а не заранее заданные критерии или LLM.
Начало работы: загрузите данные
Чтобы начать, загрузите CSV-файл со следующими столбцами:
id: позволяет сопоставлять размеченные и оценённые примеры с вашими данными input: контекст, передаваемый LLM для генерации выхода (например, текст для классификации, новости для резюмирования, извлечённые документы для ответа на вопросы) output: то, что генерирует LLM (например, метка классификации, резюме, ответ) label: ваше суждение о том, проходит ли выход (0) или не проходит (1)
Инструкция по загрузке CSV-файла.
Если у вас нет готового CSV, скачайте образец на основе Factual Inconsistency Benchmark. Он содержит 50 новостных статей, у каждой по два резюме. Одно фактологически согласованно, другое — нет. Идеально для задачи бинарной разметки в AlignEval.
После загрузки CSV вы увидите данные в гибком табличном представлении. Меняйте ширину браузера, чтобы регулировать, насколько широкой или узкой будет таблица и столбцы.
Как выглядит табличное представление после загрузки CSV-файла.
Режим разметки: смотрите на данные
В режиме разметки наша единственная задача — смотреть на данные. AlignEval сводит процесс к сравнению полей input и output. И для каждого примера нам нужно принять лишь бинарное решение — pass или fail.
Инструкция для режима разметки.
Почему бинарные метки? Это даёт более точные данные, занимает меньше времени и снижает когнитивную нагрузку. DoorDash применил похожий подход. Аналогично, Llama2 делал ставку на сбор бинарных человеческих предпочтений. Авторы Llama2 также рассказали на митапе, что собирать бинарные предпочтения было намного быстрее, чем писать примеры для обучения с учителем (supervised finetuning).
Важно смотреть на данные непредвзято и не писать критерии исходя из наших предположений. Нам также стоит сопротивляться искушению преждевременно определять критерии. Сначала нужно погрузиться в данные. Это снижает риск охоты за несуществующими дефектами или погони за нереалистичными ожиданиями. Понимая, что LLM на самом деле генерирует, мы можем задать более осмысленные и лучше откалиброванные критерии.
Ремикс «Смотрите на свои данные» — благодаря Jason Liu. Запишитесь на его следующий курс по RAG здесь.
После разметки 20 строк мы разблокируем режим оценки. (Хотя режим оценки доступен после 20 меток, я считаю, что этого слишком мало, чтобы понять данные достаточно хорошо для определения критериев, и слишком маленькая выборка для оценки. Я советую стремиться к 50–100, прежде чем писать критерии и запускать оценки. Чем лучше вы знакомы со своими данными, тем лучше будут ваши оценки.)
Режим оценки: пишем критерии, оцениваем оценщик
Разблокировав режим оценки, мы можем теперь написать наши критерии оценки, специфичные для задачи. Держите их простыми: оценивайте по одному измерению и возвращайте либо 0 (pass), либо 1 (fail).
Инструкция для режима оценки.
Вот промпт, который я использую для классификации фактологической несогласованности. Мы начинаем всего с двух предложений, определяющих, как выглядит pass и fail. Мы можем уточнить его после запуска LLM-оценщика и изучения объяснений и предсказаний.
Написание промпта и выбор моделей и полей.
Далее мы выбираем модель (gpt-4o-mini или claude-3-haiku) и поля входа (либо input и output вместе, либо только output). Для большинства задач (например, классификации, резюмирования, Q&A) мы хотим сравнивать output с input. Тем не менее для некоторых задач, например оценки соблюдения стайлгайда или тона речи, нам нужен только output. Сосредоточение только на output снижает стоимость токенов и задержку, потенциально повышая при этом качество.
Также крайне важно оценивать наши LLM-оценщики против размеченных данных. Нажмите «Evaluate», и мы увидим метрики в правом верхнем углу: размер выборки, recall, precision, F1, каппу Коэна $\kappa$, а также счётчики истинных и ложных срабатываний/пропусков (true и false positives/negatives).
Метрики для оценки LLM-оценщика.
Если размер нашей выборки мал (например, 20), метрики могут сильно колебаться, даже когда мы перезапускаем тот же самый LLM-оценщик. Это связано со стохастичностью LLM. Стабильность можно повысить, разметив больше данных. Стремитесь хотя бы к 50 размеченным примерам — это также разблокирует режим оптимизации.
Режим оптимизации: полуавтоматические улучшения 🤞
Режим оптимизации — это место, где (надеюсь) происходит магия. Нажмите «Optimize» и дайте AlignEval сделать своё дело, чтобы улучшить ваш LLM-оценщик. Хотя он всё ещё в раннем бета-тесте, для нескольких сценариев он добился неплохих улучшений. (И нет, это не dspy.)
Инструкция для режима оптимизации.
Под капотом оптимизация делит размеченные данные на наборы dev и test. (Поскольку мы не обучаем модель, мы называем это разбиением для разработки (development split), а не обучающим разбиением.) Затем она запускает $n$ испытаний на наборе dev, чтобы улучшить F1, используя ту же LLM и поля из режима оценки. После $n$ испытаний улучшенный LLM-оценщик оценивается на невиданном тестовом наборе. В таблице ниже F1 стартует с 0,571, поднимается до 0,722 на испытании 5 на dev, а затем даёт F1=0,727 на test.
Метрики из испытаний оптимизации на разбиениях all, dev и test.
Иногда метрики на dev и test значительно расходятся. При малом размере выборки (25 на разбиение, 50 в сумме) это, вероятно, связано с тем, что разбиение dev нерепрезентативно для всего распределения данных, включая разбиение test. Таким образом, LLM-оценщик может переобучиться на наборе dev и не обобщиться на набор test.
Чтобы улучшить обобщение между разбиениями dev и test, мы можем разметить больше данных, обеспечив их разнообразие и репрезентативность. Быть разнообразным — значит быть сбалансированным как по меткам 0 и 1, так и по разнообразию входов и выходов. Быть репрезентативным — значит быть похожим на реальные примеры. Мы также можем запускать несколько LLM-оценщиков параллельно и объединять их оценки в ансамбль. PoLL показал, что ансамбль из трёх меньших LLM-оценщиков превзошёл gpt-4.
Для наглядного разбора — вот демо, где я смотрю и размечаю 50 строк данных, лол.
За кулисами: как создавался AlignEval
Будучи новичком во фронтенд-разработке (это моё первое TypeScript-приложение), я опирался на мудрость толпы, опрашивая Twitter и LinkedIn в поисках совета. Я также построил одно и то же приложение пять раз, чтобы прочувствовать несколько фреймворков. В частности, я попробовал FastHTML, Next.js, SvelteKit и FastAPI + HTML (мой основной выбор для прототипирования).
По ранним прототипам Next.js показался хорошим выбором. Интуитивный, масштабируемый и идеальный повод выучить TypeScript. А благодаря Cursor на мои новичковые вопросы легко находились ответы: в чём разница между const и let? Что такое prop? Он также упростил создание UX-компонентов и исправление багов в 2–3 раза быстрее, поддерживая высокий темп и мотивацию.
Для бэкенда Python + FastAPI был очевидным выбором. Экосистема Python для анализа данных и машинного обучения упростила эксперименты с режимом оптимизации.
Когда дело дошло до LLM, я выбрал самые маленькие модели от крупнейших лабораторий: gpt-4o-mini и claude-3-haiku (скоро claude-3.5-haiku). Они дешёвые, быстрые и достаточно хороши для LLM-оценщиков бинарной классификации. Идеальная комбинация для бесплатного приложения. И с каждым релизом эти маленькие модели становятся всё более и более способными.
Для gpt-4o-mini я использовал функциональность структурированного вывода, которая пока в бете. Она позволяет пользователям задавать желаемую схему вывода с помощью Zod (JavaScript) или Pydantic (Python). Вот пример на JavaScript и его эквивалент на Python:
import { z } from "zod"; const EvaluationResponse = z.object({ explanation: z.string(), prediction: z.string().refine((val) => val === '0' || val === '1') });
from pydantic import BaseModel class EvaluationResponse(BaseModel): explanation: str prediction: str
Для claude-3-haiku я задавал XML-вывод через промпт. По моему опыту на работе и в AlignEval, это срабатывает в 99,9% случаев. Вот промпт, который я использовал для AlignEval.
Evaluate the output based on the provided criteria. First, in the
Чтобы определиться с хостингом, я провёл опрос в Twitter и изучил документацию по таким вариантам, как Dokku, Coolify, Vercel и т. д. Особенно помог разбор Dokku от Hamel. Хотя поначалу я подумывал хостить приложение на Hetzner с Dokku (ещё одна возможность научиться чему-то новому), в итоге я выбрал ленивый путь (читай: безжалостно расставлять приоритеты) и начал с хостинга на Railway. Это было хорошее решение.
Хостинг на Railway оказался проще простого. После настройки проекта через их веб-интерфейс и привязки его через CLI (railway link) выкатка новых обновлений сводится к простому railway up. Каждое обновление занимает одну-две минуты. Railway также идёт с несколькими вариантами баз данных, включая Postgres и Redis. Хотя VPS в долгой перспективе может быть дешевле, на этом этапе действует YAGNI. Возня с VPS отвлекла бы от улучшения UX, реализации фич и проработки режима оптимизации.
Моя простая настройка на Railway
Если вы хотите начать с Railway, пожалуйста, используйте мой партнёрский код — это поможет с расходами на хостинг и поддержит работу AlignEval!
Путь от прототипа на ноутбуке до публичной беты потребовал некоторых усилий. Работа включала:
Разделение на фронтенд Next.js и бэкенд FastAPI, миграцию с SQLite на Postgres Реализацию обратной связи в реальном времени для разметки, оценки и оптимизации Добавление функций для упрощения разметки (кнопки pass/fail), кастомизации моделей и полей (выпадающие списки, интеграция с провайдерами моделей) и не только Улучшение UI (как бы грубо он ни выглядел сейчас, раньше было намного хуже, лол) Истребление множества багов (и, вероятно, упущение многих других)
Вот список задач, который у меня был; было ещё много задач и багов, которые я не удосужился отслеживать. Поскольку я ограничил усилия временем до октября, несколько пунктов не были завершены. Но если AlignEval наберёт обороты и окажется полезным, я, возможно, вернусь к списку.
## Todos - [x] Split deployment into frontend and backend - https://help.railway.app/questions/how-to-expose-a-fast-api-backend-service-a1712631 - https://help.railway.app/questions/econnrefused-when-calling-another-servic-5662d969#p-1 - ~~[ ] Or consider something like this: https://vercel.com/templates/next.js/nextjs-fastapi-starter~~ (only works with Vercel) - [x] Add external database (Railway Postgres) - [x] Write interface to ensure compatibility between SQLite and Postgres - [x] Connect label-app to Railway Postgres - [x] Connect label-hpo to Railway Postgres - [x] Show feedback to users while optimization is running - [x] Update table names to use CSV file name - [x] Add support for multiple tables - [x] Replace tablename parameter with filename parameter - [x] Uploading a CSV file with an existing name should return the existing table - [x] Add llm-evaluator optimization to label-hpo - [x] Add dropdown to select evaluation fields - [x] Add ability to delete optimization table, with password - [x] Add progress bar to gamify labeling, evaluation and optimization - [x] Add buttons to click pass and fail - [x] Add usage count (upload (files, rows), evaluate (files, rows), optimize (files, trials)) - [x] Add info button intro next to header to explain the site - [x] Update favicon - [x] Add support for OpenAI models - [x] Add balanced val-test split for optimization - [x] Add columns to optimization metrics: split (dev, test), model, evaluation_fields - [x] Set max upload rows to env variable - [ ] Fix bug where alert pops up: "Failed to handle optimization: Unexpected token '<', "
• • •
Создавать AlignEval было ужасно весело, а писать об этом пути — отличный способ поразмышлять. Это легко мой любимый проект года, потому что я смог построить приложение и многому научиться по дороге. (Хотя впереди ещё ноябрь и декабрь, чтобы попробовать его превзойти.)
Если вы устали тратить дни или недели на оценки и выравнивание LLM-оценщиков, попробуйте AlignEval. Он создан, чтобы упростить ваш рабочий процесс и сосредоточиться на самом важном:
Смотреть на данные и добавлять метки Определять осмысленные критерии Оценивать LLM-оценщик Полуавтоматически оптимизировать его
Вот код на случай, если вы захотите развернуть собственный экземпляр. Это мой первый проект на TypeScript, так что обратная связь приветствуется! Как я мог бы организовать его лучше? Каким лучшим практикам мне стоило следовать? И помимо кода — что вы находили полезным при создании LLM-оценщиков? Оставьте комментарий ниже или напишите мне в личку.
Спасибо невероятным людям, благодаря которым обсуждать эту тему было так весело, и которые дали полезную обратную связь на ранних демо: Shreya Shankar, Hamel Husain, Kyle Corbitt, David Corbitt, Saumya Gandhi, Swyx, Eugene Cheah и Dennis Taylor. И спасибо Hamel Husain за чтение ранних черновиков этого текста.
Кстати, если вы хотите больше узнать об оценках, мои друзья Hamel и Shreya в июле проводят последний поток курса «AI Evals for Engineers and PMs». Вот промокод на скидку 35%.
Дальнейшее чтение
Your AI Product Needs Evals Task-Specific LLM Evals that Do & Don’t Work Who Validates the Validators Evaluating the Effectiveness of LLM-Evaluators Creating a LLM-as-a-Judge That Drives Business Results
Если этот материал оказался полезным, пожалуйста, цитируйте его так:
Yan, Ziyou. (Oct 2024). AlignEval: Building an App to Make Evals Easy, Fun, and Automated. eugeneyan.com. https://eugeneyan.com/writing/aligneval/.
или
@article{yan2024aligneval, title = {AlignEval: Building an App to Make Evals Easy, Fun, and Automated}, author = {Yan, Ziyou}, journal = {eugeneyan.com}, year = {2024}, month = {Oct}, url = {https://eugeneyan.com/writing/aligneval/} }
Присоединяйтесь к 11 800+ читателям, получающим обновления о машинном обучении, RecSys, LLM и инженерии.