用 Jev 做 RAG 重排:答案更准、成本更低

更新于 适用版本 Jev 1.13

TL;DR: 召回负责找到”看起来相关”的 chunk,重排(rerank)负责判断”哪个真的能回答问题”。用 Jev 的打分题(scoring)给每个候选 chunk 的相关性打 1-10 分,排序、按阈值截断,只让幸存者进入生成模型。用几次廉价的打分调用换来更少、更干净的上下文 token——答案更准,生成成本更低。文末附 50 行以内的最小实现。

这里的”重排”指什么

{"answer":8,"scale":[1,10],"confidence":0.86,"rationale":"直接定义了问题所问的重试策略。"}

answer 是相关性分,confidence 表示模型对自己这个分数有多大把握,rationale 在你回头排查检索质量时非常有用。

流程图

用户问题
   |
   v
第一阶段召回(top-50 候选)
   |
   v
逐 chunk 调 Jev scoring(相关性,1-10 分制)
   |
   v
按分数降序排序
   |
   +--> 分数 >= 7 且置信度可接受 --> 保留
   |
   +--> 其余 --> 丢弃
   |
   v
取前 k 个幸存 chunk 作为生成上下文

重活仍然在召回器,Jev 只负责判断”已经找到的东西够不够好”。

最小实现

import os, json, requests

URL = "https://openrouter.ai/api/v1/chat/completions"
# Confirm the exact model slug on the OpenRouter model page.
MODEL = "typesafe/jev-1.13"

def score_chunk(query: str, chunk: str) -> dict:
    resp = requests.post(
        URL,
        headers={"Authorization": f"Bearer {os.environ['OPENROUTER_API_KEY']}"},
        json={
            "model": MODEL,
            "messages": [
                {"role": "system", "content":
                 "Score how well this passage answers the query, 1-10. "
                 "1 = irrelevant, 10 = directly and completely answers it."},
                {"role": "user", "content": f"Query: {query}\n\nPassage: {chunk[:2000]}"},
            ],
            "temperature": 0,
        },
        timeout=30,
    )
    resp.raise_for_status()
    # 示例数据(example fixture):
    # {"answer":8,"scale":[1,10],"confidence":0.86,"rationale":"..."}
    return json.loads(resp.json()["choices"][0]["message"]["content"])

def rerank(query, chunks, min_score=7, top_k=5):
    scored = [(score_chunk(query, c), c) for c in chunks]
    scored.sort(key=lambda x: x[0]["answer"], reverse=True)
    return [c for s, c in scored if s["answer"] >= min_score][:top_k]

rerank() 返回清洗后的上下文列表,RAG 栈其余部分原样不动。官方 API 的端点与字段以 typesafe.ai 官方文档为准。

阈值建议

配置项建议理由
分制[1, 10]足以区分”沾边”和”能回答”
收录线分数 >= 7低于此线的 chunk 很少改变最终答案
top-k 上限5(在 3-8 之间调)即使大量 chunk 过线,生成 token 也有上限
打分低置信度丢弃,或触发更宽召回重试模型自己都没把握的分数,本身就是弱证据
批量说明串行或小并发打分批量重排案例讨论了吞吐与限流的平衡

本场景依赖 Jev 的三原语(three primitives)——scoring 是三种任务类型之一;成本与延迟(cost and latency)指南解释了为什么”廉价判断调用放在昂贵生成模型前面”通常在总花费上更划算。RAG chunk 批量重排的案例里给出了实测数据。

本文适用版本:Jev 1.13。

FAQ

常见问题

Jev 在 RAG 重排环节里扮演什么角色?

第一阶段召回拿到宽候选集后,用 Jev 的 scoring 调用给每个 chunk 的相关性打分,按分数排序、按阈值截断,只把留下的高质量 chunk 交给生成模型。

截断 chunk 的分数阈值怎么定?

在 1-10 分制上,7 分且置信度可接受是比较合理的收录线;同时叠加 top-k 上限,保证生成模型不会拿到过多上下文。

用 Jev 重排比只用向量检索更贵吗?

每个候选 chunk 多一次廉价的打分调用,但下游可以少喂、喂得更准。批量 chunk 重排案例详细测算了这笔成本账。

继续阅读