1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

この記事では、一見ばらばらに見える AI エンジニアリングのキーワードをつないで整理する。fallbackPydanticsemantic cacheprompt cachecontext cachingcheckpointRAGASDeepEval
実はこれらは、すべて同じ問いに答えるためのものだ。不安定で、高価で、確率的に振る舞う LLM を、どうやって信頼でき、復旧でき、評価できるソフトウェアシステムの中に組み込むか。

0. なぜこれらの概念はよく一緒に語られるのか?

LLM アプリケーションを作り始めたばかりの頃、多くの人は仕組みをとてもシンプルに考える。

ユーザー入力 -> LLMを呼び出す -> 回答を返す

この形は demo には向いているが、本番運用には向いていない。

実際にリリースすると、すぐに次のような問題にぶつかる。

モデルの出力形式が壊れていたらどうするのか?
同じ質問が何度も来るなら、コストを節約できないか?
RAG は vector database だけで十分なのか?
長い context を毎回送っていたら、コストが膨らみすぎないか?
Agent が途中で失敗したとき、続きから再開できないか?
system prompt を変更したあと、本当に良くなったとどう判断するのか?

そこから自然に、次のようなエンジニアリング能力が必要になる。

信頼できる出力:モデル出力は検証でき、修復でき、必要なら degrade できること
コスト制御:同じ質問、同じ context、同じ tool call は再利用すること
タスク復旧:長時間タスク、Agent、多段階フローは checkpoint から再開できること
自動評価:システムが良くなったかを感覚だけで判断しないこと

言い換えると、LLM アプリケーションエンジニアリングの本質は「賢い prompt を書くこと」ではない。

従来のソフトウェアエンジニアリングが持つ信頼性、状態管理、cache、検証、観測、評価の力を使い、確率的に振る舞うモデルを、制御可能なプロダクトシステムとして包み込むこと。

1. まず全体像を持つ:LLM アプリケーションは一度の API call ではない

本番レベルの LLM アプリケーションは、むしろ次のような姿に近い。

ユーザーリクエスト
  -> リクエストの正規化
  -> exact cache / semantic cache
  -> checkpoint の読み込み
  -> RAG retrieval / tool call
  -> prompt の組み立て
  -> provider prompt cache / context cache
  -> LLM 生成
  -> Pydantic / JSON Schema 検証
  -> fallback / repair / retry
  -> 自動 eval
  -> cache / checkpoint / trace への書き込み
  -> 結果を返す

フローチャートにすると、こうなる。

この図の各モジュールには、それぞれ明確な役割がある。

モジュール 解決する問題
Pydantic / JSON Schema モデル出力を安全に業務システムへ渡せるか
Fallback モデルが失敗したとき、システムをきれいに degrade できるか
Semantic Cache 似た質問に対して過去の回答を再利用できるか
Prompt / Context Cache 繰り返し使う長い入力のコストと latency を下げられるか
Checkpoint 多段階タスクが失敗したあと、続きから再開できるか
RAGAS / DeepEval システムの品質が本当に良くなったかをどう判断するか

2. Pydantic と Fallback:モデル出力をシステムに入れる前に検査する

LLM の出力を、そのまま信頼できる戻り値として扱ってはいけない。

むしろ、外部 API のレスポンスに近いものとして考えたほうがよい。必要なフィールドが欠けているかもしれないし、enum に存在しない値が返ってくるかもしれない。型が合っていない、JSON として壊れている、あるいは内容が論理的に矛盾していることもある。

だから本番システムでは、prompt にただ次のように書くだけでは足りない。(実は、2023年に初心者だった頃の私も、これをやってしまっていた。)

JSON を出力してください。

必要なのは、硬い制約を作ることだ。

LLM 出力
  -> JSON parse
  -> Pydantic schema 検証
  -> strict mode / validator / 業務ルール
  -> 修復して retry
  -> モデルを切り替える
  -> 保守的に degrade する
  -> 人による確認へ回す

OpenAI の Structured Outputs は、まさにこの考え方に近い。単にモデルに合法な JSON を出させるだけでなく、指定した schema にできるだけ沿った出力を得るための仕組みだ。Pydantic は Python アプリケーション層で、さらに強い検証を行うために使える。

簡単な例を見てみる。

from enum import Enum
from pydantic import BaseModel, Field, ConfigDict, ValidationError, field_validator


class Priority(str, Enum):
    low = "low"
    medium = "medium"
    high = "high"


class TicketTriage(BaseModel):
    model_config = ConfigDict(strict=True)

    category: str = Field(min_length=1)
    priority: Priority
    summary: str = Field(min_length=10)
    confidence: float = Field(ge=0, le=1)

    @field_validator("category")
    @classmethod
    def category_must_be_known(cls, value: str) -> str:
        allowed = {"billing", "technical", "account", "other"}
        if value not in allowed:
            raise ValueError(f"unknown category: {value}")
        return value


