0Pricing
AI Prompt Engineering · レッスン

取得チャンクの再ランキング

Cross-encoderによる再ランキングを学びます。

「取得チャンクの再ランキング」はCoddyKit上の無料AI Prompt Engineeringレッスンです。 これはレッスン2/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはAI Prompt Engineering学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 AI Prompt Engineeringコースには全4レッスンが含まれています。

なぜリランキングするのか

第1段階の検索(denseまたはsparse)は、大規模環境での再現率を最適化します。つまり、正解チャンクをtop 50のどこかに入れることを目指します。高速ですが、大まかな手法です。続く第2段階のリランカーは、その候補リストを並べ替えて適合率を高め、本当に関連するチャンクを上位に表示します。

この「広く検索してから正確にリランキングする」パターンが、高度なRAGの中核です。

def two_stage(query, k_retrieve=50, k_final=5):
    candidates = first_stage_retrieve(query, k_retrieve)  # high recall
    reranked = rerank(query, candidates)                  # high precision
    return reranked[:k_final]

バイエンコーダーとクロスエンコーダーの比較

バイエンコーダーはクエリとドキュメントを別々にベクトル化し、コサイン類似度で比較します。高速でインデックス化できますが、クエリとドキュメントの相互作用は失われます。クロスエンコーダーはクエリと候補を一緒にモデルへ入力し、関連性スコアを出力するため、細かな相互作用を捉えられます。

クロスエンコーダーははるかに高精度ですが、事前計算できないため、候補リストに対してのみ実行します。

# Bi-encoder: score = cos(enc(q), enc(d))     -> precomputable
# Cross-encoder: score = model(q, d) -> 0..1   -> per-pair, no index
def cross_encode(query, doc):
    return cross_encoder.predict([(query, doc)])[0]  # joint attention

クロスエンコーダーによるリランキング処理

リランカーは各候補とクエリの関連性をスコアリングし、そのスコアの降順に並べ替えます。クロスエンコーダーはクエリとドキュメントを同時に処理するため、バイエンコーダーが見逃した細かな関連性、つまり否定、完全一致の必要性、回答とトピックの区別などを解決できます。

この段階によって、他の単一のRAG改善策よりも回答精度が向上することがよくあります。

def rerank(query, candidates):
    pairs = [(query, c.text) for c in candidates]
    scores = cross_encoder.predict(pairs)        # batched
    for c, s in zip(candidates, scores):
        c.rerank_score = s
    return sorted(candidates, key=lambda c: c.rerank_score, reverse=True)

LLMをリランカーとして使う

ドメインに適した訓練済みのクロスエンコーダーがない場合は、LLMでリランキングできます。Listwiseプロンプトでは、1回の呼び出しでパッセージのリストを関連性順に並べます。pointwiseでは、各パッセージを個別にスコアリングします。

Listwiseは相対的な比較を捉えられ、トークン効率にも優れています。ただし、位置バイアスに注意し、モデルがIDを省略したり重複させたりしても堅牢に動作するよう、出力の解析を確実に行ってください。

def llm_listwise(query, candidates):
    passages = '\n'.join(
        '[' + str(i) + '] ' + c.text for i, c in enumerate(candidates)
    )
    prompt = (
        'Rank the passages by relevance to the query. '
        'Return only IDs, most relevant first.\nQuery: ' + query +
        '\n' + passages
    )
    order = parse_ids(llm(prompt, temperature=0))
    return [candidates[i] for i in order]

レイテンシと候補リストのサイズ

リランキングのコストは候補リストのサイズに応じて増加します。50個の候補に対してクロスエンコーダーを実行するほうが、500個に対して実行するよりはるかに低コストです。第1段階のkは、正解チャンクを取り込めるだけの大きさ(recall@kで検証します)にしつつ、レイテンシの予算内でリランキングできる程度に小さく設定してください。

候補ペアのスコアリングはバッチ処理し、アクセラレータ上で実行してください。クロスエンコーダーはペア間で効率よく並列化できます。

def tune_shortlist(eval_set, ks=(20, 50, 100, 200)):
    # find smallest k where recall@k saturates -> rerank fewer pairs
    return {k: (recall_at_k(eval_set, k), rerank_latency(k)) for k in ks}

ハイブリッドな第1段階と再ランキング

最も高い再現率を得られるのは、ハイブリッドな第1段階(dense と BM25 を融合)から、重複を除去した単一の候補リストを再ランキング器に渡す構成です。dense は言い換えを拾い、sparse は識別子の完全一致を拾います。そして cross-encoder が、統合された候補を真の関連性に基づいて並べ替えます。

この組み合わせは、自然言語の質問から文字どおりの検索まで、さまざまなクエリタイプに対して堅牢です。

def hybrid_then_rerank(query, k_final=6):
    dense = dense_retrieve(query, 50)
    sparse = bm25_retrieve(query, 50)
    fused = dedup(rrf(dense, sparse))     # reciprocal rank fusion
    return rerank(query, fused)[:k_final]

スコアのしきい値と打ち切り

再ランキングのスコアはキャリブレーションできます。常に top-n 件を取得するのではなく、関連性のしきい値を適用します。一定のスコアを上回るチャンクだけを残し、該当するものがなければ、正直に回答なしを返します。これにより、関連性の低い埋め草でプロンプトを埋めるのを防げます。

検証用データセットでしきい値を調整し、回答可能な範囲とノイズの混入のバランスを取ります。

def threshold_select(reranked, tau=0.3, max_n=8):
    kept = [c for c in reranked if c.rerank_score >= tau][:max_n]
    if not kept:
        return None        # signal: no sufficiently relevant context
    return kept

再ランキング後の多様性

関連性だけで並べると、同じドキュメントからほぼ重複したチャンクが複数返され、コンテキストの予算を無駄にすることがあります。再ランキング後にMMRまたはドキュメントごとの上限を適用し、最終的なセットが異なる観点と出典をカバーするようにします。

これは、回答が複数のドキュメントにまたがるマルチホップ質問で特に重要です。

def diversify(reranked, max_per_doc=2, k=6):
    out, per_doc = [], {}
    for c in reranked:
        d = c.meta['doc_id']
        if per_doc.get(d, 0) < max_per_doc:
            out.append(c)
            per_doc[d] = per_doc.get(d, 0) + 1
        if len(out) == k:
            break
    return out

生成モデルのための並べ替え

上位のチャンクを選択したら、アテンションを活用できるように配置します。lost-in-the-middle を考慮し、最も高いスコアのチャンクはコンテキストの途中に埋めず、先頭または末尾に置きます。

一部のパイプラインでは、few-shot における近接性の戦略にならい、関連性の昇順にチャンクを並べます。これにより、最も関連性の高いチャンクが質問の近くに配置されます。

def order_for_llm(chunks):
    chunks = sorted(chunks, key=lambda c: c.rerank_score)  # ascending
    return chunks                 # most relevant chunk ends up last,
                                  # nearest the trailing question

再ランキング器の評価

再ランキング器は、ラベル付きのクエリとチャンクの関連性データに対するランキング指標、主にNDCGと MRRで評価し、続いて下流の回答精度も測定します。NDCGは改善しても回答が改善しない再ランキング器は、生成モデルがすでに適切に処理していたチャンクの順序を変えているだけかもしれません。

ランキング指標だけでなく、必ず最終タスクの品質まで評価してください。

import math

def ndcg_at_k(relevances, k):
    dcg = sum(r / math.log2(i + 2) for i, r in enumerate(relevances[:k]))
    ideal = sorted(relevances, reverse=True)
    idcg = sum(r / math.log2(i + 2) for i, r in enumerate(ideal[:k]))
    return dcg / idcg if idcg else 0.0

本番環境向け再ランキングパイプライン

エンドツーエンドでは、ハイブリッド検索で50件の候補リストを取得し、重複を除去し、cross-encoder で再ランキングし、スコアのしきい値を適用し、ドキュメント単位で多様化し、アテンションを考慮して並べ、引用付きで生成します。しきい値を満たすかどうかで分岐し、正直に回答なしを返します。

トラフィックが繰り返される場合は、コストを削減するため、(query, chunk) ごとに埋め込みと再ランキングスコアをキャッシュします。

def pipeline(query):
    shortlist = hybrid_then_rerank(query, k_final=20)
    kept = threshold_select(shortlist, tau=0.3, max_n=8)
    if kept is None:
        return 'No relevant information found.'
    ctx = order_for_llm(diversify(kept))
    return generate_with_citations(query, ctx)

クイックチェック

適切な再ランキングアーキテクチャを選んでください。

まとめ

主なポイント:

  • 再現率を高めるために幅広く検索し、その後、適合率を高めるために候補リストを再ランキングします。
  • Cross-encoder はクエリとドキュメントのペアを同時にスコアリングします(精度は高いものの、インデックス化できません)。Bi-encoder は高速ですが、大まかな評価になります。
  • LLMによる listwise/pointwise 再ランキングはフォールバックとして使えますが、位置バイアスとパース処理に注意してください。
  • レイテンシー予算の範囲で再現率が飽和するように候補リストのサイズを調整し、ハイブリッドな第1段階の検索と組み合わせます。
  • スコアのしきい値を適用し、ドキュメント単位で多様化し、アテンションを考慮してチャンクを並べ、NDCG と下流の回答精度で評価します。

よくある質問

「取得チャンクの再ランキング」レッスンは無料ですか?

はい。「取得チャンクの再ランキング」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、AI Prompt Engineeringコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 AI Prompt Engineeringコースには全4レッスンが含まれています。

「取得チャンクの再ランキング」で何を学びますか?

Cross-encoderによる再ランキングを学びます。 ブラウザで直接実行するハンズオンコードでAI Prompt Engineeringを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

AI Prompt Engineeringを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのAI Prompt Engineeringは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン2/4です。

「取得チャンクの再ランキング」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このAI Prompt Engineeringレッスンでコードを書いて実行できますか?

はい。すべてのAI Prompt Engineeringレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. 素朴なRAGを超えて
  2. 取得チャンクの再ランキング
  3. コンテキスト圧縮
  4. クエリ書き換えとHyDE
← AI Prompt Engineeringに戻る