用 Jev 重排搜索结果:可测试的相关性评分标尺

检索负责快速召回,Jev 用四级 Score 标尺逐条评分,排序、平分与“没有合适结果”都由代码处理。

本文范围:请求格式与应用代码依据 2026-09-25 核对的 TypeSafe 官方文档。文中的工单、标注和阈值都是演示业务规则的合成示例。本页不提供模型输出、准确率、速度或费用对比;上线前请用你自己的标注数据测量。

1. 分工:检索负责召回,重排负责排序

快速检索(关键词或 BM25、向量检索、各类过滤条件)会把查询与整个语料比较,返回一份候选清单。重排则把查询与清单里的每个候选逐一比较,只调整这份清单内部的顺序。TypeSafe 的 Re-ranking 实践手册和 Elastic 的语义重排文档都描述了这种两阶段结构。访问权限、时效、去重和业务过滤都应在检索阶段完成,绝不能把用户无权打开的结果交给重排。

检索没有召回的文档,重排也救不回来。如果正确答案经常不在候选清单里,应先改进检索。

2. 写好评分标尺

下面是与实验室示例相同的四级标尺。右列是针对查询“怎样在 Python 中使用 Jev?”的合成候选,不是模型的判断结果。

等级含义合成候选
0与查询无关十月办公室放假安排。
1主题相关,但不是答案Jev 按输入 token 计费,输出 token 免费。
2有用的背景信息或部分答案TypeSafe 提供多种客户端 SDK,支持的语言见 SDK 页面。
3直接回答了查询官方 TypeSafe Python SDK 支持同步和异步的 System One 请求。

指令要说清判断什么:这里只看“与该查询的相关程度”,不评价来源本身的质量。如果还需要质量、时效或权威性,就作为单独的问题评估,再在代码里加权组合(TypeSafe 的 Composite scoring 模式)。

3. 每对“查询 + 候选”一次请求

在实验室打开 relevance-score 示例,会载入下面的请求。实验室示例使用英文内容,与本站英文版一致。TypeSafe 模型页面(2026-09-25 核对)说明英语是主要训练语言,中文内容请在自己的数据上测试。

{
  "model": "jev-1.13.0",
  "state": {
    "query": "How can I use Jev from Python?",
    "result": "The official TypeSafe Python SDK supports synchronous and asynchronous System One requests."
  },
  "questions": {
    "decision": {
      "type": "score",
      "instructions": "How directly does this result address the query? Judge relevance, not the source's general quality.",
      "criteria": [
        "Unrelated to the query",
        "Related topic, but not an answer",
        "Useful context or a partial answer",
        "Directly addresses the query"
      ]
    }
  }
}
curl --fail-with-body --max-time 20 https://api.typesafe.ai/v1/systemone \
  -H "Authorization: Bearer $TYPESAFE_API_KEY" \
  -H "Content-Type: application/json" \
  --data-binary @- <<'JEV_ATLAS_REQUEST'
{
  "model": "jev-1.13.0",
  "state": {
    "query": "How can I use Jev from Python?",
    "result": "The official TypeSafe Python SDK supports synchronous and asynchronous System One requests."
  },
  "questions": {
    "decision": {
      "type": "score",
      "instructions": "How directly does this result address the query? Judge relevance, not the source's general quality.",
      "criteria": [
        "Unrelated to the query",
        "Related topic, but not an answer",
        "Useful context or a partial answer",
        "Directly addresses the query"
      ]
    }
  }
}
JEV_ATLAS_REQUEST

每个候选单独发送一次请求,候选之间的文字就不会互相影响评分,这与 TypeSafe Re-ranking 手册的结构一致。该手册对每一对使用 Noul 提出是非问题,而不是 Score;两种设计都成立,哪种排序对你的用户更有用,要靠标注集来验证。每次请求都按输入 token 计费,可以用实验室的费用计算器估算(每百万输入 token 0.042 美元,2026-09-25 于 TypeSafe 模型页面核对)。

4. 排序、平分与“没有合适结果”都交给代码

// Node 18+ or any runtime with fetch. NO_ANSWER_BELOW, TIE_BAND and CONCURRENCY are
// example values to calibrate on your labeled queries, not measured results.
const ENDPOINT = 'https://api.typesafe.ai/v1/systemone';
const LEVELS = [
  'Unrelated to the query',
  'Related topic, but not an answer',
  'Useful context or a partial answer',
  'Directly addresses the query',
];
const NO_ANSWER_BELOW = 2;
const TIE_BAND = 0.1;
const CONCURRENCY = 4;

