案例四:搭建检索增强生成RAG系统

本文介绍了检索增强生成(Retrieval-Augmented Generation, RAG)技术的概念,和如何搭建并使用检索增强生成RAG系统。

概念

大语言模型(LLM)在生成回复的准确性和实时性方面存在一定的局限性,因此不太适合直接应用于需要精确信息的客户服务或问答场景。为了解决这一问题,业界广泛采用了检索增强生成(Retrieval-Augmented Generation, RAG)技术,提升LLM的性能。这一技术显著提高了问答、摘要生成以及其他需要引用外部知识的自然语言处理(NLP)任务的质量。

RAG通过将大语言模型(如通义千问)与信息检索组件相结合,增强了模型生成答案的准确性和信息量。在处理用户查询时,RAG通过信息检索组件从知识库中寻找与查询相关的文档或信息片段,将这些检索到的内容与原始查询一起输入大语言模型后,模型能够利用现有的归纳生成能力,产生基于最新信息的、符合事实的回复,而无需对模型进行重新创建模型。

PolarDB部署的对话系统服务,通过集成大语言模型(LLM)和检索增强生成(RAG)技术,有效克服了LLM在准确性和实时性方面的局限,为多种问答场景提供了准确且信息丰富的响应。这种整合显著提升了自然语言处理任务的整体效能和用户体验。

RAG系统搭建流程架构图

搭建并使用检索增强生成RAG系统的整体流程示意图如下:

image

构建文档向量化和分词索引表

被检索的文档已存在数据库中

当需要被检索的文档已经存在数据库时,我们需要将文档向量化。

文档数据表

创建文档数据表SQL语句如下:

CREATE TABLE enterprise_context(
    file_id varchar(256) COMMENT '文本溯源索引',
    file_name varchar(256) COMMENT '标题中心内容',
    content text COMMENT '文本内容', 
    category_id varchar(128) COMMENT '类目信息',
    PRIMARY KEY (file_id)
);
插入文档数据

插入文档表数据的SQL语句如下:

INSERT INTO enterprise_context(file_id,file_name,content,category_id) VALUES
('doc1','PolarDB for AI简介','PolarDB for AI是基于PolarDB MySQL版的一个数据库内的分布式机器学习组件。其基于云原生的体系架构,通过SQL语句的方式提供了支持机器学习的一系列MLOps,包括:创建模型、查看模型状态、查看模型列表、模型评估和模型推理等能力;同时提供了一系列内置的机器学习和人工智能算法,包括:分类算法、回归算法和聚类算法等。基于MLOps和内置的模型,PolarDB for AI为数据驱动的智能应用提供了高效、可靠、方便的数据智能能力,打破了数据库和业务应用之间的系统墙,提供了基于数据库数据智能的一站式服务。','c1'),
('doc2','PolarDB for AI在搜索推荐中的应用','PolarDB for AI将传统的DB+AI的数据智能应用转变为一站式数据智能应用,从数据库服务于传统的数据工程师和算法工程师转变为DB+AI服务于业务工程师,直接与业务系统对接。基于PolarDB for AI的智能推荐算法和知识图谱技术,再结合阿里巴巴电商策略,为企业提供贯穿推荐能力的一站式服务,助力企业快速过渡冷启动过程。面向不同的业务场景定制个性化解决方案,持续提升核心业务能力,以实现业务营收增长。','c2')
说明

文本转向量化模型_polar4ai_text2vec支持将长篇文档分割成多个文本块,以便增加RAG文本检索的精确度。

文本数据需要切片处理
创建索引表

RAG索引表固定了参数名称和类型,具体表结构SQL语句如下:

/*polar4ai*/CREATE TABLE file_index_table(
  chunk_id varchar(265),
  chunk_content text_ik_smart, 
  file_id varchar(256),
  file_name varchar(256),
  category_id varchar(128),
  vecs vector_768, 
  PRIMARY KEY(chunk_id)
);

RAG索引表中的参数说明如下:

参数

说明

示例值

chunk_id

