检索增强生成RAG系列6--RAG提升之查询结构化(Query Construction)

系列5中讲到会讲解3个方面RAG的提升,它们可能与RAG的准确率有关系,但是更多的它们是有其它用途。本期来讲解第二部分:查询结构化(Query Construction)。在系列3文档处理中,我们着重讲解了文档解析,但是我们说的文档都是大部分是非结构化的文档或者说它就是以一个文档的形式存储。而现实中我们很多有价值的数据可能以结构化(关系型数据库、图形数据库等)或者半结构(关系型数据库、文档数据库等)的形式存储中,并且这些数据一般都是存储于特定数据库,那么如果数据存储在结构化或者半结构化中,我们RAG又该如何与之配合。这一章就着重来讲讲结构化查询(Query Construction)

目录

  • 1 查询结构化(Query Construction)
  • 2 Text-to-metadata-filter
  • 3 Text-to-SQL
  • 4 Text-to-Cypher
  • 5 Text-to-SQL+ Semantic

1 查询结构化(Query Construction)

现实中我们很多有价值的数据可能以结构化(关系型数据库、图形数据库等)或者半结构(关系型数据库、文档数据库等)的形式存储中,并且这些数据一般都是存储于特定数据库,同时数据库提供结构化的查询功能,使用其结构化查询(比如SQL等)比使用向量化查询更为准确。那这时候如果我们RAG想要去查询这些数据,就不是将数据向量化后再去查询,而是利用大模型将用户问题转换为结构化查询,再通过结构化查询去数据库查询结果,最后利用结果回答用户问题。下图流程可以让你明显感受不同之处:

在这里插入图片描述

我们将不同结构化或者半结构化查询归纳如下表,下面也是逐一讲解各个方法

方法数据源
Text-to-metadata-filter向量数据库
Text-to-SQL关系型数据库
Text-to-Cypher图形数据库
Text-to-SQL+ Semantic关系型+向量混合数据库

2 Text-to-metadata-filter

第一个要利用大模型将用户问题转换为结构化查询的依旧是向量数据库,但是这里并非做向量查询,而是很多向量存储其实都配备了元数据过滤功能,这些元数据其实就是结构化存储,因此需要过滤的是存储在向量数据库的元数据

这里以查询ChromaDB的metadata为例,做一个demo代码演示。在运行代码之前我们需要做以下前置条件

  • 这里采用智谱AI的API接口,因此可以先去申请一个API KEY(当然你使用其它模型也可以,目前智谱AI的GLM4送token,就拿它来试验吧)
  • 下载m3e-base的embedding模型
  • 给一个文档目录,里面放入一个文档即可,文档内容不限
