Chuyển đến nội dung chính
友田 陽大
本番LLMアプリ実装(信頼できるAI)
生成AI
LLM
キャッシュ
コスト最適化
パフォーマンス
RAG
pgvector
AIエージェント
TypeScript
アーキテクチャ設計

本番LLMアプリのキャッシュ戦略 2026:プロンプトキャッシュ+セマンティックキャッシュでレイテンシとコストを削減

生成AI/LLMアプリのレイテンシとコストを削減する2種類のキャッシュを実装ガイド。プロバイダのプロンプトキャッシュ(Anthropic cache_control・OpenAI自動・Google context caching)と、アプリ層のセマンティックキャッシュ(埋め込み類似・pgvector)を、使い分け・偽ヒット対策・TTL設計・実TypeScriptコードで解説します。

Published
Reading time
9 min read
Author
友田 陽大
Chia sẻ

LLMは、1回の呼び出しが高コストで高レイテンシです。同じシステムプロンプトや長いコンテキストを毎回丸ごと処理させ、似た質問に毎回ゼロから生成させる——本番でこれを放置すると、請求書とp95レイテンシが静かに膨らみます。キャッシュは、LLMアプリのコストとレイテンシを最も安く削減できるレバーです。

ただし「キャッシュ」には性質の異なる2種類があり、使い分けが要点です。

  1. プロンプトキャッシュ(プロバイダ機能) — プロンプトの安定したプレフィックス(システム指示・長いコンテキスト)を再利用し、その入力トークンを割引する。完全一致ベース。
  2. セマンティックキャッシュ(アプリ層)埋め込みの類似度で「言い換えた似た質問」に過去の応答を返し、LLM呼び出し自体を省く。閾値ベース(=偽ヒットのリスクがある)。

この記事は、pgvectorによる本番RAGの知見をキャッシュに応用し、各プロバイダの公式ドキュメントを検証した上で、TypeScriptの実コードで両方を設計します。これは、レイテンシ・コスト面から信頼性・回復性を補完する「本番AI」の一手です。

⚠️ 本記事の価格・トークン閾値は2026年時点の公式値で、モデル名(Opus 4.8 / GPT-5系 / Gemini 3.x など)に紐づきます。頻繁に変わるため、実装前に必ず各出典を再確認してください。割引率はモデル依存です。

2種類のキャッシュの違い

プロンプトキャッシュセマンティックキャッシュ
プロバイダ(API機能)アプリ(自前 / GPTCache 等)
一致方法プレフィックスの完全一致埋め込みの意味的類似(言い換えを拾う)
効果入力トークンを割引LLM呼び出しそのものを省略
リスクほぼ無い(安全)偽ヒット(要・閾値/TTL/評価)
向く用途大きな固定コンテキスト(RAG・システム指示・few-shot)FAQ・定型質問・言い換えの多い問い合わせ

まず安全なプロンプトキャッシュから入れ、次にセマンティックキャッシュを慎重に足す——が実務の順序です。

プロンプトキャッシュ:静的コンテンツを「前」に置く

プロンプトキャッシュの効果は、プロンプトの構造で決まります。共通する原則は、変わらない大きな部分(システム指示・長いコンテキスト・few-shot例)をプロンプトの前に、変わる部分(ユーザー入力)を後ろに置くこと。プレフィックスが一致するほどキャッシュが効きます。

  • OpenAI自動です。コード変更なしに、一定長(1,024トークン)以上のプロンプトで効き、以降は128トークン単位でヒットします。静的コンテンツを前に置くだけで恩恵を受けられます。キャッシュ読み取りの割引はモデル依存(GPT-4o世代は約50%、GPT-5系は最大90%)。
  • Anthropiccache_control(ephemeral)で明示します。最大4つのブレークポイント、既定TTLは5分(1時間オプションあり)。価格はキャッシュ書き込み1.25×(5分)/2×(1時間)、読み取り0.1×(基本入力比、2026年時点)。
  • Google Gemini は明示的な CachedContent API に加え、2.5系以降は暗黙キャッシュが既定で効きます(キャッシュ保存に時間課金がある点に注意)。

Vercel AI SDK なら、最も簡単なのは AI Gateway の自動キャッシュです。

import { generateText } from "ai";

// 最も簡単:AI Gateway の自動キャッシュ。プロバイダに応じ最適な戦略を適用する
// (Anthropic系は cache_control を注入、OpenAI/Google は暗黙キャッシュを利用)。
const { text } = await generateText({
  model: "anthropic/claude-opus-4-8",
  messages,
  providerOptions: { gateway: { caching: "auto" } },
});

明示制御するなら、安定プレフィックスに cacheControl を置きます。

