LLM の正確さと動作の一貫性を最大限に高める方法
LLM の最適化は簡単ではありません。
私たちはスタートアップから大企業まで、多くの開発者と取り組んできました。最適化が難しい理由は、いつも次の点に集約されます。
- 精度の最適化を どこから始めるか の判断
- 最適化手法をいつ、どう使い分けるか の判断
- 本番環境で 十分といえる 精度の水準の判断
本稿では、LLM の精度と動作を最適化するための考え方を示します。プロンプトエンジニアリング、検索拡張生成(RAG)、ファインチューニングといった手法を取り上げ、それぞれの使い方や適した場面、陥りやすい問題を紹介します。
読み進める際は、これらの原則を、自分のユースケースにおける精度の意味と結び付けて考えることが大切です。当然に思えるかもしれませんが、人が手直ししなければならない文章を生成することと、顧客に $100 を返金すべきところで $1000 を返金することでは、影響が異なります。LLM の精度を議論する際は、失敗によるコストと、成功による節約額や収益をおおまかに把握しておく必要があります。この点は、本番環境で「十分といえる」精度を扱う最後のセクションで改めて取り上げます。
LLM 最適化の全体像
最適化の実践ガイドの多くは、プロンプトエンジニアリングから始め、検索拡張生成、ファインチューニングへと進む単純な一本道として説明しています。しかし、実際にはそうでないことがよくあります。これらの手法はそれぞれ異なる問題を解決するためのものであり、適切な方向に最適化を進めるには、問題に合った手法を選ぶ必要があります。
LLM の最適化は、次のようなマトリクスとして捉えると理解しやすくなります。

一般的な LLM タスクでは、左下のプロンプトエンジニアリングから始めます。テストを行い、そこから学び、評価してベースラインを得ます。そのベースラインとなる事例をレビューし、誤りの原因を分析したうえで、次のいずれかの最適化に取り組みます。
- コンテキストの最適化: 次の場合はコンテキストの最適化が必要です。1)学習データに含まれていなかったため、モデルに必要な背景知識がない場合、2)モデルの知識が古い場合、3)独自の非公開情報に関する知識が必要な場合です。この軸では、 応答の精度を最大限に高めます。
- LLM の最適化: 次の場合は LLM の最適化が必要です。1)モデルの出力に一貫性がなく、形式も正しくない場合、2)語調や文体が適切でない場合、3)推論の手順を一貫して踏めていない場合です。この軸では、 動作の一貫性を最大限に高めます。
実際には、評価し、最適化の方法について仮説を立て、それを適用し、再び評価して次のステップを検討する、という一連の作業を繰り返します。次の図は、典型的な最適化の流れを示しています。

この例では、次の手順で進めます。
- まずプロンプトを用意し、その性能を評価
- 固定のフューショット例を追加し、結果の一貫性の向上を図る
- 質問に応じてフューショット例を動的に取り込む取得ステップを追加。各入力に関連するコンテキストを確実に提供し、性能を向上
- 50 件以上の例からなるデータセットを用意し、モデルをファインチューニングして一貫性を向上
- 取得処理を調整し、ハルシネーションを検出するファクトチェックのステップを追加して、精度をさらに向上
- 改善した RAG 入力を含む新しい学習例で、ファインチューニング済みモデルを再学習
これは、難しいビジネス課題に対する典型的な最適化パイプラインです。より関連性の高いコンテキストが必要なのか、それともモデルの動作により高い一貫性が必要なのかを判断するのに役立ちます。それが判断できれば、最適化の第一歩としてどの手法を使うべきかが分かります。
全体の考え方を押さえたところで、各領域で具体的に取り組む方法を見ていきましょう。まずは左下のプロンプトエンジニアリングから始めます。
プロンプトエンジニアリング
通常、最初に取り組むべきなのはプロンプトエンジニアリングです**。要約、翻訳、コード生成など、ゼロショットでも本番環境で使える精度と一貫性に到達できるユースケースでは、この手法だけで十分なこともよくあります。
プロンプトエンジニアリングに取り組むと、そのユースケースで精度が何を意味するのかを定義せざるを得ないためです。入力を与えるという最も基本的な段階から始めるので、出力が期待どおりかどうかを判断できる必要があります。望む出力でなければ、 なぜ そうならなかったのかを調べることで、次の最適化に使うべき手法が見えてきます。
そのため、必ずシンプルなプロンプトと期待する出力を思い描くところから始めてください。そのうえで、望む結果が得られるまで コンテキスト、 指示、 例 を追加し、プロンプトを最適化していきます。
最適化
プロンプトの最適化については、主に OpenAI API ドキュメントのプロンプトエンジニアリングガイドで紹介されている戦略を使います。各戦略は、コンテキスト、LLM、またはその両方の調整に役立ちます。
| 戦略 | コンテキストの最適化 | LLM の最適化 |
|---|---|---|
| 明確な指示の記述 | X | |
| 複雑なタスクをより単純なサブタスクに分割 | X | X |
| GPT に「考える」時間を与える | X | |
| 変更の体系的なテスト | X | X |
| 参照テキストの提供 | X | |
| 外部ツールの利用 | X |
これだけでは少しイメージしにくいかもしれないので、実際の例で試してみましょう。gpt-4-turbo を使ってアイスランド語の文を修正し、これらの戦略がどう役立つかを見ていきます。
ここまでで、プロンプトエンジニアリングは最初に取り組む手法として適しており、適切に調整すれば性能をかなり高められることがわかりました。
ただし、プロンプトエンジニアリングの最大の課題は、対応範囲を広げる際に限界があることです。コンテキストに内容を追加するだけでは対応しきれない幅広い問題をモデルに処理させるには、コンテキストを動的に与える必要があります。また、フューショットの例で得られる以上に、一貫した振る舞いが求められることもあります。
長いコンテキストを扱えるモデルを使うと、プロンプトエンジニアリングの対応範囲をさらに広げられます。ただし、 複雑な指示を含む非常に長いプロンプトでは、 モデルが全体に注意を向け続けることが難しくなる場合があります。そのため、 長いコンテキストを扱うモデルを使う際は、コンテキストの長さを変えて必ず評価し、 途中の情報を見落とす現象が起きないことを確認してください。「Lost in the middle」と呼ばれる この現象は、LLM が与えられたすべてのトークンに対して、 一度に同じだけの注意を向けられないことを指します。その結果、 一見ランダムに情報を見落とすことがあります。長いコンテキストを使うべきではないという意味ではなく、 十分な評価と組み合わせる必要があるということです。オープンソースの貢献者である Greg Kamradt は、Needle in A Haystack (NITA) という有用な評価を作成しました。 これは、長いコンテキストの文書内のさまざまな位置に特定の情報を埋め込み、 その情報を取得する品質を評価するものです。この評価は、 すべてをコンテキストに入れることで取得処理を大幅に簡素化できる一方、 精度が犠牲になるという、長いコンテキストの課題を示しています。
では、プロンプトエンジニアリングだけで実際にどこまで対応できるのでしょうか。答えは状況によって異なり、評価を通じて判断する必要があります。
評価
こうした理由から、この段階で得られる最良の成果物は、 良いプロンプトと、質問と正解からなる評価セット です。20 組以上の質問と正解を用意し、失敗の詳細を調べ、その原因について仮説を立てていれば、より高度な最適化手法に取り組むための適切なベースラインが整っています。
より高度な最適化手法に進む前に、改善のサイクルを速めるために、この評価をどう自動化するかも検討するとよいでしょう。効果が見られた一般的な方法として、次のようなものがあります。
- ROUGE や BERTScore などの手法を使い、大まかに評価します。人間のレビュアーによる評価との相関はそれほど高くありませんが、1 回の改善によってモデルの出力がどれほど変わったかを、すばやく効果的に測定できます。
- G-Eval の論文で説明されているように、GPT-4 を評価者として使用します。LLM に採点表を与え、出力をできるだけ客観的に評価させます。
これらの手法をさらに詳しく知りたい場合は、それぞれの実践方法を紹介しているこちらの Cookbookをご覧ください。
ツールの理解
プロンプトエンジニアリングを行い、評価セットも用意したのに、モデルがまだ期待どおりに動作しないとします。次に最も重要なのは、どこで失敗しているのかを診断し、その改善に最も適したツールを見極めることです。
そのための基本的な考え方を以下に示します。