def parse_llm_output(raw: dict) -> TicketTriage | None:
    try:
        return TicketTriage.model_validate(raw)
    except ValidationError as e:
        # エラーをそのまま握りつぶさず、repair / fallback フローに入れる
        print(e)
        return None

ここで大事なのは、「Pydantic を使えば万事解決」ということではない。モデルは間違えるものだが、その間違いはシステム側で捕まえなければならない。業務ロジックへそのまま流してはいけない。

典型的な fallback chain は、次のように設計できる。

第 1 層:現在のモデル出力が有効なら、そのまま使う
第 2 層:形式エラーなら、Pydantic のエラー情報をモデルに返して修復させる
第 3 層:修復に失敗したら、より強いモデルに切り替えて再生成する
第 4 層:それでも失敗したら、保守的なテンプレート回答を返す
第 5 層:高リスクの場面では、人による確認へ回す

なお、Pydantic はデフォルトである程度の型変換を行う。たとえば文字列 "123" を整数 123 に変換することがある。本当に厳格に検証したいなら strict mode を有効にし、型が合わない場合はその場でエラーにする必要がある。

3. Cache ファミリー:すべての Cache を一緒くたにしない

LLM アプリケーションにおける「cache」は、ひとつの概念ではない。複数の概念の集まりだ。

名前 何を cache するか どの層で起きるか モデルを skip するか 典型的な用途
Exact Cache 完全に同じリクエストの結果 アプリケーション層 はい FAQ、固定クエリ
Semantic Cache 意味が近い質問への過去回答 アプリケーション層 多くの場合ははい 聞き方は違うが答えは同じ質問
RAG Retrieval Cache 検索された文書 chunk retrieval 層 いいえ 重複する vector retrieval を減らす
Prompt / Context Cache 長い prompt prefix に対するモデル側の計算 モデル provider 層 いいえ 長い context のコストと latency を下げる
Tool Cache tool や API call の結果 tool 層 間接的に減らす 検索、database、外部 API
Checkpoint Agent の実行状態 workflow 層 cache ではない 失敗復旧、途中再開

つまり、「RAG と聞いて vector database しか思い浮かばないのでは不十分」という話の要点は、vector database を否定することではない。vector database が解決するのは知識検索であって、回答の再利用、context の再利用、tool の再利用、タスク復旧までは解決しないということだ。

4. Semantic Cache:RAG の外側にある「意味の再利用」

Semantic Cache が問うているのは、次のことだ。

この質問は、過去にすでに聞かれていないか?
あるいは聞き方は違っても、意味としては十分に近くないか?
近いなら、過去の回答をそのまま再利用できないか?

たとえば、次の 2 つの質問を考える。

Q1: 会社の出張費精算ルールは何ですか?
Q2: 出張費はどうやって精算すればいいですか?

文字列としては違うが、答えは同じである可能性が高い。Semantic Cache は質問を embedding に変換し、vector similarity によって過去の質問を検索する。十分に similarity が高ければ、cache された回答をそのまま返す。

典型的な流れはこうだ。

ユーザーの質問
  -> embedding
  -> vector similarity search
  -> similarity の高い過去質問に hit
  -> tenant、権限、knowledge base version、timestamp を確認
  -> 過去回答を返す

ここでは、誤 hit のリスクにかなり注意する必要がある。

たとえば次のような場合だ。

Q1: 2025 年の精算ルールは何ですか?
Q2: 2026 年の最新の精算ルールは何ですか?

意味は近いが、回答を再利用してよいとは限らない。本番では、次のような要素を cache key または filter 条件に入れる必要がある。

tenant_id
user_role
knowledge_base_version
locale
time_range
business_domain
semantic_threshold

RedisVL は、まさにこの位置づけで登場する。

RedisVL は暗記すべき理論概念ではなく、Semantic Cache を実装するための手段のひとつだ。より正確に階層化すると、次のようになる。

概念:Semantic Cache
実装のひとつ:RedisVL SemanticCache
その他の実装:GPTCache、LangChain cache、自前の Redis + embedding、pgvector など

RedisVL の SemanticCache は Redis 上に index を作成し、embedding model、similarity threshold、TTL などの設定と組み合わせて、LLM response の semantic cache を実現する。

5. Prompt Cache と Context Caching はどういう関係なのか?

ここが最も混同されやすい。

まず結論から言う。

Prompt Cache と Context Caching は、名前こそ違うが、基本的には同じ発想に基づく仕組みだ。
モデル提供側で、何度も使われる長い入力の prefix を再利用し、コストとレイテンシを下げる。

ただし、これらは最終的な回答をキャッシュする仕組みではない。
モデルによる生成処理を省略するものでもない。
キャッシュしているのは、「モデルが長い context を処理するときの計算の一部」だ。