{file_id}-{chunk_order},对每一个切片文本设置的主键id,在同一文件内按序递增。

file1-1。

chunk_content

切片文本,使用分词器进行分词,此处可使用text_ik_smart(粗粒度拆分的词) / text_ik_max_word(细粒度拆分的词) 等分词器进行分词。

文本内容。

file_id

文件标识,用于溯源文本内容。

xxx.docx。

file_name

文件名、文件标题、与内容相关的语句(可选)。

中心内容。

category_id

用于限定文档搜索范围,精确匹配的类目ID。

c1。

vecs

切片向量,使用_polar4ai_text2vec模型将切片文本转为向量值。

说明

_polar4ai_text2vec为文本转向量化模型,目前仅支持输出768维向量。

[0.1, 0.2, ...]。

构建向量和分词索引

_polar4ai_text2vec为文本转向量化模型,目前仅支持输出768维向量。将enterprise_context中的文档数据向量化并保存到RAG索引表中,当设置to_chunk=1时,列chunk_idchunk_content将通过切片方法生成。

/*polar4ai*/SELECT chunk_id, chunk_content, file_id, file_name, category_id FROM predict(model _polar4ai_text2vec, SELECT content, file_id, file_name, category_id FROM enterprise_context) 
WITH (
  x_cols='content',
  primary_key='file_id',
  mode='async',
  vec_col='vecs',
  to_chunk=1,
  chunk_size=128,
  chunk_overlap=16
)
INTO file_index_table;

/*polar4ai*/SHOW TASK `your-task-id`;
/*polar4ai*/SELECT * FROM file_index_table;
文本数据无需切片处理
创建索引表

RAG索引表固定了参数名称和类型,具体表结构说明如下:

/*polar4ai*/CREATE TABLE file_index_table(
  file_id varchar(256),
  file_name varchar(256),
  chunk_content text_ik_smart,
  category_id varchar(128),
  vecs vector_768, 
  PRIMARY KEY(file_id)
);

RAG索引表中的参数说明如下:

参数

说明

示例值

file_id

文件标识,用于溯源文本内容。

xxx.docx。

file_name

文件名、文件标题与内容相关的语句(可选)。

中心内容。

chunk_content

文本内容,使用分词器进行分词,此处可使用text_ik_smart(粗粒度拆分的词) / text_ik_max_word (细粒度拆分的词)等分词器进行分词。

文本内容。

category_id

用于限定文档搜索范围,精确匹配的类目ID。

c1。

vecs

切片向量,使用_polar4ai_text2vec模型将切片文本转为向量值。

说明

_polar4ai_text2vec为文本转向量化模型,目前仅支持输出768维向量。

[0.1, 0.2, ...]。

构建向量和分词索引

_polar4ai_text2vec为文本转向量化模型,目前仅支持输出768维向量。将enterprise_context中的文档数据向量化并保存到RAG索引表中。

/*polar4ai*/SELECT chunk_content, file_id, file_name, category_id FROM predict(model _polar4ai_text2vec, SELECT content as chunk_content, file_id, file_name, category_id FROM enterprise_context) 
WITH (
  x_cols='chunk_content',
  primary_key='file_id',
  mode='async',
  vec_col='vecs'
)
INTO file_index_table;

/*polar4ai*/SHOW TASK `your-task-id`;
/*polar4ai*/SELECT * FROM file_index_table;

文本数据向量化,更多详细过程请参见:案例二:搭建文档检索系统

被检索的文档不存在数据库中

被检索的文档不在数据库中,我们会先将文档上传到数据库,并解析文档内容,再做文本向量化的工作。

