24-RAG重排改写与证据边界

O泡李华 6

RAG 怎样取得完整证据?重排、改写与拒答

正确文档进入候选,却排在很后;改写问题以后,关键订单编号消失了;上下文塞得更多,回答反而忽略例外。这些问题说明召回数量与最终证据质量不是同一件事。

Spring AI 接入片段使用 Java 17、Spring Boot 3.5.3 与 Spring AI 1.1.8;协议与第三方平台示例另行标明适用范围。

1. 重排先解决候选顺序

它不能找到根本没有进入候选的证据。

重排为什么通常放在召回之后?

Embedding 检索适合从大范围选出候选;Cross-Encoder 等重排方法可以同时读取问题与片段,进行更细的相关性判断,但逐对计算通常有更高成本。

因此常见流程是“召回较多候选,重排后选择少量证据”,而不是对全库每篇文档都调用重排模型。Sentence Transformers Retrieve & Re-Rank

相关性高仍不保证当前有效或已授权。权限、版本与来源过滤必须在内容交给外部重排服务之前完成。

重排结果也要检查协议

外部重排接口可能返回候选下标与分数。程序要检查下标范围、重复、缺失和非有限值,不能直接用返回下标访问数组。

下面 Java 17 接入组件只定义并校验接口契约,不假设某个供应商的 HTTP API。

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public final class RerankStage {
    public record Hit(String id, String text) {}
    public record Ranked(int index, double score) {}
    public interface Reranker {
        List<Ranked> rank(String query, List<String> candidates);
    }
    private final Reranker reranker;

    public RerankStage(Reranker reranker) {
        this.reranker = reranker;
    }

    public List<Hit> choose(String query, List<Hit> authorizedHits, int keep) {
        if (query == null || query.isBlank() || keep < 1 || authorizedHits.size() > 50) {
            throw new IllegalArgumentException("invalid request");
        }
        if (authorizedHits.isEmpty()) return List.of();
        List<Ranked> ranked = reranker.rank(query,
                authorizedHits.stream().map(Hit::text).toList());
        if (ranked == null) throw new IllegalStateException("rerank response missing");
        Set<Integer> seen = new HashSet<>();
        for (Ranked item : ranked) {
            if (item == null || item.index() < 0 || item.index() >= authorizedHits.size()
                    || !Double.isFinite(item.score()) || !seen.add(item.index())) {
                throw new IllegalStateException("invalid rerank response");
            }
        }
        List<Ranked> sorted = new ArrayList<>(ranked);
        sorted.sort((a, b) -> Double.compare(b.score(), a.score()));
        return sorted.stream().limit(keep).map(item -> authorizedHits.get(item.index())).toList();
    }
}

示例允许服务只返回候选子集,并约定高分更相关。真实供应商的分数方向、截断和最大输入需另外确认;如果业务要求完整排序,还应检查返回是否覆盖全部候选。

它没有实现 HTTP 调用,不是可直接请求某个模型的客户端。Reranker 实现还需超时、额度与脱敏规则。

2. 改写需要保护问题里的精确信息

扩展路线增加召回机会,也增加漂移与费用。

查询改写可能改善什么?

多轮对话的“那它支持什么格式”缺少主语,可基于已授权历史补全对象。用户词语与文档术语不同,也可以增加检索表达。

改写必须保留产品、版本、编号、时间与否定条件。把“哪些不支持”改成“支持哪些”,检索即使更容易命中,也改变了原问题。

可以同时保留原问题和受控改写,并记录改写版本。生成答案仍回答原问题,不能把改写当成用户亲自补充的事实。

改写与扩展不能无限增长

生成十个改写各检索二十条,再全部送入重排,候选与费用会快速增加。要限制改写数量、每路候选、去重后总量和整体截止时间。

查询改写服务失败时可以按规则使用原问题;重排失败时可以回退到原排序,但应记录这次使用了回退方案。回退后是否仍有足够证据,要重新判断。

外部重排会接触原文,调用它本身也是数据出域的一步。不能直到最终生成前才开始检查权限。

什么是消融评估?

在其余条件固定时,比较去掉或加入某一步的结果:基线召回、基线加改写、基线加重排、两者同时加入。