provider によって呼び方は異なる。

provider / 体系 よく使われる呼び方 重点
OpenAI Prompt Caching 長い prompt の重複 prefix を自動的に cache し、usage に cached_tokens を表示する
Anthropic Prompt Caching cache_control に対応し、cache breakpoint を重視する
Google Gemini Context Caching implicit caching と explicit caching があり、長い context の再利用を重視する

OpenAI の Prompt Caching は、長い prompt を扱う場面で自動的に働き、usage.prompt_tokens_details.cached_tokens によって cache hit した token を確認できる。

Anthropic の Prompt Caching はより明示的で、cache_control を使って cache breakpoint を指定できる。指定した breakpoint までの prompt prefix がすでに cache されているかを確認し、hit した場合は処理時間とコストを下げる。

Gemini のドキュメントでは Context Caching という表現が使われる。長い文書、長い動画、コードリポジトリ分析のように、大量の反復 context を短い質問から何度も参照する場面に向いている。

良い prompt の組み立て方は、次のような形だ。

安定した内容を前に置く:
  system prompt
  tool 定義
  出力形式の説明
  few-shot examples
  長い文書 / 背景資料

動的な内容を後ろに置く:
  現在のユーザー質問
  現在時刻
  この turn の tool result
  一時的な parameter

良くない書き方は、動的な内容を毎回 system prompt の途中に挟み込むことだ。そうすると prefix hash が頻繁に変わり、cache hit しにくくなる。

cache breakpoint は、次のように理解するとよい。

prompt の先頭からここまでが、安定していて再利用できる内容。
この後ろの内容は毎回変わってもかまわない。

6. API call 層の cache breakpoint:コスト削減だけでなく、復旧にも効く

「cache breakpoint」には 2 つの意味があり、混同しやすい。

1 つ目は、provider 側の cache breakpoint だ。

役割:モデル provider に長い prompt prefix を再利用させる
目的:token コストを下げ、latency を短くする
例:Anthropic cache_control、Gemini explicit context cache

2 つ目は、application 側の checkpoint だ。

役割:アプリケーションフローの中で完了済みの高コストな step を保存する
目的:失敗後に最初からやり直さずに済ませる
例:RAG retrieval result、tool call result、validation result、Agent の現在 node

たとえば、複雑な Agent flow があるとする。

1. ユーザーが調査タスクを送信する
2. システムが資料を検索する
3. システムが検索 tool を呼び出す
4. システムが資料を要約する
5. システムがレポートを生成する
6. システムが形式を検証する

第 5 step で失敗した場合、理想は第 1 step からやり直すことではない。

checkpoint を読む
  -> 前 4 step がすでに成功していると分かる
  -> 第 5 step から続行する

だから API call 層では、ひとつの習慣を持つべきだ。高コストで、再利用でき、復旧に使える step が終わるたびに、構造化された結果を保存する。

7. 永続化された状態機械:Agent が途中で落ちたらどうするか?

Agent は、ただの while loop であるべきではない。

より安定した方法は、Agent を state machine として modeling することだ。

receive_request
  -> classify_intent
  -> retrieve_context
  -> call_tools
  -> generate_answer
  -> validate_output
  -> evaluate_trace
  -> final_response

各 node には、明確な入力、明確な出力、明確な失敗戦略が必要になる。

checkpoint には、次のような情報を保存できる。

task_id
current_state
next_state
input_payload
node_outputs
tool_results
retry_count
error_message
model_name
prompt_version
trace_id
created_at
updated_at

Redis は checkpoint の保存に使える。特に低 latency、短期状態、タスク復旧には向いている。ただし、普通の Redis cache と信頼性のある永続状態は同じものではない。本番では次のような点を考える必要がある。

AOF / RDB persistence が必要か
database への長期保存が必要か
distributed lock が必要か
idempotency key が必要か
queue による async recovery が必要か
人による承認 node が必要か

タスクが非常に長く、step も多く、信頼性の要求が高い場合は、LangGraph や Temporal のような durable workflow の考え方を検討してもよい。LangGraph の persistence は graph state を checkpoint として保存するため、human-in-the-loop、memory、time travel debugging、障害復旧を支えられる。

判断の核になるのは、次の違いだ。

Cache が解決するのは、「コストを下げられるか、速くできるか」。
Checkpoint が解決するのは、「失敗後に続きから再開できるか」。

この 2 つは同じものではない。

8. 自動評価:Agent の各 step に KPI を持たせる

多くのチームは LLM アプリケーションを作るとき、最終回答を見て「なんとなく良さそう」と判断してしまう。これは危ない。

Agent のエラーは、最後の一文で起きるとは限らない。むしろ途中の step で起きることが多い。

