AI Prompt Engineering · レッスン

クエリ書き換えとHyDE

検索再現率を向上させます。

レッスン 4/413 ステップ

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

クエリが弱点

検索品質はクエリによって上限が決まります。ユーザーの元のクエリは、短く、曖昧で、代名詞が多く、ドキュメントとは異なる表現になっていることがよくあります。クエリ変換は、検索前にクエリの形を変え、再現率と適合率を高めます。

これは素朴な RAG に対する、最も安価で効果の大きい改善の一つです。クエリを改善すれば、その後のすべての段階に効果が及びます。

def transform_query(raw, history):
    # Resolve references, expand, decompose, or hypothesize
    # BEFORE embedding and retrieving.
    return rewrite(raw, history)

クエリ書き換え

最も単純な変換です。LLMがユーザーのクエリを、より明確で自己完結した、検索に適した形式に書き換えます。誤字を修正し、省略語を展開し、会話的なノイズを取り除きます。

これは、最新のメッセージだけでは文脈がなければ意味を理解できないマルチターンチャットで特に重要です(2つ目はどうですか?)。

def rewrite_query(raw):
    prompt = (
        'Rewrite the user question into a clear, standalone search '
        'query optimized for document retrieval. Keep key entities.\n'
        'Question: ' + raw
    )
    return llm(prompt, temperature=0).strip()

会話の凝縮

チャット RAG では、対話と新しいターンを1つの独立した質問に凝縮します。これを行わないと、代名詞や省略によって埋め込みが意味を持たなくなり、検索が機能しなくなります。

書き換え器が「それ」「あれ」「前のもの」を、検索器が照合できる明示的なエンティティに解決できるよう、過去のターンを渡します。

def condense(history, follow_up):
    prompt = (
        'Given the conversation, rewrite the follow-up as a standalone '
        'question with all references resolved.\nConversation:\n' +
        render(history) + '\nFollow-up: ' + follow_up
    )
    return llm(prompt, temperature=0).strip()

クエリ拡張

拡張では、同義語、関連語、別の言い回しを生成して、語彙面と意味面のカバレッジを広げます。これは語彙の不一致に対処します。ドキュメントには invalidate と書かれているのに、ユーザーは revoke と言う場合がその例です。

検索用に拡張し、その和集合で検索します。拡張後の形式をユーザーに表示してはいけません。拡張しすぎると、話題から外れた結果を拾うため注意してください。

def expand(query, n=3):
    prompt = (
        'List ' + str(n) + ' alternative phrasings of this query using '
        'synonyms and domain terms, one per line.\n' + query
    )
    variants = parse_lines(llm(prompt, temperature=0.5))
    return [query] + variants

マルチクエリ検索

多様な言い換えを複数生成し、それぞれで検索して、結果リストを融合します(reciprocal rank fusion)。表現が異なると異なる関連チャンクが見つかるため、融合によってそれぞれの長所を組み合わせ、再現率を安定させられます。

その代わり、1つの悪い言い回しに左右されにくくするために、検索呼び出しの回数が増えます。

def multi_query(raw, n=4):
    queries = expand(raw, n)
    rankings = [dense_retrieve(q, 30) for q in queries]
    fused = rrf(*rankings)
    return dedup(fused)

クエリ分解

複雑なマルチホップ質問では、分解してサブクエリごとに個別に検索し、その後で組み立てる必要があります。Xを買収した会社のCEOが誰より年上なのかを尋ねるような質問は、1回の検索では答えられません。

質問を分解し、サブクエリごとに検索して、集めた証拠を生成モデルに統合させます。

def decompose_and_retrieve(question):
    subs = parse_lines(llm(
        'Break this into independent sub-questions, one per line.\n' +
        question, temperature=0))
    evidence = {s: rerank(s, dense_retrieve(s, 30))[:3] for s in subs}
    return evidence  # generator synthesizes the final answer

HyDEの基本概念

HyDE(Hypothetical Document Embeddings、Gao et al., 2022)は問題を逆転させます。短いクエリを埋め込むのではなく、LLMに仮想的な回答ドキュメントを生成させ、それを埋め込んで検索に使います。

仮想的なドキュメントは実際のドキュメントと同じ文体になるため、その埋め込みは本物の回答に近い位置に配置され、クエリとドキュメントの不一致が解消されます。

def hyde(query):
    hypo = llm(
        'Write a short passage that would answer this question, as if '
        'from a reference document.\nQuestion: ' + query,
        temperature=0.3)
    return dense_retrieve_by_vector(embed(hypo), k=30)  # embed the answer

HyDEで再現率が向上する理由

質問とその回答は表現が異なりますが、偽の回答であってももっともらしい回答は、実際の回答と似た表現になります。HyDEはLLMの生成事前分布を利用してこの隔たりを埋めます。仮想的な回答に事実誤認が含まれていても問題ありません。

仮想的な回答の正しさはそれほど重要ではありません。真のドキュメントに近い埋め込み位置に到達するための、適切な語彙と構造があれば十分です。

# Robustness: average several hypothetical docs to reduce variance
def hyde_avg(query, n=3):
    vecs = [embed(llm(HYDE_PROMPT + query, temperature=0.5))
            for _ in range(n)]
    centroid = sum(vecs) / n
    return dense_retrieve_by_vector(centroid, 30)

HyDEのトレードオフと失敗モード

HyDEでは検索前にLLMによる生成を追加するため、レイテンシーとコストが増加します。また、仮想的な回答が話題から外れて幻覚を起こし、ニッチなクエリや、モデルが何も知らない分布外のクエリで再現率を下げることがあります。

HyDEベクトル検索と元のクエリによる検索を融合して組み合わせることで対処できます。これにより、悪い仮想的な回答だけで再現率が大きく損なわれることを防げます。

def hyde_hybrid(query):
    a = dense_retrieve_by_vector(embed(hyde_doc(query)), 30)
    b = dense_retrieve(query, 30)          # raw-query fallback
    return dedup(rrf(a, b))                 # robust to bad hypotheticals

手法の選択と組み合わせ

これらの変換は相互に補完し合います。チャットには凝縮、語彙の不足には拡張/マルチクエリ、マルチホップには分解、質問とドキュメントの文体の不一致にはHyDEを使います。本番環境の多くのスタックでは、condense、HyDE、元のクエリとの融合、再ランキングという順に連結します。

変換を1つ追加するたびにLLM呼び出しのコストが発生するため、常にすべてを実行するのではなく、クエリタイプに応じて適用するかどうかを判断します。

def route_transform(query, history, qtype):
    q = condense(history, query) if history else query
    if qtype == 'multi_hop': return decompose_and_retrieve(q)
    if qtype == 'mismatch':  return hyde_hybrid(q)
    if qtype == 'vocab_gap': return multi_query(q)
    return dense_retrieve(q, 30)

トランスフォームの評価

各トランスフォームについて、漏洩のないデータセット上で、元のクエリと比較したretrieval recall@kの向上幅と最終回答の正確性を測定します。追加されるレイテンシーとLLMコストも追跡し、費用に見合うトランスフォームだけを残します。

注意してください。再現率を向上させても、無関係な情報を増やすトランスフォームは、再ランキングや圧縮と組み合わせない限り、回答の正確性を低下させる可能性があります。

def eval_transform(name, fn, eval_set):
    return {
        'recall@10': recall_at_k(eval_set, retriever=fn, k=10),
        'answer_acc': answer_accuracy(eval_set, retriever=fn),
        'extra_latency_ms': transform_latency(fn),
    }

確認問題

不完全な仮説であっても、なぜHyDEが機能するのかを考えてみましょう。

復習

重要なポイント:

  • 検索結果はクエリによって制約されます。クエリの変換は、低コストで大きな効果が得られるRAGの改善策です。
  • 書き換えや凝縮により、チャットのクエリを単独で成立する形にできます。クエリの拡張とマルチクエリは、語彙の不足を補います。
  • 分解では、サブクエリごとに検索することで、マルチホップの質問に対応します。
  • HyDEは仮説的な回答を埋め込むことで、質問とドキュメントの文体の不一致を橋渡しします。仮説が正しい必要はありません。
  • クエリの種類に応じてトランスフォームを組み合わせ、堅牢性のために元のクエリとも統合します。再現率、回答の正確性、レイテンシー、コストを評価しましょう。
無料で開始

AI チューターと学ぶ AI Prompt Engineering — 無料

ブラウザでリアルコードを書いて実行し、24/7 の AI チューターから瞬時にサポートを受け、ウェブまたはアプリで続きから学習できます。

コース
53
レッスン
199

よくある質問

「クエリ書き換えとHyDE」レッスンは無料ですか?

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

「クエリ書き換えとHyDE」で何を学びますか?

検索再現率を向上させます。 ブラウザで直接実行するハンズオンコードでAI Prompt Engineeringを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

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

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

「クエリ書き換えとHyDE」レッスンにはどのくらい時間がかかりますか?

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

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

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

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

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