async function scoreCandidate(query, text, apiKey) {
  const response = await fetch(ENDPOINT, {
    method: 'POST',
    headers: { Authorization: `Bearer ${apiKey}`, 'Content-Type': 'application/json' },
    body: JSON.stringify({
      model: 'jev-1.13.0',
      state: { query, result: text },
      questions: {
        relevance: {
          type: 'score',
          instructions: "How directly does this result address the query? Judge relevance, not the source's general quality.",
          criteria: LEVELS,
        },
      },
    }),
    signal: AbortSignal.timeout(20_000),
  });
  if (!response.ok) throw new Error(`typesafe_http_${response.status}`);
  return (await response.json()).answers.relevance;
}

// candidates: [{ id, text }] in the order your retrieval step returned them.
export async function rerank(query, candidates, apiKey) {
  const scored = [];
  for (let start = 0; start < candidates.length; start += CONCURRENCY) {
    const batch = candidates.slice(start, start + CONCURRENCY);
    const answers = await Promise.all(batch.map(item => scoreCandidate(query, item.text, apiKey)));
    answers.forEach((answer, offset) => scored.push({
      ...batch[offset],
      retrievalRank: start + offset,
      score: answer.score,
      direct: answer.probabilities[String(LEVELS.length - 1)],
      confidence: answer.confidence,
    }));
  }
  const best = Math.max(-1, ...scored.map(item => item.score));
  // Nothing reaches "useful context": say so and keep the retrieval order.
  if (best < NO_ANSWER_BELOW) return { noDirectAnswer: true, results: candidates };
  const band = item => Math.round(item.score / TIE_BAND);
  scored.sort((a, b) => band(b) - band(a) || b.direct - a.direct || a.retrievalRank - b.retrievalRank);
  return { noDirectAnswer: false, results: scored };
}

Score 答案中的 score 是按各等级概率加权得到的值,可能落在两个等级之间。TypeSafe 的 Jev 1.13 已知局限页面指出,这个值可以用来判断是否超过阈值,但不适合还原精确的数量。因此代码把很小的差距视为平分(TIE_BAND),平分时先比较最高等级的概率,再按原检索名次排列。

如果没有任何候选达到“有用的背景信息”,就不要把勉强相关的结果顶上去,而是如实告知:保留原顺序,显示“没有找到直接答案”,并提示用户调整查询。confidence 偏低(概率分布较分散)的候选可保留原检索名次;在重要列表里,也可以交给人工复核。

5. 建一份小型标注测试集

上线前收集真实查询(需获得使用许可),对检索返回的候选逐条标注 0 到 3 级。最好由两个人分别标注,有分歧时修改标尺文字。标注必须在运行 Jev 之前定稿。下表是针对查询“怎样在 Python 中使用 Jev?”的合成示例。

候选检索名次标注(运行前写好)
c1:包含 System One 调用的 Python SDK 快速入门43
c2:JavaScript SDK 更新日志11
c3:如何设置 TYPESAFE_API_KEY 环境变量22
c4:办公室放假安排50
c5:Choice、Score、Noul 概览32
// labels: { [candidateId]: 0 | 1 | 2 | 3 }, written before any model run.
// Orders are arrays of candidate IDs; retrieval order is the baseline.
export function compareOrders(labels, retrievalOrder, rerankedOrder) {
  const summary = order => ({
    topIsDirect: labels[order[0]] === 3,
    unrelatedInTopThree: order.slice(0, 3).filter(id => labels[id] === 0).length,
    firstDirectPosition: order.findIndex(id => labels[id] === 3) + 1 || null,
  });
  return { retrieval: summary(retrievalOrder), reranked: summary(rerankedOrder) };
}

可以在自己的数据上计算的指标举例:最高位结果为 3 级的查询占比、前 3 名中 0 级结果的数量、3 级候选相对检索顺序是上升还是下降。以纯检索的顺序作为基线。本页不提供任何结果,这些数字只有在你自己的语料和查询上测量才有意义。

采用类似做法的项目

以上条目于 2026-09-18 依据各自 README 核对来源。Jev Atlas 没有运行、测评或做安全审计。

资料来源

TypeSafe 文档核对日期:2026-09-25。模型、限额和价格可能变化,接入前请以官方为准。

动手试试

在实验室打开 relevance-score · 如何写出好判断的问题