Prompt Engineering Как обмануть ИИ и решить свои проблемы

Prompt Engineering How to outsmart AI and solve your problems

7 приемов подсказок, LangChain и примеры кода на Python

Это четвертая статья в серии о практическом использовании больших языковых моделей (LLM). Здесь я расскажу о технике создания подсказок (PE) и о том, как использовать ее для создания приложений на основе LLM. Я начну с обзора основных методов PE, а затем рассмотрю примеры кода на Python, использующие LangChain для создания приложения на основе LLM.

Фото от Jason Leung на Unsplash

Когда впервые слышат о технике создания подсказок, многие технические специалисты (включая меня самого) скептически относятся к этой идее. Мы можем подумать: “Техника создания подсказок? Пфф, это скучно. Расскажите, как создать LLM с нуля”.

Однако, изучив это более глубоко, я бы предостерегал разработчиков от автоматического отказа от техники создания подсказок. Я даже пойду дальше и скажу, что техника создания подсказок может реализовать 80% ценности большинства случаев использования LLM с (относительно) небольшими усилиями.

Моя цель с этой статьей – донести эту мысль через практический обзор техники создания подсказок и иллюстративные примеры. Хотя в технике создания подсказок, конечно, есть пробелы, она открывает двери к открытию простых и умных решений для наших проблем.

Что такое техника создания подсказок?

В первой статье этой серии я определил технику создания подсказок как любое использование LLM “из коробки” (то есть без обучения внутренних параметров модели). Однако о том можно сказать намного больше.

  1. Техника создания подсказок – это “средство, с помощью которого LLM программируется подсказками”. [1]
  2. Техника создания подсказок – это “опытное искусство составления и форматирования подсказок для максимизации производительности модели при выполнении желаемой задачи”. [2]
  3. “языковые модели… хотят завершать документы, поэтому вы можете обмануть их, просто упорядочив фальшивые документы”. [3]

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

Третий пункт (от Андрея Карпати) напоминает нам, что LLM не обучаются специально для выполнения почти любых наших запросов. Таким образом, в некотором смысле, мы “обманываем” эти языковые модели для решения задач. Я считаю, что это отражает суть техники создания подсказок, которая опирается меньше на ваши технические навыки и больше на вашу креативность.

2 уровня техники создания подсказок

Существуют два различных способа использования техники создания подсказок, которые я называю “простым способом” и “менее простым способом” в первой статье этой серии.

Простой способ

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

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

Менее простой способ

Это решает многие недостатки “простого способа” путем программного взаимодействия с LLM, то есть с помощью Python. Мы уже получили представление о том, как это можно сделать в предыдущих двух статьях этой серии, где мы изучали Python API OpenAI и библиотеку Hugging Face Transformers.

Хотя для этого требуется больше технических знаний, здесь находится настоящая мощь техники создания подсказок, потому что она позволяет разработчикам интегрировать модули на основе LLM в более крупные программные системы.

Хорошим (и, возможно, ироничным) примером этого является ChatGPT. Основой этого продукта является использование предварительно обученной модели (т.е. GPT-3.5-turbo) для создания эффекта чат-бота, а затем обертывание его в удобный веб-интерфейс.

Конечно, разработка GPT-3.5-turbo – это сложная часть, но это не то, о чем нам нужно беспокоиться здесь. Со всеми предварительно обученными LLM, которые у нас есть под рукой, почти любой человек с базовыми навыками программирования может создать мощное приложение искусственного интеллекта, подобное ChatGPT, не являясь исследователем в области искусственного интеллекта или обладая степенью доктора философии по машинному обучению.

Создание приложений искусственного интеллекта с использованием инженерии запросов

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

