RAG步骤
理解(用自己的话)
RAG是提示词工程的一种,分为离线阶段-- 建立向量库和在线阶段 -- 查询阶段
这里的离线指我们拿到了所有数据,然后处理;而在线是指我们需要实时响应,只能知道用户之前和现在query
离线阶段分为:
加载文档,变成LLM能处理的纯文本
切分文档。 因为模型输入长度限制,以及向量计算中长文本的细节会消失
切分文档要保持语义,切分方案有
按照字符切分
r_splitter = RecursiveCharacterTextSplitter(
chunk_size=150,
chunk_overlap=0,
separators=["\n\n", "\n", "(?<=\. )", " ", ""]
)
这样会首先尝试用\n\n分割文档,如果长度太长,再尝试用\n,然后尝试用. 然后" " 然后""
对应分割段落, 分割段内换行,分割句子 分割单词 分割字母
按照token切分
使用token分词器会在每个chunks中加入文档metadata向量化
入库 向量和对应chunk一起入库
代码片段(关键点)
from langchain.document_loaders import PyPDFLoader
# Load PDF
loaders = [
# Duplicate documents on purpose - messy data
PyPDFLoader("docs/cs229_lectures/MachineLearning-Lecture01.pdf"),
PyPDFLoader("docs/cs229_lectures/MachineLearning-Lecture01.pdf"),
PyPDFLoader("docs/cs229_lectures/MachineLearning-Lecture02.pdf"),
PyPDFLoader("docs/cs229_lectures/MachineLearning-Lecture03.pdf")
]
# 加载文档
docs = []
for loader in loaders:
docs.extend(loader.load())
# 切分文档
from langchain.text_splitter import RecursiveCharacterTextSplitter
text_splitter = RecursiveCharacterTextSplitter(
chunk_size = 1500,
chunk_overlap = 150
)
splits = text_splitter.split_documents(docs)
# 向量化文档并持久化
from langchain.vectorstores import Chroma
persist_directory = 'docs/chroma/'
!rm -rf ./docs/chroma # remove old database files if any
vectordb = Chroma.from_documents(
documents=splits,
embedding=embedding,
persist_directory=persist_directory
)
# 查询
question = "is there an email i can ask for help"
docs = vectordb.similarity_search(question,k=3)
docs[0].page_content
遇到的坑
重复文件如何去重
向量搜索是基于semantic, 因此一些硬性要求并不会被识别出来,比如:
question = "what did they say about regression in the third lecture?"
实际上并不会识别出"the third lecture"然后去除不是"the third lecture" 的文档
解决方案:
MMR(Maximal Marginal Relevance)
\text{Score}(D_i) = \lambda \cdot \text{Sim}(D_i, Q) - (1-\lambda) \cdot \max_{D_j \in S} \text{Sim}(D_i, D_j)
第一项 (加分项): 与 Query 的向量点积
第二项 (扣分项): 与已选集 中最像的一个的向量点积。
\lambda 是要调节的参数
Self-Querying Retriever
Contextual Compression
MMR可以解决重复文件的问题,同时可以提升回答质量
self-query retriever
重构查询语句,把查询分成语义查询 + 结构化信息过滤两步
我们把结构化信息包含在metadata中,比如第几讲,第几页
重构方法:让LLM从query中提取出metadata,我们给LLM提供metadata语义讲解,LLM把query中的语义与metadata语义对比,输出结构化metadata过滤语言和去掉限制条件的语义语言
比如 "第三章中对注意力机制的解释"变成
{
"query": "注意力机制是怎么解释的",
"filter": {"lecture": 3}
}
compression
然后在加入历史对话,AI就能理解上下文,chatbot就产生了
相关链接
LangChain Chat with Your Data - DeepLearning.AI
Advanced Techniques in RAG: A Deep Dive into MMR, Self-Querying Retrievers, Contextual Compression, and Ensemble Retrieval - DEV Community
Fine-tuning和RAG 类似 重构和打补丁