FlexiPrompt: Удобное создание динамических промптов в Python

fd3160a1ac690a534cb63b013f2bba84

Эта статья будет полезна Python-разработчикам, работающим с языковыми моделями (LLM).

Недавно мне понадобился инструмент для формирования промптов в Python-коде. Не хотелось использовать сложные решения, поэтому я создал небольшую библиотеку FlexiPrompt. Вот ее основные преимущества:

  • Легко интегрируется в существующий код

  • Позволяет быстро и гибко настраивать диалог с LLM

  • Может разделить одну LLM на несколько агентов, настраивая общение через шаблоны

Как это выглядит в коде

Вот простой пример использования FlexiPrompt:

from flexi_prompt import FlexiPrompt

fp = FlexiPrompt()
inner_fp = FlexiPrompt({"another_field1": "nested value1, "})
inner_fp.another_field2 = "nested value2"
inner_fp.another_field1().another_field2()

fp.final_prompt = "Here is: $inner_fp, $some_field, $some_callback"
fp.inner_fp = inner_fp
fp.some_field = 42
fp.some_callback = input  # Пример: введите "user input"

print(fp.final_prompt().build())  
# Вывод: Here is: nested value1, nested value2, 42, user input

Пример использования: Улучшение ответов LLM с самоконтролем

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

  1. Получаем запрос от пользователя

  2. Генерируем ответ первой нейросетью

  3. Просим две разные нейросети оценить ответ и берем среднюю оценку

  4. Генерируем ответ второй нейросетью

  5. Снова оцениваем ответ

  6. Если один из ответов получает максимальную оценку, сохраняем его как лучший и завершаем процесс

  7. Повторяем шаги 2–6 до 5 раз, сохраняя лучший ответ

  8. Выдаем лучший ответ пользователю

Реализация

Для этого примера мы будем использовать API OpenAI и Anthropic. Вот основная структура кода:

from flexi_prompt import FlexiPrompt
from openai import OpenAI
from anthropic import Anthropic

# Настройка API ключей и клиентов
from google.colab import userdata
os.environ["OPENAI_API_KEY"] = userdata.get("OPENAI_API_KEY")
os.environ["ANTHROPIC_API_KEY"] = userdata.get("ANTHROPIC_API_KEY_TEST1")

def get_openai_answer(question, openai):
    openai_compleion = openai.chat.completions.create(
        model="gpt-4o-mini",
        messages=[
            {"role": "system", "content": "You are a helpful assistant."},
            {"role": "user", "content": question},
        ],

    )
    return openai_compleion.choices[0].message.content

def get_antropic_answer(question, antropic):
    message = antropic.messages.create(
        max_tokens=4096,
        temperature=0,
        model="claude-3-haiku-20240307",
        system="You are a helpful assistant.",
        messages=[{"role": "user", "content": [{"type": "text", "text": question}]}],
    )
    return message.content[0].text

fp = FlexiPrompt()

# Настройка промптов
fp.question = "Your question here"
fp.rate_prompt = """
Rate the answer to the question from 1 to 9, where 1 is the worst answer.
Be rigorous in your evaluation. Give back only one number as your answer.

Question: 
 $question
Answer: 
 $answer
"""

# Основной цикл
MAX_ATTEMPTS = 5
THRESHOLD_SCORE = 9
best_rate = 0
best_answer = ""

for attempt in range(MAX_ATTEMPTS):

    fp.answer = get_openai_answer(fp.question().build(), openai)
    answer_rate = get_answer_rate(fp.rate_prompt().build(), openai, antropic)

    if answer_rate > best_rate:
        best_rate = answer_rate
        best_answer = fp.answer

    fp.answer = get_antropic_answer(fp.question().build(), antropic)
    answer_rate = get_answer_rate(fp.rate_prompt().build(), openai, antropic)

    if answer_rate > best_rate:
        best_rate = answer_rate
        best_answer = fp.answer

    if best_rate >= THRESHHOLD_SCORE:
        break

print(best_answer)
print("The answer rate is:", best_rate)

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

Сравнение с альтернативами

Я смотрел Haystack, LangChain и несколько мелких библиотек.

Большинство out-of-the-box решений пихают кучу функций помимо промптинга. Под капотом почти все юзают jinja.

Jinja сама по себе — более тяжелое решение и не заточена под промпты. Подойдет для масштабных проектов.

FlexiPrompt заточена простые проекты. Не нужно городить классы и абстракции, но получаешь гибкость на выходе.

Планы

Пока есть очевидные вещи, которые надо добавить: возможность экранирования спец символов и безопасное добавление строк.

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

Habrahabr.ru прочитано 1314 раз