CLAUDE LABEN
FORK — Claude Code 2.1.212で/forkの挙動が変わりました。会話を新しいバックグラウンドセッションへ複製し、作業を続けたまま並走できます。従来のセッション内サブエージェントは/subtaskに移りましたLIMITS — WebSearchの呼び出しがセッション単位で既定200回に制限されました。サブエージェントの起動も既定200回が上限で、暴走した検索・委譲のループを止められますMCPBG — 2分を超えるMCPツール呼び出しは自動的にバックグラウンドへ移り、セッションが固まらなくなりました。しきい値はCLAUDE_CODE_MCP_AUTO_BACKGROUND_MSで調整できますPLANFIX — プランモードがtouchやrmといったファイルを変更するBashコマンドを、許可プロンプトもcanUseToolコールバックも通さずに実行してしまう不具合が修正されましたSONNET5 — Claude Sonnet 5は導入価格として入力100万トークンあたり2ドル、出力10ドルで提供中です。8月31日を過ぎると3ドルと15ドルに戻りますIPO — Anthropicが早ければ10月の株式公開を視野に、引受銀行が投資家との面談を組み始めたと報じられていますFORK — Claude Code 2.1.212で/forkの挙動が変わりました。会話を新しいバックグラウンドセッションへ複製し、作業を続けたまま並走できます。従来のセッション内サブエージェントは/subtaskに移りましたLIMITS — WebSearchの呼び出しがセッション単位で既定200回に制限されました。サブエージェントの起動も既定200回が上限で、暴走した検索・委譲のループを止められますMCPBG — 2分を超えるMCPツール呼び出しは自動的にバックグラウンドへ移り、セッションが固まらなくなりました。しきい値はCLAUDE_CODE_MCP_AUTO_BACKGROUND_MSで調整できますPLANFIX — プランモードがtouchやrmといったファイルを変更するBashコマンドを、許可プロンプトもcanUseToolコールバックも通さずに実行してしまう不具合が修正されましたSONNET5 — Claude Sonnet 5は導入価格として入力100万トークンあたり2ドル、出力10ドルで提供中です。8月31日を過ぎると3ドルと15ドルに戻りますIPO — Anthropicが早ければ10月の株式公開を視野に、引受銀行が投資家との面談を組み始めたと報じられています
記事一覧/API & SDK
API & SDK/2026-04-29上級

Claude API のセマンティックキャッシュを本番投入する — 類似プロンプト判定としきい値設計、汚染防止

Claude API のレスポンスをセマンティックキャッシュで再利用する本番設計を、しきい値の決め方・汚染防止・マルチテナント分離・観測性まで一気通貫で解説します。

claude-api81semantic-cache2embedding2production87cost-optimization25observability14multi-tenant

プレミアム記事

「キャッシュを入れたいんですが、似たような質問で違う答えが返ってきたら怖くて」— これは私自身が3つのプロダクトでセマンティックキャッシュを実装したときに、毎回最初に出てきた懸念でした。

完全一致のキャッシュ(Redis に SHA-256 ハッシュで保存するアレ)はすぐに実装できます。しかし本番のユーザーは同じ質問でも、句読点や語順、敬体・常体の違いで毎回キーが変わります。結果としてキャッシュヒット率は 5% にも満たず、Claude API のコストはほぼそのまま、応答時間も縮みません。

セマンティックキャッシュは「意味的に近いプロンプト」を embedding で検出し、過去のレスポンスを再利用する仕組みです。うまく設計すれば、ヒット時の応答は 50ms 程度で返り、Claude API への課金は発生しません。一方で、ナイーブに実装すると「金融商品の質問に医療系の回答を返す」ような事故が起きます。本記事は、その境界線を正しく引くための実装ガイドです。

なぜセマンティックキャッシュが必要なのか — 完全一致では届かない現実

個人開発で複数の小さなプロダクトを回している私にとって、API のコストは抽象的な費目ではなく、機能を出せるか諦めるかの分かれ目でした。だからこそ、キャッシュの設計には慎重にならざるを得ませんでした。

