Jev 案例:RAG 片段批量重排(完整代码)
更新于 适用版本 Jev 1.13 示例数据(example fixture)
TL;DR: 本案例给 RAG 流水线加一道重排工序:先用向量检索拿 8 个候选片段,再用 Jev 1.13 的打分题给每个片段按 1-10 打相关性分,最后保留前三名喂给回答环节。完整批量脚本见下文。
场景
我们的 RAG 流水线负责回答几百页产品文档相关的问题。向量检索这一步快,但糙:用户问”如何不停机轮换 API key”,它会把定价页和真正的轮换指南一起返回——因为两页都提到了 “API key”。
标准解法是上一个交叉编码器重排模型。但我们不想再托管、调优、监控第二个模型,于是换了个更轻的方案:对每个检索到的片段发一次 Jev 打分题——“这个片段对回答该问题的相关程度,1 到 10 分”——然后保留前三名。
每个用户问题的完整流程:
- 向量检索取回前 8 个候选片段(这步不变);
- 每个片段一次 Jev 调用,返回
{"answer": <1-10>, "scale": [1, 10], "confidence": <0-1>, "rationale": "..."}; - 按
answer排序,保留前三,送入回答环节。
Jev 是 TypeSafe AI 发布的 System One 判断模型(2026 年 9 月),专做判断题、选择题、打分题;打分输出是类型化 JSON,排序环节完全不用解析自然语言。本示例走 OpenRouter 的 OpenAI 兼容端点。代价是每个问题要发 8 次小调用——这是延迟和成本问题,注意事项里展开。
请求
每个片段一次调用。以下面这个片段为例:
{
"model": "typesafe/jev-1.13",
"messages": [
{
"role": "system",
"content": "Scoring question. Score how relevant the chunk is to answering the user question, on a scale of 1 to 10. Reply with JSON only: {\"answer\": <1-10>, \"scale\": [1, 10], \"confidence\": <0-1>, \"rationale\": <one sentence>}"
},
{
"role": "user",
"content": "Question: How do I rotate an API key without downtime?\n\nChunk: To avoid downtime when rotating an API key, create the new key, deploy it alongside the old one, then revoke the old key after 24 hours."
}
]
}
响应
上述片段的示例数据(example fixture)——用于说明格式,不是线上实测抓包:
{
"answer": 8,
"scale": [1, 10],
"confidence": 0.86,
"rationale": "The chunk directly describes a zero-downtime key rotation procedure, though it does not cover revocation edge cases."
}
在批量运行里,那些只在定价或营销语境里提到 “API key” 的片段得分很低(我们的示例数据里是 2-4 分)——这正是向量检索没分开、而打分题分开的地方。
复现脚本
保存为 rerank.py,设置环境变量 OPENROUTER_API_KEY 后运行 python3 rerank.py:
import json, os, urllib.request
URL = "https://openrouter.ai/api/v1/chat/completions"
MODEL = "typesafe/jev-1.13" # confirm exact slug on the OpenRouter model page
QUESTION = "How do I rotate an API key without downtime?"
CHUNKS = [
"Rotate keys from Settings > API keys. Old keys keep working for 24 hours, so you can deploy the new key first.",
"Pricing for API usage is billed per million input tokens at the rate published on the pricing page.",
"To avoid downtime when rotating an API key, create the new key, deploy it, then revoke the old key after 24 hours.",
"Our support office hours are 9am-5pm PT, Monday through Friday, excluding public holidays.",
"The API rate limit is 60 requests per minute on the standard plan and 600 on the enterprise plan.",
"Two-factor authentication is required for all administrator accounts and cannot be disabled.",
"Key rotation events are written to the audit log with the acting user and timestamp.",
"Webhooks retry with exponential backoff for up to 24 hours before being marked failed.",
]
SYSTEM = ('Scoring question. Score how relevant the chunk is to answering the '
'user question, on a scale of 1 to 10. Reply with JSON only: '
'{"answer": <1-10>, "scale": [1, 10], "confidence": <0-1>, "rationale": <one sentence>}')
def score_chunk(chunk):
body = {"model": MODEL, "messages": [
{"role": "system", "content": SYSTEM},
{"role": "user", "content": "Question: " + QUESTION + "\n\nChunk: " + chunk}]}
req = urllib.request.Request(URL, data=json.dumps(body).encode(),
headers={"Authorization": "Bearer " + os.environ["OPENROUTER_API_KEY"],
"Content-Type": "application/json"})
with urllib.request.urlopen(req) as res:
payload = json.load(res)
return json.loads(payload["choices"][0]["message"]["content"])
scored = [(score_chunk(c)["answer"], c) for c in CHUNKS]
top3 = [c for _, c in sorted(scored, key=lambda p: -p[0])[:3]]
print(json.dumps(top3, indent=2))
关键参数
| 字段 | 取值 | 说明 |
|---|---|---|
model | typesafe/jev-1.13 | 固定版本,分数才能跨批次可比。准确 slug 请以 OpenRouter 模型页为准。 |
messages[0](system) | 打分题 + 量程 + JSON 结构 | 一开始就声明 1-10 和 JSON 结构,每批调用才用同一把尺子。 |
messages[1](user) | 问题 + 一个片段 | 一次只放一个片段;问题重复带上,让每次调用自成一体。 |
answer(响应) | 8 | 排序键。 |
scale(响应) | [1, 10] | 回显量程,可用作哨兵:确认模型确实在你的量程上打分。 |
confidence(响应) | 0.86(示例数据) | 可以作为第二信号:低置信度的高分要么降权、要么打标,别盲信。 |
| 价格 | $0.0462 / 1M input tokens | 每个问题 8 次短调用;预算前请在 OpenRouter 核对当前价格。 |
注意事项
- 响应为示例数据(example fixture);字段名请与官方文档核对后再依赖。官方 API 细节在 typesafe.ai,入口是System One 模型发布公告。
- 上线前请在 OpenRouter 模型页确认准确的模型 slug(
typesafe/jev-1.13)。 - 延迟:示例脚本按顺序打分,8 次调用会叠加。生产环境请把每个片段的调用并行发(它们互相独立),延迟按”最慢的那一次”预算,而不是求和。
- 把
confidence当第二信号用:同样是 8 分,置信度 0.5 的说服力远弱于 0.9。 - 适用于 Jev 1.13(2026 年 9 月发布),演示渠道为 OpenRouter。