相似度阈值与无答案判定
阈值用来判断“知识库里到底有没有相关内容”:取回结果后看最高分是否低于阈值,低于就进入兜底话术,而不是硬让模型生成。阈值没有通用常数——它取决于 embedding 模型、是否归一化、分数口径(余弦、内积还是重排分),照抄别人博客里的数字通常会让误拒率飙升。正确做法是从标注样本里观察相关与不相关两类问题的分数分布,取一个在误拒(该答没答)与误收(没答案硬答)之间平衡的位置。
基本信息
| 作用 | 判断是否有相关内容,决定是否走兜底 |
|---|---|
| 取值来源 | 标注样本的分数分布,不照搬外部经验值 |
| 影响变量 | embedding 模型、归一化方式、分数口径、是否重排后判定 |
| 两类错误 | 误拒(漏答)与误收(答错) |
| 配套动作 | 阈值变更要重跑评测,包含“无答案集”子集 |
典型使用场景
- 内部制度问答:库里没有的问题必须明说没有,不能编造条款
- 服务健康监控:统计低于阈值的查询占比,骤升说明语料或检索链路出了问题
- 换模型后重新定标:新模型的分数分布不同,旧阈值直接失效
- 多路召回判定:在融合后的分数上定阈值,而不是在某一路的原始分数上
- 与重排配合:先按召回分做粗筛,再按重排分做最终无答案判定
阈值判定与兜底
阈值判定与兜底
hits = vector_store.search(q_vec, top_k=10)
best = hits[0].score if hits else 0.0
if best < ANSWER_THRESHOLD: # 阈值来自标注样本
return '知识库中未找到相关内容,建议转人工或换个问法。'
answer = generate(q, build_context(hits))两类错误的取舍
| 阈值 | 误拒 | 误收 | 适用 |
|---|---|---|---|
| 偏高 | 增多:有问题也拒答 | 减少 | 合规、医疗等不能出错的场景 |
| 居中 | 平衡 | 平衡 | 多数企业知识库 |
| 偏低 | 减少 | 增多:没依据也生成 | 探索性检索、辅助人工判断 |
阈值算在哪个分数上要写进文档:向量分、融合分、重排分三者分布不同,业务代码与评测脚本必须用同一个口径,否则两处逻辑会打架。