Подсказки с помощью DSPy: новый подход
Введение
Наступила эпоха, когда мы постоянно работаем над лучшими способами использования и комбинирования языковых моделей (LM). Обычно LLM используют фиксированные «шаблоны подсказок», созданные методом проб и ошибок. DSPy — это новый метод, который упрощает эту задачу, превращая конвейеры LM в простые в управлении графы преобразования текста. В этих графиках используются модули, которые могут обучаться и улучшать способы подсказок, точной настройки и обоснования.
DSPy включает в себя инструмент, который оптимизирует эти конвейеры для повышения производительности. Исследования показывают, что DSPy позволяет быстро создавать эффективные конвейеры LM, значительно повышая производительность по сравнению с традиционными методами. Это также делает меньшие открытые модели конкурентоспособными благодаря разработанным экспертами подсказкам для продвинутых моделей, таких как GPT-3.5.
Предварительные условия
Прежде чем погрузиться в DSPy, убедитесь, что у вас есть следующее:
- Базовые знания программирования: Знакомство с Python и его библиотеками.
- Понимание LLM: базовое понимание больших языковых моделей и их механизмов подсказки.
- Настройка среды. Доступ к среде разработки Python, например Jupyter Notebook или VS Code, с установленными необходимыми библиотеками.
Что такое DSPy?
DSPy — это платформа, которая упрощает оптимизацию подсказок и весов языковой модели (LM), особенно при многократном использовании LM. Без DSPy построение сложных систем с помощью LM включает в себя множество шагов вручную: определение проблем, подсказки по точной настройке, этапы настройки, создание синтетических примеров и тонкая настройка небольших LM, что может быть громоздким и запутанным.
DSPy упрощает эту задачу, отделяя поток программы от параметров (подсказок и весов) и вводя новые оптимизаторы, которые корректируют эти параметры в зависимости от желаемых результатов. Это делает мощные модели, такие как GPT-4 или T5-base, более надежными и эффективными. Вместо ручной корректировки DSPy использует алгоритмы для обновления параметров, что позволяет вам перекомпилировать вашу программу с учетом любых изменений в коде, данных или показателях.
Думайте об этом как об использовании таких фреймворков, как PyTorch, для нейронных сетей: мы не настраиваем каждую деталь вручную, а вместо этого используем слои и оптимизаторы для изучения лучших параметров. Аналогичным образом, DSPy предоставляет модули и оптимизаторы, которые автоматизируют и улучшают работу с LM, сокращая необходимость ручной настройки и увеличивая эффективность систематического улучшения и повышения производительности.
Что означает DSPy?
Бакроним «сейчас» расшифровывается как «Декларативные языковые программы самосовершенствования», созданные Стэнфордским университетом НЛП.
DSPy упрощает сложный процесс оптимизации подсказок и весов языковой модели (LM), особенно для многоэтапных конвейеров. Традиционно вам приходилось разбивать проблему на детали, уточнять подсказки, настраивать шаги, генерировать синтетические примеры и точно настраивать меньшие модели. Это беспорядочно и отнимает много времени, так как любое изменение требует переделки подсказок и точной настройки.
DSPy, отделяя поток программы от параметров LM и вводя оптимизаторы, повышает надежность таких моделей, как GPT-3.5, GPT-4, T5-base или Llama2-13b. Это делает их более эффективными и менее подверженными ошибкам, вселяя чувство доверия и уверенности в результатах.
Зачем нам нужен DSPy?
«Шаблоны подсказок» — это заранее определенные инструкции или демонстрации, предоставляемые LM для руководства его ответом на данную задачу. Шаблоны запросов часто создаются методом проб и ошибок. Это означает, что они могут хорошо работать для конкретных задач или сценариев, но не работать или давать нерелевантные результаты в разных контекстах. Поскольку эти шаблоны жестко запрограммированы, им не хватает адаптируемости и они могут не эффективно обрабатывать изменения во входных данных, требованиях задач или даже других языковых моделях. Данный шаблон приглашения может эффективно работать для определенного конвейера или платформы LM. Тем не менее, это может плохо обобщаться на другие конвейеры, разные LM, разные области данных или даже разные типы входных данных. Отсутствие обобщений ограничивает гибкость и применимость LM в различных случаях использования. Создание вручную и точная настройка шаблонов подсказок для различных задач или LM может занять много времени и труда. По мере увеличения сложности и разнообразия задач обслуживание и обновление этих шаблонов становится все более сложным и неэффективным.
Кроме того, другие проблемы могут быть связаны с генерацией ответа. Использование жестко закодированных шаблонов подсказок в конвейерах и средах языковой модели (LM) часто приводит к таким проблемам, как отсутствие контекста и релевантности, непоследовательность результатов, низкое качество ответа и неточность. Эти проблемы возникают из-за ограниченной гибкости и масштабируемости шаблонов подсказок, которые создаются вручную и не могут эффективно обобщаться для различных моделей LM, областей данных или вариантов входных данных.
Так почему же DSPy?
- DSPy фокусируется на построении новых конвейеров языковых моделей, переходя от манипулирования неструктурированными текстовыми вводами к программированию.
- Модули DSPy — это адаптивные к задачам компоненты, подобные слоям нейронной сети, абстрагирующие преобразования текста, такие как ответы на вопросы или обобщение.
- Компилятор DSPy оптимизирует качество или стоимость программы, используя входные данные для обучения и показатели проверки.
- Компилятор DSPy моделирует версии программы, загружая примеры трассировок для самосовершенствования и эффективной генерации подсказок.
- Оптимизация в DSPy является модульной и проводится телесуфлерами, которые определяют обучение модулей на основе данных.
- DSPy может отображать декларативные модули в высококачественные композиции подсказок, точной настройки, рассуждений и дополнений.
- Модели программирования DSPy направлены на снижение роли подсказок, созданных экспертами.
- Композиции модулей DSPy могут значительно повысить качество простых программ за время компиляции от нескольких минут до десятков минут.
Основные компоненты DSPy
Прежде чем мы углубимся, давайте разберемся с несколькими важными компонентами DSPy.
- Подписи
- Модули
- Телесуфлеры или оптимизаторы
Сигнатура DSPy – это объявление функции, дающее краткое описание того, о чем необходимо позаботиться при преобразовании текста, а не подробное описание того, как конкретная языковая модель должна быть предложена для достижения такого поведения. Подпись DSPy — это кортеж, содержащий поля input и output с дополнительной инструкцией. Каждое поле включает имя поля и дополнительные метаданные.
Подпись ориентирована на тип системы, которую мы создаем, например: вопрос -> ответ, документ на английском языке -> перевод на французский или контент -> резюме.
qa = dspy.Predict (" question -> answer ")
qa(question =" Where is Guaran ´ı spoken?")Out: Prediction ( answer = ’ Guaran ´ı is spoken mainly in South America . ’)
Модуль DSPy — это основной компонент для создания программ, использующих языковые модели. Каждый модуль включает в себя конкретную технику подсказок, такую как цепочка мыслей или ReAct, и разработан так, чтобы быть достаточно универсальным для работы с любой сигнатурой DSPy.
Эти модули имеют настраиваемые параметры, включая элементы весов подсказок и языковых моделей, и их можно вызывать для обработки входных данных и создания выходных данных. Более того, несколько модулей DSPy можно комбинировать для формирования более крупных и сложных программ. Модули DSPy, вдохновленные модулями нейронных сетей в PyTorch, привносят аналогичную функциональность в программирование языковых моделей.
Например:-
dspy.Predict является основным модулем, и все остальные модули DSPy построены с использованием этого модуля.
Чтобы использовать модуль, мы начинаем с его объявления с определенной сигнатурой. Далее мы вызываем модуль с входными аргументами и извлекаем выходные поля.
sentence = "it's a charming and often affecting journey." # example from the SST-2 dataset.
1) Declare with a signature.
classify = dspy.Predict('sentence -> sentiment')
2) Call with input argument(s).
response = classify(sentence=sentence)
3) Access the output.
print(response.sentiment)
Выход:-
Positive
Есть еще несколько модулей DSPy, которые мы можем использовать:
- dspy.ChainOfThought
- dspy.ReAct
- dspy.MultiChainComparison
- dspy.ProgramOfThought
и многое другое.
Телесуфлер DSPy используется для оптимизации в DSPy. Он очень гибкий и модульный. Оптимизация осуществляется телесуфлерами, которые представляют собой универсальные стратегии, определяющие, как модули должны учиться на данных.
Оптимизатор DSPy — это алгоритм, предназначенный для точной настройки параметров программы DSPy, таких как подсказки и веса языковой модели, для максимизации заданных показателей, таких как точность. DSPy предлагает множество встроенных оптимизаторов, каждый из которых использует разные стратегии. Обычно оптимизатору DSPy требуются три вещи: ваша программа DSPy (которая может представлять собой один модуль или сложную установку из нескольких модулей), метрическую функцию для оценки и оценки результатов вашей программы (более высокие оценки указывают на лучшую производительность) и несколько обучающие материалы (иногда всего 5 или 10 примеров, даже если они не имеют надписей). Хотя наличие большого количества данных может быть полезным, DSPy предназначен для достижения отличных результатов даже при минимальных затратах.
Как оптимизаторы повышают производительность?
Традиционные глубокие нейронные сети (DNN) оптимизируются с использованием градиентного спуска с функцией потерь и обучающими данными. Напротив, программы DSPy включают в себя несколько моделей обращения к языку (LM), интегрированных в виде модулей DSPy. Каждый модуль имеет три внутренних параметра: веса LM, инструкции и демонстрацию поведения ввода/вывода.
DSPy может оптимизировать все три, используя алгоритмы многоэтапной оптимизации, сочетая градиентный спуск для весов LM и оптимизацию на основе LM для уточнения инструкций и демонстраций. В отличие от типичных примеров из нескольких кадров, демонстрации DSPy более надежны и могут быть созданы и оптимизированы с нуля на основе вашей программы. Такая компиляция часто дает лучшие подсказки, чем написанные человеком, не потому, что оптимизаторы DSPy по своей сути более креативны, а потому, что они могут систематически исследовать больше вариантов и напрямую настраивать метрики.
Ниже перечислены несколько оптимизаторов DSPy:
- МаркированныйFewShot
- BootstrapFewShot
- BootstrapFewShotWithRandomSearch
- BootstrapFewShotWithOptuna
- KNNFewShot
и этот список можно продолжить.
Мы настоятельно рекомендуем документацию DSPy для получения дополнительной информации о различных видах оптимизаторов.
Сравнение с Langchain и Llammaindex
Обзор LangChain и LlamaIndex:
- И langchain, и llamaindex — популярные библиотеки в области подсказок LM.
- Обе библиотеки ориентированы на предоставление предварительно упакованных компонентов и цепочек для разработчиков приложений. Кроме того, они предлагают реализации многократно используемых конвейеров (например, агентов, конвейеров поиска) и инструментов (например, соединений с базами данных, реализаций памяти).
Обзор DSPy:
- DSPy стремится решить фундаментальные проблемы оперативного проектирования и создает новые вычислительные графики LM без оперативного ручного проектирования.
- Кроме того, в нем представлены основные компонуемые операторы, сигнатуры (для абстрактных подсказок), модули (для методов абстрактных подсказок) и телесуфлеры в качестве оптимизаторов.
- DSPy облегчает быстрое создание новых конвейеров LM и получение высококачественных результатов за счет автоматической компиляции и самосовершенствования.
Существенные различия между LangChain и LlamaIndex:
- LangChain и LlamaIndex полагаются на ручную разработку, которую DSPy стремится решить.
- DSPy предоставляет структурированную структуру, которая автоматически загружает подсказки, устраняя необходимость в рукописных демонстрациях подсказок.
- По состоянию на сентябрь 2023 года кодовая база LangChain содержала 50 строк длиной более 1000 символов и множество файлов, посвященных разработке запросов (12 файлов Prompt.py и 42 файла Prompt.py). Напротив, DSPy не содержит рукописных подсказок, но обеспечивает высокое качество с различными LM.
- DSPy оказывается более модульным и мощным, чем жестко запрограммированные подсказки.
Начало работы с DSPy
Начнем с установки пакетов:
!pip install dspy-ai
#or
!pip install git+https://github.com/stanfordnlp/dspy.git
По умолчанию DSPy устанавливает последнюю версию openai
из pip.
Импортируйте необходимые пакеты,
import sys
import os
import dspy
from dspy.datasets import HotPotQA
from dspy.teleprompt import BootstrapFewShot
from dspy.evaluate.evaluate import Evaluate
from dsp.utils import deduplicate
Начало работы и загрузка данных
turbo = dspy.OpenAI(model='gpt-3.5-turbo') #model name 'gpt-3.5-turbo'
colbertv2_wiki17_abstracts = dspy.ColBERTv2(url='http://20.102.90.50:2017/wiki17_abstracts') #the retriever ColBERTv2
dspy.settings.configure(lm=turbo, rm=colbertv2_wiki17_abstracts)
#load the data
dataset = HotPotQA(train_seed=1, train_size=20, eval_seed=2023, dev_size=50, test_size=0)
HotpotQA — это набор данных с ответами на вопросы, полученный из английской Википедии, который включает около 113 000 вопросов, полученных от краудсорсинга.
Используя эту информацию, мы создадим вопросно-ответную систему. Для этой цели мы будем использовать 20 точек данных для обучения и 50 точек данных для набора разработки или проверки.
# get the train and validation set.
trainset = [x.with_inputs('question') for x in dataset.train]
devset = [x.with_inputs('question') for x in dataset.dev]
len(trainset), len(devset)
Выход:-
(20, 50)
Далее мы рассмотрим несколько примеров.
train_example = trainset[0]
print(f"Question: {train_example.question}")
print(f"Answer: {train_example.answer}")
Выход:-
Question: At My Window was released by which American singer-songwriter?
Answer: John Townes Van Zandt
dev_example = devset[18]
print(f"Question: {dev_example.question}")
print(f"Answer: {dev_example.answer}")
print(f"Relevant Wikipedia Titles: {dev_example.gold_titles}")
Выход:-
Question: What is the nationality of the chef and restaurateur featured in Restaurant: Impossible?
Answer: English
Relevant Wikipedia Titles: {'Robert Irvine', 'Restaurant: Impossible'}
Создание чат-бота
Мы создаем функцию под названием Basic QA с подписью для вопросов, требующих кратких, основанных на фактах ответов. На каждый вопрос будет один ответ, ограниченный одним-пятью словами.
Эта подпись определяет нашу цель: разработать чат-бота, отвечающего на вопросы.
class BasicQA(dspy.Signature): #Signature
"""Answer questions with short factoid answers."""
question = dspy.InputField()
answer = dspy.OutputField(desc="often between 1 and 5 words")
Затем мы генерируем ответ с помощью dspy.predict
, передаем класс Basic QA и вызываем функцию generate_answer
с нашим примером вопроса. Наконец, мы распечатываем выходные данные, чтобы проверить, правильно ли реагирует наш чат-бот, отвечающий на вопросы.
# Define the predictor.
generate_answer = dspy.Predict(BasicQA)
Call the predictor on a particular input.
pred = generate_answer(question=dev_example.question)
Print the input and the prediction.
print(f"Question: {dev_example.question}")
print(f"Predicted Answer: {pred.answer}")
Выход:-
Question: What is the nationality of the chef and restaurateur featured in Restaurant: Impossible?
Predicted Answer: American
Здесь ответ неверный, и надо его исправить. Давайте посмотрим, как был сгенерирован этот вывод.
turbo.inspect_history(n=1)
turbo.inspect_history(n=1)
Answer questions with short factoid answers.
---
Follow the following format.
Question: ${question}
Answer: often between 1 and 5 words
---
Question: What is the nationality of the chef and restaurateur featured in Restaurant: Impossible?
Answer: American
Этот шеф-повар — британец и американец, но мы не можем знать, угадала ли модель «американец», потому что это стандартный ответ.
Давайте представим «цепочку мыслей».
Создание чат-бота с помощью Chain of Thought
Цепочка мыслей включает в себя ряд промежуточных шагов рассуждения, значительно улучшающих способность больших языковых моделей выполнять сложные рассуждения.
generate_answer_with_chain_of_thought = dspy.ChainOfThought(BasicQA)
Call the predictor on the same input.
pred = generate_answer_with_chain_of_thought(question=dev_example.question)
Print the input, the chain of thought, and the prediction.
print(f"Question: {dev_example.question}")
print(f"Thought: {pred.rationale.split('.', 1)[1].strip()}")
print(f"Predicted Answer: {pred.answer}")
Question: What is the nationality of the chef and restaurateur featured in Restaurant: Impossible?
Thought: We know that the chef and restaurateur featured in Restaurant: Impossible is Robert Irvine.
Predicted Answer: British
Здесь ответ лучше, чем ответ, который мы получили ранее.
Не стесняйтесь запускать приведенный ниже код и проверять обоснование и то, как генерируется этот ответ.
turbo.inspect_history(n=1)
Создание приложения RAG
Мы построим конвейер с расширенным поиском для генерации ответов. Сначала мы создадим подпись, затем модуль, настроим оптимизатор для ее уточнения и, наконец, выполним процесс RAG, определив класс с именем GenerateAnswer
.
РАГ Подпись
Определите подпись: контекст, вопрос --> ответ
.
class GenerateAnswer(dspy.Signature):
"""Answer questions with short factoid answers."""
context = dspy.InputField(desc="may contain relevant facts")
question = dspy.InputField()
answer = dspy.OutputField(desc="often between 1 and 5 words")
Тряпочный модуль
В классе RAG, который действует как модуль, мы определяем модель в функции init. Мы фокусируемся на «Получить» и «GenerateAnswer». «Получить» собирает соответствующие отрывки в качестве контекста, затем «GenerateAnswer» использует «ChainOfThought» для предоставления прогнозов на основе вопроса пользователя.
class RAG(dspy.Module):
def __init__(self, num_passages=3):
super().__init__()
self.retrieve = dspy.Retrieve(k=num_passages)
self.generate_answer = dspy.ChainOfThought(GenerateAnswer)
def forward(self, question):
context = self.retrieve(question).passages
prediction = self.generate_answer(context=context, question=question)
return dspy.Prediction(context=context, answer=prediction.answer)
Оптимизатор RAG
Затем мы компилируем программу RAG, которая включает в себя использование обучающего набора, определение метрики проверки и выбор телесуфлера для оптимизации программы. Телесуфлеры — это мощные оптимизаторы, подбирающие эффективные подсказки для модулей. Мы будем использовать BootstrapFewShot в качестве простого телесуфлера по умолчанию, аналогично выбору оптимизатора в традиционных системах контролируемого обучения, таких как SGD, Adam или RMSProp.
# Validation logic: check that the predicted answer is correct.Also check that the retrieved context does actually contain that answer.
def validate_context_and_answer(example, pred, trace=None):
answer_EM = dspy.evaluate.answer_exact_match(example, pred)
answer_PM = dspy.evaluate.answer_passage_match(example, pred)
return answer_EM and answer_PM
Set up a basic teleprompter, which will compile our RAG program.
teleprompter = BootstrapFewShot(metric=validate_context_and_answer)
Compile!
compiled_rag = teleprompter.compile(RAG(), trainset=trainset)
Теперь давайте попробуем выполнить этот конвейер.
# Ask any question you like to this simple RAG program.
my_question = "What castle did David Gregory inherit?"
Get the prediction. This contains `pred.context` and `pred.answer`.
pred = compiled_rag(my_question)
Print the contexts and the answer.
print(f"Question: {my_question}")
print(f"Predicted Answer: {pred.answer}")
print(f"Retrieved Contexts (truncated): {[c[:200] + '...' for c in pred.context]}")
Question: What castle did David Gregory inherit?
Predicted Answer: Kinnairdy Castle
Retrieved Contexts (truncated): ['David Gregory (physician) | David Gregory (20 December 1625 – 1720) was a Scottish physician and inventor. His surname is sometimes spelt as Gregorie, the original Scottish spelling. He inherited Kinn...', 'Gregory Tarchaneiotes | Gregory Tarchaneiotes (Greek: Γρηγόριος Ταρχανειώτης , Italian: "Gregorio Tracanioto" or "Tracamoto" ) was a "protospatharius" and the long-reigning catepan of Italy from 998 t...', 'David Gregory (mathematician) | David Gregory (originally spelt Gregorie) FRS (? 1659 – 10 October 1708) was a Scottish mathematician and astronomer. He was professor of mathematics at the University ...']
Давайте посмотрим историю.
turbo.inspect_history(n=1)
Context:
[1] «David Gregory (physician) | David Gregory (20 December 1625 – 1720) was a Scottish physician and inventor. His surname is sometimes spelt as Gregorie, the original Scottish spelling. He inherited Kinnairdy Castle in 1664. Three of his twenty-nine children became mathematics professors. He is credited with inventing a military cannon that Isaac Newton described as "being destructive to the human species". Copies and details of the model no longer exist. Gregory's use of a barometer to predict farming-related weather conditions led him to be accused of witchcraft by Presbyterian ministers from Aberdeen, although he was never convicted.»
[2] «Gregory Tarchaneiotes | Gregory Tarchaneiotes (Greek: Γρηγόριος Ταρχανειώτης , Italian: "Gregorio Tracanioto" or "Tracamoto" ) was a "protospatharius" and the long-reigning catepan of Italy from 998 to 1006. In December 999, and again on February 2, 1002, he reinstituted and confirmed the possessions of the abbey and monks of Monte Cassino in Ascoli. In 1004, he fortified and expanded the castle of Dragonara on the Fortore. He gave it three circular towers and one square one. He also strengthened Lucera.»
[3] «David Gregory (mathematician) | David Gregory (originally spelt Gregorie) FRS (? 1659 – 10 October 1708) was a Scottish mathematician and astronomer. He was professor of mathematics at the University of Edinburgh, Savilian Professor of Astronomy at the University of Oxford, and a commentator on Isaac Newton's "Principia".»
Question: What castle did David Gregory inherit?
Reasoning: Let's think step by step in order to produce the answer. We know that David Gregory inherited a castle. The name of the castle is Kinnairdy Castle.
Answer: Kinnairdy Castle
Оценивать
Последним шагом является оценка, при которой мы оцениваем производительность модели RAG: мы оценим базовую RAG, некомпилированную RAG (без оптимизатора) и скомпилированную RAG (с оптимизатором). Мы сравним баллы, полученные в результате этих оценок.
Базовая ТРЯПКА
def gold_passages_retrieved(example, pred, trace=None):
gold_titles = set(map(dspy.evaluate.normalize_text, example['gold_titles']))
found_titles = set(map(dspy.evaluate.normalize_text, [c.split(' | ')[0] for c in pred.context]))
return gold_titles.issubset(found_titles)
evaluate_on_hotpotqa = Evaluate(devset=devset, num_threads=1, display_progress=True, display_table=5)
compiled_rag_retrieval_score = evaluate_on_hotpotqa(compiled_rag, metric=gold_passages_retrieved)
Некомпилированный усатый RAG (без оптимизатора)
Изучение сложных вопросов в наборах для обучения и разработки показывает, что один поисковый запрос часто необходимо пересматривать, например, когда требуется дополнительная информация. Чтобы решить эту проблему, в литературе по НЛП, дополненной поиском, предлагаются многошаговые поисковые системы, такие как GoldEn и Baleen, которые генерируют дополнительные запросы для сбора дополнительной информации.
С помощью DSPy мы можем легко моделировать такие системы, используя сигнатуру GenerateAnswer из реализации RAG и сигнатуру для поведения «прыжка»: генерацию поисковых запросов для поиска недостающей информации на основе частичного контекста и вопроса.
class GenerateSearchQuery(dspy.Signature):
"""Write a simple search query that will help answer a complex question."""
context = dspy.InputField(desc="may contain relevant facts")
question = dspy.InputField()
query = dspy.OutputField()
Далее создайте модуль.
class SimplifiedBaleen(dspy.Module):
def __init__(self, passages_per_hop=3, max_hops=2):
super().__init__()
self.generate_query = [dspy.ChainOfThought(GenerateSearchQuery) for _ in range(max_hops)]
self.retrieve = dspy.Retrieve(k=passages_per_hop)
self.generate_answer = dspy.ChainOfThought(GenerateAnswer)
self.max_hops = max_hops
def forward(self, question):
context = []
for hop in range(self.max_hops):
query = self.generate_query[hop](context=context, question=question).query
passages = self.retrieve(query).passages
context = deduplicate(context + passages)
pred = self.generate_answer(context=context, question=question)
return dspy.Prediction(context=context, answer=pred.answer)
Основная цель Baleen — автоматически изменять вопрос или запрос, разделяя его на фрагменты. Он извлекает контекст из фрагментов, а затем сохраняет его в переменной, что помогает генерировать более точные ответы.
Осмотрите нулевую версию программы «Китовый уса».
Использование программы в нулевом (некомпилированном) режиме зависит от способности базовой языковой модели понимать подзадачи с минимальными инструкциями. Это хорошо работает с мощными моделями (например, GPT-4) для простых и распространенных задач. Однако подходы с нулевым выстрелом менее практичны для специализированных задач, новых областей и более эффективных или открытых моделей. DSPy может повысить производительность в таких ситуациях.
# Ask any question you like to this simple RAG program.
my_question = "How many storeys are in the castle that David Gregory inherited?"
Get the prediction. This contains `pred.context` and `pred.answer`.
uncompiled_baleen = SimplifiedBaleen() # uncompiled (i.e., zero-shot) program
pred = uncompiled_baleen(my_question)
Print the contexts and the answer.
print(f"Question: {my_question}")
print(f"Predicted Answer: {pred.answer}")
print(f"Retrieved Contexts (truncated): {[c[:200] + '...' for c in pred.context]}")
Question: How many storeys are in the castle that David Gregory inherited?
Predicted Answer: five
Retrieved Contexts (truncated): ['David Gregory (physician) | David Gregory (20 December 1625 – 1720) was a Scottish physician and inventor. His surname is sometimes spelt as Gregorie, the original Scottish spelling. He inherited Kinn...', 'The Boleyn Inheritance | The Boleyn Inheritance is a novel by British author Philippa Gregory which was first published in 2006. It is a direct sequel to her previous novel "The Other Boleyn Girl," an...', 'Gregory of Gaeta | Gregory was the Duke of Gaeta from 963 until his death. He was the second son of Docibilis II of Gaeta and his wife Orania. He succeeded his brother John II, who had left only daugh...', 'Kinnairdy Castle | Kinnairdy Castle is a tower house, having five storeys and a garret, two miles south of Aberchirder, Aberdeenshire, Scotland. The alternative name is Old Kinnairdy....', 'Kinnaird Head | Kinnaird Head (Scottish Gaelic: "An Ceann Àrd" , "high headland") is a headland projecting into the North Sea, within the town of Fraserburgh, Aberdeenshire on the east coast of Scotla...', 'Kinnaird Castle, Brechin | Kinnaird Castle is a 15th-century castle in Angus, Scotland. The castle has been home to the Carnegie family, the Earl of Southesk, for more than 600 years....']
Скомпилированный усатый RAG (с оптимизатором)
Во-первых, мы определим нашу логику проверки, которая будет гарантировать, что:
1. Предсказанный ответ соответствует правильному ответу. 2. Полученный контекст включает правильный ответ. 3. Ни один из сгенерированных запросов не является слишком длинным (т. е. не превышает 100 символов). 4. Ни один из сгенерированных запросов не является повторяющимся (т. е. ни один из них не имеет балла F1 0,8 или выше, чем предыдущие).
def validate_context_and_answer_and_hops(example, pred, trace=None):
if not dspy.evaluate.answer_exact_match(example, pred): return False
if not dspy.evaluate.answer_passage_match(example, pred): return False
hops = [example.question] + [outputs.query for *_, outputs in trace if 'query' in outputs]
if max([len(h) for h in hops]) > 100: return False
if any(dspy.evaluate.answer_exact_match_str(hops[idx], hops[:idx], frac=0.8) for idx in range(2, len(hops))): return False
return True
Далее мы воспользуемся одним из самых простых телесуфлеров в DSPy, а именно BootstrapFewShot
.
teleprompter = BootstrapFewShot(metric=validate_context_and_answer_and_hops)
Наконец, мы скомпилируем оптимизатор и оценим качество извлечения скомпилированных и некомпилированных уса-конвейеров.
compiled_baleen = teleprompter.compile(SimplifiedBaleen(), teacher=SimplifiedBaleen(passages_per_hop=2), trainset=trainset)
uncompiled_baleen_retrieval_score = evaluate_on_hotpotqa(uncompiled_baleen, metric=gold_passages_retrieved)
compiled_baleen_retrieval_score = evaluate_on_hotpotqa(compiled_baleen, metric=gold_passages_retrieved)
Давайте теперь распечатаем результаты для сравнения.
print(f"## Retrieval Score for RAG: {compiled_rag_retrieval_score}") # note that for RAG, compilation has no effect on the retrieval step
print(f"## Retrieval Score for uncompiled Baleen: {uncompiled_baleen_retrieval_score}")
print(f"## Retrieval Score for compiled Baleen: {compiled_baleen_retrieval_score}")
Выход:-
## Retrieval Score for RAG: 26.0
## Retrieval Score for uncompiled Baleen: 48.0
## Retrieval Score for compiled Baleen: 60.0
Следовательно, скомпилированный метод Уса дает более точные ответы, чем базовое приложение RAG. Скомпилированный уса делит вопрос на несколько небольших частей, извлекает контекст и дает более точный ответ.
compiled_baleen("How many storeys are in the castle that David Gregory inherited?")
turbo.inspect_history(n=3)
Заключение
В этой статье представлена DSPy, новая модель программирования для проектирования систем искусственного интеллекта с использованием конвейеров предварительно обученных языковых моделей (LM) и других инструментов. Мы представили три ключевые концепции: сигнатуры DSPy, модули и телесуфлеры. Далее мы исследовали структуру, создав простые q, чат-боты и приложения RAG. Благодаря этим экспериментам мы продемонстрировали, что DSPy позволяет быстро разрабатывать эффективные системы с использованием относительно небольших LM.
Надеемся, вам понравилась статья!
Ссылки
- Репозиторий DSPy на GitHub
- DSPY: СОСТАВЛЕНИЕ ВЫЗОВОВ МОДЕЛИ ДЕКЛАРАТИВНОГО ЯЗЫКА В САМОСОВЕРШЕНСТВУЮЩИЕСЯ КОНВЕЙЕРЫ