Tiny-universe手戳大模型TinyRAG--task4

news/2024/10/3 18:14:38 标签: nlp, 人工智能, 语言模型

TinyRAG

这个模型是基于RAG的一个简化版本,我们称之为Tiny-RAG。Tiny-RAG是一个基于RAG的简化版本,它只包含了RAG的核心功能,即Retrieval和Generation。Tiny-RAG的目的是为了帮助大家更好的理解RAG模型的原理和实现。

1. RAG 介绍

LLM会产生误导性的 “幻觉”,依赖的信息可能过时,处理特定知识时效率不高,缺乏专业领域的深度洞察,同时在推理能力上也有所欠缺。

正是在这样的背景下,检索增强生成技术(Retrieval-Augmented Generation,RAG)应时而生,成为 AI 时代的一大趋势。

RAG 通过在语言模型生成答案之前,先从广泛的文档数据库中检索相关信息,然后利用这些信息来引导生成过程,极大地提升了内容的准确性和相关性。RAG 有效地缓解了幻觉问题,提高了知识更新的速度,并增强了内容生成的可追溯性,使得大型语言模型在实际应用中变得更加实用和可信。

RAG的基本结构有哪些呢?

  • 要有一个向量化模块,用来将文档片段向量化。
  • 要有一个文档加载和切分的模块,用来加载文档并切分成文档片段。
  • 要有一个数据库来存放文档片段和对应的向量表示。
  • 要有一个检索模块,用来根据 Query (问题)检索相关的文档片段。
  • 要有一个大模型模块,用来根据检索出来的文档回答用户的问题。

在这里插入图片描述

RAG 的流程是什么样的呢?

  • 索引:将文档库分割成较短的 Chunk,并通过编码器构建向量索引。
  • 检索:根据问题和 chunks 的相似度检索相关文档片段。
  • 生成:以检索到的上下文为条件,生成问题的回答。

在这里插入图片描述

2. 向量化

首先让我们来动手实现一个向量化的类,这是RAG架构的基础。向量化的类主要是用来将文档片段向量化,将一段文本映射为一个向量。
那首先我们要设置一个 Embedding 基类,这样我们再用其他的模型的时候,只需要继承这个基类,然后在此基础上进行修改即可,方便代码扩展。

class BaseEmbeddings:
    """
    Base class for embeddings
    """
    def __init__(self, path: str, is_api: bool) -> None:
        self.path = path
        self.is_api = is_api
    
    def get_embedding(self, text: str, model: str) -> List[float]:
        raise NotImplementedError
    
    @classmethod
    def cosine_similarity(cls, vector1: List[float], vector2: List[float]) -> float:
        """
        calculate cosine similarity between two vectors
        """
        dot_product = np.dot(vector1, vector2)
        magnitude = np.linalg.norm(vector1) * np.linalg.norm(vector2)
        if not magnitude:
            return 0
        return dot_product / magnitude

3. 文档加载和切分

接下来我们来实现一个文档加载和切分的类,这个类主要是用来加载文档并切分成文档片段。按 Token 的长度来切分文档。我们可以设置一个最大的 Token 长度,然后根据这个最大的 Token 长度来切分文档。这样切分出来的文档片段就是一个一个的差不多相同长度的文档片段了。在切分的时候要注意,片段与片段之间最好要有一些重叠的内容,这样才能保证检索的时候能够检索到相关的文档片段。还有就是切分文档的时候最好以句子为单位,也就是按 \n 进行粗切分,这样可以基本保证句子内容是完整的。

def get_chunk(cls, text: str, max_token_len: int = 600, cover_content: int = 150):
    chunk_text = []

    curr_len = 0
    curr_chunk = ''

    lines = text.split('\n')  # 假设以换行符分割文本为行

    for line in lines:
        line = line.replace(' ', '')
        line_len = len(enc.encode(line))
        if line_len > max_token_len:
            print('warning line_len = ', line_len)
        if curr_len + line_len <= max_token_len:
            curr_chunk += line
            curr_chunk += '\n'
            curr_len += line_len
            curr_len += 1
        else:
            chunk_text.append(curr_chunk)
            curr_chunk = curr_chunk[-cover_content:]+line
            curr_len = line_len + cover_content

    if curr_chunk:
        chunk_text.append(curr_chunk)

    return chunk_text

4. 数据库 && 向量检索

一个数据库对于最小RAG架构来说,需要实现几个功能呢?

  • persist:数据库持久化,本地保存
  • load_vector:从本地加载数据库
  • get_vector:获得文档的向量表示
  • query:根据问题检索相关的文档片段

嗯嗯,以上四个模块就是一个最小的RAG结构数据库需要实现的功能

class VectorStore:
    def __init__(self, document: List[str] = ['']) -> None:
        self.document = document

    def get_vector(self, EmbeddingModel: BaseEmbeddings) -> List[List[float]]:
        # 获得文档的向量表示
        pass

    def persist(self, path: str = 'storage'):
        # 数据库持久化,本地保存
        pass

    def load_vector(self, path: str = 'storage'):
        # 从本地加载数据库
        pass

    def query(self, query: str, EmbeddingModel: BaseEmbeddings, k: int = 1) -> List[str]:
        # 根据问题检索相关的文档片段
        pass

那让我们来看一下, query 方法具体是怎么实现的呢?

首先先把用户提出的问题向量化,然后去数据库中检索相关的文档片段,最后返回检索到的文档片段。可以看到咱们在向量检索的时候仅使用 Numpy 进行加速,代码非常容易理解和修改。

