完整管线怎么组装
可用的检索管线是分层的:混合召回(向量加关键词)合并去重、交叉编码重排、按上下文条数截断,最后交给生成。每一层都有独立的评测点,调参要自下而上——先确认召回上限,再优化排序,最后调上下文条数与提示词,避免多层同时改动。
基本信息
| 层次 | 召回、融合去重、重排、截断、生成 |
|---|---|
| 关键参数 | 各层候选条数与重排后进入上下文的数量 |
| 上线顺序 | 召回、重排、上下文条数、提示词 |
| 评测点 | 每层单独看命中率与延迟,避免端到端黑盒 |
管线骨架
管线骨架
def rag_retrieve(query):
dense = vector_store.search(embed(query), top_k=50)
sparse = bm25.search(query, top_k=50)
merged = rrf([dense, sparse])[:50] # 融合去重
ranked = cross_encoder_rerank(query, merged) # 精排
return ranked[:8] # 上下文条数各层取舍
| 层 | 调大收益 | 调大代价 |
|---|---|---|
| 召回池 | 重排可选择面更大 | 粗排与重排耗时上升 |
| 重排 top_n | 上下文更准 | 生成输入更长 |
| 上下文条数 | 信息更全 | 触达中间遗忘与超长风险 |
调参顺序
- 先扩召回池到几十条,确认目标片段确实进了候选
- 再加入重排,只看前几位的命中率有没有提升
- 然后逐步压缩进入上下文的条数,观察答案完整性变化
- 最后调提示词与引用格式,此时检索侧应已稳定
- 每一步都留存指标与参数,改动才能归因
工程要求
- 各层超时可配且可降级:重排超时退回召回顺序仍能出答案
- 重排候选数设上限,防止知识库变大后延迟失控
- 记录每层的输入输出条数,异常时先看条数再看分数
- 把重排模型与向量模型的版本一并记录,排障时不必靠猜
- 评测脚本与线上管线共用同一段检索代码,避免两套实现漂移
上线顺序建议:先调召回、再上重排、最后调上下文条数与提示词,避免多层同时改动导致问题无法定位。
端到端延迟怎么分配
线上检索的耗时是各层之和:两路召回各一次查询、融合去重、重排逐对打分、上下文组装。经验做法是先给重排设上限,候选控制在几十条以内,其余环节按剩余余量分配预算;同时把每层耗时单独打点,出现抖动时能立刻看出是哪一层变慢。若重排服务与生成服务共用资源,必须单独限流与隔离,否则生成高峰会连带把重排拖垮,表现得像是检索出了问题。
常见误判
- 把延迟波动归因于向量库,实际是重排候选数随知识库增长而上升
- 只看平均延迟,忽略高分位,用户感知的卡顿都发生在长尾
- 重排与生成串行部署在同一进程,互相争抢资源却难以定位
- 上下文条数调大后没同步检查总耗时,以为是模型变慢了