0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

FAQ 1,786件を全部Geminiに渡してみた。そこから考えるFAQ検索の育て方

0
Last updated at Posted at 2026-09-27

LLMのおかげで、FAQを作るのも探すのも、ずいぶん楽になりました。

FAQが少ないうちは、全部LLMに渡して「この質問に答えるFAQを探して」と頼むだけでも動きます。では、1,000件、2,000件と増えても、そのままでよいのでしょうか。

社内FAQが増えたら、どんな検索の仕組みにすればよいのか。公開されている自治体FAQ 1,786件で試してみました。

全件をGeminiに読ませると、50問中47問で正解FAQが1位に入りました。一方、ベクトル検索で10件に絞ってから読ませても、同じ50問では同じ正解数になりました。

ただし、10件に絞る方法には、はっきりした限界もあります。

候補の中に正解があれば、LLMで順位を改善できる余地がある。候補になければ、並べ直しても届かない。

この違いが見えてくると、FAQ検索をどう育てればよいかも考えやすくなります。

まずは、FAQを全部渡してみる

使ったのは、LocalgovFAQ研究に由来する公開データです。自治体FAQが1,786件、検索用の問い合わせ文が749問あります。

749問のうち、正解のFAQが分かっている587問を使って、検索の精度を調べました。LLMには、問い合わせに合うFAQを選び、そのIDを返してもらいます。

精度は、正解のFAQが何位までに入ったかで比べます。

指標 何を数えるか
Hit@1 1位に正解FAQが入った問い合わせの数・割合
Hit@3 上位3件に正解FAQが1件以上入った問い合わせの数・割合
Hit@10 上位10件に正解FAQが1件以上入った問い合わせの数・割合

まずは、FAQ全件の質問文と回答文をGemini 3.8 Flashへ渡します。FAQと検索の指示を合わせると497,436トークンでした。トークンは、LLMが扱う文章量の単位です。今回の1,786件は、一度に渡せる量に収まりました。

実験を始める前に、587問からランダムに50問を選びました。この50問で試した結果がこちらです。

方法 Hit@1 Hit@3 Hit@10
FAQ全1,786件をGeminiに渡す 47/50 48/50 49/50

50問での結果とはいえ、かなり当たります。FAQを渡すだけで始められるのも魅力です。

FAQ全件を渡せるなら、まずこの方法を試す価値はありそうです。

ただ、続けて使うことを考えると、気になるのが待ち時間と料金でした。

このうち20問で、Gemini APIに問い合わせてから結果が返るまでの時間を測りました。中央値は2.28秒、最大は5.62秒です。共通のFAQを保存して再利用する「コンテキストキャッシュ」は、20回すべてで使われていました。

50問分の費用をAPIの使用量から計算すると、キャッシュを2時間保存する料金も含めて約392円でした。

ときどき使うなら十分かもしれません。でも、検索画面で何度も使うなら、もう少し速く、安くしたくなります。

ベクトル検索は速い。ただ、正解が1位とは限らない

そこで、ベクトル検索を試しました。文章を数値の並びに変換し、意味が近いものを探す方法です。

今回はFAQの質問文だけを gemini-embedding-2 でベクトルに変換し、保存しておきます。使ったベクトルは768次元です。検索時には問い合わせ文だけを新しくベクトルに変換し、保存済みのFAQベクトルと比べて上位10件を選びます。

587問すべてで検索の精度を調べると、こうなりました。

方法 Hit@1 Hit@3 Hit@10
質問文のベクトル検索 394/587(67.1%) 496/587(84.5%) 553/587(94.2%)

速さも30問で測ってみました。問い合わせをベクトルに変換し、上位10件を選ぶまでの時間は、中央値で0.50秒でした。その大半は、問い合わせをベクトルに変換するAPIの応答を待つ時間でした。

候補を返すまでが速い。しかも、上位10件まで見れば94.2%の問い合わせで正解が入っています。

一方、1位に正解が入ったのは67.1%です。

正解は見つかっている。でも、上に出せていない。

それなら、この10件だけをLLMに読ませたらどうでしょうか。

