网站搜索

使用 DSPy 进行提示:一种新方法


介绍

我们始终致力于更好地使用和组合语言模型 (LM) 的时代已经到来。通常,法学硕士使用通过反复试验制作的固定“提示模板”。 DSPy 是一种新方法,它通过将 LM 管道转变为易于管理的文本转换图来简化这一过程。这些图表使用的模块可以学习和改进它们的提示、微调和推理方式。

DSPy 包含一个可以优化这些管道以获得更好性能的工具。研究表明,DSPy 可以快速创建有效的 LM 管道,与传统方法相比显着提高性能。它还使更小的开放模型与 GPT-3.5 等高级模型的专家设计提示相竞争。

先决条件

在深入了解 DSPy 之前,请确保您具备以下条件:

  • 基本编程知识:熟悉Python及其库。
  • 了解法学硕士:对大型语言模型及其激励机制有基本的了解。
  • 环境设置:访问已安装所需库的 Python 开发环境,例如 Jupyter Notebook 或 VS Code。

什么是DSPy?

DSPy 是一个框架,可以更轻松地优化语言模型 (LM) 提示和权重,尤其是在多次使用 LM 时。如果没有 DSPy,使用 LM 构建复杂系统涉及许多手动步骤:分解问题、微调提示、调整步骤、生成综合示例以及微调较小的 LM,这可能会很麻烦且混乱。

DSPy 通过将程序流程与参数(提示和权重)分离并引入新的优化器来根据期望的结果调整这些参数,从而简化了这一过程。这使得 GPT-4 或 T5-base 等强大的模型更加可靠和有效。 DSPy 使用算法来更新参数,而不是手动提示调整,从而允许您重新编译程序以适应代码、数据或指标的任何更改。

可以将其视为使用 PyTorch 等神经网络框架:我们不会手动调整每个细节,而是使用层和优化器来学习最佳参数。同样,DSPy 提供的模块和优化器可以自动化和增强 LM 的工作,从而减少手动调整,而更多地关注系统改进和更高的性能。

DSPy 代表什么?

反义词“now”代表“声明性自我改进语言程序”,由斯坦福 NLP 大学创建。

DSPy 简化了优化语言模型 (LM) 提示和权重的复杂过程,特别是对于多步骤管道。传统上,您必须分解问题、完善提示、调整步骤、生成综合示例并微调较小的模型。这是混乱且耗时的,因为任何更改都需要重新处理提示和微调。

DSPy 通过将程序流与 LM 参数分离并引入优化器,增强了 GPT-3.5、GPT-4、T5-base 或 Llama2-13b 等模型的可靠性。这使他们更加有效且不易出错,从而逐渐对结果产生信任感和信心。

为什么我们需要 DSPy?

“提示模板”是提供给语言模型的预定义指令或演示,用于指导其对给定任务的响应。 提示模板通常是通过反复试验来创建的。这意味着它们可能适用于特定的任务或场景,但在不同的上下文中会失败或产生不相关的结果。由于这些模板是硬编码的,因此它们缺乏适应性,并且可能无法有效地处理输入数据、任务要求甚至其他语言模型的变化。 给定的提示模板可能适用于特定的 LM 管道或框架。尽管如此,它可能无法很好地推广到其他管道、不同的语言模型、不同的数据域,甚至不同类型的输入。这种通用性的缺乏限制了 LM 在不同用例中的灵活性和适用性。 为不同的任务或语言模型手动制作和微调提示模板可能非常耗时且费力。随着任务的复杂性和多样性的增加,维护和更新这些模板变得越来越具有挑战性和低效。

此外,其他问题可能与生成响应有关。在语言模型 (LM) 管道和框架中使用硬编码提示模板通常会导致缺乏上下文和相关性、输出不一致、响应质量差和不准确等问题。这些挑战源于提示模板的灵活性和可扩展性有限,这些模板是手动制作的,可能无法有效地跨不同的 LM 模型、数据域或输入变量进行泛化。

那么为什么选择 DSPy?

  • DSPy 专注于构建新的语言模型管道,从操作非结构化文本输入转向编程。
  • DSPy 模块是类似于神经网络层的任务自适应组件,抽象文本转换,例如问答或摘要。
  • DSPy 编译器利用训练输入和验证指标来优化程序质量或成本。
  • DSPy 编译器模拟程序版本,引导示例跟踪以进行自我改进和有效的提示生成。
  • DSPy 中的优化是模块化的,由提词器进行,决定从数据中学习的模块。
  • DSPy 可以将声明性模块映射到提示、微调、推理和增强的高质量组合。
  • DSPy 编程模型专注于减少专家制作的提示的作用。
  • DSPy模块的组合可以在几分钟到几十分钟的编译时间内显着提高简单程序的质量。

DSPy 中的主要组件

在深入研究之前,让我们了解 DSPy 的一些重要组件

  • 签名
  • 模块
  • 提词器或优化器

DSPy 签名 是函数的声明,提供了文本转换需要处理的简洁规范,而不是详细说明应如何提示特定语言模型来实现该行为。 DSPy 签名是一个由输入输出字段以及可选指令组成的元组。每个字段包括字段名称和可选元数据。

签名侧重于我们正在构建的系统类型,例如:-问题->答案、英文文档->法文翻译或内容->摘要。

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模块可以组合起来形成更大、更复杂的程序。受 PyTorch 中神经网络模块的启发,DSPy 模块为语言模型编程带来了类似的功能。

例如:-

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.思想链
  • dspy.ReAct
  • dspy.多链比较
  • dspy.思想计划

等等。

DSPy 提词器用于 DSPy 中的优化。它非常灵活且模块化。优化是通过提词器进行的,这是指导模块如何从数据中学习的通用策略。

