来自工业界的知识库 RAG 服务(五),模块化知识库 GoMate 实现方案详解

背景介绍

很早以前就看过一篇介绍 RAG 的综述性文章 Retrieval-Augmented Generation for Large Language Models: A Survey, 其中介绍了 RAG 的模块化架构:

但是一直没有看到对应的实现方案,以前也没有理解此框架的优势之处。随着在相关领域的持续实践,逐渐理解到模块化 RAG 的优势。模块化 RAG 可以方便地进行服务的迭代升级,另外模块可以自由组合,灵活性更好。

最近注意到来自中科院的 RAG 服务 GoMate 开源了,核心亮点就是模块化 RAG 设计,本文就深入介绍来 GoMate 的框架设计与实现细节。

框架设计

之前介绍的 RAG 框架存在着不同的侧重点,来自有道的 QAnything 强调其 Rerank 设计,RagFlow 强调其精细的文件处理。而 GoMate 则主要强调其模块化设计。

GoMate 的框架设计图如下所示:

可以看到,框架中将 RAG 流程拆分为不同模块,熟悉 RAG 服务还是比较容易理解的,一些核心模块如下所示:

  • Retrieval 对应的就是知识库的检索
  • Rerank&Judge 对应的就是检索内容的重排序与过滤
  • Generation 对应的就是大模型内容生成
  • Citation 对应的就是检索内容引用的处理

每个模块可以存在多种不同的实现形式,比如 Retrieval 图中包含如下所示的实现:

  • Sparse Retriever 对应的是稀疏检索,目前常见的 BM25 的检索;
  • Dense Retriever 对应的密集检索,RAG 中最常见的是向量检索;
  • Ensemble Retriever 对应的应该是混合检索;

从架构图可以看到 GoMate 就是包含了多个基础的功能模块,通过功能模块的的组合实现具体的应用。

实现细节

GoMate 是从 2024 年 2 月开始开发的,截止目前经过了 4 个月的开发,虽然功能还不够完善,但是已经可以看到模块化的完整设计思想了。

项目主要包含两部分:

  • modules 包含的就是基础模块, 与上面架构图中的模块可以对应起来
  • applications 表示的是模块组合生成的应用,实现业务所需的功能
功能模块

每个模块对应的职责比较明确,以 RAG 中核心的检索模块为例,深入查看对应的实现:

基础的检索接口在 gomate/modules/retrieval/base.py 中定义,只包含一个 retrieve() 方法:

python 复制代码
class BaseRetriever(ABC):
    @abstractmethod
    def retrieve(self, query: str) -> str:
        pass

BM25 检索算法在 gomate/modules/retrieval/bm25_retriever.py 实现,其中实现了 BM25Okapi, BM25LBM25Plus 版本的算法,具体如下所示:

python 复制代码
class BM25Retriever(BaseRetriever):
    # 实现不同的 BM25 算法

    def build_from_texts(self, corpus):
        self.corpus=corpus
        if self.algorithm == 'Okapi':
            self.bm25 = BM25Okapi(corpus=corpus, tokenizer=self.tokenizer, k1=self.k1, b=self.b, epsilon=self.epsilon)
        elif self.algorithm == 'BM25L':
            self.bm25 = BM25L(corpus=corpus, tokenizer=self.tokenizer, k1=self.k1, b=self.b, delta=self.delta)
        elif self.algorithm == 'BM25Plus':
            self.bm25 = BM25Plus(corpus=corpus, tokenizer=self.tokenizer, k1=self.k1, b=self.b, delta=self.delta)
        else:
            raise ValueError('Algorithm not supported')

    # 检索接口的实现

    def retrieve(self, query: str='',top_k:int=3) -> List[Dict]:
        tokenized_query = " ".join(self.tokenizer(query))
        search_docs = self.bm25.get_top_n(tokenized_query, self.corpus, n=top_k)
        return search_docs

向量检索算法是基于 Faiss 实现的,简化后实现如下所示:

python 复制代码
class DenseRetriever(BaseRetriever):
    # 初始化 Faiss 向量检索

    def __init__(self, config):
        self.config = config
        self.tokenizer = AutoTokenizer.from_pretrained(config.model_name)
        self.model = AutoModel.from_pretrained(config.model_name)
        self.index = faiss.IndexFlatIP(config.dim)

    # 检索接口实现

    def retrieve(self, query):
        D, I = self.index.search(self.get_embedding([query]), self.top_k)
        return [{self.doc_map[idx]: score} for idx, score in zip(I[0], D[0]) if idx in self.doc_map]

