当前位置: 首页 > news >正文

python实战(四)——RAG预热实践

一、任务目标

        为了清晰直观地展示RAG(检索增强生成)方法的有效性,我们手搓一套RAG的流程进行演示,作为后续LangChain等技术的预热。本文编程实践的目的是展示RAG的工作原理及流程(科普为主),不过多关注技术实现的效果和效率,因此如果是奔着代码拿来即用的目的阅读本文的话,那可能不会有什么大的收获。

二、常规的大模型问答

        这里直接给出本文的示例Query:

“请告诉我,花花是一个怎么样的人”

        下面,调用gpt-3.5-turbo大模型回答这个问题。我们使用openai的大模型接口,在这个过程中需要用到你个人的api_key等信息:

import openai# 可以去openai官网或者国内某些镜像网站注册一个
openai.api_key = "你的api key"
openai.api_base = "你的api base"
query = '请告诉我,花花是一个怎么样的人'
chat_completion = openai.ChatCompletion.create(model="gpt-3.5-turbo",messages=[{"role": "user", "content": query}])
response = chat_completion.choices[0].message.content
print(response)

        下面是大模型的回答,很明显,大模型也没办法在没有任何背景知识的情况下回答这个问题:

三、基于RAG的大模型问答

1、知识库构建

        首先,我们需要有一个存储着各类信息的知识库,里面需要有花花相关的内容。有了基本的知识储备,才能够正确回答问题。这里给出一个简单的知识库示例,其中包含了磊磊、花花、明明三个人各自性格、特长等信息:

dataBase = [
"磊磊是一个充满活力的北京小伙子,性格外向,总是人群中的焦点。他对生活充满了热情,喜欢与人交流,总是能够轻松地与陌生人打成一片。磊磊的运动爱好广泛,尤其擅长篮球和游泳,他经常参加各种体育活动,不仅锻炼了身体,也结交了许多志同道合的朋友。",
"磊磊的特长之一是公共演讲,无论是在学校的辩论赛还是公司的年会上,磊磊总能用他那富有感染力的言辞吸引听众的注意。此外,磊磊还对摄影有着浓厚的兴趣,喜欢捕捉生活中的美好瞬间,他的社交媒体上充满了他拍摄的风景和人物照片。",
"在人际交往方面,磊磊有着广泛的社交圈,他善于倾听,乐于助人,这使得他在朋友中非常受欢迎。磊磊总是能够用他的幽默感和积极态度为周围的人带来正能量。尽管磊磊的朋友众多,但磊磊也非常重视与家人的关系,经常抽时间陪伴家人,享受家庭的温暖。",
"花花是一个温柔而细腻的女孩,她的性格内向,喜欢安静和独处。花花来自江南的一个小镇,那里的宁静和美丽深深地影响了她的性格和审美。花花的爱好是绘画和写作,她喜欢用画笔捕捉自然的美丽,用文字记录内心的感受。",
"花花在社交场合可能显得有些害羞和保守,但她的真诚和善良总能赢得他人的尊重和喜爱。她更倾向于深度交流而非表面的寒暄,这使得她的友谊往往更加长久和稳固。在业余时间,花花喜欢阅读和研究心理学,这不仅帮助她更好地理解自己,也让她在与人交往时更加敏感和体贴。尽管她不常成为聚会的中心,但花花的存在总能为周围的人带来一份宁静和安慰。",
"明明,一个性格外向的年轻人,总是带着阳光般的笑容,他的热情和活力很容易感染周围的人。他出生在繁华的上海,这个城市的快节奏和多元文化塑造了他开朗和包容的性格。",
"明明的爱好多种多样,他特别喜欢户外运动,如徒步旅行和自行车骑行,这些活动不仅让他保持了健康的体魄,也让他有机会结识来自不同背景的朋友。明明还是各种社交活动的常客,无论是公司的团队建设还是朋友间的聚会,他总能成为调动气氛的关键人物。",
"在工作之余,明明也热衷于公益事业,他经常参与志愿者活动,帮助那些需要帮助的人。明明的这种乐于助人的精神,让他在社区中也赢得了良好的声誉。"
]

2、知识检索

        我们的示例知识库规模很小,但是实际业务过程中,数据的规模可能非常大,我们不可能把整个知识库同时作为prompt输入给大模型。那一个基本的方案就是去检索跟Query相关的知识来辅助大模型理解,例如我们可以通过计算余弦相似度的方式来选择跟Query最相似的Top N条知识,然后合并这些知识到Prompt中。

        由于我们这是一个简易版RAG,秉着简易的原则,我们在这里使用Word2Vec进行文本的向量化。这里,Word2Vec模型的训练语料就是dataBase,完成训练之后直接对dataBase中的每一句话进行向量化(Word2Vec句向量由所有词向量按位取平均所得)。

