LangChain入门2 RAG详解

RAG概述

一个典型的RAG应用程序,它有两个主要组件:

  • 索引:从源中获取数据并对其进行索引的管道。这通常在脱机情况下发生。
  • 检索和生成:在运行时接受用户查询,并从索引中检索相关数据,然后将其传递给模型。

从原始数据到答案的完整序列如下所示:

索引

  • 加载:首先我们需要加载我们的数据。我们将为此使用DocumentLoaders。
  • 拆分:文本拆分器将大型文档拆分成更小的块。这对于索引数据和将数据传递给模型都很有用,因为大块更难搜索,也不适合模型的有限上下文窗口。
  • 信息存储:我们需要一个地方来存储和索引我们的拆分,以便以后可以搜索它们。这通常使用VectorStore和Embeddings模型来完成。

检索和生成

  • 检索:给定用户输入,使用Retriever从存储中检索相关拆分。
  • 生成:ChatModel/LLM使用包含问题和检索到的数据的提示生成答案。

代码实例

依赖加载

from langchain_community.llms import Ollama
import bs4
from langchain import hub
from langchain_community.document_loaders import WebBaseLoader
from langchain_chroma import Chroma
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough
from langchain_community.embeddings import OllamaEmbeddings
from langchain_text_splitters import RecursiveCharacterTextSplitter
#实例化大模型
llm = Ollama(model="llama2")
#添加向量化
embeddings = OllamaEmbeddings()
# 加载数据
loader = WebBaseLoader(web_paths=("https://lilianweng.github.io/posts/2023-06-23-agent/",),bs_kwargs=dict(parse_only=bs4.SoupStrainer(class_=("post-content", "post-title", "post-header"))),
)
docs = loader.load()
#我们这里查看具体的下载内容
print(docs)

查看具体的下载内容
在这里插入图片描述
加载数据的拆分和灌库

#添加数据的拆分 每1000个为一组并重叠200个字符
text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)
#拆分下载的数据
splits = text_splitter.split_documents(docs)
#灌入向量数据库
vectorstore = Chroma.from_documents(documents=splits, embedding=embeddings)

构建检索生成

retriever = vectorstore.as_retriever()
#下载预制的提示词
prompt = hub.pull("rlm/rag-prompt")#调整文本
def format_docs(docs):return "\n\n".join(doc.page_content for doc in docs)

加载数据链

#RunnablePassthrough是Langchain库中的一个类,它允许您传递未更改的输入或带有附加键的输入。
#它可以与RunnableParallel一起使用,将数据传递到映射中的新键。它还可以用于通过assign()方法向链状态添加值
rag_chain = ({"context": retriever | format_docs, "question": RunnablePassthrough()} #检索加强| prompt #提示词| llm #大模型| StrOutputParser() #输出结果样式定义
)
#进行对话
rag_chain.invoke("What is Task Decomposition?")

返回内容
在这里插入图片描述

详细说明

首先加载博客文章的内容。我们可以为此使用DocumentLoaders,它们是从源加载数据并返回文档列表的对象。Document是一个具有一些page_content(str)和元数据(dict)的对象。

在这种情况下,我们将使用WebBaseLoader,它使用urllib从web URL加载HTML,并使用BeautifulSoup将其解析为文本。我们可以通过bs_kwargs将参数传递给BeautifulSoup解析器来自定义HTML->文本解析(请参阅Beautiful Soup文档)。在这种情况下,只有类为“post-content”、“posttitle”或“post-header”的HTML标记是相关的,所以我们将删除所有其他标记。

数据加载

import bs4
from langchain_community.document_loaders import WebBaseLoader# Only keep post title, headers, and content from the full HTML.
bs4_strainer = bs4.SoupStrainer(class_=("post-title", "post-header", "post-content"))
loader = WebBaseLoader(web_paths=("https://lilianweng.github.io/posts/2023-06-23-agent/",),bs_kwargs={"parse_only": bs4_strainer},
)
docs = loader.load()
print(docs)

在这里插入图片描述

print(len(docs[0].page_content))
#43131
print(docs[0].page_content[:500])
"""LLM Powered Autonomous AgentsDate: June 23, 2023  |  Estimated Reading Time: 31 min  |  Author: Lilian WengBuilding agents with LLM (large language model) as its core controller is a cool concept. Several proof-of-concepts demos, such as AutoGPT, GPT-Engineer and BabyAGI, serve as inspiring examples. The potentiality of LLM extends beyond generating well-written copies, stories, essays and programs; it can be framed as a powerful general problem solver.
Agent System Overview#
In
"""

