大模型之RAG-关键字检索的认识与实战(混合检索进阶储备)

前言

按照我们之前的分享(大模型应用RAG系列3-1从0搭建一个RAG:做好文档切分):

RAG系统搭建的基本流程

  1. 准备对应的垂域资料
  2. 文档的读取解析,进行文档切分
  3. 将分割好的文本灌入检索引擎(向量数据库)
  4. 封装检索接口
  5. 构建流程:Query -> 检索 -> Prompt -> LLM -> 回复

今天我们分享一个实现的场景:基于ES实现的关键字检索

为什么还要了解关键字检索

看到本文,可能有的jy会问,现在不都是在讲基于向量数据库的向量检索么,还需要专门再学习关键字检索么。

随着RAG的发展,单纯的关键字检索或者向量检索都很难满足我们面临的复杂场景,了解关键字检索是为了后面更好的去了解混合检索,以及为什么会出现混合检索。

关键字检索的概念

关键字检索是通过匹配查询中的关键字与文档中的关键字来进行检索的。当用户输入一个查询时,系统会在文档集合中查找包含这些关键字的文档,并将它们返回给用户。

传统的一种检索方式,RAG所使用的外挂数据库不只是狭义的数据库,搜索引擎也可以成为真实数据的一种来源,对于部分数据,使用关键词检索会高效快速得多。

关键字检索可能会受到一些问题的影响,例如同义词、拼写错误等,这可能会导致一些相关的文档被漏掉或者一些不相关的文档被检索到。

搭建一个简单关键字检索

安装必要环境

# 安装ES客户端
!pip install elasticsearch7# 安装 NLTK(文本处理方法库)
!pip install nltk

文本的处理

这里要注意,针对英文文本和中文文本的处理方法是不一样的

针对英文文本的处理实现

from elasticsearch7 import Elasticsearch, helpers
from nltk.stem import PorterStemmer
from nltk.tokenize import word_tokenize
from nltk.corpus import stopwords
import nltk
import reimport warnings
# 屏蔽 ES 的一些Warnings
warnings.simplefilter("ignore")  # 英文切词、词根、切句等方法
nltk.download('punkt')  
# 英文停用词库
nltk.download('stopwords')  def to_keywords(input_string):'''(英文)文本只保留关键字'''# 使用正则表达式替换所有非字母数字的字符为空格no_symbols = re.sub(r'[^a-zA-Z0-9\s]', ' ', input_string)word_tokens = word_tokenize(no_symbols)# 加载停用词表stop_words = set(stopwords.words('english'))ps = PorterStemmer()# 去停用词,取词根filtered_sentence = [ps.stem(w)for w in word_tokens if not w.lower() in stop_words]return ' '.join(filtered_sentence)

针对中文文本的处理实现

import re
import jieba
import nltk
from nltk.corpus import stopwordsnltk.download('stopwords')  def to_keywords(input_string):"""将句子转成检索关键词序列"""# 按搜索引擎模式分词word_tokens = jieba.cut_for_search(input_string)# 加载停用词表stop_words = set(stopwords.words('chinese'))# 去除停用词filtered_sentence = [w for w in word_tokens if not w in stop_words]return ' '.join(filtered_sentence)def sent_tokenize(input_string):"""按标点断句"""# 按标点切分sentences = re.split(r'(?<=[。!?;?!])', input_string)# 去掉空字符串return [sentence for sentence in sentences if sentence.strip()]

将文本灌入检索引擎

import os, time# 引入配置文件
ELASTICSEARCH_BASE_URL = os.getenv('ELASTICSEARCH_BASE_URL')
ELASTICSEARCH_PASSWORD = os.getenv('ELASTICSEARCH_PASSWORD')
ELASTICSEARCH_NAME= os.getenv('ELASTICSEARCH_NAME')# tips: 如果想在本地运行,请在下面一行 print(ELASTICSEARCH_BASE_URL) 获取真实的配置# 1. 创建Elasticsearch连接
es = Elasticsearch(hosts=[ELASTICSEARCH_BASE_URL],  # 服务地址与端口http_auth=(ELASTICSEARCH_NAME, ELASTICSEARCH_PASSWORD),  # 用户名,密码
)# 2. 定义索引名称
index_name = "teacher_demo_index"# 3. 如果索引已存在,删除它(仅供演示,实际应用时不需要这步)
if es.indices.exists(index=index_name):es.indices.delete(index=index_name)# 4. 创建索引
es.indices.create(index=index_name)# 5. 灌库指令
actions = [{"_index": index_name,"_source": {"keywords": to_keywords(para),"text": para}}for para in paragraphs
]# 6. 文本灌库
helpers.bulk(es, actions)# 灌库是异步的
time.sleep(2)

