检索增强生成RAG系列6--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 = None
    return 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.mfbz.cn/a/764441.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于X86+FPGA+AI的切割机控制、六轴机器人控制方案

一、智能设备控制 应用场景 智能制造(Intelligent Manufacturing, IM)是一种由智能机器和人类专家共同组成的人机一体化智能系统,它在制造过程中能进行智能活动,诸如分析、推理、判断、构思和决策等。通过人与智能机器的合作共事,去扩大、延…

从零到百万用户的扩展之路

写在前面: 此博客内容已经同步到我的博客网站,如需要获得更优的阅读体验请前往https://mainjaylai.github.io/Blog/blog/system/design-system 设计一个支持数百万用户的系统是极具挑战性的,它是一段需要持续优化和不断改进的旅程。在这篇博客中,我们将构建一个支持单个用…

开发数字药店APP实战:互联网医院系统源码详解

本篇文章,笔者将深入探讨如何开发一个功能完善的数字药店APP,并详细解析互联网医院系统的源码实现。 一、数字药店APP的需求分析 应具备以下基本功能: 用户注册与登录 药品搜索与浏览 在线下单与支付 订单管理 健康咨询与远程医疗 个人…

人脉社群平台微信小程序系统源码

🌟【解锁人脉新纪元:探索人脉社群平台小程序】🌟 🚀【开篇:为什么我们需要人脉社群平台小程序?】🚀 在这个快节奏的时代,人脉不再是简单的名片交换,而是通往成功与机遇…

发电机保护屏的作用及其重要性

发电机保护屏的作用及其重要性 发电机保护屏是电力系统中的重要组成部分,它负责监测和控制发电机的运行状态,确保发电机在正常运行和故障情况下都能得到及时、准确的保护。负责监测和控制发电机运行状态,确保及时准确的保护。它由显示屏、控制…

Nacos 2.x 系列【18】多网卡 IP 配置

文章目录 1. 前言2. 服务端3. 客户端 1. 前言 个人电脑或者服务器,存在多网卡环境时,Nacos 可能会存在IP不正确问题。 2. 服务端 Nacos 服务在启动的时候需要选择运行时使用的IP或者网卡,在启动时,可以看到打印了IP&#xff1a…

2024年【四川省安全员A证】试题及解析及四川省安全员A证模拟考试

题库来源:安全生产模拟考试一点通公众号小程序 四川省安全员A证试题及解析根据新四川省安全员A证考试大纲要求,安全生产模拟考试一点通将四川省安全员A证模拟考试试题进行汇编,组成一套四川省安全员A证全真模拟考试试题,学员可通…

如何在 Odoo 16 中将按钮添加到所有表单视图的操作按钮

在 Odoo 中,操作按钮是关键组件,允许用户触发与特定表单视图相关的特定操作或工作流。这些按钮策略性地放置在用户界面中,可简化操作并提高用户效率。它们可以自定义以执行各种任务,例如创建记录、更新信息或启动特定流程。 操作…

万界星空科技服装行业MES系统解决方案

据调查,我国大多数服装厂目前存在两大问题: 第一,是生产设备先进,但管理模式落后,仍采用手工管理模式,未实现信息化; 第二,仍有大量的人工站,短时间内难以用设备代替&a…

如何查看xpf文件

xpf文件是什么 XPF文件是“XML Paper Specification File”的缩写,它是一种文件保存格式,具有以下特点和相关信息: 一、定义与用途 定义:XPF文件用于保留文档的固定布局,包括文本、图片以及其他文档元素的确切位置。…

软件工程实验

实验环境和需求 用户可以对相片进行按类别管理,用户可以设定不同的类别,然后上传照片到相应的类别中,并能进行照片的删除,注释 运行 运行并访问 localhost 8090,图片在数据库中的信息是D:/upgrade 后面的内容 se…

Emacs之解决:java-mode占用C-c C-c问题(一百四十六)

简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 优质专栏:多媒…

一招解决 | IP地址访问怎么实现https

没有域名的情况下,使用IP地址实现HTTPS访问是可以的,但相比使用域名会有些许限制,需要通过部署专用于IP地址的SSL/TLS证书来实现。 IP地址实现HTTPS访问的过程与使用域名类似,但有几个关键的区别。以下是使用IP地址实现HTTPS访问…

day62--若依框架(基础应用篇)

若依搭建 若依版本 官方 若依官方针对不同开发需求提供了多个版本的框架,每个版本都有其独特的特点和适用场景: 前后端混合版本:RuoYi结合了SpringBoot和Bootstrap的前端开发框架,适合快速构建传统的Web应用程序,其…

java周测总结(3)

1、什么是I0流? 是一串流动的字符,从先进先出的方式要求信息的通道。 2、什么是序列化?什么是反序列化? 序例化是将对象的状态存储到特定的存储介质中的过程反序例化是将特定的有合者公质中数据重新构建对象的过程。 3、Java中线程在哪个包下…

第57期|GPTSecurity周报

GPTSecurity是一个涵盖了前沿学术研究和实践经验分享的社区,集成了生成预训练Transformer(GPT)、人工智能生成内容(AIGC)以及大语言模型(LLM)等安全领域应用的知识。在这里,您可以找…

海思NNIE部署yolov5-shufflenet

1.简要说明 由于NNIE上transpose支持的顺序是固定的,shufflenet那种x=torch.transpose(x,1,2).contiguous() 的操作一般是不支持的。需要进行调整。 2.使用工程以及修改 使用的是开源工程:GitHub - Lufei-github/shufflev2-yolov5: shufflev2-yolov5:lighter, faster and ea…

vue根据文字长短展示跑马灯效果

介绍 为大家介绍一个我编写的vue组件 auto-marquee ,他可以根据要展示文本是否超出展示区域,来判断是否使用跑马灯效果,效果图如下所示 假设要展示区域的宽度为500px,当要展示文本的长度小于500px时,只会展示文本&…

maven 根据不同环境,走不同的实现(多种环境组合)

​ 原因: 线上程序同时支持人大金仓和mysql,且支持根据环境动态选择 java JCE 的实现方式前期已完成 springboot 从mysql 迁移人大金仓 -kingbase :https://blog.csdn.net/qq_26408545/article/details/137777602?spm1001.2014.3001.5502 …
最新文章