创建文档知识库
  • 上传文档数据

    上传文档至数据库存储的SQL语句说明如下:

    /*polar4ai*/UPLOAD FILE docfile WITH (
        file_id='unique_file_id',
        file_type='.docx',
        src_file_location='your_file_url',
        dest_file_name='your_file_name.docx', 
        metadata='{}'
    );

    WITH()中的参数说明如下:

    说明

    src_file_location示例文档请参见Polar4AI-Introduction.docx

    参数

    说明

    示例值

    file_id

    文件主键(不可重复)。

    'Polar4AI'。

    file_type

    文件类型。

    '.docx'。

    src_file_location

    文件URL地址。

    'https://xxx.aliyuncs.com/Polar4AI-Introduction.docx'。

    dest_file_name

    目标文件名(可重复,不支持存储路径/)。

    'Polar4AI-Introduction'。

    metadata

    元数据,暂时保留。

    '{}'。

  • 查看已上传的文档

    查看已上传的文档的SQL语法如下,其中unique_file_id需替换为已通过UPLOAD FILE上传的文件ID。

    /*polar4ai*/SHOW FILES;
    /*polar4ai*/SHOW FILE `unique_file_id`;
  • 删除已上传的文档

    删除文档的SQL语法如下:

    /*polar4ai*/DROP FILE `unique_file_id`;
  • 创建文档元数据表

    在数据库中创建和更新元数据表,SQL语句如下:

    CREATE TABLE file_id_list(
        file_id varchar(256) PRIMARY KEY,
        action_type varchar(10),
        category_id varchar(128)
        # any data format ...
    );	
    
    INSERT INTO file_id_list(file_id, action_type, category_id, ...) VALUES ('unique_file_id', 'add', 'c1', ...);	

    文档元数据表中参数说明如下:

    参数

    说明

    示例值

    file_id

    UPLOAD FILE中指定的文件主键。

    'Polar4AI'。

    action_type

    需要对文件做的操作,可选值包括['add', 'delete'],当action_type为'add'时,在索引表中增加该文件相关内容,并重新计算索引值。当action_type为'delete'时,在索引表中删除该文件的相关内容。

    'add'

    'delete'

    ''。

    category_id

    该文件的类目标识。

    'c1'。

解析文件并构建向量和分词索引
  • 创建索引表

    向量和分词索引表固定了参数名称和类型,SQL语句如下:

    /*polar4ai*/CREATE TABLE file_index_table(
      chunk_id varchar(265),
      chunk_content text_ik_smart, 
      file_id varchar(256),
      file_name varchar(256),
      vecs vector_768, 
      PRIMARY KEY(chunk_id)
    );

    向量和分词索引表中参数说明如下:

    参数

    说明

    示例值

    file_id

    文件唯一标识,用于溯源文本内容。

    'Polar4AI'。

    file_name

    文件名、文件标题、与内容相关的语句。

    'Polar4AI-Introduction'。

    chunk_content

    切片文本,使用分词器进行分词,此处可使用text_ik_smart(粗粒度拆分的词) / text_ik_max_word(细粒度拆分的词)等分词器进行分词。

    文档文本内容。

    vecs

    切片向量,使用_polar4ai_text2vec模型将切片文本转为向量。

    [0.1, 0.2, ...]。

    chunk_id

    {file_id}-{chunk_order},对每一个chunk设置的主键id,在同一文件内按序递增。

    'Polar4AI-1'。

  • 根据文档ID构建索引表

    从文档元数据表中选取需要进行解析和构建索引的file_id,解析文档内容并使用_polar4ai_text2vec模型的predict方法插入索引表中:

    /*polar4ai*/SELECT chunk_id, file_id, file_name, chunk_content FROM predict(model _polar4ai_text2vec, SELECT file_id FROM file_id_list) 
    WITH (
        x_cols='chunk_content',
        primary_key='file_id',
        mode='async',
        resource='file',
        to_chunk=1,
        headers_to_split_on=-1,
        chunk_size=512,
        chunk_overlap=64,
        separator=''
    )
    INTO file_index_table;	

    (可选)调整索引表内容。

    根据文档元数据表file_id_list中的action_type,您可以指定增加或删除文档内容。将文档的类目标识category_id作为参数输入时,类目标识信息将存入向量与分词索引表,您可以通过设置RAG查询参数中的category_ids,限定文本检索的范围。示例如下:file_id_list中指明操作类型,添加或删除文档。

    /*polar4ai*/SELECT chunk_id, file_name, chunk_content, category_id FROM predict(model _polar4ai_text2vec, SELECT file_id, action_type, category_id FROM file_id_list) 
    WITH (
        x_cols='chunk_content',
        primary_key='file_id',
        mode='async',
        resource='file',
        to_chunk=1,
        headers_to_split_on=-1,
        chunk_size=512,
        chunk_overlap=64,
        separator=''
    ) INTO file_index_table;

    _polar4ai_text2vec为文本转向量化模型,目前仅支持输出768维向量。WITH()中的参数说明如下:

    参数

    说明

    示例值或范围

    x_cols

    用于存储文本的字段。

    chunk_content。

    primary_key

    文件列表的主键,文档ID。

    id。

    mode

    文档数据的写入模式。目前仅支持async(异步)模式。

    async。

    resource

    在文件解析流程中为file模型。

    file。

    to_chunk

    文件中的文本是否进行切片。

    0或1。

    headers_to_split_on

    to_chunk=1时按照指定标题层级进行切分

    • headers_to_split_on值为-1时,对文件中所有层级标题进行分块。

    • headers_to_split_on值为x时,对文件中小于等于x层级的标题进行分块。

    -1 ≤ x ≤ 6为整数值。

    chunk_size

    文本切分的最大长度。

    chunk_size ≥ 50。

    chunk_overlap

    相邻两个切片之间的重叠字符数量。

    chunk_overlap ≤ chunk_size。

    separator

    分块内切片之间的分隔符。

    '' /','/','等。

  • 展示task状态和结果

    taskStatusfinish时表示成功完成文件解析任务,在索引表中可以查询到切片信息。

    /*polar4ai*/SHOW TASK `task-id`;
    /*polar4ai*/SELECT * FROM file_index_table LIMIT 10;
  • 删除索引表中的记录
    /*polar4ai*/DELETE FROM file_index_table WHERE file_id = 'unique_file_id';