10件だけ読ませると、50問では全件読みと同じ正解数に

全件読みと同じ50問を使い、ベクトル検索が選んだ10件の質問文・回答文をGeminiへ渡しました。候補は増やさず、10件の順番だけを並べ直してもらいます。この処理をリランキングと呼びます。

方法 Hit@1 Hit@3 Hit@10
FAQ全1,786件をGeminiに渡す 47/50 48/50 49/50
ベクトル検索の上位10件をGeminiで並べ直す 47/50 48/50 49/50
ベクトル検索のみ 38/50 40/50 49/50

この50問では、全件を読ませても、10件だけを読ませても、正解数は同じでした。当たった問い合わせには違いがありますが、10件に絞ってもよい結果が出ています。

Geminiへ渡す文章量を減らすと、費用も下がりました。

50問分のGemini利用費用 使用量からの計算額
全件読み(キャッシュ保存2時間分を含む) 約392円
上位10件の並べ直し 約21円

金額は、記録したAPI使用量に当時の公開単価をかけ、1ドル165円で換算しました。約21円はGeminiによる並べ直しの費用です。FAQや問い合わせをベクトルに変換する費用は別にかかります。

LLMに読ませる範囲を絞ると、その分の費用を抑えられる。 その効果が見えてきました。

587問でも改善した。残った失敗は2種類ある

手応えがあったので、上位10件を並べ直す方法を587問すべてに広げました。

方法 Hit@1 Hit@3 Hit@10
ベクトル検索のみ 394/587(67.1%) 496/587(84.5%) 553/587(94.2%)
上位10件をGeminiで並べ直す 497/587(84.7%) 546/587(93.0%) 553/587(94.2%)

1位に正解が入った問い合わせは103問増えました。上位3件では50問増えています。

ただし、並べ直したことで、かえって正解が下がった問い合わせもあります。

正解が新たに1位になったのは121問。逆に、1位から外れたのは18問でした。上位3件で見ると、新たに入ったのが52問、外れたのが2問です。

改善した数だけでなく、それまで当たっていたのに外れた数も見ておきたいところです。

ここで、並べ直したあとも上位3件に正解が入らなかった41問を分けてみます。

残った失敗 問い合わせ数
候補10件には正解があるが、上位3件に上がらなかった 7問
候補10件に正解が入っていなかった 34問

この2つでは、次に直す場所が違います。

最初の7問は、順位の付け方を見直す余地があります。残る34問は、どれだけうまく並べ直しても正解に届きません。正解を候補に入れられるよう、検索の方法を見直す必要があります。

順位の問題なのか、候補をひろう段階の問題なのか。

検索の精度が足りないと感じたら、まずここを分けて見ると、次に試すことが絞れます。

なお、全件読みを試したのは先ほどの50問です。587問では、ベクトル検索と、その上位10件を並べ直す方法を比較しています。

速く見せて、あとからLLMの判断を添える

Geminiで並べ直すには、追加の待ち時間がかかります。

同じ30問で、それぞれの処理を別々に測ると、次の結果になりました。

処理 中央値 p95
問い合わせのベクトル化から上位10件の取得まで 0.50秒 0.55秒
10件をGeminiで並べ直すAPI呼び出し 1.29秒 1.50秒

p95は、かかった時間を短い順に並べたとき、全体の95%の位置にあたる値です。今回は2つの処理を別々に測りました。問い合わせから最終結果が返るまでを、通して測った時間ではありません。

それでも、画面の作り方を考える材料にはなります。

この結果を使ってFAQ検索のWebアプリを作るなら、私は次のようにしたいと思います。ここからは、まだ試していない画面の案です。

  1. ベクトル検索で候補を選ぶ
  2. まず上位3件を画面に表示する
  3. 裏で上位10件をGeminiに読ませる
  4. 結果が返ったら、有力な候補に印を付ける

最初の候補が出れば、利用者は読み始められます。そのあとで、

AIが確認したおすすめの候補です

と案内するイメージです。