import os
from typing import List
from langchain_openai import ChatOpenAI
from langchain_core.documents import Document
from langchain_community.vectorstores import Chroma
from langchain_core.prompts import ChatPromptTemplate
from langchain_huggingface import HuggingFaceEmbeddings
from langchain_core.pydantic_v1 import BaseModel, Field
from langchain_core.runnables import RunnablePassthrough
from langchain_community.document_loaders import DirectoryLoader# 前置工作1:文档存储,给文档设置author属性
encode_kwargs = {"normalize_embeddings": False}
model_kwargs = {"device": "cuda:0"}
embeddings = HuggingFaceEmbeddings(model_name='/root/autodl-tmp/model/AI-ModelScope/m3e-base',  # 换成自己的embedding模型路径model_kwargs=model_kwargs,encode_kwargs=encode_kwargs
)
if os.path.exists('VectorStore'):db = Chroma(persist_directory='VectorStore', embedding_function=embeddings)
loader = DirectoryLoader("/root/autodl-tmp/doc")  # 换成自己的文档路径
documents = loader.load()
# 这里假设设置一个author作者的属性
documents[0].metadata["author"] = "刘震云"
database = Chroma.from_documents(documents, embeddings, persist_directory="VectorStore")
database.persist()# 前置工作2:创建llm
llm = ChatOpenAI(temperature=0.95,model="glm-4",openai_api_key="你的API KEY",openai_api_base="https://open.bigmodel.cn/api/paas/v4/"
)# 前置工作3:为了将用户问题转换为结构化查询,使用LangChain可以通过Pydantic类轻松指定所需的function call schema:
# 这里假设书籍有2个字段匹配,一个是内容content_search,一个是作者author_search
class BookSearch(BaseModel):content_search: str = Field(...,description=("书籍文本内容进行相似性搜索"),)author_search: str = Field(...,description=("书籍作者,仅在使用人名查询时,才进行关键字匹配,其它情况不使用"),)# 第一步:让模型将用户问题转换成与查询字段匹配的格式
system = """你是将用户问题转换为数据库查询的专家。
你可以访问关于的书籍数据库。
给定一个问题,返回一个优化为检索最相关结果的数据库查询。"""
prompt = ChatPromptTemplate.from_messages([("system", system),("human", "{question}"),]
)# 绑定前面定义的输出数据格式,意思就是要求模型根据类结构返回数据。
structured_llm = llm.with_structured_output(BookSearch)
# 定义chain
query_analyzer = {"question": RunnablePassthrough()} | prompt | structured_llm
print(query_analyzer.invoke("作家刘震云的书"))# 第二步:转换匹配,拼接向量查询条件查询Chroma
def retrieval(search: BookSearch) -> List[Document]:if search.author_search is not None:_filter = {"author": {"$eq": search.author_search}}else:_filter = Nonereturn database.similarity_search(search.content_search, filter=_filter)retrieval_chain = query_analyzer | retrieval
# 未查询到结果
print(retrieval_chain.invoke("作家莫言的书"))
# 查询到结果
print(retrieval_chain.invoke("作家刘震云的书"))

3 Text-to-SQL

关于关系型数据库就不用在累赘了,但是使用大模型生成SQL可能会出现以下问题:

  • 幻觉:大模型容易对虚构的表或字段产生“幻觉”,从而产生无效的查询。方法必须将这些大模型 建立在现实中,确保它们生成与实际数据库模式一致的有效 SQL。
  • 用户错误:文本转 SQL 方法应能够防止用户拼写错误或用户输入中可能导致无效查询的其他不规范情况。

对于以上问题,有不少的解决方案供参考:

  • 数据库描述:要生成SQL查询,必须向大模型提供数据库的准确描述。常见的做法:为大模型提供每张表的CREATE TABLE描述,包括列名、类型等,然后再给出几个SELECT语句的示例。
  • Few-shot样例:在prompt中添加question-query的几个样例可以提高query生成的准确性。在prompt中简单的添加标准的静态示例指导大模型如何基于question创建query。
  • 错误处理:当遇到错误时,利用工具(例如SQL Agent)修复错误。
  • 查找专有名词中的拼写错误:当查询名称等专有名词时,用户可能会不小心写错。我们允许大模型Agent根据向量库搜索正确的名称,向量库在SQL数据库中存储相关专有名词的正确拼写。

下面以查询sqlite数据库为例子,,做一个demo代码演示。在运行代码之前我们需要做以下前置条件

  • 这里采用智谱AI的API接口,因此可以先去申请一个API KEY(当然你使用其它模型也可以,目前智谱AI的GLM4送token,就拿它来试验吧)
  • 准备一个本地sqlite数据库,并创建数据库test.db,以及表和存入数据,脚本如下

sqllite3 test.db
create table student(id Integer,name char,score Integer);
insert into student values(1,“student1”,100);
insert into student values(2,“student2”,80);
insert into student values(3,“student3”,50);

代码如下:


from langchain_openai import ChatOpenAI
from langchain_core.prompts import PromptTemplate
from langchain.chains import create_sql_query_chain
from langchain_community.utilities import SQLDatabase# 前置工作1:创建llm
llm = ChatOpenAI(temperature=0.01,model="glm-4",openai_api_key="你的API KEY",openai_api_base="https://open.bigmodel.cn/api/paas/v4/"
)# 前置工作2:改写了一下prompt(因为默认的prompt似乎不适合智谱AI)
_sqlite_prompt = """你是一个SQLite专家。给定一个输入问题,首先创建一个语法正确的SQLite查询来运行,然后查看查询的结果并返回输入问题的答案。
除非用户在问题中指定要获取的特定数量的示例,否则根据SQLite使用LIMIT子句查询最多{top_k}个结果。您可以对结果进行排序,以返回数据库中信息量最大的数据。
永远不要查询表中的所有列。您必须只查询回答问题所需的列。将每个列名用双引号(")括起来,以表示它们为分隔符。
注意,只使用您可以在下面的表中看到的列名。注意不要查询不存在的列。另外,要注意哪个列在哪个表中。
如果问题涉及“今天”,注意使用date('now')函数来获取当前日期
使用以下格式:问题:问题
SQLQuery:要运行的SQL查询
答案:最终答案只使用以下表格:
{table_info}问题: {input}
"""SQLITE_PROMPT = PromptTemplate(input_variables=["input", "table_info", "top_k"],template=_sqlite_prompt,
)db = SQLDatabase.from_uri("sqlite:///sqlite-autoconf-3460000/test.db")  # 你的数据库地址
# 使用create_sql_query_chain的方式,langchain还有agent方式,大家可以去探索使用
chain = create_sql_query_chain(llm, db, SQLITE_PROMPT)
response = chain.invoke({"question": "总共有多少学生"})
print(response)

4 Text-to-Cypher

对于图形数据库的作用,一般就是表示实体之间的关系,适合于知识图谱、人际关系等应用场景。
下面以查询neo4j图数据库为例子,,做一个demo代码演示。在运行代码之前我们需要做以下前置条件

  • 这里采用智谱AI的API接口,因此可以先去申请一个API KEY(当然你使用其它模型也可以,目前智谱AI的GLM4送token,就拿它来试验吧)
  • 准备一个本地neo4j数据库,并创建数据库test_relationship,录入一些作家、书籍以及相关关系
from langchain.chains import GraphCypherQAChain
from langchain_community.graphs import Neo4jGraph
from langchain_openai import ChatOpenAI# 前置工作1:创建llm
llm = ChatOpenAI(temperature=0.95,model="glm-4",openai_api_key="你的API KEY",openai_api_base="https://open.bigmodel.cn/api/paas/v4/"
)# 前置工作2:准备好图形数据库
graph = Neo4jGraph(url="bolt://localhost:7687", username="test_relationship", password="***"
)
graph.refresh_schema()# 使用langchain的GraphCypherQAChain进行封装,这里面的提示效果对于智谱AI来说一般般,没调试出来最终结果
chain = GraphCypherQAChain.from_llm(llm, graph=graph, verbose=True)print(chain.run("谁是一地鸡毛的作者?"))

5 Text-to-SQL+ Semantic

现在混合类型(结构化和非结构化)数据存储越来越普遍。向关系数据库添加向量支持是支持混合检索方法的关键推动因素。比如PostgreSQL 的开源 pgvector 扩展将 SQL 的表现力与语义搜索提供的对语义的细致入微的理解相结合。那么在如何将用户问题转换为这种混合类型数据库就提出了更高的挑战。
在对这种类型数据库,更加复杂的query生成,需要创建few-shot prompt或者增加query-checking等环节来提升准确度,这里就不举例子,有兴趣深入的同学可以搜索研究。

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

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

相关文章

C++ dll导出类的方法

要在C动态库中导出类,可以使用以下步骤: 定义一个类并实现其成员函数。在类的声明前加上__declspec(dllexport)标记(Windows平台)或__attribute__((visibility("default")))标记(Linux平台)&…