// 明示制御:静的コンテンツを"前"に置き、そこに cacheControl を付ける。
const { usage } = await generateText({
  model: "anthropic/claude-opus-4-8",
  messages: [
    {
      role: "system",
      content: largeStaticContext, // 大きく・変わらない部分(RAG文脈やfew-shot)
      providerOptions: { anthropic: { cacheControl: { type: "ephemeral" } } },
    },
    { role: "user", content: userQuestion }, // 変わる部分は後ろ
  ],
});
// usage.inputTokenDetails.cacheReadTokens でヒットを計測(読み取りは入力の約0.1×課金)

プロンプトキャッシュはほぼノーリスク(完全一致なので誤答は起きない)。まずここから入れるのが鉄則です。

セマンティックキャッシュ:呼び出しそのものを省く

一段踏み込むと、「似た質問には、そもそもLLMを呼ばない」——これがセマンティックキャッシュです。質問を埋め込みベクトルにし、過去の質問とコサイン類似度で照合。閾値を超えたら過去の応答を返します。プロンプトキャッシュが「完全一致のプレフィックス再利用」なのに対し、こちらは言い換え(paraphrase)まで拾えるのが強みです。

判定ロジック(閾値・鮮度)は純粋関数に分離してテスト容易にします。

// セマンティックキャッシュ:埋め込み類似で「言い換え」まで拾う。判定は純粋関数で分離。
interface CacheHit {
  readonly answer: string;
  readonly similarity: number; // 0..1(コサイン類似)
  readonly ageMs: number;
}

// 純粋・テスト容易:閾値と鮮度(TTL)の両方を満たすヒットだけ採用する(SRP)。
function acceptCacheHit(hit: CacheHit | null, minSimilarity: number, ttlMs: number): boolean {
  return hit !== null && hit.similarity >= minSimilarity && hit.ageMs <= ttlMs;
}

// cache-aside:ヒットなら即返す(LLM呼び出しを省く)、ミスなら生成して保存。
async function cachedGenerate(query: string, scope: string): Promise<string> {
  const embedding = await embed(query);
  // pgvector で最近傍を1件(scope でユーザー/地域を隔離し、他者の応答を返さない)
  const hit = await cache.nearest(embedding, scope);
  if (acceptCacheHit(hit, 0.95, 3_600_000)) return hit!.answer; // 高閾値で偽ヒットを抑制
  const answer = await callLlm(query);
  await cache.put({ query, embedding, answer, scope }); // ミス:保存して次回に備える
  return answer;
}

セマンティックキャッシュのリスクと制御

セマンティックキャッシュの怖さは偽ヒットです。「2024年の売上は?」と「2025年の売上は?」は埋め込みが酷似しますが、正解は別。緩い閾値は誤答を量産します。制御は4点。

  • 閾値 — 高めから(0.90〜0.95)始め、偽ヒット率を監視しながら調整(AWSも「閾値がヒット率と品質のトレードオフを決める」と明言)。
  • TTL — データの揮発性で。リアルタイム(価格・在庫)は5〜15分、静的な事実は24時間が目安。長いTTLはヒット率を上げるが陳腐化リスクも上げる。
  • スコープ — ユーザー・地域・商品IDでフィルタし、パーソナライズされた応答を他者に返さない
  • 無効化 — ソースデータ更新時に、該当エントリをコンテンツ起点で無効化する。

そしてヒットの品質を評価で測ること。オフライン評価に「キャッシュヒットが正しいか」を含め、偽ヒット率を回帰ゲートにします(LLMの評価・テスト)。定番のOSSは GPTCache で、閾値やベクトルストアを差し替えられます。

キャッシュしてはいけないケースも明確に。 常に最新性が要る、強くパーソナライズされる、監査上で毎回生成が要る——これらは偽ヒット/陳腐化のコストが便益を上回るため、素直に毎回呼びます。

可観測性:効果と副作用を測る

キャッシュは測って初めて安全に使えますヒット率・削減トークン/コスト・p95レイテンシを記録し、加えて偽ヒット率(評価由来)を監視します。「ヒット率は高いが偽ヒットも増えた=閾値が緩すぎ」のように、指標がチューニングを教えてくれます。土台は OpenTelemetryによる本番可観測性 を参照してください。なお、キャッシュはモデル/インフラの経済性(自前ホスト vs API)とは別レイヤーの最適化です。そちらは 生成AIのコスト設計 を参照してください。

導入チェックリスト

  • プロンプトキャッシュ(まず安全策) — 静的コンテンツを前に置き、OpenAIは自動、Anthropicは cacheControl(or Gateway caching:'auto')を有効化したか。
  • 構造 — 変わらない大きな部分を前、可変部分を後ろに置いているか。
  • セマンティックキャッシュ(慎重に) — 高い類似度閾値(0.90〜)から始めているか。
  • TTL — データの揮発性に応じて設定し、ソース更新で無効化しているか。
  • スコープ — ユーザー/地域でヒットを隔離し、パーソナライズを漏らしていないか。
  • 偽ヒット監視 — 評価にキャッシュヒットの正しさを含め、回帰ゲートにしているか。
  • 非キャッシュ判断 — 最新性必須・強パーソナライズ・監査要件のクエリを除外したか。
  • 可観測性 — ヒット率・削減コスト・レイテンシ・偽ヒット率を監視しているか。

