面试官真正想听的是参数背后的验证方法
很多回答一上来就是:“我们设置 chunk_size=1024,overlap=100。”
面试官接着问“为什么”,回答就变成“网上大多这样配”或者“框架默认值就是这个”。这说明只会填写配置,没有建立评测闭环。
参数选择真正要回答四个问题:
- 一个问题的完整证据通常有多长?
- 文档里哪些内容最怕被拆开?
- 召回结果重复后,会占掉多少候选位和模型上下文?
- 参数改变后,怎样证明收益来自切分,而不是其他模块同时变化?
从工程链路看,RAG 可以拆为离线解析、在线召回、上下文生成和查询理解。切分位于离线阶段,但它会沿着整条链路向后影响:块太大,向量里同时包含多个主题,检索得分可能被噪声稀释;块太小,问题所需的前提、条件和结论可能落在不同块里;重叠太小,边界信息可能断开;重叠太大,多个近似块会挤进同一个 Top K。
所以,这不是一个“字符串应该截多长”的问题,而是“证据怎样进入检索单元,并以多大代价被稳定找回”的问题。

参数同时影响语义完整性、检索区分度和上下文成本,最终要由同一批问题验证。
先分清 chunk_size 和 overlap 各自在解决什么
chunk_size 控制的是检索单元的粒度
块变大,不等于信息一定更完整。
例如,一段教学文档可能先讲适用范围,再讲申请条件,最后讲例外情况。如果三个主题全部塞进一个大块,用户只问“申请条件”时,向量表示仍会混入适用范围和例外内容。检索可能命中,但相关证据在块里的密度下降,后续模型还要从更多无关文字中找答案。
块变小,也不等于检索一定更准确。
例如,一段教学材料先写“满足以下任一条件可以申请”,后面紧跟三个列表项。如果前导句和列表项被拆成四个小块,单独召回“条件二”时,模型看见了一个条目,却不知道它属于什么规则。又如材料先写生效条件,下一句写“但以下情况除外”,把两句分开会让答案缺少限制条件。
这里先划清边界:如果切分器还不能识别标题、段落、列表和表格,应该先解决结构切分。本题讨论的是结构基本正确以后,怎样为 chunk_size 和 overlap 找到可验证、可上线的参数。
因此 chunk_size 的核心矛盾是:
- 大块更容易保留长证据,但主题可能混杂,单次向量表示更粗。
- 小块主题更集中,但需要更多块才能拼成完整证据,边界风险更高。
- 同一个知识库里,FAQ、规章条款、表格说明和技术文档的合适粒度可能不同。
overlap 控制的是相邻块之间保留多少共同上下文
重叠窗口的目的,是让切分点附近的前提和结论至少在某一个块中共同出现。
假设块 A 末尾是“申请人应满足以下条件”,块 B 开头是“第一,已完成身份核验”。如果 B 完全不带前文,单独召回 B 时语义会变弱。让 B 带上一小段 A 的尾部,可以恢复“这些条目是什么”的上下文。
但 overlap 不是越大越保险。重叠越多,同一段文字会被多次向量化。查询命中边界区域时,Top K 里可能出现内容高度相似的 A、B、C,表面上召回了三条,实际上只有一份证据。它们还会一起进入重排和提示词,占用候选位、计算和上下文长度。
因此,overlap 解决的是边界连续性,不应该拿它替代正确的结构切分。章节、表格、代码块或列表已经被错误拆散时,盲目扩大重叠只是复制错误。