C语言学习笔记--第一个程序

第一个C语言程序 #include<stdio.h> //引用输入输出头文件&#xff0c;每一次都需要引用这个文件 //.h是头文件 // .c是源文件 // .cpp是C源文件&#xff0c;兼容C //C的第一个程序 // 行注释&#xff08;只能注释这一行&#xff09; /*块注释 */ int main() {printf(&…

能保存到相册的风景视频在哪下载?下载风景视频网站分享

在当今以视觉为核心的时代&#xff0c;高清美丽的风景视频不仅能够丰富我们的日常生活&#xff0c;还能提供心灵上的慰藉。无论是为了制作视频项目&#xff0c;还是仅仅想要珍藏一些精美的风景画面&#xff0c;获取高质量的风景视频素材显得尤为重要。许多人可能会问&#xff1…

PTrade量化软件常见问题整理系列2

一、研究界面使用get_fundamentals函数报错&#xff1a;error_info:获取token失败&#xff1f; 研究界面使用get_fundamentals函数报错&#xff1a;error_info:获取token失败&#xff1f; 1、测试版本202202.01.052&#xff0c;升级202202.01.051版本后&#xff0c;为了解决不…

在虚拟仿真中学习人工智能,可以达到什么目标?

人工智能已经成为引领社会创新的关键力量&#xff0c;想要在这个充满机遇的领域中脱颖而出&#xff0c;掌握扎实的专业技能和积累丰富的实践经验至关重要。然而&#xff0c;许多学习者在追求这一目标的过程中面临着几个主要问题&#xff1a;专业技术掌握有难度、实践经验积累存…

linux中awk,sed, grep使用

《linux私房菜》这本书中将sed和awk一同归为行的修改这一点&#xff0c;虽然对&#xff0c;但不利于实际处理问题时的思考。因为这样的话&#xff0c;当我们实际处理问题时&#xff0c;遇到比如说统计文本打印内容时&#xff0c;我们选择sed还是awk进行处理呢&#xff1f; 也因…

​香橙派AIpro测评:usb鱼眼摄像头的Camera图像获取

一、前言 近期收到了一块受到业界人士关注的开发板"香橙派AIpro",因为这块板子具有极高的性价比&#xff0c;同时还可以兼容ubuntu、安卓等多种操作系统&#xff0c;今天博主便要在一块832g的香橙派AI香橙派AIpro进行YoloV5s算法的部署并使用一个外接的鱼眼USB摄像头…

React 中如何使用 Monaco

Monaco 是微软开源的一个编辑器&#xff0c;VSCode 也是基于 Monaco 进行开发的。如果在 React 中如何使用 Monaco&#xff0c;本文将介绍如何在 React 中引入 Monaco。 安装 React 依赖 yarn add react-app-rewired --dev yarn add monaco-editor-webpack-plugin --dev yarn…

学习和发展人工智能:新兴趋势和成功秘诀

人工智能(AI)继续吸引组织&#xff0c;因为它似乎无穷无尽地提高生产力和业务成果。在本博客中&#xff0c;了解学习和发展(L&D)部门如何利用人工智能改进流程&#xff0c;简化工作流程&#xff1f; 学习与发展(L&D)部门领导开始探索如何提高和支持人工智能能力的劳动…

1-认识网络爬虫

1.什么是网络爬虫 ​ 网络爬虫&#xff08;Web Crawler&#xff09;又称网络蜘蛛、网络机器人&#xff0c;它是一种按照一定规则&#xff0c;自动浏览万维网的程序或脚本。通俗地讲&#xff0c;网络爬虫就是一个模拟真人浏览万维网行为的程序&#xff0c;这个程序可以代替真人…

工业智能网关在现代工业生产中的重要性-天拓四方