私が運用しているサポートボットでは、ユーザーの質問の 70% が「同じ意図・違う表現」でした。「ログインできません」「サインインが通らない」「アカウントに入れない」— 完全一致キャッシュでは全て別のキーになります。これを embedding ベースで類似判定すれば、3つの質問は1つのキャッシュエントリに集約できます。

セマンティックキャッシュが特に効くのは、「ユーザーの語彙が広いが、回答パターンは限定的」な領域です。FAQ ボット、商品検索アシスタント、エラー対応ヘルプなどが典型例です。逆に「個別のコードを毎回レビューしてもらう」用途では効きにくく、無理に入れると却って事故になります。

最初に決めるべきは「キャッシュさせていい領域」と「絶対に新鮮な応答を返す領域」の境界線です。私の現場では、cacheable: true というフラグをエンドポイントごとに明示的に立てる設計にしました。デフォルトは false、効果が確実な箇所だけ明示的に有効化します。これだけで「うっかり全エンドポイントに入れて壊した」事故を防げます。

アーキテクチャ全体像 — 3層キャッシュとデータフロー

本番に耐えるセマンティックキャッシュは、単独で使わず「3層構造」で組むのがおすすめです。

  • 第1層: 完全一致キャッシュ(Redis、TTL 短め)— 最速・誤ヒットゼロ
  • 第2層: セマンティックキャッシュ(Vector DB、しきい値判定あり)— 中速・要ガード
  • 第3層: Claude API(フォールバック)— 最遅・最も確実

クエリは第1層から順に問い合わせ、ヒットしたら即返却します。第2層は類似度しきい値(後述の通り 0.92 前後を私は採用しています)を満たしたエントリのみを採用し、満たさなければ第3層に流します。

データフローはおおむね以下のようになります。tenant_id を含めることがマルチテナント分離の鍵で、これを忘れるとテナントAの回答がテナントBに漏れる事故になります。

# semantic_cache.py — 3層キャッシュの呼び出しフロー(pseudo-real)
import hashlib
import time
from typing import Optional
 
from anthropic import Anthropic
from redis import Redis
import qdrant_client
from qdrant_client.models import PointStruct, VectorParams, Distance, Filter, FieldCondition, MatchValue
 
EXACT_TTL_SEC = 3600                # 第1層: 1時間で失効
SEMANTIC_THRESHOLD = 0.92           # 第2層: cosine 類似度しきい値
SEMANTIC_TTL_SEC = 86400            # 第2層: 24時間で失効
 
def get_cached_response(
    tenant_id: str,
    user_query: str,
    redis: Redis,
    qdrant: qdrant_client.QdrantClient,
    embed_fn,                       # 後述: Voyage や Cohere の embedding 関数
    anthropic: Anthropic,
    feature_id: str,                # cacheable: true のエンドポイント識別子
) -> dict:
    # 第1層: 完全一致
    exact_key = f"cache:exact:{tenant_id}:{feature_id}:{hashlib.sha256(user_query.encode()).hexdigest()}"
    cached = redis.get(exact_key)
    if cached:
        return {"text": cached.decode(), "layer": "exact", "latency_ms": 1}
 
    # 第2層: セマンティック
    embedding = embed_fn(user_query)            # 1024 次元想定
    hits = qdrant.search(
        collection_name="claude_cache",
        query_vector=embedding,
        query_filter=Filter(must=[
            FieldCondition(key="tenant_id", match=MatchValue(value=tenant_id)),
            FieldCondition(key="feature_id", match=MatchValue(value=feature_id)),
        ]),
        limit=1,
        score_threshold=SEMANTIC_THRESHOLD,    # しきい値未満は返らない
    )
    if hits:
        # 第1層にも書き戻して次回を高速化
        redis.setex(exact_key, EXACT_TTL_SEC, hits[0].payload["response"])
        return {"text": hits[0].payload["response"], "layer": "semantic", "score": hits[0].score}
 
    # 第3層: Claude API(フォールバック)
    start = time.perf_counter()
    response = anthropic.messages.create(
        model="claude-sonnet-4-6",
        max_tokens=1024,
        messages=[{"role": "user", "content": user_query}],
    )
    latency_ms = int((time.perf_counter() - start) * 1000)
    text = response.content[0].text
 
    # 両層に保存(汚染検査を経たエントリのみ — 後述)
    redis.setex(exact_key, EXACT_TTL_SEC, text)
    qdrant.upsert(
        collection_name="claude_cache",
        points=[PointStruct(
            id=hashlib.sha256(f"{tenant_id}:{feature_id}:{user_query}".encode()).hexdigest()[:16],
            vector=embedding,
            payload={"tenant_id": tenant_id, "feature_id": feature_id,
                     "query": user_query, "response": text, "ts": time.time()},
        )],
    )
    return {"text": text, "layer": "api", "latency_ms": latency_ms}