from gensim.models import Word2Vec
import numpy as np
import jiebatexts_cut = [list(jieba.cut(text)) for text in dataBase]
model = Word2Vec(sentences=texts_cut, vector_size=100, window=10, min_count=1, sg=1, epochs=100)
sentence_vectors = []
for sentence in texts_cut:vector = np.mean([model.wv[word] for word in sentence if word in model.wv], axis=0)sentence_vectors.append(vector)

        现在,我们已经实现了知识库的向量化,接下来就是检索Query与知识库中的每一条知识的相似度了。这里我们直接使用Word2Vec对Query进行向量化,并比对Query向量和知识向量表示的相似度,由于数据量不大,这里直接使用for循环。

from scipy.spatial import distancequery_emb = np.mean([model.wv[word] for word in list(jieba.cut('请告诉我,花花是一个怎么样的人')) if word in model.wv], axis=0)
most_relative = -1
max_sims = -1
for idx, vec in enumerate(sentence_vectors):cosine_similarity = 1 - distance.cosine(query_emb, vec)print("向量ID:{}, 余弦相似度:{}".format(idx, cosine_similarity))if cosine_similarity>max_sims:max_sims = cosine_similaritymost_relative = idx

      结果如下:

        由于知识库数据量太小,这里我们只选择Top 1最相关的知识。可以看到,最相似的为ID为3的知识表示,对应文本为:

        “花花是一个温柔而细腻的女孩,她的性格内向,喜欢安静和独处。花花来自江南的一个小镇,那里的宁静和美丽深深地影响了她的性格和审美。花花的爱好是绘画和写作,她喜欢用画笔捕捉自然的美丽,用文字记录内心的感受。”

3、大模型问答

        我们把上述文本加入到prompt中并让大模型回答我们的问题:

query = '请告诉我,花花是一个怎么样的人。'
prompt = f"以下是一些相关的可用信息:{dataBase[most_relative]}"
chat_completion = openai.ChatCompletion.create(model="gpt-3.5-turbo",messages=[{"role": "user", "content": query+prompt}])
response = chat_completion.choices[0].message.content
print(response)

        结果如下,是否优雅了许多?

四、完整代码

