百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程网 > 正文

LangChainV0.2-基础教程:构建矢量数据库和检索器

yuyutoo 2024-10-12 00:49 3 浏览 0 评论

本课程,你将了解到LangCahin的矢量数据库和检索器的相关概念。这两个概念是为了解决将外部(矢量)数据库和其它来源的数据集成到LLM的工作流而提出的,是构建模型推理的关键知识点,通常我们称这种技术为生成式增强检索,或简称RAG。

概念

本章节将聚焦文本数据的检索。我们需要对以下概念有所了解:

  • Documents 文档
  • Vector stores 矢量数据库
  • Retrievers 检索器

Jupyter Notebook

本教程(及大部分教程)都是使用的Jupyter notebooks,并预先认为您也会使用。Jupyter notebooks非常适用来学习LLM系统或作为一个原型构建工具,因为我们在学习或开发应用过程中将会碰到很多异常情况(比如,不正确的输出,API挂掉了),使用Jupyter notebooks这种一步一步的、交互式的工具,可以让你迅速调试并学习。

Jupyter Notebook的安装和配置问题,请自行了解。

LangSmith

不再对LangSmith的安装和使用进行说明,前面有提到过。

Document 文档

LangChain对Document“类”的能力进行了增强,文档在这里代表了一定量的文本及其元数据信息,其拥有两个属性:

  • page_content文档内容:表示文档内容的字符串文本;
  • metadata元数据:任意数量的元数据字典表;

metadata 元数据属性,用于记录如文档来源一类的信息,这些信息将与其它文档或其它信息产生关联关系。这里要注意的一点,我们所说的单个文档通常是表示一个大文档的一小块。

我们先创建一些文档的示例:

from langchain_core.documents import Document

documents = [
   Document(
       page_content="Dogs are great companions, known for their loyalty and friendliness.",
       metadata={"source": "mammal-pets-doc"},
  ),
   Document(
       page_content="Cats are independent pets that often enjoy their own space.",
       metadata={"source": "mammal-pets-doc"},
  ),
   Document(
       page_content="Goldfish are popular pets for beginners, requiring relatively simple care.",
       metadata={"source": "fish-pets-doc"},
  ),
   Document(
       page_content="Parrots are intelligent birds capable of mimicking human speech.",
       metadata={"source": "bird-pets-doc"},
  ),
   Document(
       page_content="Rabbits are social animals that need plenty of space to hop around.",
       metadata={"source": "mammal-pets-doc"},
  ),
]

上面的代码中,我们创建了五个文档,每个文档的元数据里都有一个sources作为key,且其值里都使用“-”来区分不同的来源项,每个文档都有 3个来源。

矢量数据库

矢量检索常用于存储和检索非结构化数据(比如非结构化文本)。其原理是将与文本有映射关系的向量值存储起来。当给出一个查询语句时,我们先将查询语句向量化到矢量数据库的向量空间中,然后利用矢量相似性算法—距离远近从矢量数据库里查找相关联的数据。

LangChain的VectorStore矢量数据库作为一个“对象”,包含了一些方法,如添加text文本或Document文档对象到数据库,使用各种相似性算法进行检索。通常在初始化构建时,我们要用到向量化模型,该模型的作用是将文本数据通过转换映射为同一语义空间下的向量数值。

LangChain集成了大量的矢量数据库。一些矢量数据库是由第三方服务商提供的(比如,许多云服务提供商),这些就需要授权才能使用,也有一些第三方提供的矢量数据库(如Postgres)可以在本地单独运行;还有一些可以运行在内存里,适合轻量级负载任务。本课程使用LangChain的内建矢量数据库Chorma,该数据库支持在内存里运行。

在实例化一个矢量数据库之前,我们通常需要选择一个向量化模型。在这里,我们使用OpenAI的向量化模型。

from langchain_chroma import Chroma
from langchain_openai import OpenAIEmbeddings

vectorstore = Chroma.from_documents(
   documents,
   embedding=OpenAIEmbeddings(),
)

调用.from_documents方法,可以向矢量数据库里添加文档。当然,也可以在文档实例化后再存入到矢量数据库。一般在实施中,你可能需要连接一个现有的矢量数据库-- 这样,你就需要提供客户端,索引名称及其它信息进行连接。

一旦我们实例化了一个矢量数据库,且该数据库已经添加了一些文档后,我们就可以查询了。矢量数据库本身自带一些查询方式。

  • 同步和异步查询
  • 使用文本字符串查询和使用矢量值查询
  • 是否返回相似度评分值;
  • 使用相似度和最大边际相关性(最大边际相关性是一种折中方案,它同时应用了查询语句相似度与检索结果相似度)。

查询方法将返回文档列表。

相似性检索示例

使用相似性查询,提交一个文本字符串,返回一些文档。如提交查询"cat";

vectorstore.similarity_search("cat")

从 5个文档中返回 了 4个与cat相关的文档;

