Jev で検索結果をリランキング:検証できる関連度ルーブリック

検索で候補を素早く絞り込み、4 段階の Score ルーブリックで 1 件ずつ評価し、並べ替え・同点・該当なしをコードで扱います。

このガイドの範囲:リクエスト形式とアプリケーションコードは、2026-09-25 に確認した TypeSafe 公式ドキュメントに基づいています。問い合わせ文、ラベル、しきい値は業務ルールを説明するための合成例です。モデルの出力、精度、速度、費用の比較は掲載していません。利用前に、自社のラベル付きデータで測定してください。

1. 役割を分ける:検索で絞り込み、リランキングで並べ替える

高速な検索(キーワード検索や BM25、埋め込みベクトル、各種フィルター)は、問いをコーパス全体と比べて候補リストを返します。リランキングは、その候補の 1 件ずつを問いと突き合わせ、候補リストの中だけを並べ替えます。TypeSafe の Re-ranking クックブックと Elastic のセマンティックリランキングの資料も、この 2 段階の構成を説明しています。閲覧権限、鮮度、重複除去、業務上のフィルターは検索段階で処理してください。ユーザーが開けない結果をリランカーに渡してはいけません。

検索で返らなかった文書は、リランキングでは取り戻せません。正解が候補リストに入っていないことが多いなら、先に検索側を直します。

2. 評価の基準を書く

実験室の例と同じ 4 段階の基準です。右の列は、問い「Python から Jev を使うにはどうすればよいですか?」に対する合成の候補で、モデルの判定結果ではありません。

レベル意味合成した候補
0問いと無関係10 月のオフィス休業日のお知らせ。
1関連する話題だが、答えにはなっていないJev は入力トークンに対して課金され、出力トークンは無料です。
2有用な背景情報または部分的な答えTypeSafe はクライアント SDK を提供しています。対応言語は SDK のページを参照してください。
3問いに直接答えている公式 TypeSafe Python SDK は、System One への同期リクエストと非同期リクエストに対応しています。

指示文には何を判断するかを書きます。ここで見るのは「この問いへの関連度」であり、出典そのものの品質ではありません。品質、鮮度、信頼性も必要なら別の質問として評価し、重みはコードで組み合わせます(TypeSafe の Composite scoring パターン)。

3. 問いと候補 1 件ずつのリクエスト

実験室の relevance-score の例 を開くと、次のリクエストが読み込まれます。

{
  "model": "jev-1.13.0",
  "state": {
    "query": "Python から Jev を使うにはどうすればよいですか?",
    "result": "公式 TypeSafe Python SDK は、System One への同期リクエストと非同期リクエストに対応しています。"
  },
  "questions": {
    "decision": {
      "type": "score",
      "instructions": "この結果は検索の問いにどの程度直接答えていますか? 情報源全般の品質ではなく、関連性を判断してください。",
      "criteria": [
        "問いと無関係",
        "関連する話題だが、答えにはなっていない",
        "有用な背景情報または部分的な答え",
        "問いに直接答えている"
      ]
    }
  }
}
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": "Python から Jev を使うにはどうすればよいですか?",
    "result": "公式 TypeSafe Python SDK は、System One への同期リクエストと非同期リクエストに対応しています。"
  },
  "questions": {
    "decision": {
      "type": "score",
      "instructions": "この結果は検索の問いにどの程度直接答えていますか? 情報源全般の品質ではなく、関連性を判断してください。",
      "criteria": [
        "問いと無関係",
        "関連する話題だが、答えにはなっていない",
        "有用な背景情報または部分的な答え",
        "問いに直接答えている"
      ]
    }
  }
}
JEV_ATLAS_REQUEST

候補ごとに 1 回ずつリクエストを送ると、ある候補の文章がほかの候補の評価に影響しません。これは TypeSafe の Re-ranking クックブックと同じ構成です。クックブックでは Score の代わりに、候補ごとに「はい/いいえ」で答える Noul を使っています。どちらも成り立つ設計なので、どちらの並び順が利用者の役に立つかはラベル付きデータで確かめます。候補ごとのリクエストはそれぞれ入力トークン分の料金がかかります。実験室の費用計算(入力 100 万トークンあたり 0.042 ドル。TypeSafe のモデルページで 2026-09-25 に確認)で見積もってください。

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 のラベルを付けます。できれば 2 人で付け、意見が割れたら基準の文を直します。ラベルは 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 を開く · 判断しやすい質問の書き方