retrieval が間違った文書を取ってくる
tool parameter を間違えて渡す
semantic cache が誤 hit する
モデル出力が schema に合わない
repair retry が意味を壊してしまう
Agent が余計な step を踏みすぎる
context に古い情報が混ざる

だから評価は層ごとに行う必要がある。

RAGAS は RAG や Agent/tool use に関連する指標を提供する。たとえば context precision、context recall、response relevancy、faithfulness、tool call accuracy、agent goal accuracy などだ。

DeepEval も RAG、Agentic、多 turn、安全性などの指標を提供している。Agentic 系の指標には task completion、argument correctness、tool correctness、step efficiency、plan adherence などが含まれる。

実践的な KPI set は、次のように設計できる。

cache 層:
  exact_cache_hit_rate
  semantic_cache_hit_rate
  semantic_cache_false_hit_rate
  prompt_cached_tokens
  cache_eviction_rate

RAG 層:
  context_precision
  context_recall
  context_relevancy
  faithfulness
  noise_sensitivity

モデル出力層:
  schema_valid_rate
  repair_success_rate
  fallback_rate
  json_parse_error_rate
  business_rule_violation_rate

Agent 層:
  task_completion_rate
  tool_args_valid_rate
  tool_success_rate
  avg_steps_per_task
  resume_success_rate

コストと performance 層:
  cost_per_successful_task
  p50_latency
  p95_latency
  retry_rate
  timeout_rate

offline 評価だけでなく、online trace もつなげておくのが望ましい。

各リクエスト
  -> prompt_version を記録する
  -> model_version を記録する
  -> retrieved_docs を記録する
  -> tool_calls を記録する
  -> cache_hit を記録する
  -> validation_result を記録する
  -> eval_score を記録する

こうしておけば prompt の変更、モデルの切り替え、retrieval strategy の調整を行ったあと、システムが本当に良くなったのか、それとも良くなったように見えているだけなのかを判断できる。

9. 本番レベルの LLM アプリケーション参考アーキテクチャ

システム全体は、いくつかの層に分けて考えられる。

入口層:
  API Gateway
  auth
  rate limit
  request normalization

cache 層:
  exact cache
  semantic cache
  tool cache
  retrieval cache

編成層:
  workflow engine
  state machine
  checkpoint
  retry / timeout / idempotency

知識層:
  document loader
  chunking
  embedding
  vector database
  reranker

モデル層:
  prompt builder
  prompt/context cache friendly layout
  model router
  structured output

信頼性層:
  Pydantic validation
  business validators
  repair loop
  fallback policy
  human review

評価・観測層:
  tracing
  RAGAS / DeepEval
  cost metrics
  latency metrics
  quality dashboard

MVP から本番へ進化させるなら、次の順番で進めるとよい。

第 1 段階:動くものを作る
  単一モデル呼び出し
  基本 prompt
  手動テスト

第 2 段階:出力を信頼できる形にする
  JSON Schema / Pydantic
  parse error retry
  fallback answer

第 3 段階:知識を強化する
  RAG
  rerank
  citation / source tracking

第 4 段階:コストを最適化する
  exact cache
  semantic cache
  prompt/context cache
  tool result cache

第 5 段階:タスクを信頼できるものにする
  state machine
  checkpoint
  idempotency key
  resume

第 6 段階:継続的に改善する
  trace
  eval dataset
  RAGAS / DeepEval
  A/B test
  quality dashboard

大事なのは、最初からすべての component を入れることではない。それぞれの component が何の問題を解決するのかを理解しておくことだ。

10. まとめ

これらの概念を並べて見ると、役割はかなり明確になる。

RAG が解決すること:モデルがどの外部資料を知るべきか。
Semantic Cache が解決すること:過去の回答を再利用できるか。
Prompt / Context Cache が解決すること:繰り返し使う長い入力のコストと待ち時間を減らせるか。
Pydantic が解決すること:モデル出力を安全にシステムへ入れられるか。
Fallback が解決すること:モデルが失敗したとき、システムをきれいに degrade できるか。
Checkpoint が解決すること:タスクが失敗したあと、続きから再開できるか。
RAGAS / DeepEval が解決すること:システムが本当に良くなったとどう判断するか。

だから、LLM アプリケーションエンジニアリングの本質は「賢い prompt を書くこと」ではない。

より正確に言えば、それは次のような仕事だ。

従来のソフトウェアエンジニアリングが持つ信頼性、状態管理、cache、検証、観測、評価の力を使い、
確率的に振る舞うモデルを、制御可能なプロダクトシステムとして包み込むこと。

fallbacksemantic cacheprompt cachecontext cachingcheckpointeval といった言葉を見たとき、それらを孤立した小技として捉えないほうがよい。

これらは本当は、ひとつの本番運用上の問いに一緒に答えている。

モデルは間違える。高い。遅い。途中で止まることもある。
それでも、システム全体をどうすれば信頼できるものにできるのか?

参考資料

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?