实现关键字检索

def search(query_string, top_n=3):# ES 的查询语言search_query = {"match": {"keywords": to_keywords(query_string)}}res = es.search(index=index_name, query=search_query, size=top_n)return [hit["_source"]["text"] for hit in res["hits"]["hits"]]results = search("how many parameters does llama 2 have?", 2)
for r in results:print(r+"\n")

LLM 接口封装

from openai import OpenAI
import os
# 加载环境变量
from dotenv import load_dotenv, find_dotenv
_ = load_dotenv(find_dotenv())  # 读取本地 .env 文件,里面定义了 OPENAI_API_KEYclient = OpenAI()def get_completion(prompt, model="gpt-3.5-turbo"):'''封装 openai 接口'''messages = [{"role": "user", "content": prompt}]response = client.chat.completions.create(model=model,messages=messages,temperature=0,  # 模型输出的随机性,0 表示随机性最小)return response.choices[0].message.content

Prompt 模板

def build_prompt(prompt_template, **kwargs):'''将 Prompt 模板赋值'''inputs = {}for k, v in kwargs.items():if isinstance(v, list) and all(isinstance(elem, str) for elem in v):val = '\n\n'.join(v)else:val = vinputs[k] = valreturn prompt_template.format(**inputs)
prompt_template = """
你是一个问答机器人。
你的任务是根据下述给定的已知信息回答用户问题。已知信息:
{context}用户问:
{query}如果已知信息不包含用户问题的答案,或者已知信息不足以回答用户的问题,请直接回复"我无法回答您的问题"。
请不要输出已知信息中不包含的信息或答案。
请用中文回答用户问题。
"""

一个简单的RAG Pipeline就产生了

什么是Pipeline

首先,RAG不是一个单项技术,它是一个流水线,行话叫pipeline。只有对流水线上的每一步骤都进行精细打磨,最后才能出来效果,我们的目标就是努力使每个环节都达到尽可能准确

让我们根据RAG的搭建基本流程来看这个demo

user_query = "how many parameters does llama 2 have?"# 1. 检索
search_results = search(user_query, 2)# 2. 构建 Prompt
prompt = build_prompt(prompt_template, context=search_results, query=user_query)
print("===Prompt===")
print(prompt)# 3. 调用 LLM
response = get_completion(prompt)print("===回复===")
print(response)

再看下效果

===Prompt===你是一个问答机器人。
你的任务是根据下述给定的已知信息回答用户问题。已知信息:1. Llama 2, an updated version of Llama 1, trained on a new mix of publicly available data. We also increased the size of the pretraining corpus by 40%, doubled the context length of the model, and adopted grouped-query attention (Ainslie et al., 2023). We are releasing variants of Llama 2 with 7B, 13B, and 70B parameters. We have also trained 34B variants, which we report on in this paper but are not releasing.§In this work, we develop and release Llama 2, a collection of pretrained and fine-tuned large language models (LLMs) ranging in scale from 7 billion to 70 billion parameters. Our fine-tuned LLMs, called Llama 2-Chat, are optimized for dialogue use cases. Our models outperform open-source chat models on most benchmarks we tested, and based onour human evaluations for helpfulness and safety, may be a suitable substitute for closed source models. We provide a detailed description of our approach to fine-tuning and safety improvements of Llama 2-Chat in order to enable the community to build on our work and contribute to the responsible development of LLMs.用户问:
how many parameters does llama 2 have?如果已知信息不包含用户问题的答案,或者已知信息不足以回答用户的问题,请直接回复"我无法回答您的问题"。
请不要输出已知信息中不包含的信息或答案。
请用中文回答用户问题。===回复===
Llama 2有7B, 13B和70B参数。

总结

本文我们对关键字检索做了讲解以及从实战的角度做了讲解。

首先我们应该认识到RAG的核心在于外部知识库,这个外部知识库甚至可以是基于关系型数据库的sql查询。

