跳到正文

RAG 文本分块与向量索引流程

从预处理、Embedding 选型到 FAISS/Pinecone 索引优化

原题:在构建RAG系统时,如何对文本进行分块并生成向量化表示,进而利用向量数据库建立高效索引以支持精准检索?请详细说明从文本预处理、嵌入模型选择、向量存储到索引优化的关键技术流程及常用工具(如Sentence-BERT、FAISS、Pinecone等)。

文档处理 · 字节真题

回答与解析

一、文本分块(Chunking)

核心原则:语义完整性与检索粒度的平衡

策略 适用场景 工具
固定长度候选 实现简单,参数需评测 LangChain RecursiveCharacterTextSplitter
语义分块 文档结构清晰(论文、合同) 按标题/段落边界切分
递归分块 长文档层次化结构 先按章节,再按段落
滑动窗口 需要上下文连贯 比较无重叠、短重叠和较长重叠

关键细节:chunk size 必须低于实际嵌入模型的输入限制,并在同一评测集比较;过小可能造成语义碎片化,过大可能稀释关键信息。


二、嵌入模型选择

选型维度

  • 通用场景sentence-transformers/all-MiniLM-L6-v2(轻量,384维)
  • 中文场景BAAI/bge-large-zh、智谱Embedding-2
  • 领域适配:领域数据继续预训练或对比学习微调

优化技巧

  • 查询端与文档端使用不同prompt(如"为这个句子生成表示:")
  • 维度压缩:PCA或模型蒸馏降低存储成本

三、向量存储与索引

方案 特点 适用规模
FAISS 内存索引,HNSW/IVF算法,零成本 百万级,单机
Pinecone 全托管,元数据过滤,自动扩缩容 千万级+,生产环境
Milvus/Zilliz 开源/云原生,GPU加速 十亿级

索引优化

  • HNSW:构建多层图结构,查询复杂度O(logN),召回率>95%
  • IVF-PQ:倒排+乘积量化,内存压缩10-20倍,适合海量数据
  • 动态更新:增量索引避免全量重建

四、检索增强

# 混合检索示例:向量相似度 + BM25关键词
def hybrid_search(query, alpha=0.7):
    dense_score = vector_db.similarity_search(query)
    sparse_score = bm25_search(query)
    return weighted_fusion(dense_score, sparse_score, alpha)

# 重排序(Rerank)
cross_encoder = CrossEncoder('bge-reranker-base')
candidates = vector_db.search(query, top_k=100)
reranked = cross_encoder.rank(query, candidates)[:10]

关键指标:召回率@K、MRR、延迟P99。线上建议向量召回+精排两阶段架构。

学习建议

建议先掌握文本分块策略与嵌入模型原理,再动手实践使用Hugging Face和FAISS构建小型向量库,理解检索全流程。

口语版讲法(约4分钟)

  • 本质是平衡语义完整性与检索粒度的工程问题
  • 分块策略:固定切分 vs 语义切分,落地常混用
  • 嵌入选型:通用 vs 中文 vs 领域,维度与prompt优化
  • 索引:HNSW与IVF-PQ的取舍,动态更新与一致性
  • 检索:混合检索+重排两步走,风险与兜底

这道题其实问的是,怎么把非结构化文本切碎、变成向量,再建索引,让RAG能又快又准地召回。本质上是一个语义完整性和检索粒度之间的平衡问题,而且落地时不是单纯选一个方案,往往是几种策略组合。

先说分块。最直接的是固定长度切分,实现简单,但照搬一个固定值容易把一句话从中间断开,导致向量表示"碎"了。所以我在做企业知识库的时候,比如客服退款政策文档,会用递归切分,先按章节,再按段落,最后按句子边界切。这样每个chunk语义相对完整。但切得过细,检索时容易漏上下文;切得过大,关键信息又可能被稀释。所以真正落地时,我会把固定长度、递归切分与不同 overlap 设为候选,在同一评测集比较召回、答案质量、冗余成本和延迟。这里有个前提:chunk size 必须低于实际使用的嵌入模型输入限制,超出时要截断、分层或改用支持更长输入的模型。

接下来是嵌入模型。通用场景我会选sentence-transformers的all-MiniLM-L6-v2,384维,轻量快速。中文场景换成BAAI/bge-large-zh,效果更好。但如果是垂直领域,比如金融合同,我会用领域数据做对比学习微调,或者直接用开源的领域版。这里有个优化点:查询和文档可以用不同的prompt前缀,比如查询加"为这个句子生成表示:",文档加"为这个段落生成表示:",能提升匹配精度。维度上,384维已经够用,如果存储成本敏感,可以用PCA压到128维,召回率损失不大。

向量存储和索引,我分两个场景说。单机百万级,用Faiss的HNSW索引,构建多层图,查询复杂度O(logN),召回率能到95%以上。生产环境千万级以上,我倾向用Pinecone或Milvus,全托管,自动扩缩容。索引优化上,HNSW适合高召回,但内存大;IVF-PQ可以压缩10-20倍,适合海量数据,但召回会掉一点。我的取舍是:如果延迟敏感,用HNSW;如果存储成本敏感,用IVF-PQ。动态更新是个坑:知识库频繁更新时,直接原地改图索引会导致召回质量崩。我会把更新分成新增、修改、删除三类。新增直接增量插入;修改当成旧版本软删除加新版本新增;删除不原地动索引,而是维护删除标记,后台异步重建。整体用base加delta双索引,查询时合并再按版本过滤。上线前会用固定query回放,对比Recall@K和延迟,通过才原子切换。

检索阶段,我通常用混合检索加重排两步走。先用Hybrid Search,把向量相似度和BM25关键词分数加权融合,比如alpha=0.7,兼顾语义和精确匹配。然后对top 100候选用Cross-Encoder重排,比如bge-reranker-base,精排到top 10。这样延迟不会太高,但召回和精度都稳。这里有个风险:如果知识库里有大量相似文档,比如不同版本的合同,重排后可能还是混淆,我会加元数据过滤,比如版本号、日期,先缩小候选集。

还有一个点是,当知识库更新频繁时,增量索引的实时性和一致性很难兼顾。我上面提到用双缓冲,但实际工程中还要考虑索引重建的时机和回滚机制。这块如果做得不好,线上会出现搜不到刚更新的内容,或者搜到旧版本,影响用户信任。

所以整体上,我更倾向于把RAG检索看成一个多阶段pipeline,从分块到嵌入到索引到检索,每个环节都有trade-off,而且必须用业务数据验证。如果只让我抓一个关键,那就是分块粒度决定了检索的上限,后面再优化也只是在补分块的坑。

关键一句:增量索引的实时性与一致性平衡:双缓冲+异步重建+回滚机制

面试官还可能这样问

  1. 问法 1 · 场景切入

    假设你在做一个电商客服的RAG系统,用户问“这款手机拍照怎么样”,你要从产品手册里找答案。手册那么长,你打算怎么切段?切太小怕丢上下文,切太大又怕检索不准,你怎么平衡?

  2. 问法 2 · 层层追问

    文档检索系统里,文本是怎么变成向量的?……那你存到向量数据库之后,怎么建索引才能查得快?如果数据量到百万级,你用什么索引结构?……那如果还要支持关键词匹配呢?

  3. 问法 3 · 直球架构

    从原始文档到检索结果,你一步步把整个流程讲清楚:文本怎么分块、用什么嵌入模型、怎么存到向量数据库、索引怎么优化才能既快又准。中间遇到chunk size、维度、召回率这些trade-off,你怎么选?

同模块相关题目