引入RAG
RAG前的工作流程如下:向模型提问->模型从已训练数据中查询数据->组织语言->生成答案。
RAG后的工作流程如下:读取文档->分词->嵌入->将嵌入数据存入向量数据库->向模型提问->模型从向量数据库中查询数据->组织语言->生成答案。
嵌入
在人工智能中,嵌入(Embedding)是将数据向量化的一个过程,可以理解为将人类语言转换为大语言模型所需要的计算机语言的一个过程。在我们第二轮测试开始前,首先下载一个嵌入模型:nomic-embed-text 。它可以使我们的Ollama
具备将文档向量化的能力。
from langchain_text_splitters import CharacterTextSplitter
text_splitter = CharacterTextSplitter.from_tiktoken_encoder(
chunk_size=100, chunk_overlap=0
)
texts = text_splitter.split_text(state_of_the_union)
loader.load()
使用LangChain
接下来需要一个Document loaders
,文档。
from langchain_community.document_loaders import TextLoader
loader = TextLoader("./index.md")
loader.load()
接下来需要一个分词器Text Splitter
,文档。
from langchain_text_splitters import CharacterTextSplitter
text_splitter = CharacterTextSplitter.from_tiktoken_encoder(
chunk_size=100, chunk_overlap=0
)
texts = text_splitter.split_text(state_of_the_union)
接下来需要一个向量数据库来存储使用nomic-embed-text
模型项量化的数据。既然是测试,我们就使用内存型的DocArray InMemorySearch
,文档。
embeddings = OllamaEmbeddings(model='nomic-embed-text')
vectorstore = DocArrayInMemorySearch.from_documents(doc_splits, embeddings)
测试
首先下载测试文档,我们将会把此文档作为外部数据库供模型检索。注意该文档中提到的:
忽见一彪军马,尽打红旗,当头来到,截住去路。为首闪出一将,身长七尺,细眼长髯,官拜骑都尉,沛国谯郡人也,姓曹,名操,字孟德。
编写代码如下:
from langchain_community.document_loaders import TextLoader
from langchain_community import embeddings
from langchain_community.chat_models import ChatOllama
from langchain_core.runnables import RunnablePassthrough
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain.text_splitter import CharacterTextSplitter
from langchain_community.vectorstores import DocArrayInMemorySearch
from langchain_community.embeddings import OllamaEmbeddings
model_local = ChatOllama(model="qwen:7b")
# 1. 读取文件并分词
documents = TextLoader("../../data/三国演义.txt").load()
text_splitter = CharacterTextSplitter.from_tiktoken_encoder(chunk_size=7500, chunk_overlap=100)
doc_splits = text_splitter.split_documents(documents)
# 2. 嵌入并存储
embeddings = OllamaEmbeddings(model='nomic-embed-text')
vectorstore = DocArrayInMemorySearch.from_documents(doc_splits, embeddings)
retriever = vectorstore.as_retriever()
# 3. 向模型提问
template = """Answer the question based only on the following context:
{context}
Question: {question}
"""
prompt = ChatPromptTemplate.from_template(template)
chain = (
{"context": retriever, "question": RunnablePassthrough()}
| prompt
| model_local
| StrOutputParser()
)
print(chain.invoke("身长七尺,细眼长髯的是谁?"))
模型返回的答案:
身长七尺,细眼长髯的人物是曹操,字孟德,沛国谯郡人。在《三国演义》中,他是主要人物之一。
可见,使用RAG
后,模型给到了正确答案。
本篇文章我们使用LangChain
和RAG
对大语言模型进行了一些微调,使之生成答案前可以在我们给到的文档内进行检索,以生成更准确的答案。
RAG
是检索增强生成(Retrieval Augmented Generation),主要目的是让用户可以给模型制定一些额外的资料。这一点非常有用,我们可以给模型提供各种各样的知识库,让模型扮演各种各样的角色。
LangChain
是开发大语言模型应用的一个框架,内置了很多有用的方法,比如:文本读取、分词、嵌入等。利用它内置的这些功能,我们可以轻松构建出一个RAG
的应用。