期待出力は以下のようなログです。layerexactsemantic で返れば API への課金は発生していません。

{"layer": "exact",    "latency_ms": 1}
{"layer": "semantic", "score": 0.94}
{"layer": "api",      "latency_ms": 1820}

ここまでお読みいただきありがとうございます。

この記事の続きを読む

この先には、実装コードやベンチマーク結果など、実務でお役に立てる内容をご用意しています。このサイトは広告を掲載しておらず、サーバーや開発にかかる費用はメンバーの皆様のご支援で成り立っています。もしお役に立てていましたら、ご支援いただけますと大変ありがたいです。

この記事で得られること
誤ヒットを2%以下に抑えるため Precision 0.98 を固定し、PR曲線から類似度しきい値を決める評価スクリプト
プロンプトインジェクション検出・stop_reason 判定・Haiku による LLM-as-a-judge の3段ガードで汚染を防ぐ書き込み設計
FAQボットでヒット率47%・API費用38%削減を実測した3層キャッシュ構成と、無効化・テストまで含む本番チェックリスト
Stripe による安全な決済 · いつでもキャンセル可能

この記事を購入する

この先の内容をすべてお読みいただけます。一度のご購入で、いつでも何度でもアクセスできます。このサイトは広告を掲載しておらず、皆さまのご支援がサーバー費用などの運営を支えています。

または
メンバーシップなら全記事が読み放題 →
シェア

お読みいただきありがとうございます

Claude Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • コピー&ペーストで使える実装コード付き
  • 毎日新しい上級ガイドを追加
  • ¥580/月 または ¥1,480 の永久アクセス
メンバーシップを見る →

関連記事

API & SDK2026-06-18
Claude API のレスポンスキャッシュが「古い答え」と「似て非なる誤答」を返すとき — 鮮度管理と誤ヒット抑制の実装メモ
Claude API のレスポンスキャッシュは速度とコストを劇的に改善しますが、運用で問題になるのは平均ヒット率ではなく、古い答えと意味的な誤ヒットの二つです。キー設計・鮮度管理・誤ヒット抑制・観測の実装をまとめます。
API & SDK2026-07-13
Claude API の同時実行を束ねる — シングルフライトで重複推論とキャッシュ・スタンピードを防ぐ
同一プロンプトが同時に何度も Claude へ飛ぶ重複推論を、シングルフライト(request coalescing)で束ねる設計です。プロセス内・分散環境の実装、ジッター付きリトライ、負のキャッシュまで実測付きでまとめました。
API & SDK2026-06-23
Claude API のプロンプトキャッシュが本番で静かにヒットしなくなるとき — TTLと節約額の実測メモ
プロンプトキャッシュは設定した直後だけ効いて、本番では知らぬ間にヒットしなくなります。プレフィックスを壊す要因、5分と1時間TTLの選び方、節約額を推測でなく実測する計装を運用目線でまとめました。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →