セマンティックキャッシュとは?AIゲートウェイでLLM費用を削減する仕組みと実装

セマンティックキャッシュとは、意味的に類似したクエリに対して過去のLLM応答を再利用することでAPIコールを削減する技術である。本記事では、AIゲートウェイにセマンティックキャッシュを実装してLLM API費用を大幅に削減する手順を、エンジニアや技術担当者向けに具体的なステップで解説する。
セマンティックキャッシュは、クエリ文字列の完全一致ではなく「意味の近さ」でキャッシュヒットを判定する仕組みである。 言い回しが違っても意図が同じ質問には過去の応答を再利用できるため、従来の完全一致キャッシュでは取りこぼしていた再利用機会を拾える。ここでは通常のキャッシュとの違いを、ヒット判定の方式・適用できる領域・コスト削減への効き方の3点から整理していく。
完全一致キャッシュの限界とセマンティックキャッシュが解決する課題
完全一致キャッシュは、プロンプト文字列をキー(多くはそのハッシュ値)にして応答を保存し、まったく同じ文字列が再び来たときだけ再利用する方式だ。アプリケーションが固定のテンプレートで問い合わせる場面では有効に働く。
問題は、エンドユーザーが自由入力する自然言語クエリでは表記揺れが事実上無限に存在する点にある。「返品方法を教えて」「どうやって返品すればいい?」「返品の手続きは?」はいずれも同じ意図だが、文字列としては別物なので、完全一致キャッシュではすべて別のキーとして扱われ、ヒット率はほぼゼロまで落ち込む。
セマンティックキャッシュは、この「意味は同じだが文字列が違う」クエリ群をまとめて1つの応答に対応づけることを狙う。クエリを意味ベクトルに変換し、文字列ではなくベクトル空間上の距離で近さを測ることで、言い回しの差を吸収してヒット判定を行う。
ベクトル類似度を使ったキャッシュヒット判定の仕組み
セマンティックキャッシュのヒット判定は、埋め込み(エンベディング)モデルを使ってクエリを固定長のベクトルに変換するところから始まる。意味が近いクエリ同士はベクトル空間上でも近い位置に配置されるため、新しいクエリのベクトルと、過去に保存したクエリのベクトルとの距離を測れば「意味的にどれだけ近いか」を数値化できる。
距離指標にはコサイン類似度がよく使われる。新しいクエリが来たら、保存済みベクトルの中から最も近いもの(最近傍)を探し、その類似度があらかじめ決めたしきい値以上であれば「ヒット」と判定して、保存済みの応答をそのまま返す。しきい値を下回れば「ミス」とし、通常どおりLLMを呼び出す。
保存件数が増えると総当たりの比較は重くなるため、実運用では近似最近傍探索(ANN)を備えたベクトルデータベースに探索を任せるのが一般的だ。
セマンティックキャッシュがLLMコスト削減に効く理由
LLMのAPI課金は、入力トークンと出力トークンの量に比例するのが基本だ。キャッシュヒットが成立すると、その1回分のLLM呼び出しを丸ごとスキップできるため、トークン課金とネットワーク往復のレイテンシの両方を節約できる。
効果の大きさは、クエリ分布がどれだけ繰り返しを含むかに依存する。FAQ応答、社内ナレッジ検索、定型的なサポート問い合わせのように、似た質問が高頻度で繰り返される用途ほどヒット率が上がり、削減効果も大きくなりやすい。逆に、毎回ユニークで一度きりのクエリが大半を占める用途では効果は限定的だ。
コスト面のトレードオフとして、ヒット判定のたびに埋め込みモデルの呼び出しとベクトル検索が発生する。ただし埋め込みAPIの単価は生成系LLMの呼び出しに比べて小さいことが多く、ヒット時に削減できるトークン課金がこの追加コストを上回る限り、全体では費用が下がる。実際の損益分岐点は利用するモデルの単価とヒット率で変わるため、導入後の計測が欠かせない。
実装前に確認すべき前提条件と必要なコンポーネント

セマンティックキャッシュの実装には、AIゲートウェイ・ベクトルデータベース・埋め込みモデルの3つが最低限必要になる。 どれを選ぶかでレイテンシ・運用負荷・精度が変わるため、実装に入る前に各コンポーネントの役割と、しきい値や対象クエリの方針を固めておきたい。ここでは選定の観点を3つの論点に分けて整理する。
AIゲートウェイ・ベクトルデータベース・エンベディングモデルの選定
AIゲートウェイは、アプリケーションとLLMプロバイダの間に立つプロキシで、キャッシュ層を差し込む場所になる。LiteLLM、Portkey、Cloudflare AI Gateway のように、キャッシュやルーティングを備えたものを使うと実装の手数を減らせる。自前のプロキシに組み込む選択肢もある。
ベクトルデータベースは、クエリのベクトルと応答を保存し、最近傍探索を担う。pgvector(PostgreSQL拡張)、Redis のベクトル機能、Qdrant、Weaviate、Milvus、Pinecone などが候補だ。既存スタックにPostgreSQLやRedisがあるなら、それらの拡張から始めると運用対象を増やさずに済む。
埋め込みモデルは、クエリをベクトル化する。クラウドの埋め込みAPIは導入が簡単で精度も安定しやすい一方、呼び出しごとに課金とレイテンシが乗る。自前でホストする軽量モデルはコストを抑えられるが、運用とGPUの負担が増える。選定では、検索精度・1回あたりのレイテンシ・単価・データを外部に出してよいかというデータ主権の観点を併せて検討する。
類似度しきい値の考え方と許容できる回答精度のトレードオフ
類似度しきい値は、セマンティックキャッシュの挙動を決める最も重要なパラメータだ。しきい値を高く設定すると、本当に意味が近いクエリしかヒットしないため誤ったキャッシュ応答(フォールスヒット)は減るが、その分ヒット率も下がりコスト削減効果は小さくなる。
逆にしきい値を低くすると、ヒット率は上がるものの、意味が微妙に違うクエリにまで過去の応答を返してしまうリスクが高まる。特に否定や条件が反転したクエリは、ベクトル上の距離が近いのに答えが正反対になりやすく、低いしきい値では事故につながる。
適切な値はドメインや埋め込みモデルによって変わるため、一律の正解はない。回答の正確性が重視される領域では高めから始め、ログを見ながら段階的に下げて、許容できる誤り率の範囲で最大のヒット率を探るのが安全だ。
キャッシュ対象クエリと非対象クエリの分類基準
すべてのクエリをキャッシュ対象にしてよいわけではない。キャッシュに向くのは、答えが安定していて誰が聞いても同じになる質問だ。製品仕様、用語の定義、社内規程、FAQのように、一定期間は内容が変わらないものが該当する。
一方で、キャッシュに向かないクエリもはっきりしている。ユーザーのアカウント情報に依存するパーソナライズされた応答、在庫や価格・為替のようなリアルタイム性の高い情報、直前の会話文脈に依存する対話の続き、誤答が許されない重要度の高い判断などは、原則として対象外にすべきだ。これらを誤ってキャッシュすると、古い情報や他人向けの応答を返す事故になりかねない。
実装では、クエリの種類やメタデータ(ユーザー単位か、時間依存か等)を見て、キャッシュを適用するかどうかを振り分けるルーティングの仕組みを併せて用意しておく。
セマンティックキャッシュをAIゲートウェイに実装する手順

セマンティックキャッシュの実装は、クエリのベクトル化(Step 1)、ベクトルデータベースへの登録と検索(Step 2)、AIゲートウェイへの組み込みとルーティング(Step 3)の3ステップで進める。 以下では各ステップでやるべきことと、つまずきやすいポイントを具体的に見ていく。コードは方式を示すための擬似的な例であり、利用するライブラリに合わせて読み替えてほしい。
Step 1: エンベディングモデルの設定とクエリのベクトル化
最初のステップは、埋め込みモデルを設定し、入力クエリをベクトルに変換することだ。変換の前に、クエリを正規化しておくとヒット率が安定する。前後の空白の除去、全角・半角の統一、定型的な挨拶文の削除などを行い、意味に関係しない表記の差をならしておく。
正規化したクエリを埋め込みAPIに渡し、固定長のベクトルを得る。
1def embed(query: str) -> list[float]:
2 normalized = normalize(query) # 空白除去・表記統一など
3 return embedding_client.create(input=normalized).vectorここで重要なのは、キャッシュへの登録時と検索時で必ず同じ埋め込みモデルと同じ正規化処理を使うことだ。モデルやバージョンが混在すると、同じクエリでも異なるベクトルが生成され、ヒット判定が成立しなくなる。埋め込みモデルを差し替えるときは、原則としてキャッシュを作り直す前提で運用する。
Step 2: ベクトルデータベースへのキャッシュエントリ登録と検索
次に、ベクトルデータベースへの登録と検索を実装する。流れは「検索してミスならLLMを呼び、その結果を登録する」というシンプルなものだ。
検索では、新しいクエリのベクトルで最近傍を1件取得し、類似度がしきい値以上ならヒットとして保存済み応答を返す。ミスならLLMを呼び出し、得られた応答をベクトル・元クエリ・メタデータ・TTLとともに登録する。
1def get_or_generate(query: str) -> str:
2 vec = embed(query)
3 hit = vector_db.search(vec, top_k=1)
4 if hit and hit.score >= THRESHOLD:
5 return hit.response # キャッシュヒット
6 answer = llm.generate(query) # ミス: LLM 呼び出し
7 vector_db.upsert(vec, query=query, response=answer, ttl=TTL)
8 return answer登録時に元のクエリ文字列やタイムスタンプ、しきい値判定に使った類似度を一緒に保存しておくと、後からヒット内容を監査したり、しきい値をチューニングしたりする際に役立つ。
Step 3: AIゲートウェイへのキャッシュレイヤー組み込みとルーティング設定
最後に、このキャッシュ処理をAIゲートウェイのリクエスト経路に組み込む。基本の流れは、リクエスト受信 → クエリの埋め込み → キャッシュ検索 → ヒットなら即応答、ミスならLLMへフォワードし、応答を登録してから返す、というものだ。
ゲートウェイに差し込むことで、アプリケーション側のコードを変えずにキャッシュを有効化できる点が利点になる。LiteLLM や Portkey のようにキャッシュ設定を備えたゲートウェイなら、しきい値やTTLを設定値として渡すだけで済むこともある。
合わせて、キャッシュをバイパスしたいケースへの対応も用意しておく。パーソナライズや時間依存のクエリには、リクエストヘッダーやルートでキャッシュ対象外を指定できるようにし、ゲートウェイ側で振り分ける。これにより「キャッシュに向くクエリだけをキャッシュする」という前ステップで定めた方針を、実際の経路上で強制できる。
キャッシュヒット率を高めるためにどう調整するか?

ヒット率は、しきい値・TTL・クエリ正規化の3つを継続的に調整することで高められる。 どれか1つを固定値で運用するのではなく、ログを見ながら少しずつ動かして、誤ったヒットを増やさない範囲で再利用を最大化するのが基本方針だ。ここでは3つの調整ポイントを順に見ていく。
類似度しきい値のチューニング方法と評価指標
しきい値のチューニングは、実際のクエリログを使って行うのが確実だ。まず一定期間のクエリを集め、意味的に同じかどうかを人手またはルールでラベル付けする。次に、しきい値を変えながら「正しくヒットした割合」と「誤ってヒットした割合(フォールスヒット)」を計測する。
評価指標としては、ヒット率(全クエリのうちキャッシュで返せた割合)、フォールスヒット率(誤った応答を返した割合)、そして実際にユーザーへ返した応答の品質を併せて見る。ヒット率だけを追うとフォールスヒットを見落とすため、必ず両方をセットで評価する。
実務では、フォールスヒット率の上限を先に決め(たとえば許容できる誤り率を定義し)、その制約のもとでヒット率が最大になるしきい値を選ぶ、という順序が安全だ。しきい値は一度決めて終わりではなく、クエリ分布の変化に合わせて定期的に見直す。
TTL(有効期限)設計とキャッシュ無効化のタイミング
TTL(有効期限)は、キャッシュした応答をいつまで再利用してよいかを決める設定だ。クエリの種類ごとに分けて設計するのが望ましい。製品の定義や用語のように長期間変わらない情報は長めのTTLを、価格や在庫のように変化しうる情報は短めのTTL、あるいはキャッシュ対象外とする。
TTLによる時間ベースの失効に加えて、元データが更新されたタイミングで明示的にキャッシュを無効化する仕組みも用意しておきたい。たとえば社内規程やFAQの元ドキュメントが改訂されたら、それに紐づくキャッシュエントリを削除する。ドキュメントのバージョンをメタデータに持たせ、バージョンが上がったエントリを失効扱いにする方法も有効だ。
TTLが長すぎると古い情報を返し続け、短すぎるとヒット率が下がる。情報の鮮度要件とヒット率のバランスを見て、クエリ種別ごとに値を決める。
プロンプトエンジニアリングによるクエリの正規化テクニック
クエリの正規化は、埋め込みの前処理として行うことで、意味的に同じクエリを同じベクトル付近に集めやすくする。これによりヒット率が底上げされる。
具体的には、前後の空白や記号の除去、全角・半角や大文字・小文字の統一、「教えてください」「お願いします」といった意味に寄与しない挨拶や敬語表現の削除などが基本になる。さらに、クエリから意図(インテント)を抽出して正規化された短い問いに変換するアプローチもある。
ただし正規化をやりすぎると、本来区別すべきニュアンスまで削ってしまい、フォールスヒットの原因になる点に注意する。否定語(「〜できない」「〜以外」)や数量・条件のように意味を左右する要素は削ってはいけない。正規化のルールは、何を残し何を捨てるかを明示し、しきい値とセットで効果を検証する。
よくある失敗パターンと回避策

セマンティックキャッシュでよくある失敗は、しきい値の誤設定・古い応答の再利用・ベクトルデータベースの肥大化の3つに集約される。 いずれも導入直後は表面化しにくく、運用が進んでから問題になりやすい。先に回避策を押さえておくことで、コスト削減と引き換えに精度や速度を損なう事故を防げる。
しきい値が低すぎて誤ったキャッシュ応答を返すケース
しきい値を低くしすぎると、意味が異なるクエリにまで過去の応答を返してしまうフォールスヒットが起きる。特に危険なのが、否定や条件が反転したクエリだ。「AはBより安いか?」と「BはAより安いか?」はベクトル空間上でとても近いのに、求める答えは正反対になる。低いしきい値ではこれらを取り違える。
回避策としては、まずしきい値を上げて、本当に近いクエリだけをヒット扱いにする。加えて、最近傍で候補を絞ったうえで、否定や数値条件を考慮する再ランキング(リランカー)を挟むと、表層が似ていても意図が違うケースを弾きやすくなる。
導入初期はしきい値を高めに設定し、フォールスヒットが出ていないことをログで確認しながら、慎重に下げていくのが安全だ。フォールスヒットは一見ヒット率を上げて見せるため、ヒット率だけを成功指標にしないことが重要になる。
ハルシネーションを含む古いキャッシュが再利用されるリスク
LLMの応答には、もっともらしいが誤った内容(ハルシネーション)が含まれることがある。これをそのままキャッシュすると、誤答が固定化され、同じ意図のクエリに対して繰り返し返され続ける。完全一致キャッシュより影響範囲が広い分、被害も大きくなりやすい。
回避策は多層で考える。第一に、確信度が低い応答や検証していない応答はキャッシュしない方針を設ける。第二に、TTLを設けて一定期間で必ず作り直されるようにし、誤りが永続しないようにする。第三に、ユーザーからのフィードバック(低評価や訂正)を受けて該当エントリを失効・削除する仕組みを用意する。
可能であれば、キャッシュ登録の前に応答の妥当性を簡易チェックする工程を挟むとよい。少なくとも、重要度の高いクエリ群についてはキャッシュ内容を定期的に監査し、誤答が混入していないかを確認する運用を組み込む。
ベクトルデータベースの肥大化によるレイテンシ増大への対処
キャッシュエントリが増え続けると、ベクトルデータベースのメモリ使用量が膨らみ、最近傍探索のレイテンシも悪化していく。キャッシュで速度を稼ぐつもりが、検索自体が遅くなって効果を相殺してしまう。
対処の基本は、不要なエントリを増やさない・残さないことだ。一定期間アクセスのないエントリを削除するLRU方式の退避、ほぼ同一のクエリから生まれた近すぎるベクトルの重複排除(デデュープ)、TTLによる自動失効を組み合わせる。
加えて、インデックスのチューニングも効く。HNSWのような近似最近傍インデックスは、探索精度と速度のトレードオフを決めるパラメータを持つため、件数規模に合わせて調整する。件数がさらに大きくなる場合は、シャーディングや、用途別にインデックスを分ける設計も検討する。容量とレイテンシは定期的に監視し、しきい値超過の前に手を打てるようにしておく。
LLM API費用削減効果をどう測定するか?