評価で不正解だった各質問を、 コンテキスト内の記憶 の問題か、 学習による記憶 の問題かに分けて考えることができます。たとえば、試験を受ける場面を想像してください。正しい答えを出すためには、次の 2 つの方法があります。
- 過去 6 か月間、授業に出席し、ある概念の仕組みを示す例を何度も見てきました。これは 学習による 記憶です。LLM では、プロンプトと期待する応答の例を示してモデルに学習させることで、この種の問題を解決します。
- 教科書を手元に置き、質問に答えるための適切な情報を調べることができます。これは コンテキスト内の 記憶です。LLM では、関連情報をコンテキストウィンドウに入れることで、この種の問題を解決します。プロンプトエンジニアリングで静的に情報を与える方法と、RAG を使って大規模に処理する方法があります。
この 2 つの最適化手法は、 どちらか一方を選ぶものではなく、組み合わせて効果を高められるもの です。ユースケースによっては、最適な性能を得るために併用する必要があります。
ここでは、短期記憶の問題に直面していると仮定し、RAG を使って解決してみましょう。
検索拡張生成(RAG)
RAG は、コンテンツを取得( Retrieving)して LLM のプロンプトを拡張( Augment)してから、回答を生成( Generating)するプロセスです。モデルがタスクを解決できるように、 特定の分野のコンテキストを参照できるようにする ために使います。
RAG は、LLM の精度と一貫性を高めるうえで非常に有用なツールです。OpenAI のお客様による最大規模の導入事例の多くは、プロンプトエンジニアリングと RAG だけで実現されています。

この例では、統計情報のナレッジベースを埋め込みベクトルに変換してあります。ユーザーが質問すると、その質問も埋め込みベクトルに変換し、ナレッジベースから最も関連性の高いコンテンツを取得します。これをモデルに与えると、モデルが質問に答えます。
RAG アプリケーションでは、最適化すべき新たな軸として「取得」が加わります。RAG を機能させるには、適切なコンテキストをモデルに与えたうえで、モデルが正しく回答しているかを評価する必要があります。RAG の評価をシンプルに捉えられるよう、これらを次のマトリクスに整理します。

RAG アプリケーションがうまく機能しなくなる箇所は、次の 2 つです。
| 箇所 | 問題 | 解決策 |
|---|---|---|
| 取得 | 誤ったコンテキストを与えると、モデルはそもそも回答できません。また、無関係なコンテキストを与えすぎると、必要な情報が埋もれ、ハルシネーションの原因になります。 | 取得処理を最適化します。たとえば、次のような方法があります。 - 適切な結果を返すように検索を調整 - ノイズを減らすように検索を調整 - 取得した各結果に含める情報を増やす これらは一例にすぎません。RAG の性能調整はそれ自体が独立した専門分野となっており、LlamaIndex や LangChain などのライブラリでは、さまざまな調整方法が提供されています。 |
| LLM | モデルに適切なコンテキストを与えても、それを誤って扱う場合があります。 | プロンプトエンジニアリングで指示やモデルの処理方法を改善し、例を示すことで精度が上がる場合はファインチューニングも追加 |
ここで押さえておきたいのは、冒頭で示した考え方と原則は変わらないということです。評価によって何がうまくいかなかったのかを特定し、それを修正するために最適化を行います。RAG で異なるのは、取得という軸も考慮する必要がある点だけです。
RAG は有用ですが、解決できるのはコンテキスト内学習の問題に限られます。多くのユースケースでは、LLM にタスクを学習させ、一貫して確実に実行できるようにすることが課題になります。この問題には、ファインチューニングを使います。
ファインチューニング
学習による記憶の問題を解決するため、多くの開発者は、特定の分野に絞った比較的小規模なデータセットで LLM の学習を継続し、特定のタスクに最適化します。このプロセスを ファインチューニングと呼びます。
ファインチューニングは通常、次のいずれかの目的で行います。
- 特定のタスクにおけるモデルの精度向上: そのタスクを正しく実行した例を多数示し、タスク固有のデータでモデルを学習させることで、学習による記憶の問題を解決します。
- モデルの効率向上: トークン数を減らしたり、より小さなモデルを使ったりして、同じ精度を実現します。
ファインチューニングは、学習用の例を集めたデータセットの準備から始まります。これは最も重要なステップです。ファインチューニングの例は、モデルが実際の運用で受け取る内容を正確に反映している必要があるためです。
多くのお客様は、試験運用中にプロンプトの入力と出力を幅広く記録する、 プロンプトベーキングという手法を使っています。 これらのログを選別することで、 実際の利用に即した例を含む、効果的な学習セットを作成できます。

