Промпты, которые пишут себя сами: эксперимент с Kotlin

Источник: The JetBrains Blog•

Промпты, которые пишут себя сами: эксперимент с Kotlin

TL;DR Библиотека оптимизации агентов Koog (Koog Agents Optimization Library) — это исследовательская библиотека, разработанная в JetBrains Research для оптимизации промптов агентов Koog. С ее помощью вы пишете первую версию каждой инструкции, отмечаете шаги, требующие настройки, предоставляете…

JetBrains Research

Исследования имеют решающее значение для прогресса и инноваций, поэтому в JetBrains мы увлечены как научными, так и рыночными исследованиями

Исследования

TL;DR

Библиотека оптимизации агентов Koog (Koog Agents Optimization Library) — это исследовательская библиотека, разработанная в JetBrains Research для оптимизации промптов агентов Koog. С ее помощью вы пишете первую версию каждой инструкции, отмечаете шаги, требующие настройки, предоставляете библиотеке обучающий набор и задаете способ оценки вывода агента. Затем библиотека запускает ваш агент, учится на результатах и возвращает улучшенные инструкции в виде отдельного файла JSON, который вы можете прочитать, проверить и зафиксировать в системе контроля версий (commit). Переписывать самого агента не требуется.

В примерах из этой статьи используется GEPA, оптимизатор промптов, который учится на ошибках и успехах вашего агента. В этой статье мы покажем примеры работы на бенчмарке конфиденциальности PUPA. GEPA повысила результат нашего агента с 81,19 до 94,22.

👉 Библиотека оптимизации агентов Koog (GitHub)

Агент для оптимизации

Koog — это фреймворк JetBrains на Kotlin для создания агентов. Он рассматривает агента как программу: вы объявляете поток управления в виде типизированного графа из узлов и ребер, и каждый шаг может содержать собственный промпт, инструменты и модель.

У нас есть полноценный агент, написанный на нем: наш порт PAPILLON, конвейер конфиденциальности, который GEPA использует в качестве одного из своих бенчмарков. Он работает на , наборе данных пользовательских запросов, содержащих личные данные. Агент должен ответить на такой запрос с помощью большой внешней модели, не передавая ей эти личные данные, поэтому он переписывает вопрос без этих данных, отправляет эту версию и формирует ответ на основе полученного результата.

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

Пометка шага как оптимизируемого

Библиотека добавляет один билдер. Замените subgraphWithTask на optimizableSubgraphWithTask для шагов, которые вы хотите настроить, и вынесите инструкцию из строки, в которой она была скрыта:

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

Запуск оптимизатора

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

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

Эта строка вместе с тем, что шаг получил на вход и выдал на выходе, — это все, с чем GEPA пришлось работать при написании инструкции в следующем разделе.

Остальное — это всего два вызова:

train записывает артефакт, а loadOptimizedAgent считывает его и выдает вам копию вашего агента, работающего с новыми инструкциями. Каждый оптимизатор в библиотеке имеет те же два метода, поэтому переключение между ними не затрагивает окружающий код.

Что написала GEPA

Шаг, который удаляет личные данные, начинался с такой инструкции:

Учитывая частный пользовательский запрос, создайте запрос с сохранением конфиденциальности для мощной внешней LLM. LLM может оказывать помощь, не узнавая конфиденциальную информацию о пользователе.

Учитывая частный пользовательский запрос, создайте запрос с сохранением конфиденциальности для мощной внешней LLM.

LLM может оказывать помощь, не узнавая конфиденциальную информацию о пользователе.

Две строки, намеренно расплывчатые. В них ничего не говорится о том, какая степень маскировки данных будет достаточной.

К концу работы этот же шаг выполнял инструкцию длиной 4456 символов. Вот три ее фрагмента:

Каждая деталь в приведенной выше инструкции появилась в результате работы, а не была написана нами. Вы бы вряд ли сели писать словарь заполнителей (placeholder vocabulary), правило об именах профессоров и кодах курсов или общую стратегию в конце. В этой стратегии сформулирован компромисс, о котором мы никогда не упоминали: свести утечку к нулю, но оставить достаточно деталей для выполнения работы.

Результаты

Мы хотели узнать, действительно ли наша GEPA в Koog делает то, что должна, поэтому мы запустили ее на бенчмарках, которые использует сам проект, и проверили, стали ли агенты работать лучше.

В качестве примера возьмем , бенчмарк, на котором работает описанный выше агент. Его базовый показатель уже составлял 81,19 с небольшим потенциалом для роста, но оптимизация все равно улучшила его на 13 пунктов — до 94,22. Оба числа представляют собой среднее значение по результатам пяти запусков, и прирост статистически значим.

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

Еще три оптимизатора

Помимо GEPA, библиотека реализует еще три оптимизатора за тем же интерфейсом:

  • BootstrapFewShot извлекает демонстрации из ваших успешных запусков. Эта библиотека не делает никаких вызовов LLM, кроме запуска вашего собственного агента, что делает ее самым дешевым вариантом для первого знакомства.
  • MIPROv2 выполняет поиск по инструкциям и демонстрациям.
  • ACE наращивает «базу знаний» из идей, которая сопровождает системный промпт — это полезно, когда нужно, чтобы агент накапливал знания, а не просто подбирал лучшие формулировки инструкций.

Переключение между ними сводится к использованию одного конструктора; вызовы train и loadOptimizedAgent вокруг него остаются прежними. Написание собственного оптимизатора означает реализацию тех же двух методов, и все четыре наших варианта вписываются в эту схему без каких-либо обходных путей.

Где найти проект

Библиотека, ее документация и полные результаты бенчмарков находятся в репозитории с открытым исходным кодом. Поддержка оптимизируемых подграфов, на которую она опирается, в настоящее время находится в форке Koog; мы ожидаем, что она попадет в основной репозиторий (upstream).

Узнать больше

О чём эта статья