読んでいる途中でFAQの位置が動くと戸惑いそうなので、突然並べ替えるより、候補に印を添える方が使いやすそうです。

先にFAQを読み始めてもらい、あとからLLMの判断を添える。そんな見せ方も考えられます。

方法を足せば、よくなるとは限らなかった

ほかの方法も試しました。以下はすべて、同じ587問で正解FAQが上位に入った件数です。

方法 Hit@1 Hit@3 Hit@10
質問文のベクトル検索 394 496 553
回答文のBM25検索と組み合わせる 249 358 482
FAQごとに想定質問を5件追加する 379 506 558
BGEで上位10件を並べ直す 353 474 553
Geminiで上位10件を並べ直す 497 546 553

BM25は、文字や単語の一致を手がかりに探す方法です。今回は回答文の文字BM25と質問文のベクトル検索を、同じ重みで組み合わせました(RRF)。この設定では正解数が減りました。

FAQごとに、利用者が尋ねそうな質問をAIで5件ずつ作り、検索対象に加える方法では、上位3件の正解数が10問増えました。ただ、1位の正解数は15問減り、保存するベクトルは6倍になります。

並べ直し専用のモデル BAAI/bge-reranker-v2-m3 も試しましたが、今回の設定では上位1件・3件ともに正解数が減りました。

今回試した範囲では、仕組みを足せば精度が上がるとは限りませんでした。

私なら、こう育てる

まず、FAQ全件をLLMに渡すところから始めます。全部を一度に渡せて、待ち時間と料金にも問題がなければ、そのまま使えます。

そこから先は、実際に困ったことに合わせて考えます。

困ったこと 次に試すこと
全件読みの待ち時間や料金が気になる ベクトル検索で候補を絞る
候補には正解があるのに、上位に出ない 候補の質問文・回答文をLLMで並べ直す
並べ直しを待つ時間が気になる 候補を先に表示し、LLMの判断をあとから添える
候補に正解が入らない 漏れた問い合わせを調べ、候補の選び方を見直す
答えになるFAQ自体がない FAQを追加する

候補をひろえていないときには、制度名や型番の一致を重視する、FAQの見出しを直す、よくある言い換えを追加する、といった方法が考えられます。失敗の具体例に合わせて試し、改善と悪化の両方を確認します。

そのために残しておきたいのは、実際の問い合わせと、人が確認した正解FAQです。これがあれば、変更のたびに「本当によくなったか」を確かめられます。

評価の範囲と実験データ

正解の判定には、元の研究のデータを使いました。問い合わせに対する答えが書かれているFAQを正解とし、それが検索結果の上位に入ったかを数えています。

利用者がFAQを読んで問題を解決できたか、答えがないときに「回答できない」と案内できるかは、今回調べていません。

元の研究で正解かどうかを調べていないFAQにも、役に立つ回答があるかもしれません。また、今回は自治体FAQで試しています。社内FAQに使うときは、自分たちの問い合わせでも確かめたいところです。

実験コード、問い合わせごとのFAQの順位、保存したベクトル、集計結果は、GitHubに公開しています。詳しい実験条件は、各レポートにまとめました。

待ち時間は、今回の実行環境で測ったものです。料金はAPIの使用量から計算しており、請求書の金額を確認したものではありません。モデルの設定や、渡した文章の違いも、リンク先に記録しています。

元データは Sakata らの FAQ Retrieval using Query-Question Similarity and BERT-Based Query-Answer Relevance(SIGIR 2019)に由来します。FAQ本文や生成した想定質問の一括収録はしていません。元のFAQと問い合わせは、再現手順に従って配布元から取得できます。

おわりに

1,786件のFAQは、本当に全部LLMへ渡せました。そして、10件に絞ってから読ませる方法にも、十分に試す価値がありました。

全件読みが遅い・高いと感じたら、候補を絞る。候補に正解があるのに順位が低ければ、LLMに並べ直してもらう。候補に入らなければ、検索側を見直す。

まず単純に作り、困ったことが見えたら、その問題に合う方法を足す。

FAQが増えたときも、この順番で育てていこうと思います。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?