检索增强生成RAG

您可以执行以下SQL语句在线使用RAG功能,查询返回模型生成结果、召回文本、对应文件名、向量得分、分词得分、混合得分的值:

/*polar4ai*/SELECT * FROM PREDICT(MODEL _polar4ai_rag, SELECT '问题内容') WITH (
    index_name='file_index_table',
    primary_key='chunk_id',
    vec_top_k=5,
    vec_score_threshold=0.0,
    pos_top_k=3,
    pos_score_threshold=0.0,
    use_vec=1,
    use_pos=1,
    hybrid_type=0,
    hybrid_score=0.8,
    ranker_model='',
    category_ids='',
    file_id=''
);

WITH()中的参数说明如下:

参数

说明

示例值或范围

index_name

索引表名称。

index_table。

primary_key

索引表主键名称。

chunk_id、file_id。

vec_top_k

保留前K个向量检索相关度得分最高的结果。

vec_top_k ≥ 0。

vec_score_threshold

向量检索得分的阈值,去掉得分低于阈值的结果。

vec_score_threshold ≥ 0。

pos_top_k

保留前K个分词检索相关得分最高的结果。

pos_top_k ≥ 0。

pos_score_threshold

分词检索得分的阈值,去掉得分低于阈值的结果。

pos_score_threshold ≥ 0。

use_vec

是否使用向量检索,1表示是,0表示否,默认为1。

0或1。

use_pos

是否使用分词检索,1表示是,0表示否,默认为1。

0或1。

hybrid_type

混合得分类型:

0表示将两个结果取并集,排序得分通过hybrid_score计算。

1表示取并集,但只看位置,向量检索优先。

2表示取两个结果的交集,排序得分按hybrid_score计算。

0或1或2。

hybrid_score

混合得分的比例为:hybrid_score*vec_score + (1-hybrid_score)*pos_score。

0 ≤ hybrid_score ≤ 1。

ranker_model

表示创建模型后的ranker模型名称,默认为空。

''。

category_ids

用英文逗号分隔category_id。

'c1, c2'。

file_id

根据ID指定文件生成回答.

'Polar4AI'。