DSPy — 它是否名副其实?(是否名副其实是什么意思)

DSPy框架承诺用一个自动调整提示的编程框架取代手动提示工程。让我们通过一个案例研究来看看这是否名副其实。

斯坎达·维韦克 EMAlpha

提示工程已经死了。至少,这是一项大胆的研究所声称的,背后由DSPy作为引擎支持。首先,让我们来点背景知识,为什么大家都对此如此兴奋。让我们面对现实——数据科学家在过去一年里都成了提示工程师(抱歉,总得有人说出来)。那么,为什么那些工作可能被一个存储库接管的人对此如此感兴趣呢?嗯,因为它让人想起旧日的好时光(还记得一年前你训练或微调像BERT这样的模型时的情景吗——啊,感觉就像是很久以前的事了)。

DSPy的前提是迷人的——如果我们能像训练模型参数一样训练提示会怎样?这个想法在学术环境中显示出了希望——由斯坦福大学的研究带头。在另一篇论文中,来自VMware的研究人员表明,自动化提示优化(由DSPy提供动力)在与人工调整的提示相比中胜出。

随后,IEEE发布了一篇观点文章,标题为“提示工程已死”。他们大胆地声称:

根据一个研究团队的说法,人类再也不应该手动优化提示了。

那么,让我们通过一个典型的少样本提示示例深入研究DSPy,看看它的性能如何!

提示工程案例研究 以下数据来自SubjQA数据集。SubjQA提供了一个研究提取式问答系统及其性能的环境。我在fine-tuning RoBERTa模型的这个数据集上写过一篇博客:

在自定义数据上微调Transformer模型进行问答 一个教程,介绍如何在自定义数据上微调Hugging Face RoBERTa问答模型,并显著提高性能 towardsdatascience.com

下面的数据中,将ANSWERNOTFOUND附加到上下文的末尾,目标是从文本中提取相关答案,或者如果答案不存在,则为ANSWERNOTFOUND。

虽然ChatGPT和其他现代大型语言模型更多地用于生成式问答,但你可以为纯粹的提取式问答设计一个提示。

来自SubjQA的代表性数据 这里有一个示例提示:

你是一个提取式问题回答者。 从上下文中回答问题,只提取文本的部分。 确保只使用段落部分回答问题。 如果答案不相关,就用上下文的最后一个词回答:ANSWERNOTFOUND

以下是一些示例:


问题:... 上下文:... 答案:...

ChatGPT响应 如你所见,对于我的(最少)人为工程化的提示,当上下文与问题不相关时,ChatGPT能够正确回答。注意:我必须事先硬编码这些信息,因为ChatGPT倾向于不包含ANSWERNOTFOUND。

设置DSPy 现在让我们为同样任务的自动化提示工程设置DSPy。首先,DSPy提供了一个标准的基础流程,用于根据样板问题、上下文、答案模板生成答案。

class BasicQA(dspy.Signature): """用简短的事实性答案回答问题。"""

question = dspy.InputField()
answer = dspy.OutputField(desc="通常在1到5个词之间")

定义预测器。

generate_answer = dspy.Predict(BasicQA)

在特定输入上调用预测器。

pred = generate_answer(question=dev_example.question,context = dev_example.context)

打印输入和预测。

print(f"问题:{dev_example.question}") print(f"预测答案:{pred.answer}")

问题:这个好吗? 预测答案:需要更多上下文。 你还可以检查历史记录——看看提示和答案:

turbo.inspect_history(n=1)

用简短的事实性答案回答问题。


按照以下格式。

问题:${question} 答案:通常在1到5个词之间


问题:这个好吗? 答案:需要更多上下文。 你还可以添加一个思维链组件,如下所示:

定义预测器。注意我们只是改变了类。BasicQA的签名没有改变。

generate_answer_with_chain_of_thought = dspy.ChainOfThought(BasicQA)

在相同的输入上调用预测器。

pred = generate_answer_with_chain_of_thought(question=dev_example.question)

打印输入、思维链和预测。

print(f"问题:{dev_example.question}") print(f"思考:{pred.rationale.split(':', 1)[1].strip()}") print(f"预测答案:{pred.answer}")

问题:这个好吗? 思考:是 预测答案:是 设置DSPy训练 这就是魔法发生的地方。在这个简单的例子中,我只给出了4个训练示例。DSPy有一个编译器,类似于PyTorch——用于运行模型训练。

class GenerateAnswer(dspy.Signature): """用简短的事实性答案回答问题。"""

context = dspy.InputField(desc="可能包含相关事实")
question = dspy.InputField()
answer = dspy.OutputField(desc="通常在1到5个词之间")

class fs(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):
    #context = self.retrieve(question).passages
    prediction = self.generate_answer(context=context, question=question)
    return dspy.Prediction(context=context, answer=prediction.answer)

from dspy.teleprompt import BootstrapFewShot

验证逻辑:检查预测答案是否正确。

还要检查检索到的上下文是否确实包含那个答案。

def validate_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

设置一个基本的远程提示器,它将编译我们的RAG程序。

teleprompter = BootstrapFewShot(metric=validate_answer)

编译!

compiled_fs = teleprompter.compile(fs(), trainset=trainset)

那么,让我们看看这个程序的表现如何!

你可以向这个简单的少样本程序提出任何问题。

my_question = "你喜欢鳄梨吗?" context = dev_example.context

获取预测。这包含pred.context和pred.answer。

pred = compiled_fs(my_question,context)

打印问题和答案。

print(f"问题:{my_question}") print(f"预测答案:{pred.answer}") print(f"检索到的上下文:{pred.context}")

问题:你喜欢鳄梨吗? 预测答案:ANSWERNOTFOUND 它得到了正确的答案!现在让我们看看提示:

turbo.inspect_history(n=1)

用简短的事实性答案回答问题。


按照以下格式。

问题:${question}

理由:让我们一步一步地思考,以${产生答案}。我们...

答案:通常在1到5个词之间


问题:这一系列的作者是谁?

理由:让我们一步一步地思考,以产生答案。我们...

答案:ANSWERNOTFOUND


问题:这个系列好看且优秀吗?

理由:让我们一步一步地思考,以回答:这个节目是杰出的!

答案:这个节目是杰出的!

这真是太神奇了,它能够在最少的人工干预下得到正确的答案!

要点 在进行这个实验之前,我的初步假设是DSPy在学术环境中可能表现出色,但在工业界可能不那么出色,因为在工业界,为特定用例手工制作提示是常态。然而,仔细一看,我发现手工制作提示大约需要5分钟,可能需要2-3次迭代。这并不特别简单,因为我们必须确保提示在提取方面做得很好,而像ChatGPT这样的大型语言模型是生成性的大型语言模型,但可以为包括信息提取在内的各种NLP任务进行工程化。

DSPy让我感到惊讶,它在一次迭代中就得到了正确的提示,包括思维链推理和少样本示例。这非常有希望,因为手工制作提示不仅耗时,而且对于一个人来说,很难跟踪他们对提示所做的所有更改以及对数据质量的影响。当前的提示工程状态类似于一个人手动移动一条线,以找到几个数据点的最佳拟合。随着维度的增加,这变得越来越困难和荒谬。当引入更多数据时会发生什么?

这个问题最初是通过数值方法来解决线性数据拟合的问题,现在使用ML方法来拟合非线性数据已经成为常态。如果你现在以同样的方式考虑提示呢。你有多个包含输入和输出对的文本数据,需要“拟合”正确的提示。手动拟合数据不是看起来很荒谬吗?这正是像DSPy这样的自动化提示工程工具试图解决的问题。解决这个问题的方案可能不远了。

这篇博客的代码库在这里:

GitHub - skandavivek/DSPy-blog: 一个关于DSPy的教程,以及自动化提示工程是否名副其实... 一个关于DSPy的教程,以及自动化提示工程是否名副其实 - skandavivek/DSPy-blog github.com

如果你喜欢这篇文章,请关注EMAlpha——我们深入探讨AI、金融和数据的交汇点。

参考文献:

https://github.com/stanfordnlp/dspy/blob/main/intro.ipynb

天汇AI

网址:tianhuibot.com

国内合规使用ChatGPT-4o渠道,通过微软平台合规调用OpenAI接口。

天汇AI孵化平台提供面向AI创业团队的一系列生成式人工智能工具。

天汇AI配备了阅读、搜索、绘画、识图等功能。

主要特点:多功能智能图文处理板块,内置GPT-4o模型

网站优点:

1.无需国际网络进行访问

2.采用ChatGPT-4o模型

3.提供丰富的OpenAI功能模块,包括阅读、搜索、绘画、识图等,可用于多样的办公和设计场景。


稳定性强,无广告

无需魔法,合规通道

加入孵化平台会员即可使用

pc端可输入网址:https://tianihuibot.com