而本文基于ES的关键字检索也是一个比较传统和基础的检索方式,他比较简单,也有它适用的场景

关键字检索的局限性

最关键的就在于:关键字检索可能会受到一些问题的影响,例如同义词、拼写错误等,这可能会导致一些相关的文档被漏掉或者一些不相关的文档被检索到。

关键字检索通常在简单的检索场景下使用,例如在搜索引擎中用户输入关键字进行网页检索。

=

最后,随着RAG的发展,单纯的关键字检索或者向量检索都很难满足我们面临的复杂场景,了解关键字检索是为了后面更好的了解混合检索

=

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/48286.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

AI App Store-AI用户评价-多维度打分对比pk-AI社区

C端用户、创作者、AI达人们在选择众多国内外AI厂商的服务时候往往感到一头雾水&#xff0c;那么多功能接近的AI应用(智能对话类、文档总结类、文生图、AI搜索引擎) 究竟在不同用户需求场景下表现怎么样。大部分人如果有需求都会所有平台都尝试一遍&#xff0c;比如一个博主生成…

Linux内网离线用rsync和inotify-tools实现文件夹文件单向同步和双向同步

lsyncd实现方式可参考&#xff1a;https://www.jianshu.com/p/c075ccf89516 安装文件下载&#xff1a;相关文件下载 rsync默认都有&#xff0c;所以没有提供。 服务端和客户端均操作 服务端&#xff1a;双向同步其实都是服务端&#xff0c;只是单向同步时稍有区别 客户端&am…

C++自定义字典树结构

代码 #include <iostream> using namespace std;class TrieNode { public:char data;TrieNode* children[26];bool isTerminal;TrieNode(char ch){data ch;for (int i 0; i < 26; i){children[i] NULL;}isTerminal false;} }; class Trie { public:TrieNode* ro…

Android、Java反编译工具JADX

目录 介绍 主要特点: jadx-gui特性: 下载地址 使用 介绍 jadx - Dex to Java反编译器 用于从Android Dex和Apk文件生成Java源代码的命令行和GUI工具 请注意,在大多数情况下,jadx不能100%反编译所有的代码,所以会出现错误。 有关变通方法,请参阅故障排除指南。 目前…

返回倒数第 k 个节点 - 力扣(LeetCode)

面试题 02.02. 返回倒数第 k 个节点 - 力扣&#xff08;LeetCode&#xff09; /*** Definition for singly-linked list.* struct ListNode {* int val;* struct ListNode *next;* };*/int kthToLast(struct ListNode* head, int k) {struct ListNode* fastnode head…

git面面观,面试题,常见问题

1. 简述什么是Git &#xff1f; Git是一款分布式源代码管理工具(版本控制工具) 。 Git得其数据更像是一系列微型文件系统的快照。使用Git&#xff0c;每次提交或保存项目状态时&#xff0c;Git基本上都会记录当时所有文件的外观&#xff0c;并存储对该快照的引用。为了提高效…

Prompt工程:与AI聊天机器人更好地交流

Prompt工程:与AI聊天机器人更好地交流 1. 清楚地说明你想要什么2. 告诉AI它现在是谁3. 一步一步来4. 给AI一些例子5. 让AI检查自己的回答6. 把AI当作你的小助手7. 让AI帮你想主意8. 让AI告诉你它需要知道什么9. 教AI一步一步思考结语 大家好!今天我们来聊聊如何跟AI聊天机器人更…

互三群危害?如何才能正确上热榜。

前言 攀登热门榜单之巅&#xff0c;历来是才华与智慧较量的舞台&#xff0c;策略与努力的结晶。然而&#xff0c;在这片看似光鲜的网络世界里&#xff0c;也潜藏着不为人知的暗流——“互三群”的歪风邪气。揭露其真面目&#xff0c;以正网络风气&#xff0c;是每一位网络创作…

基于区块链技术的中药饮片代煎配送服务与监管平台

业务背景 近年来&#xff0c;随着公众对中医药青睐有加&#xff0c;中药代煎服务作为中医药现代化的重要一环&#xff0c;在全国各地蓬勃兴起。鉴于传统煎煮方式的繁琐耗时&#xff0c;医疗机构纷纷转向与第三方中药饮片企业合作&#xff0c;采用集中代煎模式。这些第三方煎药中…

Proactor模型