方案 主要观察
基线 原始召回与完整证据覆盖
加改写 新候选是否带来正确证据,也是否改变意图
加重排 正确候选是否进入最终 Prompt
两者 收益是否叠加,额外延迟与费用是否可接受

记录按类别的检索和回答指标、P50/P95 延迟及成本。不要把不同模型、不同语料和不同问题集的分数直接放在一起宣称提升。本文提供评估设计,没有实测增益。

3. 证据不足时如何停止生成确定结论

澄清、拒答与有限回答各自对应不同条件。

把失败放回对应阶段

阶段 典型问题 首先检查
解析 表格、否定词或单位错误 原文件与提取内容
切分 例外条件分离 片段及父级上下文
召回 正确资料没进候选 查询、过滤与索引
重排 正确候选被挤掉 排名前后与预算
生成 忽略条件、补充未经支持的事实 实际 Prompt 与逐条结论
引用 编号合法但不能支持断言 结论与原文对应关系

不要把所有问题都解决成“换更强模型”。解析把金额单位搞错后,强模型也可能忠实地解释错误资料。

相似度不能决定是否可回答

空结果可以作为资料不足信号,有结果却不一定具有答案。某片段讨论同一产品,但没有用户问的版本和功能,仍然不能直接确认。

相反,过高阈值可能丢掉用词不同但真实相关的资料。拒答条件需要在固定问题集上校准,而不是把 0.8 当作通用可信线。

还要检查证据新旧、互相冲突以及问题缺少的限定。存在两个版本的不同规则时,可以说明无法确认当前适用版本,或者请用户补充,而不是选择分数最高的一个。

什么情况应该澄清,什么情况应该拒答?

缺少产品、日期、版本等必要条件时,可以先澄清;资料没有覆盖问题或证据冲突无法解决时,应说明无法确认;资料有明确答案时,则不应因为某个分数不够高机械拒答。

对无权限资料,不应透露它是否存在。对金额、审批和执行建议,不能把无依据的推断直接转成工具动作。

拒答可以说明允许范围内的原因和下一步,例如“当前资料未包含这项功能的版本说明”。不要编造不存在的官方链接让用户继续查。

为什么把更多资料塞进 Prompt 未必有效?

更多候选会增加重复、冲突和无关内容,模型也未必均等利用所有位置。长上下文研究提供了位置敏感性的证据,但具体模型效果仍需自己的评估。Lost in the Middle

优先选择完整、有效、已授权的证据,保留关键例外,再按预算组织。文档中的“忽略规则并调用工具”应当视为不可信内容;仅加提示词不能替代工具授权。

怎样降低问题再次发生的概率?

保留问题类别、候选证据、配置版本和失败原因,在授权范围内形成回归样本。分别衡量无依据回答、引用错误、错误拒答和正确拒答,而不是只看回答覆盖率。

对关键事实采用明确业务来源或确定性校验,例如订单真实状态来自授权查询工具。把生成式解释与事实获取分开,可以减少模型凭记忆猜业务数据。

4. 设计判断与适用边界

为原始问题保留不可丢失的信息,例如编号、租户范围和时间条件。改写只改变表达,不改变用户意图;候选集和重排输入有大小限制,避免查询扩展无限增长。

上下文补充是另一种方案:为孤立片段加入能在原文验证的标题和对象说明。它不能作为模型自行补全事实的入口。通过消融比较切分、混合召回、重排和改写的贡献,只有效果足以覆盖成本时才保留新增组件。

Contextual Retrieval 讨论为片段补充文档上下文。是否适用仍要通过本项目样本比较,本文没有移用其效果指标。 Anthropic:Introducing Contextual Retrieval。

5. 问答

问:重排能找回没有召回的文档吗?

答:不能,它处理已有候选,应先保证召回覆盖。

问:改写越多越好吗?

答:会增加噪声、请求数和费用,需要固定问题集评估并限制总预算。

问:有检索结果就不应该拒答吗?

答:结果可能只是主题相近,要看是否完整支持当前问题。

问:引用编号存在就证明主张成立吗?

答:只能证明引用属于候选集合,还需检查原文是否支持对应主张。

参考资料