[Document(page_content='Cats are independent pets that often enjoy their own space.', metadata={'source': 'mammal-pets-doc'}),
Document(page_content='Dogs are great companions, known for their loyalty and friendliness.', metadata={'source': 'mammal-pets-doc'}),
Document(page_content='Rabbits are social animals that need plenty of space to hop around.', metadata={'source': 'mammal-pets-doc'}),
Document(page_content='Parrots are intelligent birds capable of mimicking human speech.', metadata={'source': 'bird-pets-doc'})]

异步查询"cat";

await vectorstore.asimilarity_search("cat")
[Document(page_content='Cats are independent pets that often enjoy their own space.', metadata={'source': 'mammal-pets-doc'}),
Document(page_content='Dogs are great companions, known for their loyalty and friendliness.', metadata={'source': 'mammal-pets-doc'}),
Document(page_content='Rabbits are social animals that need plenty of space to hop around.', metadata={'source': 'mammal-pets-doc'}),
Document(page_content='Parrots are intelligent birds capable of mimicking human speech.', metadata={'source': 'bird-pets-doc'})]

返回相似性评分值,以下是查询"cat"时,需要返回相似性评分值;

# Note that providers implement different scores; Chroma here
# returns a distance metric that should vary inversely with
# similarity.

vectorstore.similarity_search_with_score("cat")

评分值在最后一项

[(Document(page_content='Cats are independent pets that often enjoy their own space.', metadata={'source': 'mammal-pets-doc'}),
0.3751849830150604),
(Document(page_content='Dogs are great companions, known for their loyalty and friendliness.', metadata={'source': 'mammal-pets-doc'}),
0.48316916823387146),
(Document(page_content='Rabbits are social animals that need plenty of space to hop around.', metadata={'source': 'mammal-pets-doc'}),
0.49601367115974426),
(Document(page_content='Parrots are intelligent birds capable of mimicking human speech.', metadata={'source': 'bird-pets-doc'}),
0.4972994923591614)]

使用向量相似性查询,返回相关文档

embedding = OpenAIEmbeddings().embed_query("cat")

vectorstore.similarity_search_by_vector(embedding)
[Document(page_content='Cats are independent pets that often enjoy their own space.', metadata={'source': 'mammal-pets-doc'}),
Document(page_content='Dogs are great companions, known for their loyalty and friendliness.', metadata={'source': 'mammal-pets-doc'}),
Document(page_content='Rabbits are social animals that need plenty of space to hop around.', metadata={'source': 'mammal-pets-doc'}),
Document(page_content='Parrots are intelligent birds capable of mimicking human speech.', metadata={'source': 'bird-pets-doc'})]

Retrievers 检索器

LangChain的VectorStore矢量数据库并不支持“可运行”协议,因此不能直接使用LCEL语言表达式集成到chains工作流中。

但是Retrievers组件是支持“可运行”协议的。

我们可以使用RunnableLambda()方法创建一个支持“可运行的”Retrievers检索器,而不需要继承Retriever类。这样,我们能随时创建一个支持“可运行”的检索器。下面,我们使用相似性检索方法来构建了一个“可运行”的检索器,并返回一个值。

from typing import List

from langchain_core.documents import Document
from langchain_core.runnables import RunnableLambda

retriever = RunnableLambda(vectorstore.similarity_search).bind(k=1)  # select top result

retriever.batch(["cat", "shark"])

我们可以看到构建好的retriever使用了“可运行”接口里的.batch方法进行批量调用。

以下返回的是上面批量查询的结果。

[[Document(page_content='Cats are independent pets that often enjoy their own space.', metadata={'source': 'mammal-pets-doc'})],
[Document(page_content='Goldfish are popular pets for beginners, requiring relatively simple care.', metadata={'source': 'fish-pets-doc'})]]

矢量数据库使用as_retriever方法用于构建一个专有的检索器。这一类检索器可以定义检索类型和检索附加参数,以调用原有矢量数据库的一些方法。我们再修改一下检索器。

retriever = vectorstore.as_retriever(
   search_type="similarity",
   search_kwargs={"k": 1},
)

retriever.batch(["cat", "shark"])

返回结果是相同的。

[[Document(page_content='Cats are independent pets that often enjoy their own space.', metadata={'source': 'mammal-pets-doc'})],
[Document(page_content='Goldfish are popular pets for beginners, requiring relatively simple care.', metadata={'source': 'fish-pets-doc'})]]

VectorStoreRetriever矢量数据库检索器默认的检索类型是“相似性”,其它类型还有“MMR”(最大边际相关性)和“相似度评分阈值”。我们可以使用相似度评分阈值将低于该值的结果过滤掉。

检索器可以集成到更复杂的应用中去,如RAG应用,这类应用使用用户的提问,先在检索器先获取到与用户提问相关的一些上下文(或叫答案/样本),然后将其转换为提示词喂给LLM。以下是一些示例。

pip install -qU langchain-openai

导入要使用的模型;

import getpass
import os

os.environ["OPENAI_API_KEY"] = getpass.getpass()

from langchain_openai import ChatOpenAI

llm = ChatOpenAI(model="gpt-3.5-turbo-0125")

定义提示词,构建RAG工作流;

from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnablePassthrough

message = """
Answer this question using the provided context only.

{question}

Context:
{context}
"""

prompt = ChatPromptTemplate.from_messages([("human", message)])

rag_chain = {"context": retriever, "question": RunnablePassthrough()} | prompt | llm

{"context": retriever, "question": RunnablePassthrough()} 的作用是:通过用户的原始输入,检索到结构返回给context,用户的输入返回给question;

工作流调用:"tell me about cats"告诉我关于猫咪的信息;

response = rag_chain.invoke("tell me about cats")

print(response.content)

返回的结果是关于猫的信息;

Cats are independent pets that often enjoy their own space.

更多

检索策略可以使用多个,或进行复杂的组合,如下:

  • 从用户的查询语句里解除出检索规则和过滤条件
  • 返回与该文本相关的一些文档(如,相同类型文档)
  • 使用多种向量化组件对文本进行矢量化处理;
  • 从多个检索器里合并检索结果
  • 为文档增加权重,如,最近的文档权重高;

在如何去做里的检索器章节里,还会讲述更多的检索策略。

你也可以直接扩展BaseRetriever“类”,来定制化你想要的检索器。

相关推荐

jQuery VS AngularJS 你更钟爱哪个?

在这一次的Web开发教程中,我会尽力解答有关于jQuery和AngularJS的两个非常常见的问题,即jQuery和AngularJS之间的区别是什么?也就是说jQueryVSAngularJS?...

Jquery实时校验,指定长度的「负小数」,小数位未满末尾补0

在可以输入【负小数】的输入框获取到焦点时,移除千位分隔符,在输入数据时,实时校验输入内容是否正确,失去焦点后,添加千位分隔符格式化数字。同时小数位未满时末尾补0。HTML代码...

如何在pbootCMS前台调用自定义表单?pbootCMS自定义调用代码示例

要在pbootCMS前台调用自定义表单,您需要在后台创建表单并为其添加字段,然后在前台模板文件中添加相关代码,如提交按钮和表单验证代码。您还可以自定义表单数据的存储位置、添加文件上传字段、日期选择器、...

编程技巧:Jquery实时验证,指定长度的「负小数」

为了保障【负小数】的正确性,做成了通过Jquery,在用户端,实时验证指定长度的【负小数】的方法。HTML代码<inputtype="text"class="forc...

一篇文章带你用jquery mobile设计颜色拾取器

【一、项目背景】现实生活中,我们经常会遇到配色的问题,这个时候去百度一下RGB表。而RGB表只提供相对于的颜色的RGB值而没有可以验证的模块。我们可以通过jquerymobile去设计颜色的拾取器...

编程技巧:Jquery实时验证,指定长度的「正小数」

为了保障【正小数】的正确性,做成了通过Jquery,在用户端,实时验证指定长度的【正小数】的方法。HTML做成方法<inputtype="text"class="fo...

jquery.validate检查数组全部验证

问题:html中有多个name[],每个参数都要进行验证是否为空,这个时候直接用required:true话,不能全部验证,只要这个数组中有一个有值就可以通过的。解决方法使用addmethod...

Vue进阶(幺叁肆):npm查看包版本信息

第一种方式npmviewjqueryversions这种方式可以查看npm服务器上所有的...

layui中使用lay-verify进行条件校验

一、layui的校验很简单,主要有以下步骤:1.在form表单内加上class="layui-form"2.在提交按钮上加上lay-submit3.在想要校验的标签,加上lay-...

jQuery是什么?如何使用? jquery是什么功能组件

jQuery于2006年1月由JohnResig在BarCampNYC首次发布。它目前由TimmyWilson领导,并由一组开发人员维护。jQuery是一个JavaScript库,它简化了客户...

django框架的表单form的理解和用法-9

表单呈现...

jquery对上传文件的检测判断 jquery实现文件上传

总体思路:在前端使用jquery对上传文件做部分初步的判断,验证通过的文件利用ajaxFileUpload上传到服务器端,并将文件的存储路径保存到数据库。<asp:FileUploadI...

Nodejs之MEAN栈开发(四)-- form验证及图片上传

这一节增加推荐图书的提交和删除功能,来学习node的form提交以及node的图片上传功能。开始之前需要源码同学可以先在git上fork:https://github.com/stoneniqiu/R...

大数据开发基础之JAVA jquery 大数据java实战

上一篇我们讲解了JAVAscript的基础知识、特点及基本语法以及组成及基本用途,本期就给大家带来了JAVAweb的第二个知识点jquery,大数据开发基础之JAVAjquery,这是本篇文章的主要...

推荐四个开源的jQuery可视化表单设计器

jquery开源在线表单拖拉设计器formBuilder(推荐)jQueryformBuilder是一个开源的WEB在线html表单设计器,开发人员可以通过拖拉实现一个可视化的表单。支持表单常用控件...

取消回复欢迎 发表评论: