检索增强生成-RAG的基础实现

文章目录[x]
  1. 1: 1 概念
  2. 2: 2 架构
  3. 3: 3 代码实现
  4. 4:4 代码输出结果

大模型出现涌现能力之后,针对大模型的应用也如雨后春笋般。但是,在大模型真正落地之前,其实还需要做好最后一公里,而这个最后一公里,其中不同应用有着不同的方法。其中prompt、微调和RAG都是其中方法之一。本系列就是针对RAG从入门到落地应用的流程。

 

 1 概念

RAG的全称是Retrieval-Augment Generation,即称为检索增强生成。通过特定prompt方式为 LLM 提供了从某些数据源检索到的信息,并基于此修正生成的答案。其中有几个关键的点需要知道:

 

  • -一个是从某些数据源检索到的信息
  •  提供特定的prompt
  •  修正生成答案

 

简单用一句话来说就是:利用向量数据库将格外的知识以向量存储,然后在回答用户问题时,先将用户问题在向量数据库中进行相似度查询,将查询结果以prompt的方式扔给大模型,获得最终答案。

 

那么RAG与prompt、微调(fine-tuning)有何应用场景的不同,以下是整理了RAG与其对比表格:

特性 Prompt Engineering Fine-tuning RAG
定义 在不改变模型参数的前提条件下,

利用提示工程来提升大语言模型处理复杂任务场景的能力

通过一个微训练的过程来修改大模型它本身的参数,使模型能更加专业化 在不改变大模型参数下,通过大语言模型理解用户的查询需求,并将相关的片段从数据库中检索出来,将提示工程与数据库查询相结合以获得上下文丰富的答案
解决问题 提高回答的精准度 更擅长回答特定场景下的相关问题 提升生成内容的精准度且保留数据安全
场景 通用且简单的场景,比如普通聊天问答等 开放专业领域,比如医疗、法律等场景 封闭专业领域,比如企业内部数据场景
优点 无需改变模型;推理耗时低;成本低; 微调领域准确度高;推理耗时低; 无需改变模型;准确度高;安全性强;及时内容;
缺点 准确度低;稳定性低;无及时内容; 成本高:(数据、硬件、技术);

灵活度低(不能实时更新);

稳定性低(可能出现微调结果不理想、原有能力下降);

流程复杂;成本较高;
三者都有不同的优缺点,在实践中,可以参考以下图表对你的应用场景进行适配:

 

1. 横轴表示LLM本身优化,也就是优化LLM本身按照你想要的表达方式来表达
2. 纵轴表示上下文优化,也就是增加LLM的专业知识

 

- Prompt engineering:相当于告诉你要考试,但是考试内容没有告诉你。  缺点:只能使用已经知识作答。
- RAG:相当于给你一本书,在考试的时候你可以查。 缺点:但是书的内容很多,不能一次性读完再答题,需要有很准确的检索方式。
- Fine-tuning:相当于你学习了知识,然后闭卷考试。 缺点:1.存在没学好  2.忘记原来的知识。 3.考试可能有课外知识。
- Fine-tuning+RAG:相当于你学了知识的同时开卷考试。

 

 2 架构

一个RAG架构应该是怎么样的?你或许见过比较复杂的流程,但是这里先介绍一个RAG最少需要包括哪些部分。(后续会逐步介绍各个模块以及更多优化的流程)

 

RAG与非RAG对比

 

1. 专业知识:需要一个专业知识读取,这时候可能是pdf、Excel等不同类型的文档,因此需要一个文档读取工具
2. 向量化:需要将专业知识入库,而入库的操作就是将专业知识向量化,也就是embedding,因此你需要一个embedding工具
3. 数据库:一般使用向量数据库,当然也可以使用其它(但考虑到相似度搜索,向量数据库最合适),其作用就是用于存储格外的专业知识,用于问题做相似度匹配
4. prompt:给特定的prompt,比如:根据以下知识:{{{这里填入查询出来的内容}}},回答:{{{这里是问题}}}。

 

 3 代码实现

本实例是基于openai embedding模型将文档向量化,采用Chroma向量数据库,大模型使用openai  gpt-4o-mini,基础架构使用LangChain。
为了防止大模型使用训练数据,我找的是2024年奥运会相关数据。

 

import os
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_openai import OpenAIEmbeddings, ChatOpenAI
from langchain_community.vectorstores import Chroma
from langchain_community.document_loaders import Docx2txtLoader
from langchain.prompts import PromptTemplate


# 准备
os.environ['OPENAI_API_KEY'] = 'your api key'
os.environ['OPENAI_BASE_URL'] = 'openai代理地址,如果可以直连可以删掉这行'


# 第一步,设置embedding
embeddings = OpenAIEmbeddings(model='text-embedding-3-small')


# 第二步,创建数据库
db = Chroma(persist_directory='VectorStore', embedding_function=embeddings)


# 向量化的数据如果已经本地持久化,则不需要再次存储
if os.path.exists('VectorStore/chroma.sqlite3'):
    # 第三步,加载文档
    loader = Docx2txtLoader("uploads/2024巴黎奥运会.docx")  # 换成自己的文档路径
    documents = loader.load()
    text_spliter = RecursiveCharacterTextSplitter(chunk_size=256, chunk_overlap=0)
    documents = text_spliter.split_documents(documents)


    # 第四步,存储文档
    database = Chroma.from_documents(documents, embeddings, persist_directory="VectorStore")
    database.persist()


# 第五步,检索(这里这是从向量库中检索相似的原始信息,还没有发给大模型整理输出)
results = db.similarity_search(k=3, query='花样游泳集体技巧自选')
print('测试检索结果:',results)


# 第六步,创建llm
llm = ChatOpenAI(model='gpt-4o-mini')


# 第七步,设置prompt
QA_CHAIN_PROMPT = PromptTemplate.from_template("""根据下面的上下文(context)内容回答问题。
如果你不知道答案,就回答不知道,不要试图编造答案。
{context}
问题:{question}
""")


# 第八步,进行相似度查询数据
question = '冯彬的成绩是多少?'
retriever = db.as_retriever()
content = retriever.invoke(question)
final_message = QA_CHAIN_PROMPT.invoke(input={"context": content, "question": question}).to_string()
print('发给大模型最终信息:',final_message)


# 第九步,将数据和问题组成prompt格式,扔给大模型获取回答
answer = llm.invoke(final_message)
print(answer)

# 第九步,使用langchain的chain的方式
rag_chain = (
{"context": retriever, "question": RunnablePassthrough()}
   | QA_CHAIN_PROMPT
   | llm
   | StrOutputParser()
)

fi = rag_chain.invoke('竞走项目的冠军是谁?')
print(fi)



 

 

4 代码输出结果

1. **向量数据库检索结果**

 

[Document(page_content='[190-191]相关星图查看更多历届夏季奥林匹克运动会共37个词条322.8万阅读2040年奥运会第37届:未举办2036年奥运会第36届:未举办2032年布里斯班奥运会第35届:未举办2028年洛杉矶奥运会第34届:未举办2024年巴黎奥运会中国代表团金牌获得者共61个词条81.8万阅读李雯雯第40金-举重女子81公斤以上级李倩第39金-拳击女子75公斤级王柳懿第38金/第24金-花样游泳双人自由自选/花样游泳集体技巧自选王芊懿第38金/第24金-花样游泳双人自由自选/花样游泳集体技巧自选2024年巴', metadata={'source': 'uploads/2024巴黎奥运会.docx'}), Document(page_content='[190-191]相关星图查看更多历届夏季奥林匹克运动会共37个词条322.8万阅读2040年奥运会第37届:未举办2036年奥运会第36届:未举办2032年布里斯班奥运会第35届:未举办2028年洛杉矶奥运会第34届:未举办2024年巴黎奥运会中国代表团金牌获得者共61个词条81.8万阅读李雯雯第40金-举重女子81公斤以上级李倩第39金-拳击女子75公斤级王柳懿第38金/第24金-花样游泳双人自由自选/花样游泳集体技巧自选王芊懿第38金/第24金-花样游泳双人自由自选/花样游泳集体技巧自选2024年巴', metadata={'source': 'uploads/2024巴黎奥运会.docx'}), Document(page_content='[190-191]相关星图查看更多历届夏季奥林匹克运动会共37个词条322.8万阅读2040年奥运会第37届:未举办2036年奥运会第36届:未举办2032年布里斯班奥运会第35届:未举办2028年洛杉矶奥运会第34届:未举办2024年巴黎奥运会中国代表团金牌获得者共61个词条81.8万阅读李雯雯第40金-举重女子81公斤以上级李倩第39金-拳击女子75公斤级王柳懿第38金/第24金-花样游泳双人自由自选/花样游泳集体技巧自选王芊懿第38金/第24金-花样游泳双人自由自选/花样游泳集体技巧自选2024年巴', metadata={'source': 'uploads/2024巴黎奥运会.docx'})]

 

2. **整合后的提示词**

 

根据下面的上下文(context)内容回答问题。
如果你不知道答案,就回答不知道,不要试图编造答案。
[Document(page_content='会田径项目赛程公布,复活赛赛制将正式启用,2024年巴黎奥运会田径项目共设48个小项。共有来自200个国家或地区的2018名运动员参加角逐,其中男运动员1036名,女运动员982名。2024年8月1日,中国选手杨家玉在巴黎奥运会女子20公里竞走决赛中获得金牌,这是中国田径队在本届奥运会上的首枚金牌。女子铁饼决赛,中国选手冯彬以67米51的出色成绩获得亚军。女子链球决赛,赵杰以74.27米成绩获得季军8月10日,女子铅球决赛,宋佳媛掷出19米32,获得季军。最终美国队以14金11银9铜位列奖牌榜首位,中国队以', metadata={'source': 'uploads/2024巴黎奥运会.docx'}), Document(page_content='会田径项目赛程公布,复活赛赛制将正式启用,2024年巴黎奥运会田径项目共设48个小项。共有来自200个国家或地区的2018名运动员参加角逐,其中男运动员1036名,女运动员982名。2024年8月1日,中国选手杨家玉在巴黎奥运会女子20公里竞走决赛中获得金牌,这是中国田径队在本届奥运会上的首枚金牌。女子铁饼决赛,中国选手冯彬以67米51的出色成绩获得亚军。女子链球决赛,赵杰以74.27米成绩获得季军8月10日,女子铅球决赛,宋佳媛掷出19米32,获得季军。最终美国队以14金11银9铜位列奖牌榜首位,中国队以', metadata={'source': 'uploads/2024巴黎奥运会.docx'}), Document(page_content='会田径项目赛程公布,复活赛赛制将正式启用,2024年巴黎奥运会田径项目共设48个小项。共有来自200个国家或地区的2018名运动员参加角逐,其中男运动员1036名,女运动员982名。2024年8月1日,中国选手杨家玉在巴黎奥运会女子20公里竞走决赛中获得金牌,这是中国田径队在本届奥运会上的首枚金牌。女子铁饼决赛,中国选手冯彬以67米51的出色成绩获得亚军。女子链球决赛,赵杰以74.27米成绩获得季军8月10日,女子铅球决赛,宋佳媛掷出19米32,获得季军。最终美国队以14金11银9铜位列奖牌榜首位,中国队以', metadata={'source': 'uploads/2024巴黎奥运会.docx'}), Document(page_content='会田径项目赛程公布,复活赛赛制将正式启用,2024年巴黎奥运会田径项目共设48个小项。共有来自200个国家或地区的2018名运动员参加角逐,其中男运动员1036名,女运动员982名。2024年8月1日,中国选手杨家玉在巴黎奥运会女子20公里竞走决赛中获得金牌,这是中国田径队在本届奥运会上的首枚金牌。女子铁饼决赛,中国选手冯彬以67米51的出色成绩获得亚军。女子链球决赛,赵杰以74.27米成绩获得季军8月10日,女子铅球决赛,宋佳媛掷出19米32,获得季军。最终美国队以14金11银9铜位列奖牌榜首位,中国队以', metadata={'source': 'uploads/2024巴黎奥运会.docx'})]
问题:冯彬的成绩是多少?
3. **大模型输出**

 

content='冯彬在女子铁饼决赛中的成绩是67米51。' response_metadata={'token_usage': {'completion_tokens': 18, 'prompt_tokens': 933, 'total_tokens': 951, 'prompt_tokens_details': {'cached_tokens': 0}, 'completion_tokens_details': {'reasoning_tokens': 0}}, 'model_name': 'gpt-4o-mini', 'system_fingerprint': 'fp_e2bde53e6e', 'finish_reason': 'stop', 'logprobs': None} id='run-333929fc-6345-46e1-8d9d-3529ceed4162-0'

4.chain输出

竞走项目的冠军是中国选手杨家玉。

点赞

发表回复

昵称和uid可以选填一个,填邮箱必填(留言回复后将会发邮件给你)
tips:输入uid可以快速获得你的昵称和头像(已失效)