文本拆分

from langchain_text_splitters import RecursiveCharacterTextSplittertext_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200, add_start_index=True
)
all_splits = text_splitter.split_documents(docs)

RecursiveCharacterTextSplitter 通过递归地查看字符来拆分文本。 递归地尝试按不同的字符进行拆分,以找到一个有效的字符。 创建一个新的TextSplitter。

print(len(all_splits))
#66
print(len(all_splits[0].page_content))
#969
print(all_splits[10].metadata)
#{'source': 'https://lilianweng.github.io/posts/2023-06-23-agent/',
#'start_index': 7056}

索引:存储

现在我们需要对66个文本块进行索引,以便在运行时对它们进行搜索。最常见的方法是嵌入每个文档分割的内容,并将这些嵌入插入到矢量数据库(或矢量存储)中。当我们想搜索分割时,我们采用文本搜索查询,嵌入它,并执行某种“相似性”搜索,以识别嵌入与查询嵌入最相似的存储分割。最简单的相似性度量是余弦相似性——我们测量每对嵌入(它们是高维向量)之间的角度的余弦。
我们可以使用Chroma矢量存储和OpenAIEmbeddings模型将所有文档分割嵌入并存储在一个命令中。

from langchain_chroma import Chroma
from langchain_community.embeddings import OllamaEmbeddings
#添加向量化
embeddings = OllamaEmbeddings()
#灌库
vectorstore = Chroma.from_documents(documents=all_splits, embedding=embeddings)

检索与生成:检索

现在让我们来编写实际的应用程序逻辑。我们想要创建一个简单的应用程序,该应用程序接受用户问题,搜索与该问题相关的文档,将检索到的文档和初始问题传递给模型,并返回答案。

首先,我们需要定义搜索文档的逻辑。LangChain定义了一个Retriever接口,该接口封装了一个索引,该索引可以在给定字符串查询的情况下返回相关文档。

最常见的Retriever类型是VectorStoreRetriever,它使用向量存储的相似性搜索功能来促进检索。使用VectorStore.as_Retriever(),任何VectorStore都可以很容易地转换为Retriever:

"""
矢量存储是用于有效存储和查询矢量嵌入的数据结构,矢量嵌入是数据点的高维数值表示。向量存储通常用于机器学习应用程序中的任务,如相似性搜索、异常检测和聚类。
在Langchain的上下文中,VectorStore类是用于处理向量存储的接口。它提供了添加和查询矢量的方法,以及执行各种操作的方法,例如计算矢量之间的距离和根据某些标准过滤矢量。
"""
retriever = vectorstore.as_retriever(search_type="similarity", search_kwargs={"k": 6})
retrieved_docs = retriever.invoke("What are the approaches to Task Decomposition?")
print(len(retrieved_docs))
#6
print(retrieved_docs[0].page_content)

在这里插入图片描述

检索与生成

from langchain import hub
#加载的提示词
prompt = hub.pull("rlm/rag-prompt")example_messages = prompt.invoke({"context": "filler context", "question": "filler question"}
).to_messages()
print(example_messages)

返回

[HumanMessage(content=“You are an assistant for question-answering tasks. Use the following pieces of retrieved context to answer the question. If you don’t know the answer, just say that you don’t know. Use three sentences maximum and keep the answer concise.\nQuestion: filler question \nContext: filler context \nAnswer:”)]

print(example_messages[0].content)

You are an assistant for question-answering tasks. Use the following pieces of retrieved context to answer the question. If you don’t know the answer, just say that you don’t know. Use three sentences maximum and keep the answer concise.
Question: filler question
Context: filler context

LCEL

我们将使用LCEL Runnable协议来定义链,使我们能够以透明的方式将组件和函数管道连接在一起,在LangSmith中自动跟踪我们的链,从而获得流式、异步和批量调用

from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthroughdef format_docs(docs):return "\n\n".join(doc.page_content for doc in docs)rag_chain = ({"context": retriever | format_docs, "question": RunnablePassthrough()}| prompt| llm| StrOutputParser()
)
for chunk in rag_chain.stream("What is Task Decomposition?"):print(chunk, end="", flush=True)

在这里插入图片描述

模型选择

#构建提示词模版
from langchain_core.prompts import PromptTemplate
#提示词
template = """Use the following pieces of context to answer the question at the end.
If you don't know the answer, just say that you don't know, don't try to make up an answer.
Use three sentences maximum and keep the answer as concise as possible.
Always say "thanks for asking!" at the end of the answer.{context}Question: {question}Helpful Answer:"""
#模版加载
custom_rag_prompt = PromptTemplate.from_template(template)rag_chain = ({"context": retriever | format_docs, "question": RunnablePassthrough()}| custom_rag_prompt| llm| StrOutputParser()
)
#结果输出
rag_chain.invoke("What is Task Decomposition?")

在这里插入图片描述
以上是整体使用LangChain 构建RAG 的总体流程。
感谢阅读。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/660944.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

分享一份物联网 SAAS 平台架构设计

一、架构图**** 二、Nginx**** 用于做服务的反向代理。 三、网关**** PaaS平台所有服务统一入口,包含token鉴权功能。 四、开放平台**** 对第三方平台开放的服务入口。 五、MQTT**** MQTT用于设备消息通信、内部服务消息通信。 六、Netty**** Socket通信设…

标准汽车试验铁地板的技术要求

在现代科技化发展的工作中,试验平台被广泛使用。铸铁试验平台(试验铁地板)又叫试验工作平台,听名字大家也不难想象出来这是一款带有箱式体的台面,这是一种有长方形或者圆形又或者正方形的试验工作台。 铸铁试验平台&a…

spring boot运行过程中动态加载Controller

1.被加载的jar代码 package com.dl;import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;SpringBootApplication public class App {public static void main(String[] args) {SpringApplication.run(A…

基于FPGA的数字信号处理(1)--什么是无符号数?什么是有符号数?

进制 虽然在日常生活中,我们已经习惯了使用10进制数字,但在由数字电路构成的数字世界中,2进制才是效率更高的选择。 10进制与2进制 10进制(decimal)计数法(一般也叫阿拉伯计数法)是在日常生活…

DS高阶:图论基础知识

一、图的基本概念及相关名词解释 1.1 图的基本概念 图是比线性表和树更为复杂且抽象的结,和以往所学结构不同的是图是一种表示型的结构,也就是说他更关注的是元素与元素之间的关系。下面进入正题。 图是由顶点集合及顶点间的关系组成的一种数据结构&…

bite阶段性测试_数据结构

解决问题之前我们要了解什么是度,特别是二叉树中的度,和图论中的度的定义是不同的 什么是度: 在图论中,一个节点(或称为顶点)的“度”是指与该节点直接相连的边的数量。度是用来衡量一个节点与其他节点连接…

Q1营收稳健增长,云从科技如何在“百模大战”的险中求稳?

自从迈入大模型时代,AI行业可谓“一天一个样”。越来越多的企业涌现,舆论热议从未断绝。 但就像所有技术必须经历的那些考验,在现实尺度下,AI顺利走进商业化世界,仍然是少部分玩家掌握的稀缺能力。个中原因不尽相同&a…

【C++】学习笔记——string_2

文章目录 六、string类2. 反向迭代器const迭代器 string类对象的容量操作(补)size() 3. string类的元素访问4. string类的修改 未完待续 结合文档食用~ 六、string类 2. 反向迭代器 一般来说,迭代器都是正向的遍历容器,虽然可以…

MySQL与金蝶云星空对接集成执行查询语句-v2打通销售退货新增V1

MySQL与金蝶云星空对接集成执行查询语句-v2打通销售退货新增V1 数据源系统:MySQL mysql是一个关系数据库管理系统(RDBMS),所谓的关系型数据库,是建立在关系模型基础上的数据库,借助于集合代数等数学概念和方法来处理数…

[华为OD] C卷 服务器cpu交换 现有两组服务器QA和B,每组有多个算力不同的CPU 100

题目: 现有两组服务器QA和B,每组有多个算力不同的CPU,其中A[i]是A组第i个CPU的运算能 力,B[i]是B组第i个CPU的运算能力。一组服务器的总算力是各CPU的算力之和。 为了让两组服务器的算力相等,允许从每组各选出一个CPU进行一次交换。 求两…

【学习vue 3.x】(二)组件应用及单文件组件

文章目录 章节介绍本章学习目标学习前的准备工作Vue.js文件下载地址 组件的概念及组件的基本使用方式组件的概念组件的命名方式与规范根组件局部组件与全局组件 组件之间是如何进行互相通信的父子通信父子通信需要注意的点 组件的属性与事件是如何进行处理的组件的属性与事件 组…

Redis---------实现查询缓存

目录 数据库与缓存之间的工作业务逻辑: 接下来看查询缓存代码实现,主要是捋清楚业务逻辑,代码实现是死的: Controller: Service: P37作业实现:总体逻辑跟上面的业务逻辑差不多 Controller: Service&#…