一、前言
在LangChain中,检索器是一个重要模块,主要用于从数据源中检索与查询相关的文档或片段。它能高效进行信息检索,通过快速筛选和语义理解从大规模文本数据中找到相关内容,支持复杂应用场景如检索增强生成和多源数据整合,还具有可定制性和灵活性,可选择不同嵌入模型和索引后端,也支持自定义检索逻辑。例如在企业知识库系统、智能客服系统和智能文档分析系统中都能发挥重要作用。
本篇将整合检索器和带阈值的相似性搜索,旨在探索如何有效地提高信息检索的准确性和效率。
开源模型应用落地-LangChain实用小技巧-检索器-ContextualCompressionRetriever(十四)
开源模型应用落地-LangChain实用小技巧-带阈值的相似性搜索(十五)
二、术语
2.1.LangChain
是一个全方位的、基于大语言模型这种预测能力的应用开发工具。LangChain的预构建链功能,就像乐高积木一样,无论你是新手还是经验丰富的开发者,都可以选择适合自己的部分快速构建项目。对于希望进行更深入工作的开发者,LangChain 提供的模块化组件则允许你根据自己的需求定制和创建应用中的功能链条。
LangChain本质上就是对各种大模型提供的API的套壳,是为了方便我们使用这些 API,搭建起来的一些框架、模块和接口。
LangChain的主要特性:
1.可以连接多种数据源,比如网页链接、本地PDF文件、向量数据库等
2.允许语言模型与其环境交互
3.封装了Model I/O(输入/输出)、Retrieval(检索器)、Memory(记忆)、Agents(决策和调度)等核心组件
4.可以使用链的方式组装这些组件,以便最好地完成特定用例。
5.围绕以上设计原则,LangChain解决了现在开发人工智能应用的一些切实痛点。
2.2.检索器(Retriever)
是一种接口,它根据非结构化查询返回文档。它的功能比向量存储更为广泛。检索器不需要能够存储文档,只需能够返回(或检索)它们。向量存储可以作为检索器的基础,但也存在其他类型的检索器。
检索器作用:
1) 高效的信息检索
- 面对大规模文本数据,Retriever 能够迅速从数据源中找到与用户查询相关的部分,避免对整个数据集进行遍历搜索,从而显著提高检索效率。
- Retriever 利用文本向量化和相似性度量等技术,能够理解查询的语义并进行基于语义的检索。这意味着即使查询的表述与文档中的表述不完全一致,只要语义相关,Retriever 也能找到相关文档。
2) 支持复杂应用场景
- 在检索增强生成的应用中,Retriever为语言模型提供相关的上下文信息。语言模型在生成回答时,可以基于 Retriever 检索到的文档进行推理和回答,从而提高回答的准确性和可靠性。
- Retriever 可以同时从多个不同的数据源中进行检索,将来自不同来源的相关信息整合在一起。
3)可定制性和灵活性
- Retriever允许开发者根据具体需求选择不同的文本嵌入模型和索引后端。不同的嵌入模型在文本向量化方式上可能存在差异,适用于不同的应用场景;而不同的索引后端在存储和检索数据的性能、可扩展性等方面也有所区别。
- 支持自定义检索逻辑:开发者可以基于 Retriever 的基础接口,实现自定义检索逻辑。
2.3.带阈值的相似性搜索
是一种相似性搜索方法,其中用户设置一个阈值,以限制返回的结果是足够相似的对象。这种搜索方式不仅寻找与查询对象相似的其他对象,而且还确保这些对象的相似度超过用户设定的阈值。
带阈值的相似性搜索的关键要素包括:
1. 阈值设定:用户可以指定一个具体的阈值,这个值代表了对象之间需要达到的最小相似度。例如,如果使用余弦相似度,阈值可能被设定为0.8,表示只返回与查询对象相似度大于或等于0.8的对象。
2. 相似性度量:需要选择适合的数据相似性度量方法(如余弦相似度、Jaccard相似度、欧几里得距离等),以便有效地计算对象之间的相似度。
3. 过滤结果:在检索过程中,只有那些满足阈值条件的对象会被纳入最终结果。这有助于用户更快速地找到最相关的信息,并减少无关信息的干扰。
2.4.FAISS
是一个高效的相似性搜索库,专门用于处理大规模向量数据集。
三、前提条件
3.1. 基础环境
- 操作系统:不限
3.2. 安装虚拟环境
conda create --name langchain python=3.10
conda activate langchain
pip install langchain langchain-openai langchain-community
# CPU版本安装
pip install faiss-cpu
# GPU版本安装
pip install faiss-gpu
四、技术实现
4.1. 数据准备
composition.txt文件
35岁现象:中国互联网职场“人矿”的艰难求职故事
“互联网行业的发展速度非常快,大部分人到35岁左右就已经像一块‘人肉电池’一样被榨干了。”
家在上海的李女士30岁开始在中国几家互联网公司“打转”,近一年时间已经历两次裁员。35岁的她如今正积极寻找新工作,但也害怕间隔时间越长,越消耗自己的自信。
“我从不主动跟其他失业的朋友聊(失业相关的话题),我发现每个人都像易碎玻璃一样,非常脆弱。”去年夏天,32岁的方成文(化名)离开工作3年的一家杭州的知名互联网公司后,至今仍在找工作。
处于失业状态的她们并非个例。方成文说身边来自外企和互联网行业的朋友就有七、八位没有工作。“前两年是只有女性,这两年男性也开始不上班。”
方成文是上海人,本科毕业于美国波士顿的一所高等学府,在美国有八年工作经验, 2017年回中国工作。李女士则有11年从业经历,5年互联网行业经验,还带过3人的小团队,放在互联网行业如火如荼的2015年,她曾是被追捧的人才。
但近两年里,她们的求职经历并不顺。在经济下行时期,互联网企业裁员接踵而至,有用工需求的公司的招聘要求则变本加厉。在她们面前,横亘一条无法躲避的35岁年龄线,外加女性特有的婚育问题。
她们的经历,也是第一批中国互联网打工人经历行业高速增长后,撞上经济下行周期和行业迭代的缩影。没有人能对未来的职业发展路径给出确定的答案,大家似乎都在等待新工作机会的到来。
脱下“孔乙己的长衫”:中国就业形势愈发严峻,年轻人从“蓝领”工作寻出路
从“白领”到“蓝领”
中国目前对“白领”人士的需求正在减少。据经济学人智库估计,2020年,雇佣主体是大学生的专业服务岗位约占青年就业机会总数的40%,是十年前的两倍。但是,由于近几年来中国政府着手监管房地产、教培、数字经济、金融和娱乐等多个行业,有相当一部分岗位已经不存在了。
根据中国招聘网站智联招聘,2021年,仅房地产、辅导和科技公司的招聘信息就占了毕业生所有招聘信息的一半以上。一年后,这一数字降至26%。
与此同时,中国经济正趋向以服务业为导向,2020年的人口普查显示,约75%的青年雇员在服务业工作,但中国在过去十年里创造出来的许多服务业岗位都是较低端职位,比如外卖员、餐厅服务员等。对于许多受过教育的年轻人所追求的高工资、高技能的岗位,并没有很多。
张静静之前所在的房地产行业,正是近年来受政府监管影响最严重的行业之一。政府反复强调,“房子是用来住的,不是用来抄的”。监管机构对开发商贷款设定了上限,并对土地拍卖进行了全面改革。这影响到这个行业的财务业绩,许多房企压力爆棚。
为了拼业绩,张静静每天要工作10个小时以上,作息不规律,晚上只睡五、六个小时,长期下来令吃不消,两年后辞职了。之后她曾尝试考研,但没有成功。
2021年底,她在餐饮行业找到一份销售工作,但再次遇上低迷的市场。彼时疫情还没有结束,餐饮业没有完全恢复,加上小区动辄封控,她感到十分压抑。
“相当崩溃,每天在家什么事做不了,睡眠不好,吃饭也没有胃口,整个心情很低沉”。四个月后,她辞职了。后来她又多次应聘其他工作,但都没有合适的。
她曾羡慕公司的保洁阿姨,虽然一个月工资只有四、五千,但“没有什么精神压力,只不过是身体累点,还能买五险一金(五种社会保险福利),又能受到专业培训”。
今年年初,一则家政行业的招聘广告吸引了张静静的注意, 月薪8千到1万,甚至打破了她对“蓝领”工作的想象。她抱着试一试的态度入行了。
她的同事大部分是35岁至55岁,一部分从农村出来没有读过书,还有一些已经退休。这一行对于大学毕业的年轻人来说似乎有点大材小用,但张静静不这样看——她说不仅得到了专业技能培训,有助于在这一领域长期发展,还能在拿到专业证书和完成实习后拿到上万元的月薪。她目前在成都生活,这个薪资水平已经达到了她之前做销售时的提成。
不过,并非所有“蓝领”工作都能实现这样的水平。根据中国新就业形态研究中心2022年发布的报告,中国蓝领劳动者整体平均收入为每月6000元左右。并且,“蓝领”群体依然面临部分公司工资发放不及时、待遇差、管理落后等问题。
4.2. 代码示例
#!/usr/bin/env python
import os
from langchain_community.vectorstores import FAISS
from langchain_openai import OpenAIEmbeddings
from langchain_text_splitters import RecursiveCharacterTextSplitter
os.environ["OPENAI_API_KEY"] = 'sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' # 你的Open AI Key
if __name__ == '__main__':
with open("composition.txt", encoding='UTF-8') as f:
composition = f.read()
# 初始化切分器
text_splitter = RecursiveCharacterTextSplitter(
separators=["\n\n", "\n", "。|!|?" ],
is_separator_regex=True,
chunk_size=50, # 切分的文本块大小,一般通过长度函数计算
chunk_overlap=10, # 切分的文本块重叠大小,一般通过长度函数计算
length_function=len, # 长度函数,也可以传递tokenize函数
add_start_index=True, # 是否添加起始索引
)
documents = text_splitter.create_documents([composition])
embedding = OpenAIEmbeddings(model="text-embedding-3-small")
db = FAISS.from_documents(documents, embedding)
# 转换检索器
retriever = db.as_retriever(
search_type="similarity_score_threshold",
search_kwargs={"k": 5, "score_threshold": 0.2},
)
# 检索结果
documents = retriever.invoke("关于方成文的信息有哪些")
print(list(document.page_content for document in documents))
print(len(documents))
调用结果: