什么是RAG,
顾名思义,通过检索外部数据,增强大模型生成效果。可以理解为让大模型先翻书,再回答问题,比如将公司内部的工作流程大模型肯定是不知道,但是我先将工作手册先给他看,当我再询问他就知道了
为什么要引入RAG
- 首先大模型会面临着幻觉的问题,比如他会将西游记的孙悟空引入到三国演义中的赤壁之战之中。会出现事实不符,逻辑混乱看似合理缺乏真实依据的现象。形成这一现象的原因训练数据有噪声。模型从海量数据中学习数据,然而数据本身有一些问题,比如网络谣言,架空小说等情况,还有个原因是概率优先,大模型本身是概率生成式模型,而非事实真实性。
- 大模型知识更新缓慢,比如你问deekseek最新的知识库是什么时候?他会回答是在2024年7月,那么在2024年7月之后的知识他就没法回答
- 大模型对领域知识理解有限,因为大模型在训练时候,是广度优先的,训练的数据覆盖全网公开文本。单领域内部的数据可能不会对外公开,而且分布稀疏
总结: 所以RAG的引入初衷是增强大模型的事实性,时效性,减少幻觉而存在的。
RAG的流程

从上图可以看出RAG主要有三个部分,索引化,检索以及生成。
索引化:将文档切分成片段,再编码为向量,存储在向量数据库里。
检索:将问题向量化,在向量数据库中检索到与问题相似度最高的文本片段
生成:将用户提出的问题与检索出来的文本片段组装成提示词,抛向大模型,作为大模型的输入,让其组织语言生成最终的回答
代码实现(Python实现)
- 第一步,申请阿里云百炼API KEY

- 第二步,安装chromadb向量数据库
pip install chromadb
附带chromadb使用教程 zhuanlan.zhihu.com/p/680661442
- 第三步,准备文档进行分割
python
从 PDF 文件中(按指定页码)提取文字
def extract_text_from_pdf(filename, page_numbers=None):
paragraphs = []
full_text = ''
for i, page_layout in enumerate(extract_pages(filename)):
if page_numbers is not None and i not in page_numbers:
continue
for element in page_layout:
if isinstance(element, LTTextContainer):
full_text += element.get_text().replace("\n", "").replace(" ", "")
if full_text:
text_chunks = sliding_window_chunks(full_text, 250, 100)
for text in text_chunks:
paragraphs.append(text)
return paragraphs
def sliding_window_chunks(text, chunk_size, stride):
return [text[i:i + chunk_size] for i in range(0, len(text), stride)]
- 第四步,使用chromadb向量数据库,封装获取向量和添加文档的操作
python
class MyVectorDBConnector:
def __init__(self):
# 创建数据库的链接
self.db = chromadb.Client()
# 创建数据库
self.collection = self.db.get_or_create_collection(name="demo")
def get_embeddings(self, texts, model="text-embedding-v2"):
'''封装 qwen 的 Embedding 模型接口'''
data = client.embeddings.create(input=texts, model=model).data
return [x.embedding for x in data]
def add_documents(self, instructions):
# 将数据向量化
embeddings = self.get_embeddings(instructions)
#把向量化的数据和原文存入向量数据库
self.collection.add(
embeddings=embeddings,
documents=instructions,
ids=[f"id{i}" for i in range(len(instructions))]
)
'''检索向量数据库'''
def search(self, query, n_results):
results = self.collection.query(
query_embeddings=self.get_embeddings([query]),
n_results=n_results,
)
return results
- 第五步,创建机器人对象,封装与大模型API交互的方法
ini
class RAG_ROBOT():
def __init__(self, vector_db, n_res):
self.vector_db = vector_db
self.n_res = n_res
def get_completion(self, prompt, model="qwen-plus"):
messages = [{"role": "user", "content": prompt}]
response = client.chat.completions.create(
model=model,
messages=messages,
temperature=0,
)
return response.choices[0].message.content
def chat(self, queyr):
# 1.检索
search_Data = self.vector_db.search(queyr, self.n_res)
# 2. 构建提示词
prompt = prompt_template.replace('__INTRO__', '\n'.join(search_Data['documents'][0])).replace('__QUERY__', queyr)
ret = self.get_completion(prompt)
print('机器人回答:', ret)
- 第六步,调用
ini
if __name__ == '__main__':
client = OpenAI(api_key="xxxxxx", #阿里云百炼API KEY
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1")
prompt_template = """
你是一个问答机器人,如果遇到无法回答的问题,请回复"我无法回答"。
已知信息:
__INTRO__
用户问:
__QUERY__
请用中文回答用户问题。
"""
page_data = extract_text_from_pdf('财务管理文档.pdf', page_numbers=[0, 1, 2])
vector_db = MyVectorDBConnector()
vector_db.add_documents(page_data)
# 创建机器人对象
rag_bot = RAG_ROBOT(vector_db, n_res=2)
rag_bot.chat('财务管理权限划分')
以上代码仅供学习参考,上述"财务管理文档"没找到上传的地方。