图片由作者创作
DSPy 是我首选的框架,因为它简洁且设计贴心。我用它来构建最小可行产品,直到扩展系统以处理数百万请求。虽然 DSPy 和 AI 编程仍在不断发展,但在找到清晰且适合生产的指导方面却十分困难。
在这篇博客里,我分享了我的所学——从实际操作经验到文档和GitHub讨论的收获。这是一份实用指南,充满了实用DSPy工作的建议。
要是你觉得这有帮助,就关注我和 Firebird技术,了解更多这样的内容。
如何利用AI制作更可靠的报告 - 分享我与AI的协作经验 可靠的输出(也就是稳定的结果)对于使用大语言模型(LLM)的开发人员来说,面临的最大挑战是实现结构化和一致的输出结果。让代理工作起来是一回事,但要确保超过95%的可靠性则是另一回事。用户每次都希望获得好结果——他们并不在意LLM是否容易出错、不一致或偶尔表现怪异。
虽然有些问题,比如“API服务中断”,是不在你控制范围内的,但你可以处理许多在你这边的问题。使用DSPy,你可以用断言和建议来引导你的程序达到更好的输出结果,并提升程序的可靠性。这些工具还可以捕获到不良结果,并自动重试以确保高质量的响应。
怎么用dspy.Assert
和dspy.Suggest
?
当你在 DSPy 中使用 dspy.Assert
和 dspy.Suggest
时,你需要通过布尔验证检查来定义程序中的约束条件,以确保期望的结果。这些约束条件被实现为简单的 Python 函数,用于验证模型的输出。
主要的区别在于它们的严格性。
**Assert**
断言强制执行程序必须满足的严格条件;否则将会失败。**Suggest**
提供非强制性的建议来提升性能或改善输出质量。
这里有一个简单的DSPy模块验证示例。
从 dspy.primitives.assertions 导入 assert_transform_module, backtrack_handler # 使用 assert_transform_module 和 backtrack_handler 模块
# 定义一个验证函数
# 可以定义你自己的验证函数,用于特定的程序
# 一个简单的验证函数
def your_validation_fn(model_outputs):
return model_outputs.one_word_answer == "Islamabad"
# 一个简单的 DSPy 程序,用于回答问题的一词回答
your_module = dspy.ChainOfThought("question->one_word_answer")
model_outputs = your_module(question="巴基斯坦的首都是什么?")
# 在程序中添加断言
dspy.Assert(your_validation_fn(model_outputs), "验证失败", target_module=your_module) # 如果验证失败,显示错误信息
dspy.Suggest(your_validation_fn(model_outputs), "考虑修订输出", target_module=your_module) # 如果需要,建议修改输出
你甚至可以将断言添加到自定义程序的前向函数中。定义完这些约束条件后,你可以通过使用 assert_transform_module
函数将断言包裹在你的 DSPy 模块周围,并使用一个 backtrack_handler
。该函数将程序转换为包含内部断言和回溯重试逻辑的形式。
class one_word_answer(dspy.Module):
def __init__(self):
self.one_word_program = dspy.ChainOfThought("question->one_word_answer")
def forward(self, question):
# 将问题发送给 one_word_program
response = self.one_word_program(question=question)
# 断言检查是否为单个单词
dspy.Assert(response.one_word_answer.count(" ") == 0, "验证失败,不是单一答案", target_module=self.one_word_program)
return response
my_module = one_word_answer()
# 一种激活模块中断言的方法,当断言失败时会抛出错误
program_with_assertions = assert_transform_module(my_module(), backtrack_handler)
# 另一种方法激活断言
program_with_assertions = my_module().activate_assertions()
# 如果输出不是单个单词或包含空格,程序将抛出错误。
作者提供的图片 — 如果输出验证失败,你将遇到的错误,你可以捕获该错误并实现你的解决方法
使用多个大语言模型有大模型输出的难题或者需要开发AI解决方案的帮助?可以来这里联系我和我的团队:https://tally.so/r/3x9bgo
大型程序通常需要多个LLM。这里有三个原因:
- 首先,不同的LLM擅长处理不同类型的数据。
- 其次,多个LLM可以协同工作,提升程序的整体性能。
- 最后,使用多个LLM能增强程序的稳定性和可靠性。
- 成本:当你用顶级模型来处理上千个请求时,成本会非常高,因为很多请求可以用较低端的模型来处理。
- 速度:所有的大型语言模型(LLM)API提供商都有基于不同层级的请求限制,但你的用户请求需要在规定时间内得到响应。你可以将请求发送到不同的API或模型中。
- 输出质量:你可以参考LLM基准测试,看看哪个模型在处理特定请求时表现更好。有些模型在代码生成方面表现更佳(在成本相同的情况下)。
- 系统过载:许多企业用例更偏好本地部署的LLM,将所有请求都指向一个LLM时,可能会导致系统过载。
在DSPy中,你定义一个全局LLM。这是系统在你请求时会默认使用的全局LLM。你可以这样定义全局LLM:
lm = dspy.LM('openai/gpt-4o', model_type='chat', max_tokens=1000, api_key='<>')
dspy.configure(lm=lm)
你可以像这样切换LM,但每次更改全局设置可能会遇到问题,特别是在你同时发出多个请求时(这在大型系统中很常见)。
幸运的是,你可以像这样用上下文管理器来切换大型语言模型。它还是线程安全的,并且支持异步操作。
# 定义LLMs
lm1 = dspy.LM()
lm2 = dspy.LM()
lm3 = dspy.LM()
# 你可以在你的DSPy模块里设置这些条件
# 系统根据这些条件来切换
if condition1:
with dspy.settings.context(lm=lm1):
response = dspy.Predict()
if condition2:
with dspy.settings.context(lm=lm2):
response = dspy.Predict()
if condition3:
with dspy.settings.context(lm=lm3):
response = dspy.Predict()
多个大型语言模型确实不错,但如果需要处理多个请求来满足用户需求怎么办?下一章将教你如何使用DSPy进行异步或并行请求处理。
构建“自动分析师”——一个数据解析AI系统的技术指南技术指南:构建AI“自动分析师”
并发请求或异步调用构建最小可行原型很简单,因为它们通常一次只服务一个用户。但是当你需要扩展以处理成千上万甚至上百万的请求时会怎样呢?在这种情况下,你可以利用多线程或异步请求来高效地管理负载。以下是具体做法:
使用DSPy的Asyncify功能这个小代码段可以帮助你在程序中进行异步请求,
导入 asyncio
# 设置异步工人的最大数量
dspy.settings.configure(async_max_workers=4) # 默认是8
# 定义你的模块的异步版本
# 系统之前已经定义过,但可以是任何dspy.Module
异步系统模块 = dspy.asyncify(one_word_answer()) # 将 one_word_answer() 转换为异步版本
# 一个简单的异步程序
async def 获取响应(问题):
# 创建一些协程用于稍后的等待
任务 = [异步系统模块(question=q) for q in 问题]
# 你也可以使用 asyncio.wait, as_completed, 等待等
响应 = await asyncio.gather(*任务)
return 响应
问题 = [
"你的名字是什么?",
"你多大了?",
"你来自哪里?",
"你最喜欢的爱好是什么?",
"你做什么工作?",
"你最喜欢的编程语言是什么?",
"你明年有什么计划或目标?",
"你最喜欢的书或电影是什么?",
"你有没有去过国外?",
"是什么激励你学习新技能?(例如,挑战、兴趣等)"
]
# 运行异步程序
所有响应 = asyncio.run(获取响应(问题))
上述代码片段,允许你异步等待响应消息。你可以调整 async_max_worker 参数以一次处理多达 1000 个工作者。
使用DSPy的线程功能在 dspy 的最新版本中,每个模块都有一个内置的 batch
方法,让你能够并行发送请求。
这里列出的是该方法的输入。
图片由作者提供 — 展示的是批量处理方法的记录。
代码片段:
导入 dspy
# 创建用于分析的问题
问题 = [
"客户终身价值和交易频率之间有什么关系?",
"平均交易金额如何影响客户的留存率?",
"哪些客户细分显示出最高的预测CLV?为什么?",
"影响我们CLV预测准确性的关键因素是什么?",
"我们如何根据当前结果改进CLV预测模型?"
]
# 创建一个小型DSPy模块,它提供一个单词的答案
系统 = dspy.ChainOfThought("问题->一个单词的答案")
# 创建示例,这些示例可以发送到模块的批处理
问题 = [dspy.Example(question=q).with_inputs('question') for q in 问题]
# 并行发送所有五个问题,带有某些设置
响应们 = 系统.batch(问题, num_threads = 3,return_failed_examples=True,max_errors=3)
图片由作者提供 — 批处理回复
通过使用线程或异步技术,我们可以同时为数百万用户提供服务。
感谢您的阅读,我会在学到更多东西时与大家分享。请关注我以及FireBird科技,并支持我们。
想利用我的经验吗?可以点击这个链接寻求帮助:https://tally.so/r/3x9bgo
共同学习,写下你的评论
评论加载中...
作者其他优质文章