在langchain中使用自定义example selector
简介
在之前的文章中,我们提到了可以在跟大模型交互的时候,给大模型提供一些具体的例子内容,方便大模型从这些内容中获取想要的答案。这种方便的机制在langchain中叫做FewShotPromptTemplate。
如果例子内容少的话,其实无所谓,我们可以把所有的例子都发送给大语言模型进行处理。
但是如果例子太多的话,每次都发送如此多的内容,会让我们的钱包承受不住。毕竟那些第三方的大语言模型是按token收费的。
怎么办呢? 能不能找到一个经济又有效的方法来完成我们的工作呢?
答案就是使用example selector。
使用和自定义example selector
我们回想一下在使用FewShotPromptTemplate的时候,实际上是可以同时传入example_selector和examples。
prompt = FewShotPromptTemplate(
example_selector=example_selector,
example_prompt=example_prompt,
suffix="Question: {input}",
input_variables=["input"]
)
这里我们使用了一个example_selector,那么什么是example_selector呢?
从名字上看他的主要作用就是从给定的examples中选择需要的examples出来,提供给大模型使用,从而减少会话的token数目。
langchain中提供了这样的example_selector的实现,我们先来看下它的基础类的定义是怎么样的:
class BaseExampleSelector(ABC):
"""Interface for selecting examples to include in prompts."""
@abstractmethod
def add_example(self, example: Dict[str, str]) -> Any:
"""Add new example to store for a key."""
@abstractmethod
def select_examples(self, input_variables: Dict[str, str]) -> List[dict]:
"""Select which examples to use based on the inputs."""
可以看到BaseExampleSelector继承自ABC,并且定义了两个需要实现的抽象方法。
一个方法叫做add_example。目的是向selector中添加一个example。
一个方法叫做select_examples,主要目的就是根据input,从examples中找出要select出来的内容。
那么什么是ABC呢?
ABC当然就是你了解到的ABC,但是他还有一些额外的含义。ABC的全称叫做Abstract Base Class,也叫做抽象基类。主要用于在Python程序中创建抽象基类。
他提供了一些@abstractmethod,@abstarctproperty这些装饰方法,来表明具体类的特征。
所以,如果我们想自定义一个ExampleSelector,只需要继承自BaseExampleSelector,然后实现这两个抽象方法即可。
langchain中的ExampleSelector实现
除了自定义实现之外,langchain已经为我们提供了几个常用的ExampleSelector实现,一起来看看吧。
LengthBasedExampleSelector
LengthBasedExampleSelector是根据example的长度来进行选择的选择器。
我们看下它的具体实现:
def add_example(self, example: Dict[str, str]) -> None:
"""Add new example to list."""
self.examples.append(example)
string_example = self.example_prompt.format(**example)
self.example_text_lengths.append(self.get_text_length(string_example))
add_example的逻辑是先把example添加到examples这个list中。
然后使用example_prompt对example进行格式化,得到最终的输出。
最后再把最后输出的text长度添加到example_text_lengths数组中。
def select_examples(self, input_variables: Dict[str, str]) -> List[dict]:
"""Select which examples to use based on the input lengths."""
inputs = " ".join(input_variables.values())
remaining_length = self.max_length - self.get_text_length(inputs)
i = 0
examples = []
while remaining_length > 0 and i < len(self.examples):
new_length = remaining_length - self.example_text_lengths[i]
if new_length < 0:
break
else:
examples.append(self.examples[i])
remaining_length = new_length
i += 1
return examples
select_examples方法实际上就是用max_length减去输入text的长度,然后再去匹配example_text的长度,匹配一个减去一个,最终得到特定长度的examples。
这个selector的最主要作用就是防止耗尽context window。因为对于大多数大语言模型来说,用户的输入是有长度限制的。
如果超出了输入长度,会产生意想不到的结果。
这个selector使用起来很简单,下面是具体的例子:
examples = [
{"input": "happy", "output": "sad"},
{"input": "tall", "output": "short"},
{"input": "energetic", "output": "lethargic"},
{"input": "sunny", "output": "gloomy"},
{"input": "windy", "output": "calm"},
example_prompt = PromptTemplate(
input_variables=["input", "output"],
template="Input: {input}\nOutput: {output}",
)
example_selector = LengthBasedExampleSelector(
examples=examples,
example_prompt=example_prompt,
max_length=25,
)
SemanticSimilarityExampleSelector和MaxMarginalRelevanceExampleSelector
这两个selector是根据相似度来进行example的查找的。
其中MaxMarginalRelevanceExampleSelector是SemanticSimilarityExampleSelector的字类,他是对SemanticSimilarityExampleSelector进行了一些算法上的优化。所以这里我们把他们两个放在一起介绍。
这两个selector和之前介绍的selector有所不同。因为他们用到了向量数据库。
向量数据库是干什么用的呢?它的主要目的是把输入转换成各种向量然后存储起来。向量数据库可以方便的进行输入相识度的计算。
我们先来看下他们的add_example方法:
def add_example(self, example: Dict[str, str]) -> str:
"""Add new example to vectorstore."""
if self.input_keys:
string_example = " ".join(
sorted_values({key: example[key] for key in self.input_keys})
)
else:
string_example = " ".join(sorted_values(example))
ids = self.vectorstore.add_texts([string_example], metadatas=[example])
return ids[0]
这个方法先把example的key加入到input_keys中,然后进行排序。最后通过调用vectorstore的add_texts,把key和value加入到向量数据库中。
这两个selector的add_example都是一样的。只有select_examples的方法不同。
其中SemanticSimilarityExampleSelector调用了vectorstore的similarity_search方法来实现相似度的搜索。
而MaxMarginalRelevanceExampleSelector则是调用vectorstore的max_marginal_relevance_search方法来实现搜索的。
两者的搜索算法不太一样。
因为使用了向量数据库,所以他们的调用方法和其他的也不太一样:
examples = [
{"input": "happy", "output": "sad"},
{"input": "tall", "output": "short"},
{"input": "energetic", "output": "lethargic"},
{"input": "sunny", "output": "gloomy"},
{"input": "windy", "output": "calm"},
]
example_selector = SemanticSimilarityExampleSelector.from_examples(
examples,
# 使用的ebeddings
OpenAIEmbeddings(),
# 向量数据库
Chroma,
# 要返回的数目
k=1
)
NGramOverlapExampleSelector
最后一个要介绍的是NGramOverlapExampleSelector。这个selector使用的是ngram 重叠矩阵来选择相似的输入。
具体的实现算法和原理这里就不介绍了。大家有兴趣的可以自行探索。
这个selector也不需要使用向量数据库。
使用起来是这样的:
example_selector = NGramOverlapExampleSelector(
examples=examples,
example_prompt=example_prompt,
threshold=-1.0,
)
这里有个不太一样的参数叫做threshold。
对于负阈值:Selector按ngram重叠分数对示例进行排序,不排除任何示例。
对于大于1.0的阈值:选择器排除所有示例,并返回一个空列表。
对于等于0.0的阈值:选择器根据ngram重叠分数对示例进行排序,并且排除与输入没有ngram重叠的那些。
总结
有了这些selector我们就可以在提供的examples中进行特定的选择,然后再把选择的结果输入给大语言模型。
从而有效的减少token的浪费。
在langchain中使用自定义example selector的更多相关文章
- UWP中实现自定义标题栏
UWP中实现自定义标题栏 0x00 起因 在UWP开发中,有时候我们希望实现自定义标题栏,例如在标题栏中加入搜索框.按钮之类的控件.搜了下资料居然在一个日文网站找到了一篇介绍这个主题的文章: http ...
- Entity Framework 6 Recipes 2nd Edition(10-5)译 -> 在存储模型中使用自定义函数
10-5. 在存储模型中使用自定义函数 问题 想在模型中使用自定义函数,而不是存储过程. 解决方案 假设我们数据库里有成员(members)和他们已经发送的信息(messages) 关系数据表,如Fi ...
- Android XML中引用自定义内部类view的四个why
今天碰到了在XML中应用以内部类形式定义的自定义view,结果遇到了一些坑.虽然通过看了一些前辈写的文章解决了这个问题,但是我看到的几篇都没有完整说清楚why,于是决定做这个总结. 使用自定义内部类v ...
- ASP.NET Core中显示自定义错误页面-增强版
之前的博文 ASP.NET Core中显示自定义错误页面 中的方法是在项目中硬编码实现的,当有多个项目时,就会造成不同项目之间的重复代码,不可取. 在这篇博文中改用middleware实现,并且放在独 ...
- TP中关于自定义类库的添加和使用
ThinkPHP的类库主要包括公共类库和应用类库,都是基于命名空间进行定义和扩展的.只要按照规范定义,都可以实现自动加载. 类库存放位置:Think目录:系统核心类库Org目录:第三方公共类库demo ...
- [asp.net mvc 奇淫巧技] 01 - 封装上下文 - 在View中获取自定义的上下文
我们在asp.net 开发中已经封装了最强大的HttpContext,我们可以在HttpContext中可以获取到几乎任何想获取的东西,也可以在HttpContext写入需要返回客户端的信息.但是这些 ...
- ASP.NET中处理自定义错误的最佳方式
要在ASP.NET中处理好自定义错误(Custom Errors)首先要抛弃使用web.config\customErrors. <customErrors mode="RemoteO ...
- iOS 在UITableViewCell中加入自定义view时view的frame设定注意
由于需要重用同一个布局,于是在cellForRowAtIndexPath中把自定义view加在了cell上,我是这样设定view的frame的 var screenFrame = UIScreen.m ...
- 在ASP.NET中引用自定义提示框
在html网页中自定义提示框 正文: 在一般的B/S架构中项目,与用户的交互信息是非常重要的.在一般的情况下,设计人员都在把用户信息呈现在html中,用div和span去弹出相关信息.对于一般的情况而 ...
- WPF中实现自定义虚拟容器(实现VirtualizingPanel)
WPF中实现自定义虚拟容器(实现VirtualizingPanel) 在WPF应用程序开发过程中,大数据量的数据展现通常都要考虑性能问题.有下面一种常见的情况:原始数据源数据量很大,但是某一时刻数据容 ...
随机推荐
- selenium web控件的交互进阶
Action ActionChains: 执行PC端的鼠标点击,双击,右键,拖曳等事件 TouchActions: 模拟PC和移动端的点击,滑动,拖曳,多点触控等多种手势操作 动作链接 ActionC ...
- 2022-08-03:以下go语言代码输出什么?A:2;B:3;C:1;D:0。 package main import “fmt“ func main() { slice := []i
2022-08-03:以下go语言代码输出什么?A:2:B:3:C:1:D:0. package main import "fmt" func main() { slice := ...
- 2022-06-10:薯队长从北向南穿过一片红薯地(南北长M,东西宽N),红薯地被划分为1x1的方格, 他可以从北边的任何一个格子出发,到达南边的任何一个格子, 但每一步只能走到东南、正南、西南方向的
2022-06-10:薯队长从北向南穿过一片红薯地(南北长M,东西宽N),红薯地被划分为1x1的方格, 他可以从北边的任何一个格子出发,到达南边的任何一个格子, 但每一步只能走到东南.正南.西南方向的 ...
- 2021-09-27:Pow(x, n)。实现 pow(x, n) ,即计算 x 的 n 次幂函数(即,x**n)。力扣50。
2021-09-27:Pow(x, n).实现 pow(x, n) ,即计算 x 的 n 次幂函数(即,x**n).力扣50. 福大大 答案2021-09-27: 遍历n的二进制位. 时间复杂度:O( ...
- Dapr在Java中的实践 之 环境准备
Dapr简介 Dapr (Distributed Application Runtime)是一个可移植的.事件驱动的运行时,它使任何开发人员都可以轻松地构建运行在云和边缘上的弹性.无状态和有状态的应用 ...
- Java(包机制、doc、Scanner对象)
包机制 本质:文件夹 用于区别类名的命名空间 一般利用公司域名倒置作为包名 import与通配符* 导入包 例: import java.util.Scanner; import com.xxx.xx ...
- 读文献先读图——主成分分析 PCA 图
上周五彩斑斓的气泡图 有让你眼花缭乱吗? 本周,化繁为简的PCA图 你值得拥有! 数据分析| 科研制图﹒PCA 图 关键词:主成分分析.降维 1665 年的鼠疫 牛顿停课在家提出了万有引力 ;183 ...
- NLM 公布了一个新的重新设计的 PubMed 数据库
经常使用 PubMed 的童鞋可能已经发现,美国国家医学图书馆(NLM)在今年 10 月份左右发布了一个新的重新设计的版本以取代 PubMed 数据库的现有版本,新版本现在已经上线,可以通过下面的链接 ...
- MQ系列13:消息大量堆积如何为解决
MQ系列1:消息中间件执行原理 MQ系列2:消息中间件的技术选型 MQ系列3:RocketMQ 架构分析 MQ系列4:NameServer 原理解析 MQ系列5:RocketMQ消息的发送模式 MQ系 ...
- mybatis拦截器实现数据权限
前端的菜单和按钮权限都可以通过配置来实现,但很多时候,后台查询数据库数据的权限需要通过手动添加SQL来实现. 比如员工打卡记录表,有id,name,dpt_id,company_id等字段,后两个表示 ...