LESSON 30分

ストーリー

田中VPoE
コスト構造を分析した結果、チャットボットの問い合わせの30%が類似した質問だとわかった。毎回APIを呼び出すのは無駄だ
あなた
同じ質問には過去の回答をキャッシュから返せば、APIコストを30%削減できますね
田中VPoE
その通り。ただしLLMのキャッシュは従来のWebキャッシュとは違う課題がある。完全一致だけでなく、意味的に類似した質問にもヒットさせる「セマンティックキャッシュ」が有効だ
あなた
類似度を使ったキャッシュですね。面白いです

LLMキャッシュの種類

キャッシュ戦略の比較

種類仕組みヒット率実装複雑度
完全一致キャッシュプロンプトの完全一致低(5-10%)
セマンティックキャッシュ埋め込みベクトルの類似度中(20-40%)
プロンプトテンプレートキャッシュテンプレート+パラメータの一致中(15-30%)
RAGコンテキストキャッシュ検索結果のキャッシュ高(30-50%)

セマンティックキャッシュの実装

import hashlib
import json
import numpy as np
from openai import OpenAI
from datetime import datetime, timedelta

client = OpenAI()

class SemanticCache:
    """セマンティックキャッシュ"""

    def __init__(self, similarity_threshold: float = 0.95, ttl_hours: int = 24):
        self.threshold = similarity_threshold
        self.ttl = timedelta(hours=ttl_hours)
        self.cache: list[dict] = []  # 実運用ではベクトルDBを使用

    def get(self, prompt: str) -> dict | None:
        """キャッシュから類似プロンプトの結果を検索"""
        query_embedding = self._get_embedding(prompt)
        now = datetime.now()

        best_match = None
        best_similarity = 0

        for entry in self.cache:
            # TTLチェック
            if now - entry["timestamp"] > self.ttl:
                continue

            similarity = self._cosine_similarity(
                query_embedding, entry["embedding"]
            )
            if similarity > self.threshold and similarity > best_similarity:
                best_match = entry
                best_similarity = similarity

        if best_match:
            return {
                "response": best_match["response"],
                "similarity": best_similarity,
                "cached": True
            }
        return None

    def set(self, prompt: str, response: str):
        """キャッシュに結果を保存"""
        embedding = self._get_embedding(prompt)
        self.cache.append({
            "prompt_hash": hashlib.sha256(prompt.encode()).hexdigest(),
            "embedding": embedding,
            "response": response,
            "timestamp": datetime.now()
        })

    def _get_embedding(self, text: str) -> list[float]:
        response = client.embeddings.create(
            model="text-embedding-3-small",
            input=text
        )
        return response.data[0].embedding

    def _cosine_similarity(self, a: list[float], b: list[float]) -> float:
        a, b = np.array(a), np.array(b)
        return float(np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b)))

キャッシュ設計のベストプラクティス

キャッシュの有効性判断

条件キャッシュ適性理由
FAQ的な問い合わせ同じ質問が繰り返される
商品情報の問い合わせ商品データは頻繁に変わらない
パーソナライズされた推薦ユーザーごとに異なる結果
リアルタイムデータ依存在庫、価格は常に変動
クリエイティブ生成類似リクエストの再利用が可能

キャッシュ無効化(Invalidation)

トリガー対応
TTL超過自動削除24時間経過で削除
データ更新タグベース無効化商品情報更新時に関連キャッシュを削除
モデル変更全キャッシュクリアプロンプト変更時にキャッシュをリセット
品質問題手動無効化誤った回答がキャッシュされた場合

キャッシュの効果測定

主要メトリクス

メトリクス計算式目標値
ヒット率キャッシュヒット数 / 総リクエスト数20-40%
コスト削減率削減コスト / キャッシュなし時のコスト15-30%
レイテンシ改善キャッシュヒット時のレイテンシ / APIコール時のレイテンシ10倍以上速い
品質維持率キャッシュ返却時の品質スコア / API返却時の品質スコア95%以上

まとめ

キャッシュ種類適用場面期待効果
セマンティックキャッシュFAQ、定型問い合わせコスト20-40%削減
テンプレートキャッシュ構造化された入力コスト15-30%削減
RAGコンテキストキャッシュRAGシステム検索コスト50%削減

チェックリスト

  • LLMキャッシュの種類と特性を理解した
  • セマンティックキャッシュの仕組みと実装方法を把握した
  • キャッシュの有効性判断基準を理解した
  • キャッシュ無効化の戦略を学んだ

次のステップへ

次はモデル選択最適化を学び、タスクに応じた最適なモデルの使い分けを習得します。


推定読了時間: 30分