DSPy 优化器是一种算法,旨在微调 DSPy 程序的参数(例如提示和语言模型权重),以最大限度地提高准确性等指定指标。 DSPy 提供了多种内置优化器,每种优化器都采用不同的策略。通常,DSPy 优化器需要三件事:您的 DSPy 程序(可以是单个模块或复杂的多模块设置)、用于评估程序输出并对其进行评分的度量函数(分数越高表示性能越好)以及一些训练输入(有时只有 5 或 10 个示例,即使它们缺少标签)。虽然拥有大量数据可能是有益的,但 DSPy 的设计目的是即使使用最少的输入也能提供强大的结果。

优化器如何提高性能?

传统的深度神经网络 (DNN) 使用带有损失函数和训练数据的梯度下降进行优化。相比之下,DSPy 程序包含多个集成为 DSPy 模块的语言调用模型 (LM)。每个模块都有三个内部参数:LM 权重、指令和输入/输出行为的演示。

DSPy 可以使用多阶段优化算法来优化所有这三个算法,结合 LM 权重的梯度下降和用于细化指令和演示的 LM 驱动的优化。与典型的少数示例不同,DSPy 演示更加强大,可以根据您的程序从头开始生成和优化。这种编译通常会产生比人工编写更好的提示,这并不是因为 DSPy 优化器本质上更具创造性,而是因为它们可以系统地探索更多选项并直接微调指标。

下面列出了一些 DSPy 优化器:-

  • 标签FewShot
  • BootstrapFewShot
  • BootstrapFewShotWithRandomSearch
  • BootstrapFewShotWithOptuna
  • KNN新射击

这样的例子不胜枚举。

我们强烈推荐 DSPy 文档,以获取有关不同类型优化器的更多信息。

与 Langchain 和 Llamaindex 的比较

LangChain 和 LlamaIndex 概述:

  • langchain 和 llamaindex 都是提示 LM 领域的流行库。
  • 这两个库都专注于为应用程序开发人员提供预打包的组件和链。此外,它们还提供可重用管道(例如代理、检索管道)和工具(例如数据库连接、内存实现)的实现。

DSPy 概述:

  • DSPy 旨在解决即时工程的基本挑战,并在无需手动即时工程的情况下构建新的 LM 计算图。
  • 此外,它还引入了核心可组合运算符、签名(用于抽象提示)、模块(用于抽象提示技术)和提词器作为优化器。
  • DSPy通过自动编译和自我改进,有助于快速构建新的LM管道并获得高质量的结果。

LangChain和LlamaIndex之间的显着差异:

  • LangChain和LlamaIndex依赖于手动提示工程,DSPy旨在解决这个问题。
  • DSPy 提供了一个结构化框架,可以自动引导提示,无需手写提示演示。
  • 2023年9月,浪链的代码库包含50个超过1000个字符的字符串以及大量专用于提示符工程的文件(12个prompts.py和42个prompt.py文件)。相比之下,DSPy 不包含手写提示,但可以通过各种 LM 实现高质量。
  • 事实证明,DSPy 比硬编码提示更模块化、更强大。

DSPy 入门

让我们从安装软件包开始:

!pip install dspy-ai
#or
!pip install git+https://github.com/stanfordnlp/dspy.git

默认情况下,DSPy 从 pip 安装最新的 openai

导入必要的包,

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'}

创建聊天机器人

我们正在创建一个名为“基本 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 生成响应,传递基本 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 应用程序

我们将构建一个用于生成答案的检索增强管道。首先,我们将创建一个签名,然后创建一个模块,设置一个优化器来优化它,最后通过定义一个名为 GenerateAnswer 的类来执行 RAG 过程。

拉格签名

定义签名:上下文、问题 --> 答案

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模块

在充当模块的 RAG 类中,我们在 init 函数中定义模型。我们重点关注“Retrieve”和“GenerateAnswer”。“Retrieve”收集相关段落作为上下文,然后“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(带优化器)。我们将比较从这些评估中获得的分数。

基本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)

未编译的 Baleen RAG(无优化器)

探索训练/开发集中的挑战性问题表明,单个搜索查询通常需要修改,例如当需要更多细节时。为了解决这个问题,检索增强的 NLP 文献提出了 GoldEn 和 Baleen 等多跳搜索系统,它们会生成额外的查询来收集更多信息。

借助 DSPy,我们可以使用 RAG 实现中的GenerateAnswer 签名和“跳跃”行为的签名轻松模拟此类系统:生成搜索查询以根据部分上下文和问题查找丢失的信息。

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 的主要目的是通过将问题或查询分成多个块来自动修改问题或查询。它从块中检索上下文,然后将其保存在变量中,这有助于生成更准确的答案。

检查 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....']

已编译的 Baleen 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)

最后,我们将编译优化器并评估已编译和未编译的 baleen 管道的检索质量。

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

因此,编译后的 Baleen 方法比基本 RAG 应用提供了更准确的答案。 Compiled Baleen 将问题分成多个小块,检索上下文,并提供更精确的答案。

compiled_baleen("How many storeys are in the castle that David Gregory inherited?")
turbo.inspect_history(n=3)

结论

本文介绍了 DSPy,这是一种新的编程模型,用于使用预训练语言模型 (LM) 和其他工具的管道来设计 AI 系统。我们提出了三个关键概念:DSPy 签名、模块和提词器。此外,我们通过创建简单的 q 和 a 聊天机器人以及 RAG 应用程序来探索该框架。通过这些实验,我们证明了 DSPy 能够使用相对较小的 LM 快速开发有效的系统。

我们希望您喜欢这篇文章!

参考

  • DSPy github 存储库
  • DSPY:将声明性语言模型调用编译到自我改进的管道中

相关文章: