【ITニュース解説】My LLM reranker did nothing, and every test passed
2026年10月17日に「Dev.to」が公開したITニュース「My LLM reranker did nothing, and every test passed」について初心者にもわかりやすく解説しています。
ITニュース概要
AIによるデータ並び替え機能が、AIが「思考」する際の文字数制限を超え動作しなかった。エラーは安全策で隠され、テストも未検出。修正で機能し性能が向上した。安全な代替処理が発動した際は、ログでその事実を記録する重要性を説く。
ITニュース解説
schemagateというツールは、私たちが普段使う言葉(自然言語)で書かれた質問から、データベースが理解できるSQLという命令文を生成する際に、非常に重要な役割を果たす。具体的には、数多くのデータベーステーブルの中から、質問に答えるために本当に必要なテーブルだけを賢く選び出すのだ。なぜなら、無関係なテーブルがたくさんあると、情報が多すぎて処理が遅くなったり、間違った答えを出してしまったりする可能性があるからだ。
このテーブル選定プロセスは、大きく二段階で行われる。最初の段階では、数学的な手法を用いてテーブルをランク付けする。例えば、質問のキーワードとテーブル名が一致するか、テーブルの内容と質問の意味がどれだけ似ているかなどを、BM25といったアルゴリズムや、埋め込み(単語や文章の意味を数値で表したもの)を使って評価する。これらの複数の評価結果をRRF(Reciprocal Rank Fusion)という技術で統合し、関連性の高いテーブルが上位に来るように並べ替える。
そして、二段階目が「リランカー」と呼ばれる部分だ。これはオプション機能であり、大規模言語モデル(LLM)の力を借りて、最初の数学的なランク付けで選ばれた上位20件のテーブルの順序をさらに最適化する役割を担う。LLMは人間が使う言葉のニュアンスを理解できるため、より文脈に即した賢い判断でテーブルの順序を改善することが期待されていた。
しかし、筆者はこのLLMリランカーが、実は全く機能していなかったという衝撃の事実に直面した。自分が開発した機能であるにもかかわらず、リランカーが動作していないことを指摘され、実際に確認してみたところ、--rerankというオプションをつけてLLMリランカーを有効にした場合と、つけない場合とで、得られるテーブルの順序が全く同じだったのだ。これは、LLMリランカーが何の仕事もしていなかったことを明確に示していた。
最初は、数学的な手法が常に完璧な答えを出しているのかもしれない、とも考えられた。しかし、詳細なログを調べてみると、LLM自体は確かに呼び出されていたものの、肝心の「回答」を一切返していなかったことが判明した。LLMは沈黙していたのだ。
このバグの根本原因は、LLMへの問い合わせ方法にあった。コードでは、LLMに回答を求める際にmax_tokens=120という設定をしていた。ここで「トークン」とは、LLMが言語を処理する際の最小単位で、単語や記号の一部のようなものだ。期待される回答は「3, 1, 7, 2, 5」のような数字の羅列であり、120トークンあれば十分だと考えられていた。しかし、Claude 5のような最新のLLMは、回答を生成する前に「思考」する内部プロセスを持っている。そして、この「思考」にもトークンが消費されるのだ。今回のケースでは、設定された120トークンがすべてLLMの「思考」に使われてしまい、肝心な数字の羅列を一つも出力する前に、モデルがトークン切れで停止してしまっていた。
LLMからの回答がなかった場合、システムはエラーを発生させる。リランカーの設計では、このエラーを捕捉するように作られていた。具体的には、except Exception: return list(docs) というコードが、何らかのエラーが発生した際に、エラーを無視して最初の数学的な順序をそのまま返す、という安全なフォールバック(代替処理)を実行していた。結果として、システムはクラッシュすることなく、エラーメッセージも表示されず、あたかもリランカーが存在しなかったかのように、数学的な手法で並べられたテーブル順序がそのまま返されていた。これが、「機能していないのに、まるで正常に動いているかのように見えていた」という状況の正体だった。
さらに厄介だったのは、既存のテストコードではこのバグが検出されなかったことだ。test_rerank.pyというテストファイルには、優れたテストが書かれていた。例えば、LLMがエラーを起こした場合でもテーブルの順序が元のままであること、LLMが意味不明な回答を返した場合でも順序が元のままであること、といった「失敗しても安全であること」を保証するテストは全てパスしていた。しかし、これらのテストは「モデルが実際に期待通りの回答を生成するかどうか」を検証するものは含まれていなかったのだ。フォールバック処理が「目に見えない」ように設計されていたため、リランカーが完全に機能停止していても、テスト上は全てが成功しているように見えてしまっていたのである。
この問題に対処するため、いくつかの修正が施された。まず、LLMへの問い合わせにおけるmax_tokensを120から1024に大幅に増やした。これにより、LLMが思考に十分なトークンを使い、その上で実際の回答を生成できるようになる。次に、将来的に同様の問題が再発しないように、テストスイートに新しい仕組みを導入した。それは、512トークン未満では絶対に回答を返さない「フェイクモデル」を使ったテストだ。もし開発者が誤ってmax_tokensを低く設定し直した場合、このフェイクモデルが回答しないことでテストが失敗し、すぐに問題に気づけるようになる。さらに、ベンチマークテストでは、単に最終的なスコアだけでなく、LLMが個々の質問に対して実際に回答を生成したかどうかをログに記録するように変更された。
これらの修正がどれほど効果があったか、リリース版パッケージで確認された。修正前のバージョン1.4.4では、3つの質問のうちLLMが回答したのは1つだけで、テーブルの順序が変更されたケースは0件だった。それが修正後のバージョン1.5.0では、3つの質問すべてでLLMが回答を生成し、そのうち2つの質問でテーブルの順序が変更されたことが確認された。
そして、この修正がシステム全体の性能にどれほど貢献したかを初めて定量的に評価した。公開されている大規模なベンチマークデータセット(Spider devとBIRD dev)を使用し、何百ものテーブルの中から、質問に関連するテーブルが上位5位以内に入っているかを基準に評価を行った。その結果は驚くべきものだった。数学的な手法のみではSpiderデータセットで80.3%の成功率だったのに対し、リランカーが機能するようになったことで96.5%に向上した。BIRDデータセットでも、88.6%から96.7%へと大幅な改善が見られた。この数値は、この修正がベンチマークにおける過去最大の性能向上をもたらしたことを示している。この測定は、最終的なSQLの正確さではなく、LLMがプロンプト(指示文)に送るべき適切なテーブルを選び出せたかどうかを測るものだ。LLMは数学的な手法で既に絞り込まれたテーブルに対してのみ再順序付けを行い、テーブル名や短い要約しか見ていない中でこの成果を上げた。
この経験から得られた最も重要な教訓は、「安全なフォールバック処理を構築する際には、それがいつ発動したかを必ずログに記録すること」だ。フォールバックはシステムを安定させるために不可欠な機能だが、それが「目に見えない」形で機能してしまうと、今回のように、機能が完全に停止していても、まるで何も問題がないかのように見えてしまう。これにより、開発者は問題の存在に気づくことができず、システム改善の機会を逃してしまう。トラブルシューティングを容易にするためにも、異常系処理やフォールバック処理が発動した際には、必ずその事実と状況を記録する仕組みを組み込むべきである。この教訓は、堅牢なソフトウェア開発において極めて重要だと言える。