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

本文将为您介绍检索增强生成(Retrieval-Augmented Generation,RAG)的概念,以及如何搭建和使用检索增强生成RAG系统。

概念

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

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

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

RAG系统搭建流程架构图

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

image

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

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

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

  1. 数据准备

    1. 创建文档数据表

      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)
      );
    2. 插入文档数据

      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');
  2. 文档向量化及构建向量和分词索引

    说明
    • 文本转向量化模型_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;

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

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

  1. 创建文档知识库

    1. 上传文档数据

      /*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

      元数据,暂时保留。

      '{}'

    2. 查看已上传的文档

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

      /*polar4ai*/SHOW FILES;
      /*polar4ai*/SHOW FILE `unique_file_id`;
    3. (可选)删除已上传的文档

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

      在数据库中创建和更新元数据表,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'

  2. 解析文件并构建向量和分词索引

    1. 创建索引表

      向量和分词索引表固定了参数名称和类型,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'

    2. 根据文档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;	

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

      参数

      说明

      示例值或范围

      x_cols

      用于存储文本的字段。

      chunk_content

      primary_key

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

      id

      mode

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

      async

      resource

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

      file

      to_chunk

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

      01

      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

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

      ''、英文逗号,、中文逗号

    3. (可选)调整索引表内容

      根据文档元数据表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;
    4. 查询task状态和结果

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

      /*polar4ai*/SHOW TASK `task-id`;
      /*polar4ai*/SELECT * FROM file_index_table LIMIT 10;
    5. (可选)删除索引表中的记录

      /*polar4ai*/DELETE FROM file_index_table WHERE file_id = 'unique_file_id';

检索增强生成RAG

  1. 在线使用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='',
        generate=1
    );

    文本数据未分片

    /*polar4ai*/SELECT * FROM PREDICT(MODEL _polar4ai_rag, SELECT '问题内容') WITH (
        index_name='file_index_table',
        primary_key='file_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='',
        generate=1
    );

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

    参数

    说明

    示例值或范围

    index_name

    索引表名称。

    index_table

    primary_key

    索引表主键名称。

    chunk_id、file_id

    说明

    根据您的文本数据是否切片,当前参数有所差异。

    • 分片: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:否

    0、1

    use_pos

    是否使用分词检索。

    • 1(默认):是

    • 0:否

    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'

    generate

    是否使用大模型生成。

    • 1(默认):是,使用大模型归纳生成结果。

    • 0:否,不使用大模型归纳生成结果,直接返回检索结果。

    0、1

  2. (可选)调用通义千问

    您可以根据RAG的检索结果,调用通义千问生成结果。具体操作,请参见通义千问大模型数据推理和交互