RAG系列(二):如何优化索引

上篇文章总览了RAG的各个环节,这篇我们接着讲第一个环节也就是“索引”环节如何做优化。具体细节“人人都是产品经理”的这篇文章里有非常详细的说明,不过我对微软体系搜索优化了解的多些,看到过的一些优化方法这里没有提到,比如微软的AI Search还有Dataverse Semantic Search里用到一些优化方法这里就没看到。知识搜索是一个可以扣出很多细节的领域,这里做个备考、补充学习过程中的一些体会并持续完善。RAG实战篇:优化数据索引的四种高级方法,构建完美的信息结构 (ifeng.com)

1. 回顾RAG系列:如何从整体视角看待RAG?-CSDN博客谈到完整的RAG分为索引、查询翻译、路由、查询构建、检索、生成六个步骤。

2. 索引环节主要是解决原始文档的处理问题,遇到的挑战比如分块的时候把完整的一句话或者一个意思拆断了、对于比较长的语境被拆断丢失重要信息、如果一个内容相关的知识要根据距离比较远的多个块来总结如何解决、数据量增多后检索中的噪声会增大导致频繁与错误数据匹配等等

3. "人人都是产品经理"的文章里谈到索引优化主要有四种方式:块优化(Chunk Optimization)、多层表达索引(Multi-representation indexing)、特殊嵌入(Specilized embeddings)和多级索引(Hierachical Indexing)。下面这篇Dify.AI的播客文章谈到了另外一种Q2Q(Question to Question)的优化策略,我们在一个实际的案例中使用过,感觉效果很不错。Major Update: AI Online Search Capability Now Available, Significantly Enhancing Dataset Hit Rate! - Dify Blog

4. 块优化就是把原始文章分块的时候可以采取的不同优化方式,下面有代码示例展示不同的块优化策略,均使用的是langchain提供的封装方法:

# 第一种:指定多少个字来进行分块,并设置相连的块之间保留多少个重复文字,以免分块的时候丢失意思
text = "..." 
CharacterTextSplitter text_splitter = CharacterTextSplitter( chunk_size = 256, chunk_overlap = 20)
docs = text_splitter.create_documents([text])

# 第二种:回归式分块,主要考虑基于分段(\n\n)、换行(\n)等指定的分隔符来进行分块,分块的大小和块重复文字可以指定
text = "..."
text_splitter = RecursiveCharacterTextSplitter(chunk_size=256, chunk_overlap=20, separators=["\n\n", "\n"])
docs = text_splitter.create_documents([text])

# 第三种:根据指定的分隔符来分块
text = "..."
docs = text.split(".")

# 第四种:针对特定的文档结构比如Markdown、HTML等,能确保内容类型不会在块内混合,从而保持完整性
markdown_text = "..."
markdown_splitter = MarkdownTextSplitter(chunk_size=100, chunk_overlap=0)
docs = markdown_splitter.create_documents([markdown_text])

# 第五种:基于语义理解的复杂方法,通过检测主题的重大转变来进行分块,确保语义一致性,需要高级NLP技术
text = "..." 
text_splitter = NLTKTextSplitter
docs = text_splitter.split_text(text)

5. 多层次表达索引就是将原始文档生成summary,然后将summary向量化后存到数据库,检索的时候首先通过数据库找到最相关的summary,然后再追溯到原始文档中。

6. 特殊向量索引,文章里提到常用语多模态数据,比如图片数据,利用特殊的向量去做索引,还提到了ColBERT这个由斯坦福大学开发的旨在通过引入“延迟交互”机制来实现高效精确的信息检索。看起来比较高级,好像用不到,先mark。

7. 分层索引,核心思想是把文档构建成一棵树,然后逐层递归查询,听起来也比较高级,先mark。

8. Dify.ai里提到的Q2Q,分块后让LLM基于块来生成所有潜在的问题和答案对,后续检索的时候不是针对分块的文档而是生成的问题答案对来检索,匹配的准确度要高很多,而且如果答案质量不高,可以直接修改答案对来提升结果质量。在我们的一个实践里,让LLM针对了当前块+前块+后块来生成问题和答案对,以避免分块时丢失意思。

总结来说这里介绍了5种索引优化方法,其中块优化、多层表达索引、Q2Q经常被用到,特殊向量和分层索引有使用经验的同学欢迎分享。

你可能感兴趣的:(kotlin,android,开发语言)