費用削減効果は、キャッシュヒット率と、それによって回避できたLLM呼び出しのトークン量・コストを計測することで把握できる。 体感や推測ではなく、導入前後を同じ指標で比較することが重要だ。ここでは計測すべき具体的な数値と、可視化の方法を整理する。
トークン消費量・API呼び出し回数・コストの計測方法
費用削減効果の計測は、まず基本指標を取得するところから始める。計測すべきは、キャッシュヒット率、回避できたLLM呼び出し回数、そして回避できたトークン量だ。削減額の概算は「回避できた呼び出し回数 × 1回あたりの平均トークン量 × 単価」で見積もれる。
正確に評価するには、キャッシュ導入前のベースライン(一定期間の呼び出し回数・トークン量・コスト)を記録し、導入後の同じ期間と比較する。ヒット時にもわずかに発生する埋め込みとベクトル検索のコストを差し引いて、純粋な削減額を出す。
なお、LLMや埋め込みモデルの単価は変動するため、金額を記載・試算する際は執筆時点の参考値として扱い、最新の料金ページで確認してから本番の見積もりに使う。
<!-- TODO: 当社の実運用での具体的な削減率・金額を計測して挿入 -->AIオブザーバビリティツールを使ったキャッシュ効果の可視化
計測した指標を継続的に追うには、AIオブザーバビリティツールを使うのが効率的だ。Langfuse や Helicone のようなツールは、リクエストごとのトークン消費・コスト・レイテンシを記録し、キャッシュのヒット/ミスを区別して可視化できる。
ダッシュボードでヒット率の推移を追えば、しきい値やTTLを変更した効果を時系列で確認でき、チューニングの判断材料になる。コストの推移と並べて見れば、キャッシュ導入による削減額がひと目で分かる。フォールスヒットの兆候(特定クエリでの品質低下や苦情)も、ログをたどって原因のエントリまで遡れる。
ゲートウェイのアクセスログに、ヒット/ミスの別・使用したしきい値・類似度スコアを記録しておくと、オブザーバビリティツールと組み合わせて、コスト削減と回答品質の両面を継続的に監視できる。導入はゴールではなく、計測と調整を回し続ける運用が定着して初めて、安定した費用削減につながる。
著者・監修者
Yusuke Ishihara
13歳でMSXに触れプログラミングを開始。武蔵大学卒業後、航空会社の基幹システム開発や日本初のWindowsサーバホスティング・VPS基盤構築など、大規模システム開発に従事。 2008年にサイトエンジン株式会社を共同創業。2010年にユニモン株式会社、2025年にエニソン株式会社を設立し、業務システム・自然言語処理・プラットフォーム開発をリード。 現在は生成AI・大規模言語モデル(LLM)を活用したプロダクト開発およびAI・DX推進を手がける。


