构建一个RAG增强的ChatGPT用于法律研究:以General v MCP & Others (1995)案为案例研究
人工智能(AI)领域已经被大型语言模型(LLMs)的出现所彻底改变,这些模型正在席卷整个行业。这些先进的AI系统,例如ChatGPT,被设计为能够理解和生成类似人类语言的文本。经过大量数据的训练,LLMs在与语言理解和生成相关的任务中被证明非常熟练。
不过,尽管它们在训练数据上表现出色,但是当涉及到超出其训练材料范围的深度知识时,语言模型有时会显得不足。这就是创新技术,例如检索增强生成(Retrieval-augmented generation,简称RAG)发挥作用的地方。
RAG通过整合从外部来源获取的事实信息,为生成式人工智能模型提供了解决这个限制的方案,从而能够以更广泛的范围和深度提供更准确可靠的结果。
允许我用法律领域的一个例子来阐释这个概念。想象一下,法官和律师需要引用来加强他们的论点。这些引用可能来自各种法律文件,这些文件可以是PDF或其他格式,或者来自类似案例中的过去判决。找到和引用这些信息可能是一项艰巨的任务,但这正是RAG真正擅长的地方。
让我们来看看在我在大学的商法课上学到的著名的马拉维国民大会党(MCP)诉马拉维共和国总统案件(向我的讲师致敬,哈哈)。这个案例是如何利用案例研究方法(RAG)高效地定位和参考相关信息的一个绝佳示例,使法律专业人员更容易构建更有力的论点并作出更明智的决策。
重要声明:尽管本案的细节无疑是有趣的,但本文的主要目标是展示如何利用RAG语言生成模型开发一项对法律专业人士有用的工具。因此,如果您有兴趣了解更多关于这个案例的内容,可以从这里阅读。
所以,让我们开始建立我们的聊天机器人。
这是一个逐步指南,教你如何构建我们的基于RAG的聊天机器人:
- 首先,获得包含法官对该案件的裁决的PDF文档是第一步。这个文档将作为我们聊天机器人的主要信息来源。
- 接下来,我们需要使用一种叫做“文档分割”的技术将PDF文档拆分成更小、更易管理的单元。
- 一旦文档被切分,我们将使用一个“向量存储”来将文档的内容存储在一个可以轻松检索的格式中。
- 最后,聊天机器人使用检索器根据用户输入从向量存储中获取相关的文档部分。
- ChatGPT生成回答,使用包含问题和检索到的数据的提示,从法官裁决文件中提供准确信息。
为了跟随这个项目的代码,您需要具备以下内容:
- 一个用于OpenAI的API密钥,将用于访问ChatGPT所需的语言模型和处理工具。
- 在您的系统上安装Python 3。
- 朗链LLM框架。
太棒了,现在我们已经准备好我们的工具,让我们开始编写代码吧。
步骤1:文档加载中
首先,让我们安装LangChain,这将帮助我们连接到ChatGPT。
pip install langchain
为了加载文档,我们将使用来自LangChain的PyPDFLoader(请确保您事先安装了PyPDF包)。如果您没有安装它,则可以使用pip进行安装,如下所示。
pip install PyPDF2
根据您的要求更改路径,导入PDF文档。
from langchain.document_loaders import PyPDFLoader
# Replace 'path_to_your_document' with the actual path to your PDF document
document_path = 'path_to_your_document'
# Load the document using PyPDFLoader
loader = PyPDFLoader(document_path)
docs = loader.load()
步骤2:文档拆分
现在,我们已经加载了PDF文档,让我们将其分割成更小且更易管理的块。我们这样做是因为文档太大,无法在一个提示中完整传递,这是由于ChatGPT的令牌限制,而且这也不具有成本效益。
为了拆分文档,让我们导入RecursiveCharacterTextSplitter。
from langchain.text_splitter import RecursiveCharacterTextSplitter
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=1000, chunk_overlap=200, add_start_index=True
)
all_splits = text_splitter.split_documents(docs)
len(all_splits)
这是RecursiveCharacterTextSplitter中每个参数的含义:
- chunk_size: 每个块中的最大字符数。
chunk_overlap: 一块结束时,将在下一块开头重复的字符数。这确保了块之间不会丢失重要上下文。
- add_start_index:如果设置为True,将会为每个块添加一个索引,表示它在原始文档中的位置。
len(all_splits)显示了文档被分割成的块数,对于这个案例,它将为260。
第三步:向量存储
将文档分成较小的块后,下一步是将这些块存储在向量存储器中,以便高效地检索和比较文档的内容。当用户向聊天机器人输入查询时,我们需要从分割的文档中检索出最相关的块。这通过将用户的查询嵌入到向量存储器中,并对索引的260个文本块执行余弦相似度搜索来实现,从而允许我们在运行时快速搜索它们。
为了在代码中实现这一点,我们将从.env文件中使用Python的'dotenv'包加载OpenAI密钥。请确保.env文件位于与您的Jupyter笔记本相同的文件夹中。以下是代码:
import dotenv
dotenv.load_dotenv()
接下来,导入必要的库,Chroma和OpenAIEmbeddings。
from langchain_community.vectorstores import Chroma
from langchain_openai import OpenAIEmbeddings
使用以下代码创建一个向量存储器
vectorstore = Chroma.from_documents(documents=all_splits, embedding=OpenAIEmbeddings())
第四步:检索
既然我们已经将文档分割并存储在一个向量存储中,我们可以执行相似性搜索来检索基于用户查询的相关块。我们将使用向量存储中的as_retriever方法来创建一个具有相似性搜索类型的检索器。以下是代码:
retriever = vectorstore.as_retriever(search_type="similarity", search_kwargs={"k": 6})
retrieved_docs = retriever.invoke("What did the Attorney General say about Quroam?")
我们使用这个问题“司法部长对Quroam有何说法?”进行查询,现在让我们检查一下第一个检索到的块包含什么。
print(retrieved_docs[0].page_content)
如果我们通过打印页面内容来检查第一个检索到的文档,我们可以看到相关信息已经成功从PDF文档中检索出来。
步骤5:生成
最后,让我们使用强大的GPT-4语言模型基于检索到的信息生成回应。我们将使用LangChain Hub的自定义提示来增强生成回应的上下文。
首先,让我们从已安装的包中导入所有所需的类。
from langchain_openai import ChatOpenAI
from langchain import hub
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough
让我们首先引入用于生成输出的大型语言模型。
llm = ChatOpenAI(model_name="gpt-4", temperature=0)
prompt = hub.pull("rlm/rag-prompt")
让我们通过编写这段代码来查看将发送给ChatGPT的最终提示:
example_messages = prompt.invoke(
{"context": "filler context", "question": "What did the Attorney General say about Quroam?"}
).to_messages()
print(example_messages[0].content)
将实际传递给ChatGPT的提示保留用户输入的问题和从我们文档中检索的相关部分的上下文。
现在让我们把所有东西放在一起
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 = (
{"context": retriever | format_docs, "question": RunnablePassthrough()}
| prompt
| llm
| StrOutputParser()
)
实际用户的输入将在此处进行
for chunk in rag_chain.stream("What did the Attorney General say about Quroam?"):
print(chunk, end="", flush=True)
使用这些步骤,您成功地构建了一个以RAG为动力的聊天机器人,可以根据PDF文档检索和生成准确的信息。
结论
本文演示了如何使用ChatGPT创建一个自定义的聊天机器人,它根据PDF文档回答用户的问题。然而,需要注意的是,虽然用几行代码创建一个简单的原型很容易,但开发一个适用于生产的、由RAG驱动的聊天机器人需要多次迭代。它可能还涉及到更复杂的步骤来解决诸如幻觉等问题,这超出了本文的范围。尽管如此,我相信这对许多对RAG感兴趣的组织和个人来说是一个绝佳的起点。为了进一步学习,我推荐DeepLearning.AI的一些短期课程,比如“LangChain:与您的数据聊天”和“LangChain用于LLM应用开发”。
要了解更多信息,请查看下面的来源。
1. 介绍 | 🦜️ Langchain,https://python.langchain.com/docs/get_started/introduction。于2024年1月21日访问。
2. 司法审查案件。“马拉维国民党诉马拉维共和国总统(司法审查案件34/2020)[2021] MWHC 39(2021年6月2日)。” MalawiLII,https://malawilii.org/akn/mw/judgment/mwhc/2021/39/eng@2021-06-02。2024年1月26日访问。
3. Nvidia 博客。 "什么是检索增强生成(RAG)?" Nvidia, Nvidia。2024年1月25日访问。