def query(self, query: str, EmbeddingModel: BaseEmbeddings, k: int = 1) -> List[str]:
    query_vector = EmbeddingModel.get_embedding(query)
    result = np.array([self.get_similarity(query_vector, vector)
                        for vector in self.vectors])
    return np.array(self.document)[result.argsort()[-k:][::-1]].tolist()

5. 大模型模块

那就来到了最后一个模块了,大模型模块。这个模块主要是用来根据检索出来的文档回答用户的问题。

一样的,我们还是先实现一个基类,这样我们在遇到其他的自己感兴趣的模型就可以快速的扩展了。

class BaseModel:
    def __init__(self, path: str = '') -> None:
        self.path = path

    def chat(self, prompt: str, history: List[dict], content: str) -> str:
        pass

    def load_model(self):
        pass

BaseModel 包含了两个方法,chatload_model,如果使用API模型,比如OpenAI的话,那就不需要load_model方法,如果你要本地化运行的话,那还是会选择使用开源模型,那就需要load_model方法发啦。

6. 训练结果

在这里插入图片描述调包在这里插入图片描述加载模型在这里插入图片描述
最后结果

7. 总结

检索增强生成技术(RAG)旨在解决大型语言模型(LLM)存在的误导性、信息过时、知识处理效率低和推理能力不足等问题。该技术通过引入一个额外的检索步骤,在生成答案之前先从文档数据库中检索相关信息,以此提高内容的准确性和相关性。RAG的基本结构包含向量化模块、文档加载与切分模块、数据库存储、检索模块以及大模型生成模块。其核心流程分为索引构建、相关文档检索和基于检索内容的答案生成三个阶段。
为了实现RAG,需要开发能够加载并合理切分文档的类,以及将文本片段转换为向量的向量化类。同时,还需要构建一个数据库,用于存储文档片段及其向量表示,并支持向量的持久化存储、加载、检索等功能。在检索过程中,query方法负责将用户问题向量化,并在数据库中查找最相关的文档片段,为后续的答案生成提供有力支持。通过这些模块和流程的协同工作,RAG能够显著提升语言模型在实际应用中的实用性和可信度。

8. 参考文献

  • When Large Language Models Meet Vector Databases: A Survey
  • Retrieval-Augmented Generation for Large Language Models: A Survey
  • Learning to Filter Context for Retrieval-Augmented Generation
  • In-Context Retrieval-Augmented Language Models
  • https://github.com/datawhalechina/tiny-universe/tree/main/content/TinyRAG

http://www.niftyadmin.cn/n/5688792.html

相关文章

【部署项目】禹神:前端项目部署上线笔记

1.项目打包 ● 我们开发用的脚手架其实就是一个微型服务器&#xff0c;用于&#xff1a;支撑开发环境、运行代理服务器等。 ● 打包完的文件中不存在&#xff1a;.vue、.jsx、.less 等文件&#xff0c;而是&#xff1a;html、css、js等。 ● 打包后的文件&#xff0c;不再借助…

SpringBoot介绍及整合Mybatis Plus

目录 SpringBoot背景及特点 SpringBoot整合Mybatis Plus SpringBoot背景及特点 SpringBoot的设计目是抛弃之前Spring、SpringMVC繁杂的配置过程&#xff0c;简化开发过程。之前的Spring框架需要大量的手动配置&#xff0c;包括XML配置文件或Java配置类&#xff0c;配置过程繁…

数值分析作业(第二章):代码+手写计算

《数值计算方法》丁丽娟-数值实验作业-第二章&#xff08;MATLAB&#xff09; 作业P58: 1 &#xff0c;2&#xff0c;3&#xff0c;6&#xff0c;8(1), 12, 13 数值实验P61: 2, 3 数值实验&#xff08;第二章&#xff09; 代码仓库&#xff1a;https://github.com/sylvanding/b…

使用 Vue3 和 Axios 实现 CRUD 操作

文章目录 1、准备工作2、创建 Vue 3 项目3、项目结构4、实现 CRUD 操作5、运行项目6、小结在当今的前端开发中,Vue.js 作为一款流行的 JavaScript 框架,正在被越来越多的开发者所青睐。尤其是 Vue 3 引入了 Composition API 和更优雅的响应式处理,使得模板编写和状态管理变得…

Python、C++、java阶乘算法

最近&#xff0c;我除了Python还学了C和Java&#xff0c;然后在网上看到编程考题&#xff1a;阶乘。 首先&#xff0c;我们先理解什么是阶乘。 阶乘是数学中的一个概念&#xff0c;通常定义为从1乘到指定的数。具体来说&#xff0c;一个正整数的阶乘&#xff08;记作n!&#…

RAC被修改权限及相关问题

RDBMS &#xff1a; 19.19 修改RAC权限及相关问题 修改RAC权限&#xff0c;参考文档&#xff1a; How to check and fix file permissions on Grid Infrastructure environment (Doc ID 1931142.1) Script to capture and restore file permission in a directory (for eg. O…

接口 抽象类

接口和抽象类都是用来实现面向对象编程中的抽象概念的工具。 接口是一种抽象的数据类型&#xff0c;它定义了一组抽象方法。接口中的方法没有具体的实现&#xff0c;只有方法的声明。类可以实现一个或多个接口&#xff0c;并实现接口中的方法。接口提供了一种规范&#xff0c;…

uniapp实战教程:如何封装一个可复用的表单组件

在uniapp开发过程中&#xff0c;表单组件的使用场景非常广泛。为了提高开发效率&#xff0c;我们可以将常用的表单组件进行封装。本文将带你了解如何在uniapp中封装一个表单组件&#xff0c;让你只需要通过属性配置轻松实现各种表单&#xff0c;效果图如下&#xff1a; 一、准备…