如何让你的RAG应用程序返回来源信息

81 阅读3分钟

如何让你的RAG应用程序返回来源信息

在问答应用程序中,显示生成答案所使用的来源给用户是很重要的。本文将介绍如何通过两种方法实现这一目的:使用内置的create_retrieval_chain以及自定义实现的简单LCEL。我们还将展示如何将来源结构化为模型响应的一部分,以便模型能够报告其使用的具体来源。

引言

了解和引用答案生成过程中使用的具体来源,不仅可以提高用户对系统输出的信任,还能提供有价值的信息进行进一步探索。这篇文章的目的就是帮助开发者在RAG(Retrieval-Augmented Generation)应用中实现这一需求。

主要内容

1. 环境设置

我们将在这个示例中使用OpenAI嵌入和Chroma向量存储,但这里演示的内容适用于任何Embeddings、VectorStore或Retriever。

首先,我们需要安装以下包:

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

设置环境变量OPENAI_API_KEY

import getpass
import os

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

2. 使用create_retrieval_chain

我们先来选择一个大语言模型(LLM):

pip install -qU langchain-openai
from langchain_openai import ChatOpenAI

llm = ChatOpenAI(model="gpt-4o-mini")  # 使用API代理服务提高访问稳定性

以下是我们构建的问答应用程序示例:

import bs4
from langchain.chains import create_retrieval_chain
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import OpenAIEmbeddings
from langchain_text_splitters import RecursiveCharacterTextSplitter

loader = WebBaseLoader(
    web_paths=("https://lilianweng.github.io/posts/2023-06-23-agent/",)
)
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()

system_prompt = (
    "You are an assistant for question-answering tasks. "
    "Use the following pieces of retrieved context to answer the question."
)

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)

3. 自定义LCEL实现

下面是一个自定义的实现,展示了如何构建一个类似create_retrieval_chain的链:

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
)

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

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

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

常见问题和解决方案

  1. 网络访问限制:在某些地区访问API时可能存在网络限制。建议使用API代理服务提高访问稳定性。

  2. 结果不一致:确保使用最新版本的库,并仔细检查环境变量的设置。

总结和进一步学习资源

通过本文,我们了解了如何在RAG应用中返回来源信息以及结构化来源的基本方法。建议继续深入阅读LangChain和API代理相关文档。

参考资料

  • LangChain 官方文档
  • OpenAI API 文档
  • Chroma 向量存储文档

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

---END---