Интеграция Milvus с DSPy
Что такое DSPy
DSPy, представленный Стэнфордской группой NLP, является революционным программным фреймворком, предназначенным для оптимизации подсказок и весов в языковых моделях, что особенно ценно в сценариях, где большие языковые модели (LLM) интегрированы на нескольких этапах конвейера. В отличие от традиционных методов разработки подсказок, основанных на ручном подборе и настройке, DSPy использует подход, основанный на обучении. Усваивая примеры запросов и ответов, DSPy динамически генерирует оптимизированные подсказки, адаптированные к конкретным задачам. Эта инновационная методология позволяет беспрепятственно перестраивать целые конвейеры, устраняя необходимость в постоянной ручной корректировке подсказок. Питонический синтаксис DSPy предлагает различные композитные и декларативные модули, упрощающие создание LLM.
Преимущества использования DSPy
- Подход к программированию: DSPy обеспечивает систематический подход к программированию для разработки LM-конвейеров, абстрагируя конвейеры как графы текстовых преобразований, а не просто подсказывая LLM. Его декларативные модули обеспечивают структурированное проектирование и оптимизацию, заменяя метод проб и ошибок традиционных шаблонов подсказок.
- Повышение производительности: DSPy демонстрирует значительный прирост производительности по сравнению с существующими методами. На конкретных примерах он превосходит стандартные подсказки и демонстрации, созданные экспертами, демонстрируя свою универсальность и эффективность даже при компиляции в небольшие модели LM.
- Модулированная абстракция: DSPy эффективно абстрагирует сложные аспекты разработки конвейера LM, такие как декомпозиция, тонкая настройка и выбор модели. С помощью DSPy краткая программа может быть легко преобразована в инструкции для различных моделей, таких как GPT-4, Llama2-13b или T5-base, что упрощает разработку и повышает производительность.
Модули
Существует множество компонентов, которые вносят свой вклад в построение конвейера LLM. Здесь мы опишем некоторые ключевые компоненты, чтобы обеспечить высокоуровневое понимание того, как работает DSPy.
Модули DSPy
Сигнатура: Сигнатуры в DSPy служат декларативными спецификациями, определяющими входное/выходное поведение модулей и направляющими языковую модель при выполнении задач. Модуль: Модули DSPy служат фундаментальными компонентами для программ, использующих языковые модели (ЯМ). Они абстрагируют различные техники подсказок, такие как цепочка мыслей или ReAct, и адаптируются для работы с любой сигнатурой DSPy. Благодаря обучаемым параметрам и способности обрабатывать входные данные и создавать выходные, эти модули можно объединять в более крупные программы, черпая вдохновение в модулях NN в PyTorch, но адаптируя их для применения LM. Оптимизатор: Оптимизаторы в DSPy точно настраивают параметры программ DSPy, такие как подсказки и веса LLM, чтобы максимизировать заданные метрики, такие как точность, повышая эффективность программы.
Почему Milvus в DSPy
DSPy - это мощный фреймворк программирования, который способствует развитию RAG-приложений. Таким приложениям необходимо извлекать полезную информацию для повышения качества ответов, для чего нужна векторная база данных. Milvus - это известная векторная база данных с открытым исходным кодом, позволяющая повысить производительность и масштабируемость. С MilvusRM, модулем ретривера в DSPy, интеграция Milvus становится простой. Теперь разработчики могут легко определять и оптимизировать RAG-программы с помощью DSPy, используя сильные возможности векторного поиска Milvus. Это сотрудничество делает приложения RAG более эффективными и масштабируемыми, объединяя возможности программирования DSPy с функциями поиска Milvus.
Примеры
Теперь давайте рассмотрим быстрый пример, демонстрирующий использование Milvus в DSPy для оптимизации RAG-приложений.
Предварительные условия
Перед созданием приложения RAG установите DSPy и PyMilvus.
$ pip install "dspy-ai[milvus]"
$ pip install -U pymilvus
Загрузка набора данных
В этом примере в качестве обучающего набора данных мы используем HotPotQA, коллекцию сложных пар "вопрос-ответ". Мы можем загрузить их через класс HotPotQA.
from dspy.datasets import HotPotQA
# Load the dataset.
dataset = HotPotQA(
train_seed=1, train_size=20, eval_seed=2023, dev_size=50, test_size=0
)
# Tell DSPy that the 'question' field is the input. Any other fields are labels and/or metadata.
trainset = [x.with_inputs("question") for x in dataset.train]
devset = [x.with_inputs("question") for x in dataset.dev]
Загрузка данных в векторную базу данных Milvus
Загрузите контекстную информацию в коллекцию Milvus для векторного поиска. В этой коллекции должно быть поле embedding
и поле text
. В данном случае мы используем модель OpenAI text-embedding-3-small
в качестве функции встраивания запроса по умолчанию.
import requests
import os
os.environ["OPENAI_API_KEY"] = "<YOUR_OPENAI_API_KEY>"
MILVUS_URI = "example.db"
MILVUS_TOKEN = ""
from pymilvus import MilvusClient, DataType, Collection
from dspy.retrieve.milvus_rm import openai_embedding_function
client = MilvusClient(uri=MILVUS_URI, token=MILVUS_TOKEN)
if "dspy_example" not in client.list_collections():
client.create_collection(
collection_name="dspy_example",
overwrite=True,
dimension=1536,
primary_field_name="id",
vector_field_name="embedding",
id_type="int",
metric_type="IP",
max_length=65535,
enable_dynamic=True,
)
text = requests.get(
"https://raw.githubusercontent.com/wxywb/dspy_dataset_sample/master/sample_data.txt"
).text
for idx, passage in enumerate(text.split("\n")):
if len(passage) == 0:
continue
client.insert(
collection_name="dspy_example",
data=[
{
"id": idx,
"embedding": openai_embedding_function(passage)[0],
"text": passage,
}
],
)
Определите MilvusRM.
Теперь вам нужно определить MilvusRM.
from dspy.retrieve.milvus_rm import MilvusRM
import dspy
retriever_model = MilvusRM(
collection_name="dspy_example",
uri=MILVUS_URI,
token=MILVUS_TOKEN, # ignore this if no token is required for Milvus connection
embedding_function=openai_embedding_function,
)
turbo = dspy.OpenAI(model="gpt-3.5-turbo")
dspy.settings.configure(lm=turbo)
Построение сигнатур
Теперь, когда мы загрузили данные, давайте начнем определять сигнатуры для подзадач нашего конвейера. Мы можем определить наши простые входные question
и выходные answer
, но поскольку мы строим конвейер RAG, мы будем получать контекстную информацию из Milvus. Поэтому давайте определим нашу сигнатуру как context, question --> answer
.
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")
Мы включаем краткие описания для полей context
и answer
, чтобы определить более четкие ориентиры того, что будет получать и генерировать модель.
Построение конвейера
Теперь давайте определим конвейер RAG.
class RAG(dspy.Module):
def __init__(self, rm):
super().__init__()
self.retrieve = rm
# This signature indicates the task imposed on the COT module.
self.generate_answer = dspy.ChainOfThought(GenerateAnswer)
def forward(self, question):
# Use milvus_rm to retrieve context for the question.
context = self.retrieve(question).passages
# COT module takes "context, query" and output "answer".
prediction = self.generate_answer(context=context, question=question)
return dspy.Prediction(
context=[item.long_text for item in context], answer=prediction.answer
)
Выполнение конвейера и получение результатов
Теперь мы построили этот конвейер RAG. Давайте опробуем его и получим результаты.
rag = RAG(retriever_model)
print(rag("who write At My Window").answer)
Townes Van Zandt
Мы можем оценить количественные результаты на наборе данных.
from dspy.evaluate.evaluate import Evaluate
from dspy.datasets import HotPotQA
evaluate_on_hotpotqa = Evaluate(
devset=devset, num_threads=1, display_progress=False, display_table=5
)
metric = dspy.evaluate.answer_exact_match
score = evaluate_on_hotpotqa(rag, metric=metric)
print("rag:", score)
Оптимизация конвейера
После определения программы следующим шагом будет компиляция. Этот процесс обновляет параметры в каждом модуле для повышения производительности. Процесс компиляции зависит от трех важнейших факторов:
- Обучающий набор: Для демонстрации мы будем использовать 20 примеров вопросов-ответов из нашего обучающего набора данных.
- Метрика проверки: Мы создадим простую метрику
validate_context_and_answer
. Эта метрика проверяет точность предсказанного ответа и гарантирует, что найденный контекст включает ответ. - Специфический оптимизатор (телесуфлер): В компилятор DSPy встроено несколько телесуфлеров, предназначенных для эффективной оптимизации ваших программ.
from dspy.teleprompt import BootstrapFewShot
# Validation logic: check that the predicted answer is correct.# Also check that the retrieved context does 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)
# Now compiled_rag is optimized and ready to answer your new question!
# Now, let’s evaluate the compiled RAG program.
score = evaluate_on_hotpotqa(compiled_rag, metric=metric)
print(score)
print("compile_rag:", score)
Оценка Ragas увеличилась с предыдущего значения 50,0 до 52,0, что свидетельствует о повышении качества ответа.
Резюме
DSPy знаменует собой скачок в области взаимодействия с языковыми моделями благодаря программируемому интерфейсу, который облегчает алгоритмическую и автоматизированную оптимизацию подсказок и весов моделей. Использование DSPy для реализации RAG позволяет легко адаптироваться к различным языковым моделям и наборам данных, что значительно сокращает необходимость утомительного ручного вмешательства.