Почему важно тестировать промпты и как это делать
Что входит в обязанности промпт-инженера?
Prompt Engineer — очень перспективная профессия. На рынке труда, в том числе российском, появляется всё больше вакансий с солидной зарплатой. Удивительно, но к специалистам в этой области, как правило, нет конкретных требований. Иногда кажется, что некоторые компании ищут промпт-инженеров, просто чтобы соответствовать тренду. Недавно я видел в одном из объявлений такой пассаж:»…Будет преимуществом опыт работы на смежной позиции (продактом, дата-сайентистом, разработчиком) и знание Python…».
Если всё перечисленное — только преимущество, то что тогда считать требованиями? Ручное написание промптов и проверка качества на глаз? Для личного использования это работает, но речь идёт о том, что спроектированный промпт будет внедрён в сервис компании, и значит, он будет использоваться потенциально тысячи раз. Что если с какой-то вероятностью он выдает недопустимые ответы?
Мы должны задаться вопросом: «Как часто и насколько хорошо промпт справляется с задачей?». Чтобы дать на это ответ, потребуется отправлять много запросов к LLM с нашей инструкцией и смотреть на результаты. То есть, собирать и анализировать данные.
К счастью, сегодня уже можно найти библиотеки, которые предлагают инструменты для автоматизации тестирования промптов. Одна из них — с подробной документацией и большим количеством полезных методов — называется promptfoo. Именно её мы и будем использовать.
Процесс проектирование промпта
На мой взгляд, алгоритм проектирования промпта должен выглядеть примерно так:
1. Определение целей и ограничений.
2. Написание чернового варианта промпта.
3. Написание тестов для этого промпта.
4. Итерации обратная связь/изменение промпта.
5. Финальная проверка на статистически значимом количестве экспериментов.
Чтобы работа была более наглядной, мы будем следовать этому пайплайну, реализуя чат-бота для онлайн-магазина одежды.
1. Определение целей и ограничений. Нам нужно, чтобы чат-бот давал пользователям всю вложенную в него информацию без каких-либо галлюцинаций. Он должен правильно передавать заявленные в ассортименте названия вещей, цены и размеры, помогать решать стандартные ситуации и не поддерживать общение на сторонние темы.
2. Написание чернового варианта промпта. Первый вариант промпта (далее жирным шрифтом выделены непосредственно инструкции, остальное — модули вложенной информации):
»Ты являешься диспетчером техподдержки магазина одежды N3VERZzz. Чтобы валидно ответить на следующий вопрос:»{{input}}», используйследующую информацию:
[Информация о Бренде N3VERZzz]
[Ассортимент Магазина]
[Информация о Доставке]
[Политика Возврата]
[Скидки и Акции]
[Способы Обратной Связи]
[Контактная Информация]
[Инструкция для Ответов] — Отвечай на вопросы прямо и кратко. Не повторяй вопрос в ответе.[Инструкции для Запросов не по теме] — Если интенция запроса НЕ попадает ни в одну из перечисленных категорий, задавай уточняющие вопросы и напоминай, что ты являешься диспетчером техподдержки магазина одежды N3VERZzz.[Инструкции по сложным запросам] — Для сложных вопросов, требующих комбинации информации из разных категорий, старайся агрегировать данные так, чтобы ответ был полным и точным. Использу доступную информацию из всех соответствующих разделов для формирования краткого и информативного ответа.
[Примеры Ответов] »
3. Написание тестов. Теперь нам нужно протестировать этот промпт с помощью библиотеки promptfoo. Чаще всего я пользуюсь следующими методами:
— Метод »contains» проверяет ответ LLM на наличие определенного значения. Поскольку этот метод учитывает регистр букв, его удобно использовать для проверки ожидаемых в ответе числительных.
— Метод »regex» предназначен для проверки соответствия выходных данных заданному регулярному выражению. Регулярные выражения позволяют задавать сложные правила поиска и обработки текста. Например, можно проверить, упоминается ли в тексте Санкт-Петербург в разных падежах.
— Метод »llm-rubric» проверяет выходные данные, используя встроенную LLM. Этот метод анализирует текст и оценивает его на предмет соответствия заявленным указаниям.
Почти все проверки можно реализовать, используя только метод «llm-rubric». Но здесь есть нюансы. Например, проверка на «человекоподобное поведение» может пройти успешно, хотя в ответе прямым текстом будет написано «поскольку я являюсь искусственным интеллектом». Похоже, что основная цель такой проверки — убедиться в релевантности ответа, а не в том, как искусственный интеллект определяет свою идентичность.
Давайте напишем первые тесты:
Так выглядит наш файл. В providers выбираем модель для тестирования, в prompts передаем файл, в котором находится промпт.
Отобразить результаты тестов можно в удобном формате:
4. Итерации обратная связь/изменение промпта. Пока я работал с этим промптом, было очень много итераций 'тест-правка-тест'. Расскажу про самые интересные ошибки и решения.
Периодически ответ LLM начинался с повторения вопроса. Это было топорно и слегка комично — модель будто размышляла вслух. Кажется, я полностью избавился от этого, добавив в инструкцию для ответов input и дополнительное описание ситуации.
Изначально было так:
[Инструкция для Ответов] — Отвечай на вопросы прямо и кратко. Не повторяй вопрос в ответе.
Такое изменение убрало корявости в ответе:
[Инструкция для Ответов] — Отвечай на вопросы прямо и кратко. Не повторяй вопрос:»{{input}}» в ответе.
Еще один интересный случай произошел с запросом о WhatsApp. Хотя в инструкции единственной указанной социальной сетью был YouTube, LLM подтвердила, что с нашим брендом можно связаться через мессенджер. Дело в том, что в инструкции был дан номер горячей линии, и LLM проявила инициативу, соединив номер телефона с мессенджером.
Конечно, такая дезинформация как минимум разозлила бы пользователя. Эту проблему очень просто решить: нужно прописать, что нет никаких других социальных сетей и мессенджеров, кроме указанных. Но кажется, что понятия, лежащие в концептуальном поле близко друг к другу, будут неизбежно срастаться, и заблаговременно понять, где это произойдет, невозможно. Полностью обезопасить себя от этого не получится, и лучший совет здесь — делать больше тестов и внимательно смотреть на ответы.
5. Финальная проверка. Поскольку этот промпт не является коммерческим проектом, я решил не реализовывать полноценную проверку на статистически значимом количестве экспериментов. Я остановился на тестировании базового функционала, написав в общей сложности 59 тестов. К сожалению, у меня так и не получилось полностью ограничить LLM в ответах на темы, не касающиеся магазина. Как бы я ни запрещал это делать, лояльный GPT хочет поделиться советом. Это достаточно сложная задача (может быть, для GPT-3.5).
При работе с LLM можно установить «температуру» креативности. Если мы выставим её на ноль, то в генерации всегда будет отдаваться предпочтение следующему токену с наибольшим процентом вероятности выхода. Таким образом, на одинаковые вопросы будут одинаковые ответы. Поскольку LLM, имплементированные в сервисы, должны работать с вложенной информацией, в большинстве кейсов предпочтение будет отдаваться повторяемости ответов, а не их креативности. Это значит, что температуру будут выкручивать на ноль, и запускать один и тот же тест два раза будет бессмысленно. Придется писать очень большое количество разнообразных тестов.
Здесь может помочь генерация текста: предоставить LLM текст промпта и уже написанные тесты с указанием сделать нечто похожее. Потом добавить эти тесты, проверить их и повторить операцию еще раз.
Почему это важно?
Во время написания этой статьи я постоянно ловил себя на том, что говорю очевидные вещи. Я продолжал работу только потому, что не нашел никого, кто бы высказал эту точку зрения.
Мы наблюдаем зачаток новой профессии, поэтому сейчас в этой области нет стандартов. Впереди много исследований и открытий, которые через время сформируют эту область. Кажется, если промпт-инженер станет промпт-аналитиком, это не только многократно увеличит его вклад, но и даст возможность говорить с отделом разработки на одном языке. Значит, улучшится координация команды. Все это станет возможным и даже закономерным, если к промптам начнут относиться как к абстрактным программам.
Промпт — это абстрактная программа. Поскольку промпт — программа, мы должны его тестировать. Нужно понимать, решает ли он поставленную задачу. Если решает, не вызывают ли они попутно какие-то другие косвенные проблемы. Поскольку это абстрактная программа, мы должны тестировать его более тщательно, чем код.
Ключевой аспект тестирования промптов — это учет субъективности естественного языка. Важно понимать, что промпт является определенного рода линзой, надетой на LLM. Мы тестируем возможный реестр ответов, а не один ответ.
_______________________________
Ссылка на документацию promptfoo: https://promptfoo.dev/docs/intro
По всем вопросам пишите мне в телеграм.