はじめに
GMOコネクトの永田です。
ある稼働中の業務サービスのバックエンドで、LLMが複数の機能で使われていました。動いているモデルはサービスイン当初に選んだ gpt-4.1-mini のままで、その後は一度も見直されていません😇
最新モデルが出て、LLM-as-a-judge(LLMに採点させる方式)で精度を機械採点できるようになった今、精度とコストで本気で選び直しました。
やってみて一番の収穫は、モデル選定でもプロンプト改善でもありませんでした。どちらも当然やります。その上で効いたのは、「その処理、そもそもLLMにやらせるべきか?」と問い直すこと ── ハイブリッド化でした。この記事はその記録です。
先にまとめ
LLMアプリの改善は、次の3軸で考えると整理できました。①と②は当然やるとして、見落としがちな③を足すと効きます。
| 軸 | やること | 今回の学び |
|---|---|---|
| ① モデル選定 | 現行 vs 新世代を精度×コストで比較 | 新世代は概要・キーワード抽出といったタスクで現行精度を上回る傾向 |
| ② プロンプト改善 | Thinkingの要否、呼び出し回数、書き方の明示 | Thinkingは抽出に不要/3コール→1コールJSON統合でコスト-35%・レイテンシ2.3倍速/PII(個人情報)は書き方の明示だけで人名の取りこぼしがほぼゼロに(recall 52%→100%) |
| ③ ハイブリッド化 | 「LLMにやらせない」選択肢を足す | 見落としがちだが効く。一覧のある値は生成でなく選択(郵便番号100%)、形の決まった値は正規表現へ |
- 生成させず、選択させる。郵便番号のような一覧のある値は、LLMに生成させると最良でも56〜81%しか当たりません。権威データ(日本郵便の公開データ)から候補を絞ってLLMには選ばせるだけにすると、100%になり、幻覚が構造的に消えます。
- 餅は餅屋。電話番号・メールは正規表現、人名はLLM、集計・整形はコード。「何でもLLMにやらせる」のをやめ、カテゴリごとに最適な手段を割り当てます。
- 測り方を先に決める。精度は観点を決めた採点(出力元は伏せる。LLM-as-a-judge)、安定性はK=3の自己一貫性(同じ入力を3回投げてぶれを見る)、コストは思考トークンまで込みで換算。ここを固めると、新モデルが出ても同じ物差しで測り直せます。
モデルもプロンプトも当然詰めます。その上で「LLMにやらせない」を足す、というのが今回の結論です。面白いことに、どの軸が一番効くかはタスクで変わりました(概要は①モデル、PIIは②プロンプト、住所は③選択)。だから先に測り方を決めておくと、タスクごとに「どの軸を動かすか」を見極められます。
1. どう測ったか ── 測り方を先に決める
概要やキーワードは、正解が一意に決まりません。「同じ意味の妥当な要約」が複数あるので、単一の正解との一致率では測れません。そこで測り方を先に設計しました。
- 精度は「観点を決めた採点」で測る。事実網羅・誤りの有無・簡潔さ・(今回の用途での)有用性の4観点を各5点で採点します。このとき「どのモデルの出力か」は審査員に伏せます。人が全部見るのは続かないので、評価対象とは別のモデルを審査員(LLM-as-a-judge)にしました。
- 安定性はK=3の自己一貫性。同じ入力を設定固定で3回投げて、出力のぶれを測ります。後述しますが、小型モデルは郵便番号すら3回で74%しか一致しませんでした。単発の測定は当てになりません。
- コストは思考トークンまで込みで換算。推論(Thinking)を使うモデルは、思考トークンも出力として課金されます。ここを含めないとコストを大幅に過小評価します。
2. 軸①②でわかったこと ── 傾向だけ
具体的なモデル名の勝敗は、半年もすれば古くなります。ここは傾向だけ残します。
- 新世代は概要・キーワード抽出タスクで現行を上回る傾向。現行の小型モデルは特に「事実網羅」と「有用性」が弱く、新世代は重要事実を落とさず要約しました。
- Thinkingは抽出・要約には効かない。推論水準を上げても精度は横ばいか、キーワード抽出はむしろ悪化しました。字数制約に固執して出力が壊れる事故も起きました。推論が効くのは、複数の制約を同時に満たすような複雑なタスクで、単一項目の要約・分類にはその複雑さがありません。今回の抽出系は推論オフが最適でした。
- 呼び出し回数の最適化が効く。概要・キーワード・住所詳細を別々の3コールで呼んでいたのを、1回のJSON呼び出しに統合したら、コスト-35%・レイテンシ2.3倍速・JSON妥当性100%になりました。テキストをパースしていたときの書式崩れ事故も消えます。これはモデルに依存しない改善です。
ここまでが「モデルとプロンプトを詰める」話です。どちらも大事ですが、これだけでは頭打ちになる部分がありました。それが次の住所(郵便番号)です。
3. 一番効いた「ハイブリッド化」 ── LLMにやらせない
生成させず、選択させる
郵便番号のような一覧のある値は、LLMに生成させると根本的に不安定でした。
同じ投稿でも、推論水準を変えるだけで郵便番号がぶれます。実測では、推論オフ/低/高で値が変わり、どれも正解と一致しませんでした。イメージとしては、渋谷のある住所(正解が 150-0031)に対してモデルが 150-0002(近隣の別地域)を返し、しかも推論水準ごとに答えが変わる、といった取り違えです。これはモデルを新しくしても消えません。記憶から郵便番号を「作らせている」という方式そのものの限界です。生成方式の完全一致は、現行で15%、新世代の最良でも56%、別系統の中型モデルで最良81%どまりでした。
対策は、生成をやめて選択に変えることです。
[本文から抽出(LLM)] 地名・番地・建物名を読み取る
↓
[候補を絞る(コード)] 日本郵便データ 約12万件から本文に近い候補を機械的に抽出
↓
[選ぶだけ(LLM)] 候補の中から正しいものを選択(生成はしない)
↓
[合成(コード)] 郵便番号・都道府県・市区町村・町域(権威側)+番地・建物名(本文側)
LLMには郵便番号を作らせず、日本郵便データから絞った候補を「選ばせる」だけにしました。番地や建物名は本文にしかないのでLLMが抽出し、権威データがある部分(郵便番号・都道府県・市区町村・町域)は選択に委ねて合成します。結果、住宅系27件で27/27、位置が特定できる全36件で36/36と、完全一致100%になりました。必ず実在するコードを返すので、幻覚はゼロです。しかも正解が確定するので、完全一致で自動採点できるようになりました。
「住所はLLMに正規化させず専用APIに渡せ」という話は既にあります。今回のポイントは少し違って、LLMを外すのではなく「選択器」として残すことです。本文からの地名抽出はLLMが得意なので任せ、正規化(どのコードが正しいか)だけを選択に落とす、という役割分担です。
餅は餅屋 ── カテゴリ別ハイブリッド
住所だけでなく、パイプライン全体を「カテゴリごとに最適な手段」で割り当て直しました。全体像はこうです。
| カテゴリ | 割り当てた手段 | ポイント |
|---|---|---|
| 電話番号・メール | 正規表現 | 形が決まっているのでルールで十分(recall 100%)。LLM不要、外部にも送らない |
| 人名 | LLM + プロンプトの作り込み | 意味判断なのでLLMが優位。ただし精度を左右したのはモデルより書き方 |
| 郵便番号・住所 | 権威データからの選択 | 前節の通り100% |
| 集計・整形・書式 | コード | 決定的に処理(LLMのぶれを出力に持ち込まない) |
この中で特に工夫が要ったのがPII(個人情報)検出でした。電話番号のように形が決まっているものは正規表現で十分です。コストもレイテンシも下がり、しかもPIIを外部に送らずに済みます。
一方、人名のように「意味で判断する」部分はLLMが優位でした。ただし、ここで一番効いたのはモデルの入れ替えでもNER(固有表現抽出。日本語ならGiNZAなど)への置換でもなく、プロンプトの書き方でした。最初はモデルを上げたりNERに替えたりを試しましたが、決め手になったのは「姓だけの氏名も対象・肩書は除く・文脈で地名と区別する」とプロンプトに明記することで、人名のrecall(取りこぼしの少なさ)が52%→100%に跳ね上がりました。同じ書き方の修正で、安い新世代モデルでも現行と同じrecall 100%を、約半額・推論オフの高速で出せています(ただし正解データ40件に合わせた作り込みなので、実データでの過学習チェックは残ります)。
PIIは「電話は正規表現へ(軸③)/人名はLLMに残して書き方で詰める(軸②)」という組み合わせで、先の住所(軸③の選択)とはまた違う軸が効いた例でした。「全部LLM」でも「全部やめる」でもなく、カテゴリごとに手段を割り当て、そのカテゴリで効く軸を動かすのが答えです。
分業の原則
3つに共通するのは、次の分業でした。
LLMは「読む・選ぶ・意味を判断する」。計算・集計・答えが決まっている値(郵便番号・電話)はコードが決定的に。
この原則は今回のサービスだけでなく、別の業務のパイプラインを組み直したときにも同じ形に行き着きました。意味判断はLLMに残し、値を確定させる部分はコードが決定的に持つ。順序が変わっても、この線引きは効きます。
まとめ
- LLMアプリの改善は、モデル選定 × プロンプト改善 × ハイブリッド化の3軸です。①②は当然詰めた上で、③「その処理、そもそもLLMにやらせるべきか」を足すと効きます。しかもどの軸が一番効くかはタスク次第でした(概要は①モデル、PIIは②プロンプト、住所は③選択)。
- 一覧のある値は生成させず選択させる、意味判断(人名など)はLLMに残して書き方で詰める、形の決まった値は正規表現へ ── どれも「LLMを外す」のではなく、LLMを得意なところ(読む・選ぶ・判断する)に専念させる分業です。
- 先に測り方(観点を決めた採点・K=3・思考トークン込み換算)を固めておくと、新モデルが出るたびに同じ物差しで測り直せます。具体的なモデルの勝敗は古びますが、この測り方と分業の設計は古びません。
最後に、GMOコネクトではサービス開発支援や技術支援をはじめ、幅広い支援を行っておりますので、何かありましたらお気軽にお問合せください。