このように整理したデータセットができたら、 学習 を実行してファインチューニング済みモデルを作成できます。学習に使うプラットフォームやフレームワークによっては、ほかの機械学習モデルと同様に、ハイパーパラメーターを調整できる場合があります。過学習を検出するため、学習には使わないホールドアウトセットを必ず確保し、学習後の 評価 に使うことをお勧めします。良い学習セットを作るためのヒントは、ファインチューニングのドキュメントにあるガイダンスをご覧ください。学習が完了すると、新しいファインチューニング済みモデルを推論に使用できるようになります。
ファインチューニングの最適化については、OpenAI のモデルカスタマイズサービスで得られたベストプラクティスを中心に紹介します。ただし、これらの原則は、ほかのプロバイダーや OSS の製品にも当てはまるはずです。押さえておきたい主なポイントは次のとおりです。
- プロンプトエンジニアリングから開始: プロンプトエンジニアリングの段階で、ベースラインとして使える確かな評価セットを用意します。これにより、基本となるプロンプトに確信が持てるまで、少ない投資で取り組めます。
- 少量から始め、品質を重視: 基盤モデルをファインチューニングする際は、学習データの量よりも品質が重要です。まず 50 件以上の例で始めて評価します。必要な精度にまだ達しておらず、誤答の原因がコンテキストではなく一貫性や振る舞いにある場合は、学習セットを増やします。
- 実際の利用を代表する例の用意: よく見られる落とし穴の 1 つは、学習データが実際の利用を代表していないことです。ファインチューニングに使う例の書式や形式が、本番環境で LLM が受け取る内容と微妙に異なっている場合があります。たとえば RAG アプリケーションなら、RAG の例を含むデータでモデルをファインチューニングし、コンテキストの使い方をゼロショットで学ばなくても済むようにします。
すべての手法の組み合わせ
これらの手法は組み合わせて使えます。初期の評価でコンテキストと振る舞いの両方に問題が見つかった場合、最終的な本番環境のソリューションでは、ファインチューニングと RAG を併用することになるかもしれません。それで問題ありません。組み合わせることで、両方の手法の弱点を補えます。主な利点は次のとおりです。
- 指示やフューショットの例の代わりに、多数の学習例を使ったファインチューニングでモデルに一貫した振る舞いを定着させ、プロンプトエンジニアリングで使う トークン数を最小化
- 十分なファインチューニングによる複雑な振る舞いの学習
- RAG を使い、より新しいコンテンツやユースケースに必要な専門情報などの コンテキストを追加
ここまでで、RAG とファインチューニングの役割や、それぞれが適している場面を理解できたと思います。最後に押さえておきたいのは、これらを導入すると、改善を繰り返す速度とのトレードオフが生じることです。
- RAG では、LLM の振る舞いに加えて、取得の仕組みも調整する必要があります
- ファインチューニングでは、追加の調整を行うたびに、ファインチューニングのプロセスを再実行し、学習セットと検証セットを管理する必要があります。
どちらも時間と手間のかかる複雑なプロセスになり得ます。また、LLM アプリケーションが複雑になるにつれて、以前はできていたことができなくなるなどのリグレッションが発生する可能性もあります。この記事から一つだけ覚えておくなら、複雑な RAG やファインチューニングに進む前に、基本的な手法で可能な限り精度を高めることです。目指すべきは目標とする精度の達成であり、最も高度な手法だと思われているからといって RAG + FT に飛びつくことではありません。
本番環境で「十分」といえる精度の目安
LLM の精度を高める調整は、終わりのない取り組みになり得ます。既存の手法をそのまま使うだけで 99.999% の精度に達することは、まず期待できません。このセクションでは、どの時点で精度が十分だと判断するかを考えます。LLM を本番環境に導入する判断にどうすれば納得できるのか、そして提供するソリューションのリスクをどう管理するのかを説明します。
この問題は、 ビジネス と 技術 の両面から考えると整理しやすくなります。それぞれに取り組む際の基本的な考え方を説明し、カスタマーサービスのヘルプデスクを例に、両面のリスクをどう管理するかを示します。
ビジネス
ルールベースや従来の機械学習システム、さらには人間による対応のように、比較的結果を予測しやすいものに慣れていると、ビジネスの立場から LLM を信頼するのは難しいかもしれません。どのような失敗が起こるかに際限がなく、予測もできないシステムを受け入れるのは簡単ではありません。
ここで成功したアプローチとして、カスタマーサービスの事例があります。この事例では、次のように取り組みました。
まず、主な成功と失敗のケースを洗い出し、それぞれのコストを見積もります。これにより、試験運用の結果に基づいて、ソリューションによってどれだけの費用削減やコストの発生が見込まれるかを明確にできます。
- たとえば、従来は人間が解決していた案件を AI が解決すれば、$20 を削減できるかもしれません。
- 人間へのエスカレーションが不要な案件をエスカレーションすると、 $40 のコストがかかるかもしれません
- 最悪の場合、顧客が AI への不満を募らせてサービスを解約し、 $1000 の損失が発生します。これが案件の 5% で起こると仮定します。
| 事象 | 金額 | 案件数 | 合計金額 |
|---|---|---|---|
| AI の成功 | +20 | 815 | $16,300 |
| AI の失敗(エスカレーション) | -40 | 175.75 | $7,030 |
| AI の失敗(解約) | -1000 | 9.25 | $9,250 |
| 結果 | +20 | ||
| 損益分岐点となる精度 | 81.5% |
もう一つ行ったのは、ソリューション全体の影響を把握するために、業務プロセスの実測データを集めることです。カスタマーサービスを例にすると、次のような指標が考えられます。
- 人間のみで対応した場合と AI が対応した場合の CSAT スコアの比較
- 対応後のレビューに基づく、人間と AI の判断精度の比較
- 人間と AI の解決までにかかる時間の比較
カスタマーサービスの例では、数回の試験運用で明確なデータを集めたうえで、これらの指標をもとに次の 2 つの重要な判断を下しました。
- LLM ソリューションから人間へのエスカレーションが想定より多くても、既存のソリューションと比べて運用コストを大幅に削減できました。つまり、不正解となる 15% の大部分が早い段階でのエスカレーションであれば、精度が 85% でも許容できると考えられます。
- 不正行為に関する案件を誤って処理する場合など、失敗による損失が非常に大きいケースでは、人間が主導し、AI はアシスタントとして機能する方針にしました。この場合、判断精度の統計をもとに、完全な自律対応を任せるには不安が残ると判断しました。
技術面
技術面での役割は、より明確です。ビジネス側が期待する価値と、問題が起きた場合の損失を明確にしたら、開発者の役割は、ユーザー体験を損なわずに失敗に対処できるソリューションを構築することです。
もう一度カスタマーサービスを例に考えてみましょう。ユーザーの意図を 85% の精度で判定できるモデルがあるとします。技術チームとして、誤った判定が生じる 15% の影響を最小限に抑えるには、次のような方法があります。
- プロンプトエンジニアリングにより、モデルが判断に自信を持てない場合は顧客に追加情報を求めるようにできます。初回の精度は下がるかもしれませんが、意図を判定する機会が 2 回あれば、精度が上がる可能性があります。
- 二次対応のアシスタントが意図の判定段階に差し戻せるようにすることもできます。これも、ユーザーの待ち時間が多少増える代わりに、誤りから自動で回復できる UX を実現する方法です。
- プロンプトエンジニアリングにより、意図が不明確な場合は人間に引き継ぐようにモデルを設定できます。短期的には運用コストの削減効果が一部失われますが、長期的には顧客離れのリスクを抑えられる可能性があります。
こうした判断は UX に反映され、精度を高めるために応答が遅くなったり、人間が対応する機会が増えたりします。これらの影響は、前述のビジネス面で取り上げたコストモデルにも反映されます。
ここまでで、ビジネスの実情に即した精度目標を設定するために、ビジネス面と技術面の判断を整理する方法がわかりました。
今後の実践に向けて
ここまで、LLM の精度を最大化するための基本的な考え方、そのために使えるツール、そして本番環境で十分といえる精度を判断する方法を紹介しました。これで、着実に本番運用へと進めるための枠組みとツールがそろいました。これらの手法を使って他社が達成したことからヒントを得たい場合は、ぜひお客様事例をご覧ください。Morgan Stanley や Klarna のユースケースから、これらの手法で何を実現できるかがわかります。
皆さんの取り組みがうまくいくことを願っています。これらの手法でどのようなものを開発されるのか、楽しみにしています!
チューニング手法別の BLEU スコア(100 点満点)