先把结构切对,再在确有断裂风险的边界补最小必要上下文。
为什么不能复制别人的参数
即使两套系统都叫“企业知识库 RAG”,以下差异也会让参数结论完全不同。
第一,文档结构不同。
一问一答式 FAQ 本身就是短而完整的语义单元。制度、合同和技术手册则可能把定义、条件、例外和步骤分散在多个自然段。平均长度相同,并不代表证据跨度相同。
第二,Embedding 模型的输入限制和训练方式不同。
如果块长超过当前 Embedding 模型实际接收的长度,超出部分可能被截断;是否截断、从哪里截断,要以所用模型的文档和实测结果为准。即使没有截断,长块里混入多个主题,也可能让向量表达变得不够聚焦。不能只看数据库保存了多少字,还要确认多少内容真正进入了向量编码。
第三,检索和重排链路不同。
只用向量召回、向量加 BM25 的混合召回、是否有 Cross-Encoder 重排,都会改变“大块”和“小块”的表现。粗召回与精排的职责不同:前者尽量带回候选,后者在较小候选集中做更细判断。切分实验如果同时更换检索器或重排模型,就无法判断收益来自哪里。
第四,问题类型不同。
精确术语问题可能只需要一小段定义;比较题可能同时需要两组证据;流程题需要连续步骤;否定和例外问题必须把限制条件带回来。只用一类问题调出的参数,很容易在另一类问题上失效。
第五,上下文预算不同。
最终能送入模型的不是无限文本。块越大,每次能放入的候选越少;块越小,可能需要更多候选才能补齐证据。参数要和 Top K、重排截断、提示词模板共同考虑,但实验时仍应一次只改一个变量组。
一次合格的参数实验应该怎样设计
第一步:先定义问题,而不是先枚举参数
先从真实文档类型中抽样,再为每类文档准备能够定位到原文证据的问题。评测集至少要覆盖:
- 单段即可回答的事实题;
- 前提与结论相隔较远的条件题;
- 带“除外、不得、仅限”等限制词的问题;
- 前导句加列表项的流程题;
- 表头与数据行共同决定含义的表格题;
- 需要两个片段共同回答的组合题。
这里的“标准答案”不能只有一段自然语言。还要标注支撑答案的原文位置,最好标出最小证据范围。否则系统答对了,也不知道是正确召回、模型常识碰巧答中,还是错误片段碰巧包含相似表述。
第二步:给评测样本分层
把不同风险的样本混成一个平均分,会掩盖问题。
可以按文档形态分层:FAQ、普通段落、长条款、列表、表格、代码或步骤说明。也可以按证据跨度分层:单块证据、跨边界证据、跨多个自然段证据。查询还可分成精确词、口语化表达、否定条件和多约束问题。
分层之后,才看得见某个参数组合到底改善了什么。它可能提高普通事实题的召回,却让表格和列表题变差;也可能让边界问题更完整,却制造大量重复候选。
第三步:固定其他变量
实验期间至少固定这些项目:
- 同一批原始文档和同一版解析结果;
- 同一个 Embedding 模型及其输入处理;
- 相同的向量索引类型与搜索参数;
- 相同的 BM25 配置和召回路数;
- 相同的候选数量、重排模型和最终 Top K;
- 相同的提示词与生成模型,如果要评估最终回答。
唯一改变的是切分配置。若必须同时比较“按段落切”和“固定长度切”,应该把它明确当成另一个实验维度,而不是把算法和参数混在同一张结果表里。
第四步:建立可重跑的配置矩阵
参数值应优先根据当前语料的长度分布和证据跨度来确定,而不是直接复制文章里的数值。实验程序读取一组配置,为每组配置重新切分、建索引、运行同一批查询并记录结果。下面是只说明实验步骤的教学伪代码,不是可直接运行的项目实现:
def evaluate_chunk_config(config, documents, questions, pipeline):
chunks = pipeline.chunk(
documents,
chunk_size=config.chunk_size,
overlap=config.overlap,
)
index = pipeline.build_index(chunks)
rows = []
for sample in questions:
results = pipeline.retrieve(index, sample.query)
rows.append({
"query_id": sample.id,
"retrieved_chunk_ids": [item.id for item in results],
"evidence_hit": hit_evidence(results, sample.evidence_spans),
"first_hit_rank": first_hit_rank(results, sample.evidence_spans),
"duplicate_ratio": duplicate_ratio(results),
})
return summarize(
rows,
chunk_count=len(chunks),
index_bytes=index.size_bytes,
)
关键是每次运行都能追溯配置、索引版本、问题集版本和结果明细。只有一张最终分数截图,而没有逐题结果,出现退化时很难定位。

固定模型、Top K、Rerank 与 Prompt,只比较切分配置带来的真实变化。
指标怎么选,才不会只优化一个漂亮数字
Recall@K:正确证据有没有进入候选集
如果标准证据完全没进前 K,后面的重排和生成通常无从补救。Recall@K 适合观察切分后“该找的内容能不能找到”。
但它也可能被重复结果欺骗。三个高度相似的重叠块都命中同一证据,不能算找回了三份有效信息。因此评估时应按证据或原文区间去重,而不是只按 chunk ID 计数。
MRR 或 nDCG:正确证据排在什么位置
MRR 关注第一个相关结果出现得早不早。nDCG 适合存在多条不同相关度证据时,观察整体排序。这些指标常用于比较召回和排序方案;在切分实验里,它们能帮助判断参数变化是否只把相关块“塞进了候选尾部”,还是让它真正靠前。
证据完整性:召回的块能不能独立支撑回答
传统检索指标只能判断相关,不一定判断完整。
一个块包含“可以申请”,却没有包含后面的“仅限以下情形”;它与问题高度相关,但不能安全支撑答案。可以由人工标注或规则辅助检查:答案所需的前提、主体、条件、结论和例外是否在同一块或允许拼接的少量块中完整出现。
这项指标不必先追求自动化总分。首批高风险样本逐条审查,往往比一个无法解释的模型评分更有价值。
重复率:Top K 里有多少位置被近似内容占据
Overlap 增大后,一个常见的副作用是候选重复。可以比较结果之间的文本重合、来源区间重合或相邻 chunk 关系,统计同一证据占用了多少候选位。
如果 Recall@K 略有提升,但 Top K 中大部分结果都来自同一段相邻文本,后续模型获得的信息覆盖面反而可能下降。
工程成本:索引规模、建库时间、检索延迟与上下文占用
小块和大 overlap 都会增加 chunk 数。chunk 数增加,会影响向量生成量、索引体积、重建时间和候选去重成本。大块则会增加单块 token 数和后续上下文占用。
参数实验还要记录索引更新、在线检索延迟和全链路监控数据。不要预填一个“可接受”的成本数字,应该记录当前项目的真实资源和延迟,再把它作为参数选择的约束。
如何从实验结果里选出真正能上线的一组
不要简单地取 Recall@K 最高的一行。
可以先设业务底线:高风险条件题和否定题不能出现已知退化;正确证据必须在重排候选范围内;重复率、索引规模和延迟不能超过当前系统能承受的边界。在满足底线的配置中,再比较整体排序和成本。
更直观的做法,是画一张“收益与代价”图:横轴是索引或延迟成本,纵轴是证据召回与完整性。位于劣势区域的配置通常可以排除:它比另一个配置更慢、更大,效果还更差。剩下的候选再做人工 bad case 审查。
如果不同文档类型的最优区间差异明显,不必强行全库共用一个数字。可以按明确、稳定的文档类别采用少量策略,例如 FAQ 以问答单元为主,长制度按结构单元再受最大长度约束。前提是分类逻辑可解释、可监控,不要让每份文档都进入一套无法维护的“自动猜参数”流程。
从结果反推参数问题,而不是重复讲结构切分
参数回归应把现象映射到可能原因,先判断它是否真的能由 Size 或 Overlap 修复:
| 观察到的现象 | 优先检查的参数问题 | 不能靠参数掩盖的根因 |
|---|---|---|
| 条件句与结论分开召回 | 块是否过小,边界处是否缺少最小重叠 | 解析器没有识别列表与段落结构 |
| Top K 出现多个近似片段 | Overlap 是否过大,块是否过碎 | 重复入库或版本过滤错误 |
| 命中正确章节却带回大量无关内容 | 块是否过大,单块是否混入多个主题 | 标题路径或结构元数据丢失 |
| 表格问题只找到数据行 | 行组是否过大或过小 | 表头没有作为结构信息继承 |
| 跨页问题长期失败 | 分页附近的证据跨度是否超过块长 | 页面阅读顺序在解析阶段已经错误 |
一组配置即使平均分领先,只要高风险条件题持续退化,也不能直接上线。这个诊断表的作用,是阻止团队把解析、入库和版本问题都错误归因给两个参数。
参数改动上线时,为什么要把索引当成版本化产物
修改切分参数意味着文档会生成一套新的 chunk ID、向量和索引。直接覆盖旧索引,一旦发现回归,很难快速恢复。
更稳妥的流程是:
- 保存切分配置、解析版本、Embedding 版本和评测集版本;
- 用新配置构建独立索引,不覆盖当前可用版本;
- 离线跑完整评测,并逐条检查高风险 bad case;
- 在受控流量或影子请求上比较新旧结果,记录每路候选、最终排名与延迟;
- 通过后再切换索引别名,保留旧版本作为回退入口;
- 切换完成后继续观察无答案率、人工反馈、重复候选和典型问题回归。
若基础设施支持,可以用独立索引、别名切换和受控对照降低切换风险;具体采用哪一种,要按现有存储与发布流程决定。
参数回归还需要固定样本。每次发现新问题,都把原始查询、标准证据位置、当时的切分配置和错误结果加入回归集。下一次优化不只看新问题有没有修好,还要确认旧问题没有重新出现。

