1. 面试官视角:为什么RAG全链路是必考项?
如果你最近在准备AI应用或者大模型相关的面试,尤其是涉及搜索、问答、知识库构建的岗位,那么“RAG全链路”这个词出现的频率,可能已经让你耳朵起茧了。面试官为什么总爱问这个?因为RAG(检索增强生成)早已不是一两年前那个“把文档切块、向量化、然后塞进向量数据库”的简单概念了。它已经演变成一个复杂的系统工程,任何一个环节的疏忽,都可能导致最终效果天差地别。面试官想看的,不是你背了多少个术语,而是你是否真的理解每个环节的“为什么”,以及如何将它们串联成一个高效、鲁棒的系统。
一个典型的RAG系统,从用户提问到给出答案,背后是一条精密的流水线。这条链路上的核心节点,正是标题中提到的: 父子分块、Rerank、查询重写、标准化改写 。它们分别对应着知识存储、召回优化、意图理解和输入净化这四个关键维度。只懂向量检索,那是两年前的认知;能把这条链路上的技术选型、权衡取舍和实战坑点讲清楚,才是当下合格候选人应有的水平。接下来,我们就抛开教科书式的定义,从一个实战构建者的角度,把这四个核心环节掰开揉碎了讲透。
2. 知识组织的基石:超越简单分块的父子文档策略
当我们拿到一份PDF、一份长文档,第一反应往往是“切块”。但怎么切,直接决定了后续检索的精度上限。传统的固定长度重叠分块(比如每500字符,重叠50字符)简单粗暴,但问题很明显:它粗暴地割裂了文档的语义完整性。一个完整的解决方案描述,可能被切成两半;一个关键的定义,可能正好在块与块的边缘被腰斩。
2.1 父子分块的核心思想与实现
父子分块(Parent-Child Chunking)就是为了解决这个问题。它的核心思想是建立两个层级的索引:
- 父文档(Parent Document) :一个较大的、语义完整的文档单元,比如一整节、一个完整的案例描述或一个API接口说明。
- 子文档(Child Document) :在父文档基础上,进一步细分的、用于检索的小块。这些子块通常就是传统固定长度分块的结果。
它们之间的关系是:多个子文档归属于同一个父文档。在检索时,我们先用用户的查询去匹配最相关的 子文档 ,因为子文档小,语义更集中,更容易被向量模型精准匹配。一旦找到相关的子文档,我们不是直接把这个子文档扔给大模型去生成答案,而是取出这个子文档所属的整个 父文档 ,将其作为上下文提供给大模型。
为什么这样做更有效? 因为大模型(LLM)需要足够的上下文来理解细节和做出准确推断。一个孤立的子文档可能缺少必要的背景信息。例如,用户问“如何配置XX参数?”,检索到的子文档可能只写了“将该参数设为True”。但如果把整个父文档(包含参数定义、使用场景、依赖条件等)提供给LLM,它就能生成更全面、更准确的答案:“在‘高级设置’章节中,找到‘性能优化’部分,将 enable_optimization 参数设为True,注意这需要先满足前提条件A和B。”
2.2 实操中的关键参数与工具
在LlamaIndex、LangChain等框架中,父子分块都有现成的实现。以LlamaIndex为例,你可能会用到 SentenceSplitter 来创建子块,然后通过 ParentDocumentRetriever 来建立关联。
from llama_index.core import SimpleDirectoryReader, VectorStoreIndex
from llama_index.core.node_parser import SentenceSplitter
from llama_index.core.retrievers import ParentRetriever
# 1. 创建文本分割器(用于生成子节点)
text_splitter = SentenceSplitter(
chunk_size=256, # 子块大小
chunk_overlap=50, # 子块重叠
)
# 2. 读取文档并解析为节点(Nodes)
documents = SimpleDirectoryReader("./data").load_data()
nodes = text_splitter.get_nodes_from_documents(documents)
# 3. 假设我们根据某种规则(如标题)定义了父节点,这里简化表示
# 在实际中,可能需要更复杂的逻辑来定义父节点(如按章节)
parent_nodes = ... # 定义父节点逻辑
# 4. 创建父文档检索器
retriever = ParentRetriever(
vector_store_index, # 子节点的向量索引
parent_nodes=parent_nodes,
search_kwargs={"k": 5} # 检索5个最相关的子节点
)
这里的关键参数 chunk_size 和 chunk_overlap 需要根据你的文档类型和模型上下文长度来调整。对于技术文档, chunk_size=512 可能是个不错的起点;对于法律或金融文档,可能需要更长的块(如1024)来保持条款的完整性。
注意: 父子分块会增加存储和检索的复杂度,因为你需要维护两套索引(子文档的向量索引和父子关系的映射)。在文档量极大时,需要权衡其带来的精度提升与系统开销。
2.3 一个常见的踩坑点:父文档的定义
什么才算一个“父文档”?是按章节标题?是按固定页数?还是按语义段落?这没有标准答案。一个实战经验是: 结合文档的结构化信息和语义相似度来定义 。例




427

被折叠的 条评论
为什么被折叠?