Предположим, вы хотите создать автоматический оценщик для исторического класса старшей школы. Однако проблема в том, что на все вопросы требуются письменные ответы, поэтому может быть несколько версий правильного ответа. Например, на вопрос “Кто был 35-м президентом Соединенных Штатов Америки?” могут быть следующие ответы:

  • Джон Ф. Кеннеди
  • JFK
  • Джек Кеннеди (общепринятый псевдоним)
  • Джон Фицджеральд Кеннеди (вероятно, в попытке получить дополнительные баллы)
  • Джон Ф. Кенеди (неправильно написанная фамилия)

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

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

Вы - учитель истории старшей школы, проверяющий домашние задания. На основе вопроса к домашнему заданию, указанного как "Вопрос:" и правильного ответа, указанного как "Ответ:", ваша задача - определить, является ли ответ ученика правильным. Оценка двоичная; поэтому ответы учеников могут быть правильными или неправильными. Мелкие опечатки допустимы. Вопрос: {question}Ответ: {correct_answer} Ответ ученика: {student_answer}

Мы можем рассматривать этот запрос как функцию, где при заданном вопросе, правильном_ответе и ответе_ученика он генерирует оценку ученика. Затем это можно интегрировать в более крупное программное обеспечение, реализующее автоматический оценщик.

В терминах экономии времени, этот запрос мне потребовал около 2 минут для написания, тогда как, если бы я пытался разработать алгоритм, сделать то же самое заняло бы мне часы (если не дни), и, вероятно, имело бы более плохую производительность. Так что экономия времени для задач подобного рода составляет 100–1000 раз.

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

7 приемов для инженерии запросов

Хотя пример запроса из предыдущего раздела может показаться естественным и очевидным способом формулировки задачи автоматической оценки, в нем преднамеренно использовались определенные эвристики инженерии запросов (или “приемы”, как я их называю). Эти (и другие) приемы стали надежными способами улучшения качества ответов LLM.

Хотя существует много советов и приемов для написания хороших запросов, здесь я ограничиваюсь наиболее фундаментальными (по моему мнению) на основе нескольких ссылок [1,3–5]. Если вы хотите углубиться в тему, я рекомендую вам изучить приведенные здесь источники.

Прием 1: Будьте описательными (Чем больше, тем лучше)

Особенностью LLM является то, что они обучаются на огромных корпусах текста. Это дает им огромные знания о мире и способность выполнять множество задач. Однако, эта впечатляющая общность может затруднить выполнение конкретной задачи, если не предоставить правильный контекст.

Например, давайте сравним две подсказки для создания поздравления с Днем рождения для моего папы.

Без уловки

Напишите мне поздравление с Днем рождения для моего папы.

С уловкой

Напишите мне поздравление с Днем рождения для моего папы, не превышающее 200 символов. Это большой день рождения, потому что ему исполняется 50 лет. Чтобы отпраздновать это, я забронировал нам поездку в Канкун. Не забудьте добавить немного шуток, он их обожает.

Уловка 2: Давайте примеры

Следующая уловка заключается в том, чтобы предоставить примеры ответов LLM для улучшения его производительности в определенной задаче. Технический термин для этого – это обучение на нескольких примерах, и он доказал свою эффективность в значительном улучшении производительности LLM [6].

Давайте рассмотрим конкретный пример. Предположим, мы хотим написать подзаголовок для статьи на Towards Data Science. Мы можем использовать существующие примеры, чтобы помочь руководить завершением LLM.

Без уловки

Учитывая заголовок блога Towards Data Science, напишите подзаголовок для него.Заголовок: Инженерия запросов — Как обмануть искусственный интеллектПодзаголовок:

С уловкой

Учитывая заголовок блога Towards Data Science, напишите подзаголовок для него.Заголовок: Практическое введение в LLMПодзаголовок: 3 уровня использования LLM на практикеЗаголовок: Взлом OpenAI (Python) APIПодзаголовок: Полное начало с примерами кодаЗаголовок: Инженерия запросов — Как обмануть искусственный интеллектПодзаголовок:

Уловка 3: Использование структурированного текста

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