まとめ

LLMアプリのキャッシュは、**「安全なプロンプトキャッシュを土台に、セマンティックキャッシュを慎重に重ねる」**のが定石です。

  • プロンプトキャッシュは完全一致でほぼノーリスク。静的コンテンツを前に置くだけで入力コストが下がる(Anthropic読み取りは約0.1×、OpenAIは自動)。
  • セマンティックキャッシュは呼び出しごと省ける強力な手段だが、偽ヒットが本質的リスク。高い閾値・TTL・スコープ・評価で管理する。
  • 測って運用する。 ヒット率だけでなく偽ヒット率を監視し、キャッシュしない判断も設計に含める。

速く・安く・正確に——この3つは、キャッシュを正しく設計すれば同時に得られます。

Câu hỏi thường gặp

プロンプトキャッシュとセマンティックキャッシュの違いは?
プロンプトキャッシュはプロバイダの機能で、プロンプトの安定した『プレフィックス(システム指示・長いコンテキスト)』を完全一致で再利用し、その入力トークンを割引します(Anthropicは読み取りが基本入力の約0.1×)。セマンティックキャッシュはアプリ層の仕組みで、埋め込みの類似度により『言い換えた似た質問』にも過去の応答を返し、LLM呼び出し自体を省きます。両者は併用できます。
Anthropic/OpenAIのプロンプトキャッシュはコードが必要ですか?
OpenAIは自動で、コード変更なしに一定長(1024トークン)以上のプロンプトで効きます。Anthropicは cache_control(ephemeral)で明示します(Vercel AI SDKなら providerOptions.anthropic.cacheControl、AI Gatewayなら caching: 'auto')。どちらも静的コンテンツを『前』に置くとヒット率が上がります。割引率はモデル依存で(GPT-5系は最大90%、Anthropicの読み取りは約0.1×)、価格は2026年時点の値なので実装前に一次情報を再確認してください。
セマンティックキャッシュは危険ではありませんか?
最大のリスクは偽ヒットです。意味は似ていても意図が違う質問(時点・肯定否定・対象が違う等)に、誤った過去応答を返してしまいます。高い類似度閾値(0.90〜0.95から始めて監視しながら調整)・TTL・ユーザー/地域などのスコープ・評価(eval)でのヒット品質監視で管理します。時間依存や強くパーソナライズされた応答には慎重に。
キャッシュのTTLはどう決めますか?
データの揮発性で決めます。目安は、リアルタイムなデータ(価格・在庫)は5〜15分、静的な事実は24時間。TTLを長くするほどヒット率は上がりますが、古い応答を返すリスクも上がります。ソースデータが更新されたら、その分を明示的に無効化します。
どんなときにキャッシュしてはいけませんか?
常に最新性が必須、強くパーソナライズされる、あるいは法的・監査上で毎回の生成が必要な場合です。偽ヒットや陳腐化のコストが、削減できるコスト・レイテンシの便益を上回るなら、そのクエリはキャッシュしない判断が正解です。
キャッシュの効果はどう測りますか?
ヒット率・削減したトークン/コスト・p95レイテンシを監視します。Anthropicは usage の cacheReadTokens/cacheWriteTokens で読み書きを計測できます。ヒットの『品質』(偽ヒットが混ざっていないか)は評価(eval)で継続的に測ります。

Tài liệu tham khảo

友田

友田 陽大

Người phát triển sản phẩm đoạt Giải thưởng Bộ trưởng (METI). Với TypeScript + Python + AWS, tôi một mình triển khai trọn gói SaaS, chuyển đổi số công nghiệp và AI tạo sinh (RAG) sẵn sàng cho production — từ phân tích yêu cầu đến hạ tầng và vận hành.

Got a challenge?

From design to implementation and operations — solo × generative AI

Implementation like this article's, end to end from requirements to production. Start with a free 30-minute technical consult and tell me about your situation.

Nhận cả dự án trọn gói lẫn vai trò cố vấn kỹ thuật. Hãy bắt đầu bằng buổi tư vấn miễn phí 30 phút.

最短ルート:カレンダーから直接予約

相談内容が固まっている方は、フォーム送信よりその場で日程を確定する方がスムーズです。下記から空き時間をお選びください。

  • 30分のオンライン無料相談
  • Google Meet / Zoom / Microsoft Teams
  • NDA 商談前締結可・無理な営業はいたしません
無料相談の空き枠を予約する

Cũng đáng đọc