文章目录 概述1. 异步I/O操作2. 事件通知3. 事件处理函数4. 事件循环5. 多线程支持6. 非阻塞I/O7. 可扩展性8. 错误处理9. 资源管理10. 编程复杂性11. 应用场景流程图 结论 概述 Proactor模型是一种基于异步I/O操作的事件驱动编程模型&#xff0c;主要用于处理并发的I/O事件&a…

冒泡排序(数组作为函数参数)

什么是冒泡排序&#xff1f; 冒泡排序&#xff08;Bubble Sort&#xff09;也是一种简单直观的排序算法。它重复地走访过要排序的数列&#xff0c;一次比较两个元素&#xff0c;如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换&#xff0c;…

【Unity】RPG2D龙城纷争(十五)特殊加成型要诀

更新日期:2024年7月22日。 项目源码:第五章发布(正式开始游戏逻辑的章节) 索引 简介一、特殊加成型要诀基类二、扩充要诀数据集三、移动寻路时,应用特殊加成效果四、攻击寻路时,应用特殊加成效果五、攻击别人时,应用特殊加成效果六、被别人攻击时,应用特殊加成效果七、…

docker--容器数据进行持久化存储的三种方式

文章目录 为什么Docker容器需要使用持久化存储1.什么是Docker容器&#xff1f;2.什么是持久化存储&#xff1f;3.为什么Docker容器需要持久化存储&#xff1f;4.Docker如何实现持久化存储&#xff1f;(1)、Docker卷(Volumes)简介适用环境:使用场景:使用案例: (2)、绑定挂载&…

pycharm+pytorch2.3.1安装

成功运行 Anaconda简介 Anaconda 就是可以便捷获取包且对包能够进行管理&#xff0c;同时对环境可以统一管理的发行版本。Anaconda包含了conda、Python在内的超过180个科学包及其依赖项。 Anaconda安装 去官网地址下载 Download Anaconda Distribution | Anaconda​www.ana…

PHP常量

PHP 常量是在脚本执行期间其值不会改变的量。它们通常用于存储不经常改变的值&#xff0c;如配置选项、数据库连接信息等。在 PHP 中&#xff0c;常量与变量不同&#xff0c;一旦定义就不能被重新定义或取消定义&#xff08;直到脚本执行结束&#xff09;。下面是关于 PHP 常量…

SpringBoot启动原理详解

透彻理解SpringBoot启动原理&#xff08;一&#xff09; 一张Spring启动顺序图我们对Spring启动原理有多少理解呢一起看一下Spring有那些扩展点和启动过程有关通过打印日志学习Spring的执行顺序实例化和初始化的区别Spring重要扩展点的启动顺序1.BeanFactoryPostProcessor2.实例…

python3.10.4——Windows环境安装

python下载官网&#xff1a;https://www.python.org/downloads/ 如果安装在C盘&#xff0c;需要右键→选择“以管理员身份运行” 勾选2个按钮&#xff0c;选择自定义安装 全部选择&#xff0c;点击Next 更改安装路径 命令行检查python是否安装成功&#xff1a; 出现版本号说明…

内存泄漏详解

文章目录 什么是内存泄漏内存泄漏的原因排查及解决内存泄漏避免内存泄漏及时释放资源设置合理的变量作用域及时清理不需要的对象避免无限增长避免内部类持有外部类引用使用弱引用 什么是内存泄漏 内存泄漏是指不使用的对象持续占有内存使得内存得不到释放&#xff0c;从而造成…

【Hot100】LeetCode—416. 分割等和子集

目录 题目1- 思路2- 实现⭐152. 乘积最大子数组——题解思路 3- ACM 实现 题目 原题连接&#xff1a;416. 分割等和子集 1- 思路 理解为背包问题 思路&#xff1a; 能否将均分的子集理解为一个背包&#xff0c;比如对于 [1,5,11,5]&#xff0c;判断能否凑齐背包为 11 的容量…

面试场景题系列--(1)如果系统的 QPS 突然提升 10 倍该怎么设计?--xunznux

1. 如果系统的 QPS 突然提升 10 倍该怎么设计&#xff1f; 1.1 硬件的扩展微服务的拆分 如果所有的业务包括交易系统、会员信息、库存、商品等等都夹杂在一起&#xff0c;当流量一旦起来之后&#xff0c;单体架构的问题就暴露出来了&#xff0c;机器挂了所有的业务就全部无法…