Однако есть бесчисленное количество способов структурировать запросы. Вот несколько примеров: использование ПРОПИСНЫХ БУКВ для выделения, использование разделителей, таких как “` для выделения блока текста, использование языков разметки, таких как Markdown или HTML для форматирования текста, использование JSON для организации информации и т. д. Теперь давайте посмотрим, как это работает на практике.

Без уловки

Напишите мне рецепт шоколадных печеньков.

С уловкой

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

Уловка 4: Последовательная мысль

Эта уловка была предложена Вэй и др. [7]. Основная идея заключается в том, чтобы направить LLM мыслить «шаг за шагом». Это помогает разбить сложные задачи на управляемые подзадачи, что дает LLM «время для размышлений» [3,5]. Чжан и др. показали, что это может быть так просто, как включение текста «Давайте думать шаг за шагом» в запрос [8].

Это понятие может быть распространено на любой процесс, подобный рецепту. Например, если я хочу создать сообщение в LinkedIn на основе своего последнего блога VoAGI, я могу направить LLM зеркально отразить процесс, который я следую.

Без уловки

Напишите мне сообщение в LinkedIn на основе следующего блога VoAGI.Блог VoAGI: {текст блога VoAGI}

С уловкой

Напишите мне сообщение в LinkedIn на основе шагового процесса и блога VoAGI, приведенных ниже.  Шаг 1: Придумайте крючок, соответствующий блогу. Шаг 2: Выделите 3 ключевых момента из статьи. Шаг 3: Сократите каждый момент до менее чем 50 символов. Шаг 4: Объедините крючок, сжатые ключевые моменты из Шага 3 и призыв к действию для генерации конечного результата.Блог VoAGI: {текст блога VoAGI}

Хитрость 5: Персонажи чатбота

Весьма неожиданной техникой, которая обычно улучшает производительность языковой модели LLM, является задание ей определенного образа, например, “вы эксперт”. Это полезно, потому что вы можете не знать наилучший способ описать свою проблему LLM, но вы можете знать, кто поможет вам решить эту проблему [1]. Вот как это может выглядеть на практике.

Без хитрости

Составьте для меня маршрут путешествия на выходные в Нью-Йорк.

С хитростью

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

Хитрость 6: Обратный подход

Бывает сложно оптимально составить запрос для LLM, когда мы не знаем, что он знает и как он мыслит. Именно здесь может пригодиться “обратный подход”. Вы задаете LLM вопросы до тех пор, пока он не получит достаточное понимание (т.е. контекст) проблемы, которую вы пытаетесь решить.

Без хитрости

Какая идея для приложения на основе LLM?

С хитростью

Я хочу, чтобы вы задавали мне вопросы, чтобы помочь мне придумать идею \приложения на основе LLM. Задавайте мне вопросы по одному, чтобы поддерживать беседу.

Хитрость 7: Отражайте, проверяйте и улучшайте

Эта последняя хитрость побуждает модель обдумать свои предыдущие ответы, чтобы улучшить их. Обычные сценарии использования включают просьбу модели критически оценить свою работу, задавая ей вопрос, “завершила ли она задание”, или просить ее “объяснить логику и предположения” за ответом [1, 3].

Кроме того, вы можете попросить LLM улучшить не только свои ответы, но и ваш запрос. Это простой способ автоматически переформулировать запросы так, чтобы модели было “проще понять”.

С хитростью

Проанализируйте ваш предыдущий ответ, найдите области для улучшения и предложите \улучшенную версию. Затем объясните свои рассуждения о том, как вы улучшили ответ.

Пример кода: Автоматический оценщик с использованием LangChain

Теперь, когда мы рассмотрели несколько эвристик для составления запросов, давайте посмотрим, как мы можем применить их к конкретной задаче. Для этого вернемся к примеру автоматического оценщика, который мы рассматривали ранее.

Вы - учитель истории в старшей школе, проверяющий домашние задания. \Основываясь на вопросе задания, обозначенном "Q:", и правильном ответе, обозначенном "A:", ваша задача состоит в определении, правильный ли ответ дал студент.Оценка бинарная, поэтому студенческие ответы могут быть правильными или неправильными.Небольшие орфографические ошибки допустимы. Q: {вопрос}A: {правильный_ответ} Ответ студента: {ответ_студента}

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

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

LangChain

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

Центральным классом, который это делает, является класс chain (отсюда и название библиотеки). Он абстрагирует процесс создания запроса, отправки его на LLM и разбора вывода, чтобы его можно было легко вызывать и интегрировать в больший скрипт.

Давайте посмотрим, как использовать LangChain для нашего случая использования автоматической оценки. Пример кода доступен на GitHub Repo для этой статьи.

Импорт

Сначала мы начинаем с импорта необходимых библиотечных модулей.

from langchain.chat_models import ChatOpenAIfrom langchain.prompts import PromptTemplatefrom langchain.chains import LLMChainfrom langchain.schema import BaseOutputParser

Здесь мы будем использовать gpt-3.5-turbo, для которого требуется секретный ключ для API OpenAI. Если у вас его нет, я дал пошаговое руководство о том, как его получить, в предыдущей статье этой серии. Я предпочитаю хранить секретный ключ в отдельном файле Python (sk.py) и импортировать его с помощью следующей строки кода.

from sk import my_sk #импорт секретного ключа из другого файла Python

Наша 1-я цепь

Для определения нашей цепи нам нужно два основных элемента: LLM и промпт. Мы начинаем с создания объекта для LLM.

# определение объекта LLMchat_model = ChatOpenAI(openai_api_key=my_sk, temperature=0)

LangChain имеет класс, специально предназначенный для моделей чатов OpenAI (и многих других). Я передаю свой секретный ключ API и устанавливаю температуру равной 0. Здесь используется модель по умолчанию gpt-3.5-turbo, но вы также можете использовать gpt-4, используя аргумент ввода “model_name”. Вы также можете настроить модель чата, установив другие аргументы ввода.

Затем мы определяем наш промпт-шаблон. Этот объект позволяет нам динамически генерировать промпты через строковые значения ввода, которые автоматически обновляют базовый шаблон. Вот как это выглядит.

# определение промпт-шаблонапrompt_template_text = """Вы - учитель истории старшей школы, проверяющий домашние задания. \На основе вопроса домашнего задания, обозначенного «**Q:**», и правильного ответа, обозначенного «**A:**», ваша задача - определить, правильный ли ответ студента. \Оценка бинарная; поэтому ответы студентов могут быть правильными или неправильными. \Простые орфографические ошибки допустимы.**Q:** {question}**A:** {correct_answer}**Ответ студента:** {student_answer}"""prompt = PromptTemplate(input_variables=["question", "correct_answer", "student_answer"], \                  template = prompt_template_text)

С нашим LLM и промпт-шаблоном теперь мы можем определить нашу цепь.

# определение цепочкиchain = LLMChain(llm=chat_model, prompt=prompt)

Затем мы можем передавать входные данные в цепочку и получать оценку в одной строке кода.

# определение входных данныхquestion = "Кто был 35-м президентом Соединенных Штатов Америки?"correct_answer = "Джон Ф. Кеннеди"student_answer =  "ФДР"# запуск цепочкиchain.run({'question':question, 'correct_answer':correct_answer, \    'student_answer':student_answer})# вывод: Ответ студента неправильный.

Хотя эта цепочка может выполнять задачу оценки эффективно, ее выводы могут быть не подходящими для автоматической обработки. Например, в приведенном выше блоке кода LLM правильно сказал, что ответ студента “ФДР” неверный, но было бы лучше, если бы LLM дал нам вывод в стандартном формате, который можно использовать для последующей обработки.

Парсер вывода

Здесь пригодны парсеры вывода. Это функции, которые мы можем интегрировать в цепочку для преобразования выводов LLM в стандартный формат. Посмотрим, как мы можем создать парсер вывода, который преобразует ответ LLM в булевый (т.е. True или False) вывод.

# определение парсера выводаclass GradeOutputParser(BaseOutputParser):    """Определение правильности оценки"""    def parse(self, text: str):        """Разбор вывода вызова LLM."""        return "неправильный" not in text.lower()

Здесь мы создаем простой парсер вывода, который проверяет, есть ли слово “неправильный” в выводе LLM. Если нет, мы возвращаем True, указывая на правильный ответ студента. В противном случае мы возвращаем False, указывая на неправильный ответ студента.

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

# обновление цепочкиchain = LLMChain(    llm=chat_model,    prompt=prompt,    output_parser=GradeOutputParser())

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

# запускаем цепочку в цикле for
student_answer_list = ["Джон Ф. Кеннеди", "JFK", "ФДР", "Джон Ф. Кенеди", \
                  "Джон Кеннеди", "Джек Кеннеди", "Джаклин Кеннеди", "Роберт Ф. Кенеди"]
for student_answer in student_answer_list:
    print(student_answer + " - " + str(chain.run({'question':question, 'correct_answer':correct_answer, 'student_answer':student_answer})))
    print('\n')
# Вывод:
# Джон Ф. Кеннеди - True
# JFK - True
# ФДР - False
# Джон Ф. Кенеди - True
# Джон Кеннеди - True
# Джек Кеннеди - True
# Джаклин Кеннеди - False
# Роберт Ф. Кенеди - False

YouTube-Blog/LLMs/langchain-example at main · ShawhinT/YouTube-Blog

Коды для дополнения видеороликов на YouTube и блогов на VoAGI. – YouTube-Blog/LLMs/langchain-example at main ·…

github.com

Ограничения

Инженерия подсказок – это не только просьба ChatGPT о помощи в написании электронной почты или изучении квантовых вычислений. Это новая парадигма программирования, меняющая то, как разработчики могут создавать приложения.

Хотя это мощное новшество, у него есть свои ограничения. Во-первых, оптимальные стратегии подсказок зависят от LLM. Например, подсказка GPT-3 “думать пошагово” привела к значительному повышению производительности на простых задачах математического рассуждения [8]. Однако для последней версии ChatGPT эта же стратегия не кажется полезной (он уже думает пошагово).

Еще одно ограничение инженерии подсказок заключается в том, что для нее требуются масштабные языковые модели общего назначения, такие как ChatGPT, что сопряжено с значительными вычислительными и финансовыми затратами. Это может быть перебором для многих случаев использования, которые имеют более узкое определение, например, сопоставление строк, анализ настроения или суммирование текста.

Мы можем преодолеть оба этих ограничения с помощью настройки предварительно обученных языковых моделей. Здесь мы берем существующую языковую модель и настраиваем ее для конкретного случая использования. В следующей статье этой серии мы рассмотрим популярные техники настройки с примерами кода на Python.

👉 Больше о LLMs: Введение | OpenAI API | Hugging Face Transformers

Ресурсы

Связь: Мой веб-сайт | Запись на звонок | Спросите меня о чем угодно

Соцсети: YouTube 🎥 | LinkedIn | Twitter

Поддержка: Купите мне кофе ☕️

Предприниматели данных

Сообщество предпринимателей в сфере данных. 👉 Присоединяйтесь к Discord!

VoAGI.com

[1] arXiv:2302.11382 [cs.SE]

[2] arXiv:2106.09685 [cs.CL]

[3] State of GPT by Andrej Karpathy at Microsoft Build 2023

[4] arXiv:2206.07682 [cs.CL]

[5] ChatGPT Prompt Engineering for Developers by deeplearning.ai

[6] arXiv:2005.14165 [cs.CL]

[7] arXiv:2201.11903 [cs.CL]

[8] arXiv:2210.03493 [cs.CL]