上线前同时检查证据完整、结果重复与变更可控,参数必须能够复现和回归。
面试官继续追问,怎么接
为什么不用一个更大的 chunk,彻底避免信息被切断?
因为大块只降低某些边界风险,却会把多个主题塞进同一个向量,降低证据密度,并占用更多上下文。还要确认 Embedding 模型是否真正编码了整块内容。正确做法是先保护结构边界,再在评测集上验证长度,而不是无限增大。
overlap 越大,Recall@K 是否一定越高?
不一定。它可能让边界附近的证据更容易命中,也可能产生大量近似 chunk,挤占 Top K。即使 Recall@K 上升,也要同时看去重后的证据覆盖、MRR 或 nDCG、重复率和上下文占用。
如果最终答案变好了,能否证明参数选对了?
不能单凭最终答案判断。模型可能依靠自身知识答对,也可能碰巧从错误证据生成正确表述。需要先看标准证据是否被召回、排名在哪里、内容是否完整,再看基于证据的回答质量。
为什么要固定重排模型和 Top K?
因为它们会改变候选进入最终上下文的方式。切分参数、候选数量和重排同时改变,实验就失去归因能力。先控制其他变量找到可解释结论,再做组合实验。
线上出现某类问题,应该先调 chunk_size 还是 overlap?
先定位错误发生在哪一层。正确内容在解析结果里不存在,是解析问题;自然结构被错误拆开,是边界策略问题;只在相邻边界缺少少量上下文,才可能由 overlap 改善;正确块存在却没被召回,则要检查查询、Embedding、检索和排序。不能把所有问题都归结为两个参数。
怎样向面试官说明自己的参数,而不编造项目指标?
说清楚真实语料、测试集来源、对比配置、指标和 bad case。如果还没有完成实验,就明确说“这是候选方案,下一步会按这套方法验证”,不要把教学材料里的数字改成第一人称成果。
如果资料类型差异很大,我还会先问是否真的需要全库共用一组参数。规章正文、表格、FAQ 和代码的自然边界不同,可以按文档类型选择切分器,但每条 Chunk 必须保留统一的来源与版本字段。分类型策略增加了维护成本,因此要用分层评测证明它确实修复了共用参数无法覆盖的错误,而不是为了显得复杂。
另外,评测记录必须保存切分器版本与字符、Token 的计量口径。否则同一个 chunk_size 在模型或分词器升级后可能对应不同的实际长度,旧实验也就无法直接复现。
Chunk 参数没有标准答案,实验和版本才是依据
我不会直接给
chunk_size和overlap一个通用数字。chunk_size决定检索单元的信息完整性和主题纯度,overlap用来保护相邻块的边界上下文,但会增加重复索引、重复召回和上下文成本。我的做法是先用当前文档构建带原文证据位置的评测集,并按普通事实、条件例外、列表、表格和跨段问题分层。然后固定解析、Embedding、召回、Top K 和重排,只改变切分配置,对比 Recall@K、MRR 或 nDCG、证据完整性、重复率、索引规模和延迟。最终选择满足高风险样本底线、效果与成本都可接受的配置,而不是只拿最高召回率。上线时新旧索引分版本,先离线回归和受控对照,再切换,并保留旧索引回退。这样参数是由证据和约束共同决定的,也能持续复现和迭代。