gomate/modules/retrieval/tree_retriever.py 中还实现了 RAPTOR 检索,感兴趣的也可以深入查看实现细节。

可以看到检索模块包含的就是不同算法的实现,上层应用可以根据需要选择合适的检索算法。

其他的模块与检索模块类似,对应的就是单个功能的实现。

应用

目前实现的应用比较少,只有 Rerank,Rewrite 和 RAG ,目前只有 RAG 属于一个完整的应用,其他都是单个模块的测试,深入查看 RAG 应用的实现,具体如下所示:

python 复制代码
class RagApplication():
    # 初始化向量库

    def init_vector_store(self):
        docs=self.reader.get_content(max_token_len=600, cover_content=150)
        self.vector_store.document=docs
        self.vector_store.get_vector(EmbeddingModel=self.embedding_model)
        self.vector_store.persist(path='storage')
        self.vector_store.load_vector(path='storage')

    # 向量库中添加文件

    def add_document(self, file_path):
        docs = self.reader.get_content_by_file(file=file_path, max_token_len=512, cover_content=60)
        self.vector_store.add_documents(self.config.vector_store_path, docs, self.embedding_model)

    # RAG 对话

    def chat(self, question: str = '', topk: int = 5):
        # 向量检索

        contents = self.vector_store.query(question, EmbeddingModel=self.embedding_model, k=topk)
        content = '\n'.join(contents[:5])

        # 大模型聊天

        response, history = self.llm.chat(question, [], content)
        return response, history,contents

可以看到目前实现的 RAG 应用只是一个简单的向量库模块和大模型聊天的模块的组合,暂时看不到模块化的优势之处。

但是从目前的设计来看,模块化的设计存在一些明显的优势。基础模块可以独立进行迭代,上层应用可以根据需要组合所需的模块,比如大模型聊天只需要将下面的模块组合在一起:

  • Query Processing
  • Prompt Engineering
  • Generation

而 RAG 完整流程可以组合下面的模块:

  • Query Processing
  • Query Transformation
  • Retrieval
  • Rerank&Judge
  • Prompt Engineering
  • Generation
  • Prompt Engineering
  • Generation
  • Citation
  • Post Processing

应用中的各个模块可以独立测试和优化,组合的模块也可以根据需要进行替换升级,比如 RAG 的检索方案从 DenseRetriever 调整为 BM25Retriever 只需要简单的参数修改即可。

总结

本文介绍了中科院的模块化 RAG 项目 GoMate,项目目前还处于初始阶段,还有不少功能等待实现,但是可以看到的一个模块化 RAG 的实现思路,通过精细的模块拆分,模块的迭代升级可以变得更加便利,应用的实现也会演变成简单的模块组合。对 GoMate 项目感兴趣的可以前往官网深入了解。

相关推荐
Mr_凌宇6 分钟前
codex开启1M上下文
人工智能·程序员
AI英德西牛仔7 分钟前
豆包导出 pdf 颜色不一样怎么办,选用 AI 导出鸭优化文档导出,结合行业白皮书数据解析色彩失真成因
人工智能·ai·chatgpt·pdf·deepseek·ai导出鸭
神奇小汤圆8 分钟前
RAG检索优化实战:从67%到92%,我做了这4步
人工智能
老司机张师傅22 分钟前
让 AI 之间自动对话:基于 TRAE Solo 的多智能体团队协作系统设计与实现
人工智能·aiaitrae
一知半解仙38 分钟前
大国博弈与机器人纪元:我们正站在怎样的历史拐点?
大数据·人工智能·机器人
qpsj1 小时前
DeepSeek 缓存命中涨价 12 倍:4 个改动,账单回到涨价前
人工智能·llm
哈尔ai1 小时前
分布式锁没有失效:真正危险的是锁与事务的提交边界
人工智能
哈尔ai1 小时前
JavaScript 异步竞态治理:先定义谁能写,再谈取消请求
人工智能
jinggongszh1 小时前
MES\WMS软件前端开发工程师:与AI协同前行,解锁前端开发新范式
人工智能·前端开发·开发工程师·制造业转型
亚古数据1 小时前
亚古数据:新西兰公司工商报告Company Extract全解析
大数据·人工智能