import openai
from gensim.models import Word2Vec
import numpy as np
import jieba
from scipy.spatial import distance# api配置
openai.api_key = "你的api key"
openai.api_base = "你的api base"dataBase = [
"磊磊是一个充满活力的北京小伙子,性格外向,总是人群中的焦点。他对生活充满了热情,喜欢与人交流,总是能够轻松地与陌生人打成一片。磊磊的运动爱好广泛,尤其擅长篮球和游泳,他经常参加各种体育活动,不仅锻炼了身体,也结交了许多志同道合的朋友。",
"磊磊的特长之一是公共演讲,无论是在学校的辩论赛还是公司的年会上,磊磊总能用他那富有感染力的言辞吸引听众的注意。此外,磊磊还对摄影有着浓厚的兴趣,喜欢捕捉生活中的美好瞬间,他的社交媒体上充满了他拍摄的风景和人物照片。",
"在人际交往方面,磊磊有着广泛的社交圈,他善于倾听,乐于助人,这使得他在朋友中非常受欢迎。磊磊总是能够用他的幽默感和积极态度为周围的人带来正能量。尽管磊磊的朋友众多,但磊磊也非常重视与家人的关系,经常抽时间陪伴家人,享受家庭的温暖。",
"花花是一个温柔而细腻的女孩,她的性格内向,喜欢安静和独处。花花来自江南的一个小镇,那里的宁静和美丽深深地影响了她的性格和审美。花花的爱好是绘画和写作,她喜欢用画笔捕捉自然的美丽,用文字记录内心的感受。",
"花花在社交场合可能显得有些害羞和保守,但她的真诚和善良总能赢得他人的尊重和喜爱。她更倾向于深度交流而非表面的寒暄,这使得她的友谊往往更加长久和稳固。在业余时间,花花喜欢阅读和研究心理学,这不仅帮助她更好地理解自己,也让她在与人交往时更加敏感和体贴。尽管她不常成为聚会的中心,但花花的存在总能为周围的人带来一份宁静和安慰。",
"明明,一个性格外向的年轻人,总是带着阳光般的笑容,他的热情和活力很容易感染周围的人。他出生在繁华的上海,这个城市的快节奏和多元文化塑造了他开朗和包容的性格。",
"明明的爱好多种多样,他特别喜欢户外运动,如徒步旅行和自行车骑行,这些活动不仅让他保持了健康的体魄,也让他有机会结识来自不同背景的朋友。明明还是各种社交活动的常客,无论是公司的团队建设还是朋友间的聚会,他总能成为调动气氛的关键人物。",
"在工作之余,明明也热衷于公益事业,他经常参与志愿者活动,帮助那些需要帮助的人。明明的这种乐于助人的精神,让他在社区中也赢得了良好的声誉。"
]# 知识库文本向量化
texts_cut = [list(jieba.cut(text)) for text in dataBase]
model = Word2Vec(sentences=texts_cut, vector_size=100, window=10, min_count=1, sg=1, epochs=100)
sentence_vectors = []
for sentence in texts_cut:vector = np.mean([model.wv[word] for word in sentence if word in model.wv], axis=0)sentence_vectors.append(vector)
print(sentence_vectors)# query
query = '请告诉我,花花是一个怎么样的人。'# 余弦相似度匹配/知识检索
query_emb = np.mean([model.wv[word] for word in list(jieba.cut(query)) if word in model.wv], axis=0)
most_relative = -1
max_sims = -1
for idx, vec in enumerate(sentence_vectors):cosine_similarity = 1 - distance.cosine(query_emb, vec)print("向量ID:{}, 余弦相似度:{}".format(idx, cosine_similarity))if cosine_similarity>max_sims:max_sims = cosine_similaritymost_relative = idx# 结合知识库知识的大模型问答
prompt = f"以下是一些相关的可用信息:{dataBase[most_relative]}"
chat_completion = openai.ChatCompletion.create(model="gpt-3.5-turbo",messages=[{"role": "user", "content": query+prompt}])
response = chat_completion.choices[0].message.content
print(response)

五、总结

        本文使用极其简单的流程实现了一个简易版RAG。可见,结合RAG技术,大模型能够轻松回答原先无法回答的一些需要知识背景的问题。RAG的概念非常简单,但是它对于提升大模型的表现却非常有效。本文只是进行了一个科普性质的讲解,后续将会详细介绍RAG技术的实现。毕竟,实际业务知识库的规模可能达到了大数据的量级,因此必然无法直接逐条知识和Query比较相似度,这使得我们需要进行一些必要的检索优化;另外,将知识文本添加到Prompt中的方式也较为原始,实际上有更加高效的知识应用策略;最后,RAG的链路也早就有诸如LangChain等开源解决方案帮助我们进行开发了,无需人工重复造轮子。


http://www.mrgr.cn/news/60607.html

相关文章:

  • qt配置https请求
  • 新增新质生产力论文复刻(SSCI)10份新质生产力数据合集-最新出炉 附下载链接
  • Spring Boot 应用开发全攻略:从入门到精通
  • Flutter主题最佳实践
  • MySql中表的复合查询
  • Android token JJWT
  • ssm智慧社区电子商务系统+vue
  • Radar Fields: Frequency-Space Neural Scene Representations for FMCW Radar 笔记
  • 容器化实践:优化DevOps环境下的容器交付流程
  • 【CSS/SCSS】@supports的介绍与用法
  • 【深度学习|地学应用】人工智能技术的发展历程与现状:探讨深度学习在遥感地学中的应用前景
  • arduino uno R3更换328pb-au芯片,烧录bootloader
  • “药品追溯到客户管理:数字化转型下的药企发展之路”
  • 基于LLaMA Factory对LLama 3指令微调的操作学习笔记
  • 新增、修改弹窗封装
  • java溯本求源之基础(二十七)之--Map常用子类及源码分析(6000字长文)
  • 中项到高项:软考信息系统项目管理师证书进阶指南
  • Pytest用例执行顺序和跳过执行详解
  • SQL-lab靶场less1-4
  • 《C++ 旧项目全局变量模块化改造:稳扎稳打,守护原有功能》
  • Flow-based生成模型理解
  • DevSecOps在数字政府建设中的实践研究
  • MinIO方法封装
  • 【C++】Type punning类型双关、union联合体、C++中的类型转换casting
  • 手机也能开数电票了,可能我也即将要失业了
  • Codigger桌面模式之Size Look介绍