工业智能网关是一款具备挖掘工业设备数据并接入到自主开发的云平台的智能嵌入式网络设备。它具备数据采集、协议解析、边缘计算&#xff0c;以及4G/5G/WiFi数据传输等功能&#xff0c;并能接入工业云平台。这种网关不仅支持采集PLC、传感器、仪器仪表和各种控制器&#xff0c;还…

iss文件本机可以访问,其他电脑无法访问解决

1.搜索的时候有很多答案&#xff0c;总结就是2种 引用来自这位大佬的博客跳转 2.我实际解决了的方法 将这里的ip地址修改为你局域网wifi的ip 如何看自己wifi的ip&#xff0c;大家自行百度&#xff01;

linux中与网络有关的命令

本文的命令总览 ifconfig命令 在 Linux 系统中&#xff0c;ifconfig 命令用于配置和显示网络接口的信息&#xff0c;包括 IP 地址、MAC 地址、网络状态等。同时我们也可以利用ifconfig 命令设置网络接口对应的ip地址&#xff0c;子网掩码等 当你使用 ifconfig 命令时&#xf…

06-6.3.3 图的深度优先遍历

&#x1f44b; Hi, I’m Beast Cheng &#x1f440; I’m interested in photography, hiking, landscape… &#x1f331; I’m currently learning python, javascript, kotlin… &#x1f4eb; How to reach me --> 458290771qq.com 喜欢《数据结构》部分笔记的小伙伴可以…

UE5.4新功能 - Texture Graph上手简介

TextureGraph是UE5.4还在实验(Experimental)阶段的新功能&#xff0c;该功能旨在材质生成方面达到类似Subtance Designer的效果&#xff0c;从而程序化的生成一些纹理。 本文就来简要学习一下。 1.使用UE5.4或以上版本&#xff0c;激活TextureGraph插件 2.内容视图中右键找到…

万字 | 菊花厂C语言编程10大规范

本文是大厂C代码规范&#xff0c;有点长&#xff0c;有时间可以学习下。 1 代码总体原则 1、清晰第一 清晰性是易于维护、易于重构的程序必需具备的特征。代码首先是给人读的&#xff0c;好的代码应当可以像文章一样发声朗诵出来。 目前软件维护期成本占整个生命周期成本的…

【INTEL(ALTERA)】为什么Nios® II构建流程报告无法在 Windows WSL 上确定程序大小?

目录 说明 解决方法 说明 由于英特尔 Quartus Prime 专业版软件 19.3 版中的 nios2-elf-stackreport 实用程序出现问题&#xff0c;nios2-elf-stackreport 实用程序确实如此 不报告程序大小或堆栈堆栈大小。 解决方法 要解决此问题&#xff0c;编辑 nios2-stackreport.pl …

1)并发事务的问题

1) 并发事务的问题&#xff1f; &#xff08;1&#xff09;读“脏”数据 事务T1修改数据后T2读取了该数据&#xff0c;但是T1撤消了修改&#xff0c; 事务T1进行了回滚&#xff0c;导致事务T2读取的数据与数据库中的数据不一致。&#xff08;2&#xff09;丢失修改 两个事务…

面向对象(Java)

构造方法只能在对象实例化的时候调用 this可以作为方法参数&#xff0c;表示调用方法的当前对象 this可以作为方法返回值&#xff0c;表示返回当前对象 封装 通过方法访问数据&#xff0c;隐藏类的实现细节 static&#xff1a;类对象共享&#xff0c;类加载时产生&#xff0c;…

Qt 实战(7)元对象系统 | 7.2、MOC(Meta-Object Compiler 元对象编译器)

文章目录 一、MOC1、MOC的作用2、MOC的工作原理3、MOC的使用方式4、MOC生成的文件结构 前言&#xff1a; 在Qt框架中&#xff0c;MOC&#xff08;Meta-Object Compiler&#xff09;是一个至关重要的工具&#xff0c;它负责处理Qt特有的元对象系统&#xff08;Meta-Object Syste…