在人工智能和大语言模型席卷全球的今天,如何更好地利用这些强大的工具来解决实际问题,成为了许多开发者和研究人员关注的焦点。今天要介绍的 DSPy 框架,为我们提供了一个全新的视角和方法,让我们能够像编写传统程序一样,轻松地"编程"大语言模型,构建复杂的 AI 应用。让我们一起来探索这个激动人心的新领域吧!
🌟 什么是 DSPy?
DSPy 是斯坦福大学自然语言处理实验室开发的一个框架,全称是"Programming with Foundation Models"(使用基础模型编程)。它的核心理念是将提示工程(Prompting)、微调(Fine-tuning)、推理增强(Reasoning)和工具/检索增强(Tool/Retrieval Augmentation)等技术统一起来,通过一组简洁的 Python 操作来表达和学习。
简单来说,DSPy 让我们能够像编写普通 Python 程序一样,定义和组合各种 AI 模块,然后通过自动化的编译和优化过程,生成高质量的提示或微调模型,以完成复杂的任务。
🔍 DSPy 的核心概念
要理解 DSPy,我们需要先了解几个关键概念:
- Signature(签名) : 定义了一个 AI 模块的输入和输出。例如,问答任务的签名可能包含"问题"作为输入,"答案"作为输出。
- Predictor(预测器) : 实现了某个签名的具体模块,知道如何使用语言模型来完成任务。
- Module(模块) : DSPy 程序的基本构建块,可以包含多个预测器和其他模块。
- Teleprompter(远程提示器) : 用于优化 DSPy 程序的编译器,可以自动生成高质量的提示或微调。
- Metric(度量) : 用于评估程序输出质量的函数。
🚀 DSPy 的工作流程
使用 DSPy 构建 AI 应用的一般流程如下:
- 收集数据: 定义任务的输入和输出示例。
- 编写程序: 使用 DSPy 的模块和操作定义任务的解决方案。
- 定义验证逻辑: 指定如何判断程序运行的好坏。
- 编译: 使用 DSPy 编译器优化程序。
- 迭代: 根据需要改进数据、程序或验证逻辑。
💡 DSPy 实战:多跳问答系统
为了更直观地理解 DSPy 的强大之处,让我们来看一个具体的例子:构建一个多跳问答系统。这个系统能够回答需要多步推理的复杂问题,比如"David Gregory 继承的城堡有几层?"
首先,我们定义问答和搜索查询的签名:
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")
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)
这个程序的核心逻辑是:
- 根据问题生成搜索查询
- 使用查询检索相关段落
- 将检索到的信息加入上下文
- 重复上述步骤,直到达到最大跳数
- 根据收集到的上下文生成最终答案
接下来,我们定义验证逻辑和使用编译器优化程序:
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
teleprompter = BootstrapFewShot(metric=validate_context_and_answer_and_hops)
compiled_baleen = teleprompter.compile(SimplifiedBaleen(), teacher=SimplifiedBaleen(passages_per_hop=2), trainset=trainset)
经过编译后,我们的程序就可以回答复杂的多跳问题了。例如:
question = "How many storeys are in the castle that David Gregory inherited?"
pred = compiled_baleen(question)
print(f"Question: {question}")
print(f"Predicted Answer: {pred.answer}")
print(f"Retrieved Contexts: {[c[:200] + '...' for c in pred.context]}")
输出结果:
Question: How many storeys are in the castle that David Gregory inherited?
Predicted Answer: Five
Retrieved Contexts: ['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...', '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....', ...]
🌈 DSPy 的优势
- 声明式编程: 开发者只需关注任务的逻辑流程,而不必深入提示工程的细节。
- 模块化和可组合性: 可以轻松构建和组合复杂的 AI 应用。
- 自动优化: 编译器能自动生成高质量的提示或微调,减少手动调优的工作量。
- 灵活性: 支持多种语言模型和检索模型,可以根据需求选择合适的底层模型。
- 可解释性: 程序的每个步骤都清晰可见,便于调试和改进。
🔮 未来展望
DSPy 的出现,标志着 AI 应用开发正在向更加系统化、工程化的方向发展。它为我们提供了一种新的范式,让我们能够更加高效、可靠地构建复杂的 AI 系统。
随着 DSPy 的不断发展和完善,我们可以期待:
- 更多预定义的模块和工具,覆盖更广泛的 AI 任务。
- 与其他 AI 框架和工具的深度集成。
- 更强大的编译器和优化策略。
- 专门针对 DSPy 的开发环境和调试工具。
📚 结语
DSPy 为我们开启了一个崭新的 AI 编程世界。它不仅简化了复杂 AI 应用的开发过程,还为我们提供了一种全新的思考方式,让我们能够更好地利用和组合各种 AI 能力。无论你是 AI 研究人员、软件工程师,还是对 AI 应用感兴趣的爱好者,DSPy 都值得你深入探索和尝试。
让我们一起拥抱这个 AI 编程的新时代,用 DSPy 构建更智能、更强大的应用吧!
参考文献
- Khattab, O., Santhanam, K., Li, X., Hall, D., Liang, P., Potts, C., & Callison-Burch, C. (2023). Demonstrate-Search-Predict: Composing retrieval and language models for knowledge-intensive NLP. arXiv preprint arXiv:2212.14024.
- Khattab, O., & Zaharia, M. (2020). ColBERT: Efficient and Effective Passage Search via Contextualized Late Interaction over BERT. In Proceedings of the 43rd International ACM SIGIR Conference on Research and Development in Information Retrieval (pp. 39-48).
- Brown, T., Mann, B., Ryder, N., Subbiah, M., Kaplan, J. D., Dhariwal, P., ... & Amodei, D. (2020). Language models are few-shot learners. Advances in neural information processing systems, 33, 1877-1901.
- Raffel, C., Shazeer, N., Roberts, A., Lee, K., Narang, S., Matena, M., ... & Liu, P. J. (2020). Exploring the limits of transfer learning with a unified text-to-text transformer. Journal of Machine Learning Research, 21(140), 1-67.
- Devlin, J., Chang, M. W., Lee, K., & Toutanova, K. (2018). Bert: Pre-training of deep bidirectional transformers for language understanding. arXiv preprint arXiv:1810.04805.
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于