0


【AI大模型应用开发】【LangChain系列】实战案例4:再战RAG问答,提取在线网页数据,并返回生成答案的来源

  • 大家好,我是同学小张,日常分享AI知识和实战案例
  • 欢迎 点赞 + 关注 👏,持续学习持续干货输出
  • +v: jasper_8017 一起交流💬,一起进步💪。
  • 微信公众号也可搜【同学小张】 🙏

本站文章一览:

在这里插入图片描述


文章目录

0. 背景

目前为止,我们已经系统学习了一下内容:

(1)RAG的基本流程与实践

  • 【AI大模型应用开发】3. RAG初探 - 动手实现一个最简单的RAG应用

(2)网页数据抓取

  • 【AI大模型应用开发】【LangChain系列】实战案例2:通过URL加载网页内容 - LangChain对爬虫功能的封装

(3)langchain基本使用:

  • 【AI大模型应用开发】【LangChain系列】1. 全面学习LangChain输入输出I/O模块:理论介绍+实战示例+细节注释
  • 【AI大模型应用开发】【LangChain系列】2. 一文全览LangChain数据连接模块:从文档加载到向量检索RAG,理论+实战+细节
  • 【AI大模型应用开发】【LangChain系列】4. 从Chain到LCEL:探索和实战LangChain的巧妙设计

今天,我们将综合以上技能,完成 网络数据+RAG 问答的实践,并且学习如何在返回结果中添加结果的来源(原文档)。

在结果中添加该结果的参考来源是RAG问答中非常重要的一环,一方面让我们更加了解答案的生成原理和参考内容,防止参考错误的文档,另一方面,可以展示给用户,我们的答案是有参考的,不是胡说,增加信任度。例如下面这个检索工具的展示,有了来源之后,显得更加专业和更高的可信度:

在这里插入图片描述

1. 代码实现

参考:

1.1 加载网页数据

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()

代码中以加载

https://lilianweng.github.io/posts/2023-06-23-agent/

链接的数据为例。

使用

WebBaseLoader

进行数据加载。

WebBaseLoader

是LangChain封装的专门用于加载网页数据的类。其定义和初始化参数如下,原理就是利用

urllib

加载html页面,然后通过

BeautifulSoup

进行

Html

解析,找出其中指定

tag

的内容。以上代码中

class_=("post-content", "post-title", "post-header")

表明只提取

HTML

页面中这些

tag

的数据。

classWebBaseLoader(BaseLoader):"""Load HTML pages using `urllib` and parse them with `BeautifulSoup'."""def__init__(
        self,
        web_path: Union[str, Sequence[str]]="",
        header_template: Optional[dict]=None,
        verify_ssl:bool=True,
        proxies: Optional[dict]=None,
        continue_on_failure:bool=False,
        autoset_encoding:bool=True,
        encoding: Optional[str]=None,
        web_paths: Sequence[str]=(),
        requests_per_second:int=2,
        default_parser:str="html.parser",
        requests_kwargs: Optional[Dict[str, Any]]=None,
        raise_for_status:bool=False,
        bs_get_text_kwargs: Optional[Dict[str, Any]]=None,
        bs_kwargs: Optional[Dict[str, Any]]=None,
        session: Any =None,)->None:"""Initialize loader.

        Args:
            web_paths: Web paths to load from.
            requests_per_second: Max number of concurrent requests to make.
            default_parser: Default parser to use for BeautifulSoup.
            requests_kwargs: kwargs for requests
            raise_for_status: Raise an exception if http status code denotes an error.
            bs_get_text_kwargs: kwargs for beatifulsoup4 get_text
            bs_kwargs: kwargs for beatifulsoup4 web page parsing
        """

怎么查看网页中想要提取的数据的tag?参考这篇文章:【提效】让GPT帮你写爬虫程序,不懂爬虫也能行

在这里插入图片描述

1.2 数据分块

指定分块方式:

RecursiveCharacterTextSplitter

,这个在之前咱们也介绍过(这篇文章),它就是将文本块分成 1000 字左右的段,相邻段之间有 200 字左右的重复,以保证相邻段之间的上下文连贯。

text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)
splits = text_splitter.split_documents(docs)

1.3 数据向量化和存储

使用

Chroma

作为向量数据库,向量化计算采用

OpenAIEmbeddings

接口和模型。

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

1.4 向量检索

将向量数据库作为 retriever。

retriever = vectorstore.as_retriever()

1.5 组装Chain

prompt = hub.pull("rlm/rag-prompt")
llm = ChatOpenAI(model_name="gpt-3.5-turbo", temperature=0)defformat_docs(docs):return"\n\n".join(doc.page_content for doc in docs)

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

(1)首先是Prompt,直接使用

hub.pull("rlm/rag-prompt")

加载一个Prompt模板,也可以自己写。加载到的Prompt模板内容:

在这里插入图片描述
(2)以上Prompt接收两个参数:

context

question

,所以chain组装的第一步就是传递这两个参数。

(3)整体解释下以上 rag_chain 的数据流:

  • retriver先运行,检索回来信息
  • 检索回来的信息给 format_docs,组装信息
  • 组装信息后填到context Key里,连同 question Key内容一起给 prompt
  • prompt 给 llm
  • llm 结果给 StrOutputParser

1.6 运行

通过

invoke

函数运行。

result = rag_chain.invoke("What is Task Decomposition?")print(result)

别忘了所有的依赖:

import bs4
from langchain import hub
from langchain_community.document_loaders import WebBaseLoader
from langchain_community.vectorstores import Chroma
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
from langchain_text_splitters import RecursiveCharacterTextSplitter

运行结果:

在这里插入图片描述

2. 加入Sources(答案来源)

2.1 代码修改

加入Sources很简单,主要改下 Chain 的组装:

from langchain_core.runnables import RunnableParallel

rag_chain_from_docs =(
    RunnablePassthrough.assign(context=(lambda x: format_docs(x["context"])))| prompt
    | llm
    | StrOutputParser())

rag_chain_with_source = RunnableParallel({"context": retriever,"question": RunnablePassthrough()}).assign(answer=rag_chain_from_docs)

先不管它是如何实现的,先运行看下结果:

result = rag_chain_with_source.invoke("What is Task Decomposition")print(result)

在这里插入图片描述

2.2 代码解释

看到结果后应该就对这段程序有了一个感性的认识。下面我们来看下这段程序是如何实现的。

rag_chain_with_source

开始看。

rag_chain_with_source = RunnableParallel({"context": retriever,"question": RunnablePassthrough()}).assign(answer=rag_chain_from_docs)

它使用了

RunnableParallel

来传递

context

的值 和

question

的值。

RunnableParallel().assign()

实现的功能就是将以上

{}

的内容传递给

assign

函数的参数,也就是传递给

rag_chain_from_docs

那么

rag_chain_from_docs

RunnablePassthrough.assign(context=(lambda x: format_docs(x["context"])))

,这里的

x

就知道是什么了:

{"context":xxxx, "question":xxxx}

x["context"]

也就是将检索出的文档进行组装。

然后

rag_chain_from_docs

的返回值:

answer=rag_chain_from_docs

,就是将返回值填到

"answer"

为Key的值中。

最后,

rag_chain_with_source

的返回值就是刚开始的

"context"

,

"question"

,再加上后面的

"answer"

3. 总结

简单总结一下本文内容。

本文利用 LangChain 实现了一个完整的问答RAG应用。

其中RAG中的数据源采用加载网页数据的形式获取,而不是采用之前实践中传统的本地知识库(加载本地PDF文件)的方式。

然后我们还在RAG的返回中增加了参考文本的输出,这是之前我们没有实践过的,算是一点新知识。在实现这个功能的过程中,最主要的是学会使用 LangChain 中提供的

RunnablePassthrough

RunnableParallel

进行值的传递。

如果觉得本文对你有帮助,麻烦点个赞和关注呗 ~~~


  • 大家好,我是 同学小张,日常分享AI知识和实战案例
  • 欢迎 点赞 + 关注 👏,持续学习持续干货输出
  • +v: jasper_8017 一起交流💬,一起进步💪。
  • 微信公众号也可搜【同学小张】 🙏

本站文章一览:

在这里插入图片描述


本文转载自: https://blog.csdn.net/Attitude93/article/details/136503386
版权归原作者 同学小张 所有, 如有侵权,请联系我们删除。

“【AI大模型应用开发】【LangChain系列】实战案例4:再战RAG问答,提取在线网页数据,并返回生成答案的来源”的评论:

还没有评论