Evaluation driven development (EDD) - способ разработки, при котором поведение LLM-продукта сначала описывают набором evals, а каждое изменение проверяют по двум условиям: не потерять качество там, где продукт уже работает, и улучшить там, где он ошибается. Dosu, AI-тиммейт для разработки, поддержки и сопровождения программных проектов, строит на этой схеме цикл итераций и использует LangSmith, чтобы масштабировать его: платформа даёт мониторинг и поиск по активности продукта. Разбор команды на блоге LangChain описывает, как EDD меняет сам порядок работы над промптами.
Дальше - устройство цикла, потолок ручного просмотра логов через grep и print, набор сигналов для поиска аномалий и чек-лист критериев, по которым сравнивают инструменты мониторинга.
Сразу о границах источников: публичный текст Dosu в доступной версии покрывает принципы и общий ход проекта, но не приводит цифр по конкретным инцидентам и не раскрывает деталей интеграции с SDK. Там, где фактуры не хватает, стоит явная пометка, а инженерные рекомендации отделены от подтверждённых утверждений.
Что такое evaluation driven development и почему обычные тесты не спасают LLM-продукт
Обычный тест отвечает на вопрос, вернула ли функция ожидаемое значение. Для LLM такой вопрос часто некорректен: один запрос даёт разные формулировки, часть из них правильные, часть уверенно ошибочные. Проверять нужно соответствие критерию: решена ли задача пользователя, соблюдён ли формат вывода, нет ли выдуманных фактов. Набор таких проверок называют evals.
EDD добавляет к этому порядок работы: evals появляются до изменения, а не после. Для каждой правки Dosu формулирует две цели - сохранить производительность в областях, где продукт уже справляется, и улучшить её там, где есть проблемы. В разборе на блоге LangChain это описано как условие, без которого изменение не выпускают.
Чем EDD отличается от классического тестирования кода
Граница проходит по природе проверки. Юнит-тест сравнивает значение с эталоном и либо проходит, либо падает. Eval сравнивает ответ с критерием и требует интерпретации: корректный по смыслу ответ может не совпасть с эталонной строкой, а некорректный может выглядеть правдоподобно.
| Аспект | Юнит-тест | Eval для LLM |
|---|---|---|
| Вход | Конкретные аргументы | Реальный запрос с контекстом |
| Критерий успеха | Точное совпадение значения | Соответствие правилу или оценка судьи |
| Стабильность | Результат повторяем | Ответ меняется от прогона к прогону |
| Источник кейсов | Спецификация и баги | Продовый трафик и инциденты |
| Стоимость прогона | Миллисекунды | Платные вызовы модели и время |
Критерий в eval бывает жёстким и оценочным. Жёсткий проверяется кодом: валидный JSON, нужный файл в диффе, отсутствие запрещённого вызова. Оценочный требует судьи - человека или модели с рубрикой, и здесь критична калибровка: плохо настроенная рубрика маскирует улучшения. Как это ломается на практике, показано в кейсе Similarweb про оценку длинных отчётов агентов в LangSmith.
Второе отличие: набор evals живёт вместе с продуктом. Он не фиксируется на старте и не считается завершённым, а пополняется кейсами из прода. Тест, который годами не менялся, для LLM-продукта быстро теряет смысл.
Почему маленькая правка промпта даёт большую регрессию
Промпт - общий контекст для всех типов запросов сразу. Инструкция, добавленная под один сценарий, меняет поведение и на остальных. Dosu фиксирует это наблюдение прямо: незначительная правка промпта нередко улучшала результаты в одной предметной области и одновременно вызывала регрессию в другой.
Пример гипотетический, не из материала Dosu: если ужесточить требование к формату ответа, разметка pull request станет стабильнее, а развёрнутые объяснения для новичков сократятся до сухих списков. Обе реакции вызваны одной строкой в промпте.
Отсюда рабочее правило: правку оценивают на всём наборе evals, а не только на том кейсе, ради которого её сделали. Иначе исправление одного бага привозит два новых, и узнаете вы о них от пользователей.
Зачем Dosu такая дисциплина: продукт берёт на себя ответы на ad-hoc вопросы, триаж issues и процессный overhead. В разборе приводится отраслевая оценка, что до 85% времени разработчиков уходит на не-кодинговые задачи; методология оценки не раскрыта, так что цифру разумно воспринимать как порядок величины.
Цикл EDD в Dosu: от начальных evals до прода и обратно
Цикл состоит из пяти шагов, каждый следующий зависит от предыдущего.
- Описать ожидаемое поведение набором начальных evals: что продукт должен делать на типовых запросах.
- Выпустить изменение.
- Наблюдать прод: смотреть трейсы, фидбек, внутренние ошибки и время ответа.
- Превратить найденный сбой в кейс офлайн-датасета.
- Прогнать датасет перед следующей итерацией и убедиться, что старые сбои не вернулись.
Смысл в том, что выпуск перестаёт быть ставкой на удачу: для каждого изменения понятно его влияние на конечных пользователей, и EDD позволяет выпускать с уверенностью. Dosu запустился в конце июня 2023 года, и тогда объём запросов позволял замыкать цикл вручную. С ростом нагрузки ручной контур перестал справляться, понадобился инструмент мониторинга.
Как описать поведение LLM-продукта начальными evals
Минимальный eval состоит из трёх частей: вход, критерий качества и причина, по которой кейс важен. Причина нужна, чтобы через полгода никто не удалил проверку как непонятную.
Источник кейсов - реальные запросы. На старте ручная инспекция дала команде Dosu понимание, как люди пытаются использовать продукт, какие типы запросов он выполняет хорошо, а на каких проваливается. Эти наблюдения и легли в основу первых проверок.
Практическое правило: начальный набор может быть небольшим, 15-30 кейсов по самым частым сценариям, и это полезнее попытки покрыть всё сразу. Датасет на двести кейсов, написанных из головы, проверяет фантазии автора, а не поведение продукта.
Что делать с найденным сбоем: путь от прода в офлайн-датасет
Правило простое: каждый сбой, найденный в проде, становится кейсом офлайн-датасета. Тогда следующая итерация проверяется и на нём, и повторить ту же ошибку незаметно уже не получится.
Ограничение проявляется быстро: датасет надо чистить. Дублирующиеся кейсы раздувают прогон и растягивают проверку, а противоречивые (два кейса требуют разного поведения на похожих входах) дают ложные падения. Плюс приватность: токены, персональные данные и внутренний код клиентов попадают в датасет только после обезличивания.
Почему ручная инспекция через grep и print перестала работать
До появления полноценного мониторинга Dosu держался на голой дисциплине. Каждый день команда просматривала ответы вручную с помощью grep и print statements, выискивая в логах места для улучшения. При объёме первых недель после запуска это было выполнимо и полезно: в разборе отмечено, что именно такой просмотр дал глубокое понимание того, как люди используют продукт, и где он проседает.
Потолок подхода очевиден: ручная инспекция линейна по количеству запросов, а трафик растёт быстрее, чем команда. К тому же print показывает отдельные точки, а не путь запроса: чтобы разобрать сбой, контекст приходится склеивать вручную из нескольких мест. LangSmith в этом смысле позволил масштабировать EDD, упростив мониторинг и поиск по активности продукта.
Что даёт трассировка на уровне кода: SDK и декоратор @traceable
Здесь придётся обозначить границу фактов: какие именно обёртки и структуру трейсов использует Dosu, публичный текст в доступной версии не раскрывает. Механика трассировки на уровне кода в целом такая: SDK подключается к приложению, а декоратор @traceable оборачивает функцию так, что каждый её вызов попадает в трейс вместе с аргументами и результатом. По документации LangSmith по кастомной инструментации декоратор доступен в вариантах для Python (@traceable), TypeScript и Kotlin (traceable), а для Java используется Tracing.traceFunction; контекст вложенных вызовов платформа распространяет автоматически.
Для LLM-продукта это даёт три вещи в одном месте: входы функций (какой запрос и какой контекст реально пришли), отрендеренный промпт (что именно ушло в модель после подстановки переменных) и вывод модели. Разбор сбоя перестаёт быть археологией по логам.
Практическая ценность ещё и в связке версий. Трейс соединяет версию кода, версию промпта и результат, поэтому при регрессии видно, какой прогон её показал, а не только итоговую метрику.
Как искать аномалии в проде: сигналы, которые стоит отслеживать
Мониторинг без фильтров превращается в тот же ручной просмотр, только в другом интерфейсе. Смысл в поиске по сигналам: сначала отбираем подозрительные трейсы, затем читаем только их. Публичный текст Dosu в доступной версии не перечисляет конкретные поля фильтрации, поэтому таблица ниже - инженерный чек-лист, а не пересказ конфигурации команды.
| Сигнал | Что ловит | Слепое пятно |
|---|---|---|
| Явный фидбек | Пользователь прямо сказал, что ответ плохой | Сигнал редкий и смещённый: жалуются немногие |
| Тональность сообщений | Раздражение, путаницу, повторные попытки | Эвристика, требует валидации на примерах |
| Внутренние ошибки | Исключения, сбои инструментов, таймауты | Не видны, если пользователю отдали вежливую заглушку |
| Время ответа | Деградацию UX и тяжёлые входы | Быстрый, но неверный ответ выглядит здоровым |
Явный фидбек и тональность: как поймать недовольство без жалобы
Явный фидбек - самый точный сигнал и самый редкий. Те, кто нажал «плохой ответ» или написал «не работает», дают готовый кейс для датасета, но их доля в трафике мала, а мотивация смещена: жалуются активные и раздражённые, остальные молча уходят.
Тональность закрывает часть пробела. Раздражение, повторные формулировки одного вопроса, «я уже писал это выше» - признаки того, что ответ не решил задачу, хотя формально всё прошло. Такой кейс тоже становится eval: если пользователь злится, продукт не справился.
Ограничение: тональность ошибается на сдержанных пользователях и на неродном языке, поэтому разметку валидируют вручную на выборке, прежде чем строить на ней автоматику.
Внутренние ошибки и время ответа: техническая деградация под нагрузкой
Внутренние ошибки (исключения, сбои инструментов, таймауты) выглядят как инфраструктура, но пользователь читает их как «продукт стал хуже». Ловушка в том, что при сбое часто отдаётся вежливая заглушка: метрика ошибок чистая, а качества в ответе нет.
Время ответа - часть качества, а не только DevOps-метрика. Агент, который отвечает на простой вопрос за 40 секунд, теряет доверие даже при верном ответе. Обратная ситуация опаснее: быстрый и неверный ответ по latency выглядит здоровым, поэтому сигнал смотрят вместе с качеством. Как дашборд создаёт ложное чувство контроля, разобрано в материале про полезный и опасный дашборд.
Реальные сбои, которые выявил мониторинг
Ниже два класса сбоев, которые всплывают при таком мониторинге. Оговорка по источникам: детали и цифры этих эпизодов в доступной версии текста Dosu не раскрыты, поэтому разбираем механику обнаружения, а не хронологию.
Медленные ответы на огромные логи
Класс проблемы: на вход приходит очень большой лог, ответ формируется долго. Причина обычно в объёме контекста: чем длиннее вход, тем больше токенов уходит в модель и тем дольше ожидание.
Обнаружение: фильтр по времени ответа вместе с размером входа. Одиночный медленный ответ ничего не значит, а систематическое удлинение на категории «большие входы» видно сразу.
Что делать: покрыть большие входы отдельными evals и следить за latency по категориям запросов, а не по среднему. Средняя latency по продукту маскирует проблему, если на тяжёлые запросы приходится малая доля трафика.
Случай с некорректной разметкой pull request
Класс проблемы: модель оформляет pull request неверно - не тот уровень заголовка, потерянная секция, сломанная структура описания.
Почему это видно в трейсе: сравнение ожидаемого формата с фактическим выводом даёт расхождение на конкретном шаге, а не расплывчатое «в целом плохой ответ». Формат проверяется детерминированно, без судьи, поэтому такой кейс дешёвый в поддержке.
Что делать: добавить кейс в офлайн-датасет с жёсткой проверкой формата. Регрессия после следующей правки промпта поймается прогоном, а не жалобой в чате поддержки.
Критерии выбора инструмента мониторинга LLM
Ниже чек-лист из четырёх требований. Это рамка для сравнения вариантов, а не утверждение, что Dosu выбирал инструмент именно по этим пунктам: публичный текст такого разбора не содержит. Часть требований можно сверить с документацией LangSmith: экспорт трейсов и расширяемость под метаданные там описаны явно.
Промпты в Git и трассировка на уровне кода
- Промпты в Git. Дают воспроизводимость: видно, какая версия промпта работала в конкретный момент. Боль закрывается на ревью: изменение проходит как обычный diff, а не живёт в веб-интерфейсе без истории.
- Трассировка на уровне кода. SDK и декораторы связывают вызовы функций с трейсами. Без этого логи сопоставляют по времени вручную. Ограничение: обвязка добавляет код в приложение, и его надо поддерживать.
Вместе два требования дают главное: конкретный плохой ответ привязывается к версии промпта и версии кода. Без такой связки разбор регрессии превращается в гадание.
Экспорт данных и расширяемость под свои метаданные
- Экспорт данных. Нужен, чтобы история трейсов не осталась заложником вендора и чтобы строить собственные отчёты. В LangSmith есть массовый экспорт трейсов: данные проекта за заданный диапазон дат выгружаются в S3-совместимый бакет в формате Parquet, что подходит для офлайн-анализа в BigQuery, Snowflake, Redshift или Jupyter Notebooks. Ограничение: выгруженные трейсы надо где-то хранить и чистить, а это отдельная инфраструктура.
- Расширяемость под свои метаданные. Поля вроде типа запроса, источника, версии агента или языка позволяют искать аномалии по сигналам продукта. В LangSmith поиск и фильтрация трейсов поддерживают пользовательские метаданные, прикреплённые к трассировкам, - это даёт отбор по темам разговоров, сегментам пользователей и категориям запросов. Ограничение: чем больше кастомных полей, тем выше цена дисциплины - незаполненное поле ломает фильтр.
LangSmith не единственный вариант на этом рынке, и выбор зависит от стека, требований к хранению данных и готовности команды поддерживать обвязку. Если нужен только просмотр метрик без трассировки, платформа с трейсами окажется избыточной.
Как автоматическая сборка eval-датасетов из прода замыкает цикл улучшений
Ручная версия цикла упирается в человека: кто-то должен заметить сбой и перенести его в датасет. Автоматическая сборка убирает этот шаг из критического пути. Логика такая: сигналы мониторинга отбирают подозрительные трейсы, из них формируются кейсы, кейсы попадают в офлайн-датасет, датасет прогоняется перед следующей итерацией.
Что это меняет: датасет растёт из реального трафика, а не из представлений команды о том, как пользуются продуктом. Регрессии ловятся на тех входах, которые действительно приходят, включая уродливые: обрезанные логи, вопросы на смеси языков, вставки кода без контекста.
Важная оговорка о зрелости: в кейсе Dosu автоматизация сбора датасетов из продового трафика описана как инициатива в работе, а не как уже работающий контур. По документации LangSmith по датасетам платформа умеет автоматически генерировать примеры эталонного датасета из производственных трассировок, но конкретные правила отбора и сигналы мониторинга в материале Dosu не раскрыты.
Три ограничения, которые закладывают заранее:
- Фильтрация шума. Без неё датасет зарастает кейсами, где ошибся пользователь, а не продукт. Автоматический отбор требует правил отбраковки.
- Приватность. В датасет не попадают секреты, персональные данные и клиентский код без обезличивания.
- Периодическая ревизия. Устаревшие кейсы удаляют, противоречивые переписывают. Иначе прогон растёт по времени, а польза падает.
Отдельный риск - привыкание к датасету. Когда все проверки знакомы, команда перестаёт видеть новые классы сбоев: метрики ровные, а пользователи уходят. Часть выборки держат «слепой»: свежие кейсы, которые не обсуждали при правке промпта.
Кому подходит EDD и какие у подхода ограничения
EDD окупается там, где сходятся три условия: LLM-агент или промпт-ориентированный продукт, частые изменения в промптах и логике, живой продовый трафик. Если продукт меняется раз в квартал или работает на жёстко заданных сценариях с детерминированной проверкой, обычных тестов хватает.
Издержки реальные: поддержка набора evals, стоимость прогонов (каждый вызов модели платный), инфраструктура мониторинга и время на разбор. На старте это выглядит как налог на скорость. Отдача появляется, когда правки промптов идут потоком: без evals каждая несёт риск незаметной регрессии, и цена такого риска выше стоимости проверок. Как ИИ-инструменты в разработке ускоряют не всё и где проходят границы применимости, разобрано в отдельном материале.
Стартовать разумно с малого: 15-30 кейсов из реальных запросов, два-три сигнала мониторинга, ручной перенос сбоев в датасет. Автоматизацию сборки подключать, когда поток сбоев превысит возможности команды разбирать их руками. Дальше цикл держится сам: прод показывает, где больно, датасет не даёт боли вернуться.