システムデザイン完全ガイド ⑥|アーキテクチャの型

システムデザイン

SYSTEM DESIGN GUIDE — PART 6 / 7

  1. アーキテクチャの型
  2. CHAPTER 36モノリスとマイクロサービス
    1. 36.1まず結論
    2. 36.2サービス境界の引き方
    3. 36.3サービス間通信
    4. 36.4移行戦略:ストラングラーフィグ・パターン
  3. CHAPTER 37イベント駆動・CQRS・イベントソーシング
    1. 37.1イベント駆動アーキテクチャ
    2. 37.2CQRS(コマンドクエリ責務分離)
    3. 37.3イベントソーシング
    4. 37.4CDC(変更データキャプチャ)
  4. CHAPTER 38バッチ処理とストリーム処理
    1. 38.1バッチ処理
    2. 38.2ストリーム処理
    3. 38.3イベント時刻 vs 処理時刻(重要)
    4. 38.4Lambda / Kappa アーキテクチャ
    5. 38.5データ基盤の全体像
  5. CHAPTER 39マルチリージョンと災害対策
    1. 39.1なぜマルチリージョンにするのか
    2. 39.2構成パターン
    3. 39.3データ複製の選択
    4. 39.4リージョン障害時の運用
    5. 39.5データレジデンシー(法規制)
  6. CHAPTER 40セキュリティ
    1. 40.1認証と認可
    2. 40.2OWASP Top 10 的な脆弱性(最低限)
      1. 脅威モデリング:境界・資産・悪用経路
    3. 40.3暗号化と鍵管理
    4. 40.4ゼロトラストと多層防御
    5. 40.5DDoS 対策
  7. CHAPTER 41プライバシーとコンプライアンス
    1. 41.1個人データの扱い
    2. 41.2GDPR / 各国法が要求する機能
    3. 41.3データ分類とアクセス制御
  8. CHAPTER 42コストの設計
    1. 42.1コストの内訳(クラウドの相場感)
    2. 42.2コスト最適化の手段
    3. 42.3設計におけるコストの考え方
  9. CHAPTER 43AI・機械学習・LLM・AI エージェントのシステム設計
    1. 43.1なぜ「AI / ML のシステムデザイン」が特別なのか
      1. モデルライフサイクルと評価
    2. 43.2大規模推薦システム(Two-Tower モデルと 3 段階パイプライン)
      1. 1. Candidate Generation(Two-Tower Model / Dual Encoder)
      2. 2. Heavy Ranking(精密ランキングモデル)
      3. 3. Re-ranking(多様性とビジネスルール)
    3. 43.3特徴量ストア(Feature Store)の設計
    4. 43.4LLM 推論サービング基盤の基礎
      1. ① Prefill(プロンプト処理)vs Decode(トークン生成)
      2. ② KV Cache と PagedAttention(最重要)
      3. ③ Continuous Batching(動的・インフライトバッチング)
      4. ④ 投機的デコーディング(Speculative Decoding)
    5. 43.5RAG(検索拡張生成)の完全アーキテクチャ
      1. セマンティックキャッシュ(Semantic Cache)
    6. 43.6AI エージェントの本番システム設計
      1. ① 基本ループと責任の分離
      2. ② ツール契約(Agent–Computer Interface)
      3. ③ 状態、メモリ、長時間実行
      4. ④ セキュリティとプロンプトインジェクション
      5. ⑤ 評価・観測・運用
      6. ⑥ 単一エージェント、ワークフロー、マルチエージェント

アーキテクチャの型

モノリスとマイクロサービス、イベント駆動、バッチとストリーム、マルチリージョン、セキュリティ、プライバシー、コスト、そして AI・LLM・エージェントのシステム設計。

収録:第 36 章 〜 第 43 章

CHAPTER 36モノリスとマイクロサービス

🎯 GOAL

サービス分割の判断基準を持ち、境界を引ける。

36.1まず結論

📐 数字・公式

ほとんどのシステムはモノリスで始めるべきです。マイクロサービスは、チームの独立性に加え、独立スケール、障害隔離、規制境界、異なるライフサイクルなどのために選ぶことがあります。組織上の利点だけでなく、分散システムの運用コストを正当化できるかで判断します。

モノリス マイクロサービス
開発初速 速い 遅い(基盤整備が必要)
デプロイ 全体を一度に 独立して可能
技術選択 統一される サービスごとに自由(=混沌にもなる)
トランザクション DB のトランザクションで済む Saga / 結果整合が必要
デバッグ スタックトレースで追える 分散トレースが必須
障害の影響 全体が落ちる 部分的に degrade できる(設計次第)
可用性 単純 依存の掛け算で下がる(第 28 章)
チーム 組織・所有境界が明確なら運用しやすい チームごとに独立して動けるが、境界が悪いと調整コストが増える
運用コスト 低い 高い(CI/CD、監視、サービスメッシュ、オンコール)
⚠️ 分散モノリス(最悪の形)

サービスは分かれているのに、

  • デプロイは全部同時にしないと動かない
  • 1 つの機能追加に 5 サービスの変更が必要
  • 同期呼び出しが数珠つなぎ

マイクロサービスのコストだけ払い、利点が何もない状態。実際に非常に多い失敗です。

🎤 面接

SCRIPT
「初期はモジュラーモノリスにします。ドメインごとにモジュール境界を明確にし、
 モジュール間はインターフェース経由でのみ呼ぶ規約にします。
 こうしておけば、後から本当に必要になった部分だけをサービスとして切り出せます。
 分割の判断基準は、① スケール特性が大きく異なる、② デプロイ頻度が大きく異なる、
 ③ チームが独立して動く必要がある、のいずれかです。」

36.2サービス境界の引き方

📐 良い境界の条件

  1. 高凝集・疎結合:一緒に変更されるものは一緒に置く
  2. データの所有が明確1 つのテーブルは 1 つのサービスだけが書く
  3. 同期呼び出しが少ない:境界を跨ぐ呼び出しが多いなら、境界が間違っている
  4. チームの境界と一致(コンウェイの法則)
💡 コンウェイの法則

「システムの構造は、それを設計した組織のコミュニケーション構造を反映する。」逆に使うのが逆コンウェイ戦略:理想のアーキテクチャに合わせて組織を作る。

ドメイン駆動設計 (DDD) の道具

  • 境界づけられたコンテキスト (Bounded Context):同じ「顧客」でも、営業コンテキストと配送コンテキストでは意味が違う → 別モデルにしてよい
  • 集約 (Aggregate):トランザクション整合性を保つドメイン境界。実装上のロック範囲や DB 行と必ず一致するわけではない
  • コンテキストマップ:サービス間の関係(上流/下流、腐敗防止層)
⚠️ 技術レイヤで分割してはいけない

❌ 「DB サービス」「ビジネスロジックサービス」「API サービス」
   → 1 つの機能追加に全部の変更が必要(=分散モノリス)
✅ 「注文サービス」「在庫サービス」「決済サービス」
   → 各サービスが縦にフルスタックを持つ

36.3サービス間通信

同期(REST/gRPC) 非同期(イベント)
結合 強い(相手が生きている必要がある) 弱い
一貫性 同期応答に必要な時点での保証を設計する。同期だから自動的に即時整合ではない 結果整合になりやすいが、セッション保証や強い部分を組み合わせられる
障害伝播 する(タイムアウト・サーキットブレーカが必要) しにくい
デバッグ 追いやすい 追いにくい
使いどころ 即座に結果が必要(残高照会、認証) 通知、派生データ更新、他システムへの伝播
📐 数字・公式

同期呼び出しの深さは、SLO、タイムアウト予算、依存の可用性、負荷試験で上限を決めます。深いチェーンは可用性とレイテンシを悪化させやすいので、固定の段数ではなく測定と設計レビューで管理します。

共通の課題 道具
どこにサービスがいるか サービスディスカバリ(Consul, k8s Service, DNS)
認証・暗号化 mTLS、サービスメッシュ
リトライ・サーキットブレーカ サービスメッシュ(Envoy)or ライブラリ
クライアントが N 個のサービスを呼ぶ API Gateway / BFF(Backend For Frontend)
共通データ(ユーザー情報など) 所有サービスへの問い合わせ + キャッシュ、またはイベントで複製
🔬 深掘り

BFF パターン:モバイル用・Web 用・パートナー用にそれぞれ専用のゲートウェイを作る。各クライアントに最適化された API を提供でき、バックエンドサービスは汎用的なままでいられます。

36.4移行戦略:ストラングラーフィグ・パターン

モノリスを一気に置き換えるのは(ほぼ必ず)失敗します。

STRANGLER FIG
① モノリスの前にプロキシを置く
② 新機能・切り出す機能だけを新サービスにルーティング
③ 少しずつルーティング先を移していく
④ モノリス側の該当コードを削除
⑤ 最終的にモノリスが空になる(or 小さな核だけ残る)
💡 たとえ話

名前の由来は「絞め殺しのイチジク」— 宿主の木を覆って、最後に宿主が枯れる植物です。

⚠️ データの移行が最難関

コードは徐々に移せても、DB は共有されがちです。

段階1: 新サービスが旧 DB を直接読む(暫定。書きは旧のまま)
段階2: 新サービスが自分の DB を持ち、CDC で同期(両方に存在)
段階3: 書き込みを新サービスへ移す
段階4: 旧テーブルを削除

第 36 章 一問一答

マイクロサービスの主な動機は。
技術ではなく組織のスケール(チームの独立性・デプロイ独立性)。
分散モノリスとは。
サービスは分かれているが独立デプロイできず、コストだけ払って利点がない状態。
サービス境界の第一原則は。
データの所有が明確であること(1 テーブル 1 所有サービス)。
段階的な移行手法は。
ストラングラーフィグ・パターン(プロキシで徐々にルーティングを移す)。

CHAPTER 37イベント駆動・CQRS・イベントソーシング

🎯 GOAL

「状態」ではなく「出来事」で設計する考え方を使える。

37.1イベント駆動アーキテクチャ

COMMAND vs EVENT
【命令 (Command)】「注文を作成せよ」 — 特定の相手に、実行を依頼する。拒否されうる
【イベント (Event)】「注文が作成された」 — 過去形。事実の通知。誰が聞くかは知らない
📐 数字・公式

イベントは過去形で命名するOrderCreated, PaymentFailed)。これにより「送り手は受け手を知らない」疎結合が保たれます。

EVENT BUS
[注文サービス] ──OrderCreated──► [イベントバス]
                                    ├──► [在庫サービス] 引き当て
                                    ├──► [通知サービス] メール送信
                                    ├──► [分析基盤]    集計
                                    └──► [検索インデックス] 更新
       ↑ 新しい購読者を追加しても、注文サービスは一切変更不要
⚠️ イベント駆動の代償

  • 全体のフローがどこにも書かれていない(コードを読んでも順序が分からない)
  • デバッグに分散トレースが必須
  • イベントスキーマの変更が全購読者に影響する(スキーマレジストリで管理)
  • イベントの重複・順序入れ替わりを前提に作る必要がある
イベントの粒度 内容 特徴
通知イベント {order_id: 123} だけ 小さい。受け手が詳細を問い合わせる(結合が残る)
イベント伝送状態 (Event-Carried State Transfer) 注文の必要な状態を含む 受け手が自己完結しやすい。データ最小化、PII、鮮度、スキーマ互換性、権限を設計する
デルタイベント 変更差分のみ 小さいが、受け手が全履歴を追う必要がある
📐 数字・公式

実務では Event-Carried State Transfer が扱いやすいことが多いです(受け手が問い合わせ不要になり、可用性が上がる)。

37.2CQRS(コマンドクエリ責務分離)

書き込みモデルと読み取りモデルを分ける。

CQRS
【書き込み側】                  【読み取り側】
正規化されたモデル              クエリに最適化された非正規化ビュー
トランザクション整合             結果整合
  │                                ▲
  └──── イベント / CDC ────────────┘

使いどころ

  • 読み:書き比、クエリ形状、独立スケール、整合性要件が大きく異なる
  • 読み取りが複雑(複数テーブルの JOIN、集計)
  • 読み取りと書き込みでスケール特性が違う
  • 同じデータを複数の形で見せたい(一覧用・詳細用・分析用)
⚠️ 落とし穴

常に使うものではありません。単純な CRUD に CQRS を入れるのは過剰設計です。

具体例(面接で使える)
書き込み: PostgreSQL の正規化テーブル(orders, order_items, users)
   ↓ CDC (Debezium) → Kafka
読み取り: Elasticsearch の非正規化ドキュメント(検索用)
          Redis の集計値(ダッシュボード用)
          BigQuery(分析用)

37.3イベントソーシング

状態を保存するのではなく、「状態を変化させた出来事の列」を保存する。

EVENT SOURCING
【従来】現在の状態だけを保存
   account: {id: 1, balance: 900}     ← 過去の経緯は失われている

【イベントソーシング】出来事を追記していく
   [AccountOpened  {id:1}]
   [Deposited      {amount: 1000}]
   [Withdrawn      {amount: 100}]
   → 再生 (replay) すると balance = 900

現在の状態 = fold(すべてのイベント)

利点

  • 完全な監査ログ(金融・医療で強力。「なぜこの状態になったか」が必ず分かる)
  • タイムトラベル(任意の過去時点の状態を再現できる)
  • 新しい読み取りビューを後から作れる(過去に遡って再構築できる)
  • バグの修正後、イベントを再生して正しい状態を作り直せる

欠点(実務では重い)

  • 現在の状態を得るのに再生が必要 → スナップショットは有力な最適化だが、イベント数、復旧時間、再構築コストに応じて導入する
  • イベントスキーマの変更が極めて困難(過去のイベントは変更できない → アップキャスタが必要)
  • クエリが難しい(CQRS とほぼセットで使う)
  • GDPR の削除権と相性が悪い(暗号化消去:個人ごとの鍵を捨てることで実質削除する手法を使う)
  • 学習コストが高く、チーム全員の理解が必要
📐 判断

監査要件が強い一部の集約(口座、在庫、注文の状態遷移)にだけ適用し、システム全体には適用しないのが現実的です。

37.4CDC(変更データキャプチャ)

DB の変更ログ(binlog / WAL)を読んで、他システムへ流す。

CDC
MySQL binlog / PostgreSQL WAL
      │  Debezium などが読み取る
      ▼
   Kafka トピック(テーブルごと)
      ├──► Elasticsearch(検索)
      ├──► データウェアハウス(分析)
      ├──► キャッシュの無効化
      └──► 他のマイクロサービス
📐 CDC の価値

DB の変更ログを読み、コミットされた物理変更を下流へ伝播しやすくします。ただし、スナップショット、ログ保持、スキーマ変更、DDL、順序、再送、権限、障害時の穴を検証します。ドメイン上の意図を漏れなく伝えたい場合は、Outbox パターン(第 18 章)と組み合わせます。

⚠️ 注意点

  • スキーマ変更への追従
  • 初期スナップショット(既存データの流し込み)
  • 順序保証(テーブル間の順序は保証されない)
  • 大量更新(一括 UPDATE)が下流を洪水にする

第 37 章 一問一答

コマンドとイベントの違いは。
コマンドは実行の依頼(拒否されうる)、イベントは起きた事実の通知(過去形)。
CQRS が有効な場面は。
読み書きの比率・複雑さ・スケール特性が大きく異なる場合。
イベントソーシングの最大の難点は。
イベントスキーマ変更の困難さと、状態取得のためのリプレイコスト(スナップショットが必須)。
CDC の利点と限界は。
コミット済み変更を下流へ伝播しやすく、既存アプリへの変更を減らせる。一方、ドメインイベントの意味、順序、スキーマ、再送、欠落検知を別途設計する。

CHAPTER 38バッチ処理とストリーム処理

🎯 GOAL

大量データの処理方式を選び、時刻の扱いを説明できる。

38.1バッチ処理

BATCH
特徴: 有限のデータ(昨日のログ全部)を、まとめて処理する
   入力が固定でも、処理ロジックと出力先が冪等とは限らない
   → deterministic な処理、checkpoint、冪等な sink、再実行方針を設計する
   高スループット、レイテンシは時間単位
📐 MapReduce の考え方

Map    : 各レコードを (key, value) に変換する。並列に実行できる
Shuffle: 同じ key を同じマシンに集める ← ここが最も重い(ネットワーク)
Reduce : key ごとに集約する

例: 単語カウント
  Map:    "the cat sat" → ("the",1), ("cat",1), ("sat",1)
  Shuffle: 同じ単語を同じ Reducer へ
  Reduce: ("the", [1,1,1,...]) → ("the", 1523)
⚠️ Shuffle がボトルネック

データがネットワークを渡るため。

  • Combiner(Map 側での事前集約)で転送量を減らす
  • データの偏り (skew):1 つのキーに 90% のデータが集中すると 1 台だけ終わらない → ソルティング(キーに乱数を付けて分散 → 2 段階集約)
🔬 深掘り

現代は Spark(メモリ上の DAG 実行、MapReduce より遥かに速い)、Flink、BigQuery(Dremel)などが使われます。

38.2ストリーム処理

STREAM
特徴: 無限に続くデータを、到着するたびに処理する
   レイテンシは秒〜ミリ秒
   状態を持つ処理(集計)が難しい ← 「いつ終わりか」が分からないから
ウィンドウ 説明
タンブリング 重ならない固定区間 1 分ごとの件数
ホッピング / スライディング 重なる区間 直近 5 分の値を 1 分ごとに
セッション 活動の途切れで区切る ユーザーの操作セッション

38.3イベント時刻 vs 処理時刻(重要)

EVENT TIME vs PROCESSING TIME
イベント時刻 (event time): 出来事が実際に起きた時刻(スマホでボタンを押した時刻)
処理時刻 (processing time): システムがそれを処理した時刻

→ 圏外だった端末のログが 3 時間後に届く、という状況が普通に起きる
⚠️ 落とし穴

処理時刻で集計すると、「3 時間前の出来事」が今の分に入ってしまい、統計が壊れます。

📐 ウォーターマーク

「イベント時刻 T まではもう全部届いたはず」という推定値。

ウォーターマークが 10:05 を超えた → 10:00〜10:05 のウィンドウを確定して出力する
その後に届いた 10:03 のデータ = 遅延データ (late data)
  → ① 捨てる  ② サイドアウトプットに送る  ③ 結果を訂正して再出力する
🎤 面接

SCRIPT
「モバイルからのイベントは遅延が大きいので、イベント時刻で集計し
 ウォーターマークを設定します。許容遅延は 10 分とし、
 それを超えたデータは別ストリームに退避して日次バッチで補正します。
 リアルタイムの数値は暫定値である旨を UI にも明示します。」

38.4Lambda / Kappa アーキテクチャ

LAMBDA
                ┌─► バッチ層(正確・遅い)──┐
生データ ──────┤                            ├─► サービング層(統合ビュー)
                └─► スピード層(速い・近似)┘
  • ✅ 速さと正確さの両立
  • 同じロジックを 2 回実装する(バッチ用とストリーム用)→ 保守が地獄
KAPPA
生データ ──► ストリーム処理のみ ──► サービング層
(再計算が必要なら、ログの先頭からリプレイする)
  • ✅ ロジックが 1 つだけ。Kafka の保持期間を長くしておけば再処理できる
  • ❌ 大規模な過去データの再処理は時間がかかる
📐 数字・公式

現代の主流は Kappa 寄り(Flink + Kafka)。ただしデータウェアハウス側での日次バッチ補正は今も広く併用されます。

38.5データ基盤の全体像

DATA PLATFORM
【収集】アプリのイベント、CDC、ログ
    ▼
【転送】Kafka / Pub/Sub
    ▼
【保存】
  データレイク(S3/GCS + Parquet/Iceberg): 生データ、安価、スキーマ後付け
  データウェアハウス(BigQuery/Snowflake): 構造化、SQL、高速分析
    ▼
【処理】ELT(生のまま入れて、SQL で変換)が現代の主流。dbt など
    ▼
【利用】BI ダッシュボード、機械学習、レポート、逆 ETL
📐 列指向フォーマットが必須な理由

行指向: [id,name,age][id,name,age]...  → age だけ集計したくても全部読む
列指向: [id,id,id...][name,name...][age,age...] → age の列だけ読めばよい
      → 同じ型が並ぶので圧縮率も劇的に高い(10 倍以上)
🔬 深掘り

Google の Dremel(BigQuery の元)は、この列指向 + ツリー状の集約を組み合わせて、ペタバイト級を秒で集計します。

第 38 章 一問一答

MapReduce で最も重い工程は。
Shuffle(ネットワーク越しのデータ再配置)。
イベント時刻で集計すべき理由は。
遅延して届くデータを正しい時間帯に集計するため。
ウォーターマークとは。
「この時刻までのイベントは出揃った」という推定。ウィンドウ確定の判断に使う。
列指向フォーマットが分析に向く理由は。
必要な列だけ読め、同型データが並ぶため圧縮効率が高い。

CHAPTER 39マルチリージョンと災害対策

🎯 GOAL

グローバル展開の構成を、要件から選べる。

39.1なぜマルチリージョンにするのか

  1. レイテンシ:日本のユーザーに米国から返すと +120 ms(第 1 章の光速の壁)
  2. 災害対策:リージョン全体の障害に耐える
  3. 法規制:データ主権(GDPR、中国、ロシアなど)
  4. 可用性:単一リージョンの障害モデルを超える可用性目標を満たしたい
⚠️ 落とし穴

コストは劇的に上がります(インフラ 2 倍 + リージョン間転送費 + 複雑さ)。本当に必要かを毎回問うべきです。

39.2構成パターン

パターン 読み 書き RPO/RTO 難易度
① 単一リージョン + バックアップ 1 箇所 1 箇所 RPO 時間単位 / RTO 数時間
② Active-Passive(ウォームスタンバイ) 主のみ 主のみ RPO 数秒〜分 / RTO 数分 ★★
③ Active-Active(読みのみ分散) 各地 1 箇所 読みは即時 ★★★
④ Active-Active(書きも分散) 各地 各地 競合解決が必要 ★★★★★
⑤ 地理パーティション 各地 各地(自地域のデータを優先) 通常時の競合と越境を減らせるが、移行・フェイルオーバー・グローバル操作では競合が起き得る ★★★★
📐 ⑤ が実は最も現実的

EU ユーザーのデータ → 通常時は EU リージョンを優先する
US ユーザーのデータ → 通常時は US リージョンを優先する
→ 通常時の競合と越境を減らし、レイテンシも改善しやすい。
  ただし移住・フェイルオーバー・グローバル操作では例外を設計し、
  法的適合はデータ種別、処理者、移転根拠、削除・復旧手順まで確認する
→ ユーザーが移動・越境する場合の扱いを決める必要がある
🔬 深掘り

Spanner の地理パーティショニング、CockroachDB の REGIONAL BY ROW がこれです。

39.3データ複製の選択

REPLICATION
【同期複製(クロスリージョン)】
  書き込みに +100〜200 ms(大陸間 RTT)
  → 書き込みが遅くて許容できないことが多い
  → Spanner は Paxos + TrueTime でこれを実用化している(ただしレイテンシは正直に払う)

【非同期複製】
  書き込みは速い
  → フェイルオーバー時に直近のデータが失われる(RPO > 0)
  → 大半のシステムはこちらを選ぶ
📐 判断基準

「1 分間のデータ損失は許容できるか」。

  • 許容できる(SNS の投稿、ログ)→ 非同期
  • 許容できない(決済、金融)→ 同期 or 同期的なコミット確認を含む設計

39.4リージョン障害時の運用

FAILOVER
① 検知(ヘルスチェック、複数の外部監視地点から)
② トラフィックを切り替える(GeoDNS、Anycast、グローバル LB)
③ Passive 側の DB を昇格(プライマリに)
④ 整合性の確認(未複製データの扱い)
⑤ 旧リージョン復旧後の再同期(split-brain の解消が最難関)
⚠️ フェイルバックの方が難しい

旧リージョンが復旧したとき、その間に新リージョンで発生した変更をどう戻すか。手順書と訓練がなければ、実際には切り替えられません。

⚠️ 「マルチリージョンだから安全」の罠

  • 両リージョンが同じグローバルサービス(認証、設定配信、DNS)に依存していると、そこが落ちれば両方落ちる
  • 設定変更を全リージョンに一斉展開すれば、全リージョンが同時に壊れる

リージョン間の独立性を意図的に設計し、展開も時間差をつける必要があります。

39.5データレジデンシー(法規制)

REGULATIONS
GDPR (EU)      : 域内拠点、域内の個人へのサービス提供・監視などで適用範囲を判断。
                 移転、削除権、アクセス権に条件がある
中国 (PIPL)    : データの種類、事業者、処理規模などに応じた越境・保存要件を確認
ロシア、インド等: それぞれの国内保存要件
医療 (HIPAA)、決済 (PCI DSS): 業界別の要件
📐 設計への影響

  • データを地理でパーティションする(ユーザーの居住地でシャード)
  • グローバルなインデックスには識別子のみ(PII を含めない)
  • ログ・バックアップ・分析基盤も規制の対象。「本体だけ対応」では不十分

第 39 章 一問一答

書き込みも各地で受ける構成の最大の課題は。
書き込み競合の解決。
地理パーティションが有利な理由は。
通常時の書き込み先を限定し、競合と越境を減らせる。ただし移住、フェイルオーバー、グローバル操作では競合・例外処理が必要。
マルチリージョンでも同時に落ちる原因は。
共通の依存(グローバル認証・設定配信・DNS)と、全リージョンへの一斉変更展開。

CHAPTER 40セキュリティ

🎯 GOAL

設計に必ず含めるべきセキュリティ要素を列挙し、説明できる。

40.1認証と認可

AUTHN vs AUTHZ
認証 (Authentication): あなたは誰か   → パスワード、MFA、生体、証明書
認可 (Authorization) : 何をしてよいか → ロール、権限、ポリシー
セッション(サーバー側で状態を持つ) JWT(自己完結トークン)
検証 Redis/DB を参照 署名検証のみ(ネットワーク不要)
失効 即座にできる 難しい(有効期限まで有効)
スケール ストア参照が必要 ステートレス
サイズ 小さい (ID のみ) 大きい(ヘッダに毎回乗る)
📐 数字・公式

OAuth 2.0 と OIDC は役割が違います。OAuth 2.0 は認可、OIDC は認証・ID 情報の標準です。アクセストークンは JWT とは限らず、失効や機密性を優先して不透明トークンを使う設計もあります。

一例(OAuth 2.0 / OIDC)
アクセストークン(JWT、有効期限 5〜15 分)  ← 短命なので失効の問題を軽減
リフレッシュトークン(不透明な文字列、長命)← サーバー側で管理し、失効可能
                                            + ローテーション(使い捨て)で盗難検知
⚠️ JWT のよくある脆弱性

  • alg: none を受け入れてしまう → アルゴリズムを固定して検証する
  • 署名検証をしていない(デコードしただけで信用する)
  • 機密情報を payload に入れる(JWT は暗号化されていない。Base64 は誰でも読める
  • 有効期限が長すぎる
  • localStorage に保存する → XSS で盗まれやすい。HttpOnly + Secure + SameSite Cookie はトークン読み取りを減らすが、CSRF 対策、XSS 対策、CORS、ログアウト設計も必要
認可モデル 説明
RBAC ロールに権限を紐付け(admin, editor, viewer)。単純
ABAC 属性で判断(部署 = 経理 かつ 金額 < 10万)
ReBAC 関係で判断(「このドキュメントの所有者の同僚」)。Google の Zanzibar が代表

40.2OWASP Top 10 的な脆弱性(最低限)

脆弱性 対策
SQL インジェクション プリペアドステートメント(パラメータ化クエリ)。文字列連結は絶対禁止
XSS 出力時のエスケープ、CSP ヘッダ、フレームワークの自動エスケープを無効化しない
CSRF SameSite=Lax/Strict Cookie、CSRF トークン
認可の欠落 (IDOR) すべてのリクエストでリソースの所有者を確認。URL の ID を信用しない
SSRF 外部から与えられた URL へのリクエストを禁止/許可リスト化。メタデータサービス (169.254.169.254) の保護
安全でないデシリアライズ 信頼できないデータを deserialize しない
秘密情報の漏洩 リポジトリに鍵を置かない、ログにトークンを出さない
依存関係の脆弱性 SCA ツール、定期更新、SBOM
📐 最も多い実害は IDOR

GET /api/orders/12345
   ← このユーザーが本当に 12345 の所有者か毎回確認しているか?

脅威モデリング:境界・資産・悪用経路

コンポーネントを並べる前に、次の順で脅威を洗い出します。

  1. 境界を描く:ユーザー、ブラウザ、API、ワーカー、DB、外部 SaaS、管理者、テナントの間で、信頼が切り替わる場所を示す
  2. 資産と損失を定義する:認証情報、個人データ、決済、モデル・プロンプト、可用性、完全性を列挙する
  3. 悪用経路を列挙する:認証情報の盗難、認可バイパス、リプレイ、SSRF、サプライチェーン、データ汚染、プロンプトインジェクション、内部者の誤操作を考える
  4. 防御と検証を割り当てる:最小権限、入力・出力の検証、分離、レート制限、暗号化、監査、アラート、復旧手順を各脅威に対応づけ、残余リスクと受け入れ条件も記録する

特にマルチテナントと AI ツール実行では、モデルの出力や取得文書を命令ではなく untrusted input として扱います。テナント・ユーザー・操作ごとに能力を絞り、破壊的操作は dry-run や人間承認を経由させ、監査ログから「誰が、どのモデルの、どのツールで、何を変更したか」を再現できるようにします。

40.3暗号化と鍵管理

ENCRYPTION
転送中 (in transit): TLS 1.2+ (内部通信も mTLS)
保存時 (at rest)   : ディスク暗号化 + 列レベル暗号化(PII、カード番号)
使用中 (in use)    : 機密コンピューティング(TEE)。特殊用途
📐 エンベロープ暗号化(クラウドの標準)

データ → DEK(データ暗号鍵)で暗号化
DEK   → KEK(マスター鍵、KMS/HSM 内)で暗号化して一緒に保存
→ KEK のローテーションでは、保存済み DEK を新しい KEK で再ラップする。
  全データの再暗号化を避けられるが、
  鍵の世代管理・失効・バックアップ・復旧手順は必要
パスワードの保存
❌ 平文、MD5、SHA-256(高速すぎて総当たりされる)
✅ bcrypt / scrypt / Argon2id(意図的に遅く、メモリを食う)+ ソルト(自動付与される)
📐 秘密情報の管理

環境変数よりも Secret Manager / Vault。短命な動的認証情報(DB パスワードを 1 時間ごとに自動発行)が理想形です。

40.4ゼロトラストと多層防御

ZERO TRUST
従来(境界防御): 「社内ネットワークの中は安全」→ 一度侵入されたら終わり
ゼロトラスト   : 「すべてのリクエストを毎回検証する」
                ネットワーク位置ではなく、ID とデバイスの状態で判断
🔬 深掘り

Google の BeyondCorp がこの分野の先駆けです。VPN を廃止し、すべてのアクセスを認証プロキシ経由にしました。

DEFENSE IN DEPTH
DDoS 対策(CDN / Anycast で吸収)
  → WAF(SQLi/XSS のパターン遮断)
  → レート制限
  → 認証・認可
  → 入力バリデーション
  → 最小権限(DB ユーザーに DROP 権限を与えない)
  → 監査ログ(誰が何をしたか)
  → 暗号化(漏洩しても読めない)
📐 最小権限の原則

サービスアカウントには必要最小限の権限だけ。「とりあえず admin」は最も多い設計ミスです。

40.5DDoS 対策

種類 対策
帯域枯渇型(L3/L4) CDN / Anycast で分散吸収、クラウドの DDoS 保護
アプリ層(L7) レート制限、WAF、CAPTCHA、Proof of Work、Bot 検知
リソース枯渇型(Slowloris 等) 接続タイムアウト、接続数制限
増幅攻撃(DNS/NTP) 自分が踏み台にならない設定
🎤 面接

SCRIPT
「認証は OIDC で行い、アクセストークンは 10 分の JWT、
 リフレッシュトークンはサーバー側で管理してローテーションします。
 すべての API でリソースの所有者チェックを行い、URL の ID を信用しません。
 サービス間通信は mTLS で相互認証し、DB の認証情報は
 Secret Manager から短命の動的認証情報として取得します。」

第 40 章 一問一答

JWT の最大の弱点は。
即座に失効できないこと。短い有効期限とリフレッシュトークンで緩和する。
パスワード保存に使うべきアルゴリズムは。
bcrypt / scrypt / Argon2id(意図的に低速)。
IDOR とは。
リクエスト内の識別子を検証せず、他人のリソースにアクセスできてしまう認可の欠落。
エンベロープ暗号化の利点は。
マスター鍵の交換だけで鍵ローテーションでき、全データの再暗号化が不要。

CHAPTER 41プライバシーとコンプライアンス

🎯 GOAL

個人データを扱う設計上の要件を説明できる。

41.1個人データの扱い

PII
PII(個人識別情報): 氏名、メール、電話、住所、IP、Cookie ID、位置情報、
                    デバイス ID、生体情報
機微情報          : 人種、信条、健康、性的指向、犯罪歴 → より厳格な扱い
設計原則(Privacy by Design) 実装
データ最小化 そもそも集めない。必要ないログは出さない
目的限定 集めた目的以外に使わない(分析用途の同意は別)
保持期間の制限 TTL を設定し、自動削除する
仮名化 / 匿名化 ID を置き換える(仮名化は復元可能、匿名化は不可)
アクセス制御と監査 誰がいつ誰のデータを見たか記録する

41.2GDPR / 各国法が要求する機能

権利 必要な機能
アクセス権 ユーザーの全データをエクスポートできる
削除権(忘れられる権利) 適用される例外、法定保存、法的請求、公共利益などを確認したうえで、対象システムから削除・不可視化・再利用停止できる
訂正権 修正できる
データポータビリティ 機械可読形式で提供
同意の撤回 追跡を停止できる
⚠️ 削除権が最も難しい

法域ごとの例外と保存義務を確認し、削除要求の認証、期限、監査、第三者処理者への通知も設計します。

本体 DB     → 削除・匿名化する
レプリカ     → 伝播する
バックアップ → 保持期間中は変更せず、復元時に削除済み状態を再適用する設計もある
ログ         → PII を最小化し、保持期間・マスキングを適用
データレイク → 個人単位の削除・再生成・暗号鍵の分離を検討
イベントログ → 削除イベント、投影の再構築、暗号化消去を組み合わせる
検索インデックス、キャッシュ、CDN、第三者 SaaS → 削除伝播と監査を設計
📐 選択肢の一つ: 暗号化消去

CRYPTO-SHREDDING
ユーザーごとに個別の暗号鍵で PII を暗号化して保存する
削除要求 → その鍵を破棄する
→ その鍵で暗号化されたデータを復号できなくする。
  ただし共有データ、メタデータ、バックアップ、鍵のコピー、法的要件を別途確認する。
🎤 面接

暗号化消去を面接で言えると非常に強いです。実務的で、原理的な問題を解いているからです。

41.3データ分類とアクセス制御

DATA CLASSIFICATION
Public       : 公開情報
Internal     : 社内限定
Confidential : 顧客データ(アクセスログ必須)
Restricted   : 決済情報、健康情報(暗号化 + 承認フロー + 監査)
📐 数字・公式

本番データを開発環境にコピーしない。必要ならマスキング / 合成データを使う。

第 41 章 一問一答

削除権の実装が難しい理由は。
バックアップ、ログ、分析基盤、イミュータブルなストアなど、データが多数の場所に複製されているため。
暗号化消去とは。
ユーザー固有の鍵を破棄して復号不能にする手法。ただし例外、共有データ、バックアップ、鍵管理を別に評価する。
仮名化と匿名化の違いは。
仮名化は追加情報があれば復元可能、匿名化は復元不可能(法的扱いが異なる)。

CHAPTER 42コストの設計

🎯 GOAL

設計判断にコストの観点を入れられる。

42.1コストの内訳(クラウドの相場感)

COST BREAKDOWN
計算 (Compute)     : 全体の 40〜60%
ストレージ          : 10〜20%
データ転送          : 10〜30% ← 見落とされがち。特にリージョン間・インターネット向け
マネージドサービス  : DB、キュー、監視(意外と高い)
監視・ログ          : ログの量に比例して爆発しがち
📐 相場の扱い

価格はクラウド事業者、リージョン、契約、ストレージ階層、時期で変わります。以下は固定値ではなく、見積もりの例として日付・リージョン・料金表の出典を併記して使います。

オブジェクトストレージ: 料金表から、保存容量・リクエスト・取り出しを分けて計算
インターネットへの外向き転送: 料金表から、データ量・宛先・無料枠を分けて計算
同一リージョン内の AZ 間転送: 料金表から、方向・サービス間転送を確認
CDN 経由の転送: CDN のリージョン、キャッシュヒット率、オリジン転送を含めて計算
💡 重要な直感

保存費と配信費は別の料金体系で、配信が保存より高くなることがある。正確な倍率は料金表と実際の転送量で再計算する。CDN・キャッシュ・圧縮は性能施策であると同時にコスト施策です。

42.2コスト最適化の手段

手段 効果 注意
適切なインスタンスサイズ 20〜50% 定期的な見直しが必要
リザーブド / Savings Plan 30〜70% コミットのリスク
スポットインスタンス 60〜90% 中断耐性のある設計が前提
オートスケール 20〜40% 夜間・週末の縮小
ストレージ階層 50〜80% アクセスパターンの分析が必要
ログの削減・サンプリング しばしば劇的 DEBUG ログの垂れ流しは高コスト
圧縮 転送・保存とも CPU とのトレードオフ
キャッシュヒット率の改善 全方位に効く
アーキテクチャの単純化 大きい 部品が減れば運用費も減る

42.3設計におけるコストの考え方

🎤 面接

コストに言及すると、シニアなシグナルになります。

SCRIPT
「動画のサムネイルを全解像度で事前生成すると、生成コストとストレージが膨らみます。
 アクセス分布が上位コンテンツに偏るという仮説を、ログで検証します。
 偏りが確認できるならオンデマンド生成 + CDN キャッシュにします。
 生成回数、TTL、ヒット率、鮮度 SLO を測り、事前生成とのコストと体験を比較します。」
📐 コスト効率の指標

「1 リクエストあたりのコスト」「1 ユーザーあたりの月額コスト」を測ることで、機能追加の是非を定量的に議論できます。

⚠️ 早すぎる最適化に注意

月 $500 のコストを 30% 削るためにエンジニア 2 人が 1 ヶ月使うのは明確な損失です。大きい費目から順に見るのが鉄則です。

第 42 章 一問一答

クラウドで見落とされがちなコストは。
データ転送(特にインターネット向けとリージョン間)。
CDN がコスト面で有利な理由は。
オリジンからの直接転送より単価が安く、転送量そのものも減らせる。
スポットインスタンスの前提条件は。
中断されても安全なステートレス・再実行可能なワークロードであること。

CHAPTER 43AI・機械学習・LLM・AI エージェントのシステム設計

🎯 GOAL

大規模推薦システム、特徴量ストア、LLM 推論サービング基盤、RAG、AI エージェントの主要な構成とトレードオフを理解する。数値や性能はモデル、ハードウェア、ワークロードごとに実測する。

43.1なぜ「AI / ML のシステムデザイン」が特別なのか

従来の Web システム(CRUD)と機械学習システムには、根本的な 4 つの違いがあります。

観点 従来の Web システム AI / ML・LLM システム
計算特性 I/O 律速(DB・ネットワーク待ち) 計算律速 (GPU Compute) またはメモリ帯域律速 (VRAM Bandwidth)
データの性質 正確性(ACID・1 行の不整合も許さない) 統計的・確率的(データの分布、鮮度、埋め込みベクトル)
パイプライン 同期的なリクエスト/レスポンス オフライン学習・リアルタイム推論・特徴量抽出の三重構造
障害モード 500 エラー、タイムアウト モデルの劣化(Data Drift / Concept Drift)、ハルシネーション

モデルライフサイクルと評価

本番の ML は「モデルを学習してデプロイしたら終わり」ではありません。データとモデルの版を追跡し、同じ入力から同じ特徴量・予測を再現できるようにします。

ML LIFECYCLE
データ収集・同意確認
  → 品質検査(欠損、外れ値、ラベル漏洩、PII)
  → 学習・再現可能な実験
  → モデルレジストリ(モデル、特徴量、データ、コード、評価の版)
  → オフライン評価
  → シャドー / カナリア / A/B
  → 監視(品質、ドリフト、遅延、コスト、公平性、安全性)
  → 承認・ロールバック・再学習

オフラインの精度だけで本番品質を代表させず、オンラインのビジネス指標、ガードレール違反、セグメント別の性能、推論コストを分けて測ります。ラベルが遅い場合は代理指標と人手サンプルを併用し、データ削除・同意撤回・モデル更新が学習データと特徴量ストアへどう伝播するかも設計します。

43.2大規模推薦システム(Two-Tower モデルと 3 段階パイプライン)

Google YouTube、Instagram、TikTok などの推薦システムは、数億件のコンテンツから数十ミリ秒でパーソナライズされたフィードを生成します。これを 1 つの巨大なモデルで解くのは計算量的に不可能です。

3-STAGE PIPELINE
10 億件の動画
    │
    ▼ ① Candidate Generation (Retrieval / 候補抽出)   [10〜20 ms]
数千件(1,000 件)  ← Two-Tower Model + ANN (ScaNN / HNSW)
    │
    ▼ ② Heavy Ranking (Scoring / 精密ランキング)      [20〜30 ms]
数百件(100 件)    ← 深層学習モデル (DLRM / Transformer) + 数千の特徴量
    │
    ▼ ③ Re-ranking & Policy (ビジネスロジック・多様性) [5 ms]
数十件(20 件)     ← 重複排除、探索と活用、鮮度ブースト、広告挿入
    │
    ▼
ユーザーの画面へ

1. Candidate Generation(Two-Tower Model / Dual Encoder)

  • ユーザー Tower:ユーザーの閲覧履歴、検索クエリ、年齢、時間帯などを入力し、ユーザー埋め込みベクトル u(D 次元)を出力
  • アイテム Tower:動画のタイトル、タグ、カテゴリ、制作者情報を入力し、アイテム埋め込みベクトル v(D 次元)を出力
  • 検索の仕組み:アイテムベクトルはオフラインで事前計算してベクターインデックス(ScaNN / HNSW)に格納。オンラインリクエスト時、ユーザー Tower だけをミリ秒で計算し、ANN 検索で内積 u・v の上位 1,000 件を 10 ms 以内に抽出

2. Heavy Ranking(精密ランキングモデル)

  • 抽出された 1,000 件に対し、リッチな特徴量(「このユーザーがこの作者の動画を過去に最後まで見た確率」「過去 10 分間のクリック数」など)を結合
  • 深層学習ランキングモデル(DLRM、Wide & Deep、Transformer など)で、CTR(クリック率)や視聴完了時間を予測

3. Re-ranking(多様性とビジネスルール)

  • 同じ作者の動画が連続しないように分散(MMR: Maximal Marginal Relevance)
  • 「探索と活用(Exploration vs Exploitation)」:新着動画を一定割合混ぜてユーザーの反応をテスト

43.3特徴量ストア(Feature Store)の設計

推薦や不正検知では、モデルに渡す「特徴量(Features)」の管理がシステムの成否を分けます。

FEATURE STORE
                   ┌─────────────────────────────────────────┐
                   │           Feature Store (Feast 等)       │
                   ├────────────────────┬────────────────────┤
                   │  オフラインストア  │   オンラインストア │
                   │ (BigQuery / GCS)   │ (Bigtable / Redis) │
                   └─────────┬──────────┴─────────┬──────────┘
                             │                    │
                   学習時(バッチ)      推論時(リアルタイム)
                   ・過去 1 年のログ     ・直近 5 件の閲覧履歴
                   ・Point-in-Time 一貫性・p99 < 5 ms の低遅延
📐 Training-Serving Skew の防止

  • 「推論時に使っている特徴量計算ロジック」と「過去ログから学習用データセットを作るロジック」がずれると、モデルの精度が壊滅します
  • 解決策:特徴量の定義コードを 1 つにまとめ、Feature Store がオフライン・オンライン両方に自動配信する
  • Point-in-Time Correctness(タイムトラベル):過去のイベント時点での正確な特徴量を復元し、未来のデータが学習に混入する「データリーク」を防ぐ

43.4LLM 推論サービング基盤の基礎

ChatGPT や Gemini のような大規模言語モデル(LLM)の推論は、通常の Web サーバーとは全く異なるリソース制約を持ちます。

① Prefill(プロンプト処理)vs Decode(トークン生成)

フェーズ やること ボトルネック 性質
Prefill 入力プロンプト(例:1000 トークン)を一度に処理 Compute-bound(GPU 計算律速) 並列化が効く。TTFT(最初の 1 トークンが出るまでの時間)を支配
Decode 1 トークンずつ自己回帰的に生成 Memory Bandwidth-bound(VRAM 帯域律速) 1 系列の時間方向は逐次だが、系列間バッチング、テンソル並列、投機的デコードなどの並列化は可能

② KV Cache と PagedAttention(最重要)

Transformer は過去の全トークンの Key と Value の行列(KV Cache)を保持して計算をスキップします。

📐 KV Cache のメモリ計算式

KV bytes = 2 × layers × KV heads × head dim × sequence length
           × batch size × bytes per element
  • 先頭の 2 は K と V の 2 種類です。MHA では KV heads × head dim = hidden size になりますが、GQA/MQA では KV ヘッド数が小さいため、隠れ層サイズだけで計算してはいけません
  • 例:80 層、GQA の 8 KV ヘッド、head dim 128、4K トークン、FP16 なら、1 リクエストは約 1.34 GB(10 進)です。MHA で 8192 次元なら約 10.7 GB です
  • 実際の同時実行数は、モデル重み、ランタイム、ワークスペース、断片化、バッチングの余裕を引いて実測します
⚠️ 断片化問題と PagedAttention (vLLM)

  • 従来は「最大コンテキスト長(例:8K)」分の連続メモリを事前に確保していたため、実際の長さの分布によってはメモリ利用率が大きく落ち、無駄な OOM が発生する
  • PagedAttention(OS の仮想メモリページングと同じ思想):KV Cache を固定サイズ(例:16 トークン)の「ブロック(ページ)」に分割し、物理 VRAM の不連続な領域に動的割り当て。メモリ利用率と同時処理数の改善幅は、実装、ベースライン、モデル、ワークロードで測定する

③ Continuous Batching(動的・インフライトバッチング)

  • 静的バッチングの課題:10 人のリクエストをまとめた場合、一番長い出力(1000 トークン)が終わるまで、短い出力(10 トークン)の人も GPU を拘束し続ける
  • Continuous Batching:1 トークン生成するイテレーションごとに、生成が完了したリクエストを即座に排出し、キューにある新しいリクエストを動的にバッチへ差し込む。スループットの向上幅は、出力長、バッチサイズ、スケジューラ、モデル、SLO を同じ条件で測定する

④ 投機的デコーディング(Speculative Decoding)

軽量なドラフトモデル(7B)が高速に 4〜5 トークンを先読み生成し、巨大なターゲットモデル(70B)が 1 回のフォワードパスで検証する。速度向上は受理率、モデル、負荷に依存する。

43.5RAG(検索拡張生成)の完全アーキテクチャ

LLM に最新情報や社内ドキュメントを参照させる標準パターンです。

RAG PIPELINE
[ユーザーの質問]
       │
       ▼
[① Query Rewriting / HyDE](質問を検索しやすい形・仮想回答に変換)
       │
       ▼
[② ハイブリッド検索] ──┬──► [BM25 転置インデックス]
                      └──► [Embedding モデル] → [ベクター DB (HNSW)]
       │
       ▼
[③ RRF 統合](上位 50 件を抽出)
       │
       ▼
[④ Cross-Encoder リランカー](上位 5 件に高精度に絞り込み)
       │
       ▼
[⑤ コンテキスト圧縮 & プロンプト構築]
       │
       ▼
[⑥ LLM 推論サービング] ──(ストリーミング SSE)──► [クライアント]

セマンティックキャッシュ(Semantic Cache)

  • プロンプトの完全一致(MD5)ではなく、Embedding の類似度で候補を探す方式。ただし、類似度の閾値はデータで検証する
  • キャッシュキーにはテナント、ユーザー権限、モデル版、システムプロンプト、ツール、データ鮮度を含める。個人情報・高リスク回答を無条件に共有せず、コストとレイテンシの改善幅は実測する

43.6AI エージェントの本番システム設計

AI エージェントは「LLM に長いプロンプトを渡すこと」ではありません。モデルが計画を立て、ツールを呼び、結果を解釈し、状態を更新して次の行動を選ぶ制御ループです。手順が固定されているなら、自由なエージェントより通常のワークフローやステートマシンの方が安く、再現性が高く、検証しやすい、という判断から始めます。

① 基本ループと責任の分離

AGENT LOOP
[要求 + ユーザー/テナント境界]
          │
          ▼
[ポリシー・能力チェック] ── 許可されたツールだけを公開
          │
          ▼
[計画 / ルータ] ──► [ツール実行(サンドボックス、期限、予算)]
          │                         │
          │                         ▼
          │                [結果の検証・副作用の確認]
          │                         │
          └──── [状態・監査ログへチェックポイント] ◄─┘
                         │
              継続 / ユーザー確認 / 完了 / 停止

モデルには「何を考えたか」ではなく、必要な構造化出力(ツール名、引数、根拠、次の状態)を返させます。認証・認可、予算、リトライ、監査、外部副作用の確定は、モデルの判断に任せず決定的な実行器で担保します。

② ツール契約(Agent–Computer Interface)

ツールは関数呼び出しの名前だけでは不十分です。各ツールに次の契約を持たせます。

契約 設計すること
入出力 型付きスキーマ、単位、必須・任意、許容範囲、エラー形式
副作用 read-only / 可逆変更 / 不可逆変更を分類し、dry-run を用意
信頼性 タイムアウト、キャンセル、冪等キー、重複検知、状態照会 API
権限 ユーザー・テナント・リソース単位の最小権限。ツールごとに許可範囲を制限
安全性 URL、SQL、シェル、ファイル、プロンプトを無害化。ツール結果も untrusted input として扱う
監査 呼び出し元、モデル版、引数のハッシュ、結果、承認者、相関 ID を記録

「タイムアウトしたので再実行」は、外部で既に処理されたか分からない非原子的失敗を起こします。冪等キーで重複を抑え、再試行前に状態照会または事後条件(残高が減った、チケットが発行された等)を検証します。支払い、削除、送信、権限変更など不可逆操作は、明示的な確認・人間承認・二重チェックを要求します。

③ 状態、メモリ、長時間実行

「コンテキストに履歴を全部詰める」設計は、トークン費用・漏洩・コンテキスト上限で破綻します。少なくとも次を分離します。

  • 作業コンテキスト:現在のターンで必要な短期情報。要約・圧縮・期限を持つ
  • タスク状態:ステートマシン、実行 ID、試行回数、期限、チェックポイント、未完了ツールを永続化する
  • 知識・長期メモリ:出典、テナント、権限、鮮度、削除状態、モデル版を付けた検索可能なデータ

ワーカーが落ちてもチェックポイントから再開できるようにし、同じステップを再実行しても結果が壊れないようにします。最大ステップ数、最大トークン、経過時間、外部 API の費用、並列数を上限にし、上限到達時は安全に停止してユーザーへ引き継ぎます。

④ セキュリティとプロンプトインジェクション

取得文書、メール、Web ページ、ツール応答に含まれる「指示」は、システムポリシーより下位のデータです。それらを命令として実行すると、秘密情報の持ち出し、越権操作、SSRF、データ汚染につながります。

  • システム指示、ユーザー入力、取得データ、ツール結果を構造的に分離する
  • ツールを能力(capability)単位で分け、不要な秘密・ネットワーク・ファイルにアクセスさせない
  • 外部 URL は許可リスト、DNS 再解決、プライベート IP・メタデータサービス遮断を行う
  • 出力だけでなく、引数・権限・副作用を決定的なポリシーエンジンで検査する
  • テナント境界、削除、監査、保持期限を RAG・キャッシュ・メモリ・ログにも適用する

⑤ 評価・観測・運用

最終回答の正しさだけでなく、軌跡(trajectory)を評価します。代表的な指標は、タスク成功率、正しいツール選択・引数率、不要な呼び出し率、再試行・停止の適切さ、制約・ACL 違反率、人間への引き継ぎ率、p95/p99 レイテンシ、トークン・ツール費用です。

固定のゴールデンケース、過去トレースのリプレイ、敵対的入力、権限境界、長時間・部分障害を組み合わせます。LLM-as-a-judge は補助に留め、人手サンプルや決定的な検査(スキーマ、ACL、状態遷移、事後条件)で校正します。本番では、モデル版・プロンプト版・ツール版・入力要約・各呼び出し・判断結果を Trace ID で結び、カナリア、キルスイッチ、予算アラート、ロールバックを用意します。

⑥ 単一エージェント、ワークフロー、マルチエージェント

方式 向く状況 主なリスク
決定的ワークフロー 手順・分岐・SLO が明確 例外が増えると分岐の保守が難しい
単一エージェント ツール数が少なく、探索や計画が必要 ループ、権限過剰、費用の予測困難
マルチエージェント 独立した専門タスクを並列化し、契約で結果を渡せる 通信・調停・重複作業・障害の増幅。最初から採用しない

マルチエージェントにする場合も、各役割の入力・出力スキーマ、タイムアウト、予算、再試行、停止条件、責任者を定義します。共有の自由文メモだけで協調させず、中央のオーケストレータが権限と状態遷移を管理します。

🎤 面接での最小回答例

SCRIPT
「まず固定手順ならワークフローにします。探索が必要な部分だけエージェントにし、
 ツールは read-only と副作用ありに分けます。
 各呼び出しに期限・冪等キー・最小権限・事後条件を持たせ、
 タイムアウト時は状態照会してから再試行します。
 実行状態をチェックポイント保存し、ステップ数・費用・時間の上限で停止します。
 削除や決済は人間承認、全文書とツール結果は untrusted input、
 監査トレースとリプレイ評価でモデル更新をカナリアします。」

第 43 章 一問一答

推薦システムで Two-Tower モデルを使う最大の理由は。
アイテム埋め込みをオフライン事前計算し、オンラインではユーザー埋め込みと ANN 検索だけで数ミリ秒で数億件から候補を絞り込めるから。
LLM の Decode フェーズがメモリ帯域律速になる理由は。
1 トークン生成するごとにモデルの全パラメータと KV Cache を VRAM から読み出す必要があり、GPU コアの計算能力ではなくメモリ転送速度が限界を決めるため。
PagedAttention の効果は。
KV Cache を不連続なブロックで管理して内部断片化を減らす。利用率や同時処理数の改善幅は実装とワークロードで評価する。
Continuous Batching とは。
トークン生成の 1 ステップごとに完了したリクエストを排出し、新規リクエストを動的にバッチに追加する手法。
固定手順をエージェントにしない理由は。
決定的ワークフローの方が再現性、費用、検証可能性を確保しやすく、自由な探索が必要な部分だけをエージェントにできるから。
ツール呼び出しがタイムアウトしたら即再試行してよいか。
いいえ。外部で実行済みかを状態照会または事後条件で確認し、冪等キーと予算の範囲で再試行する。
AI エージェントの評価で最終回答以外に見るものは。
ツール選択・引数、状態遷移、制約・ACL 違反、不要な呼び出し、停止・引き継ぎ、遅延と費用を軌跡単位で測る。
プロンプトインジェクションへの基本姿勢は。
取得文書やツール結果を命令ではなく untrusted input として扱い、能力・権限・副作用を決定的な層で制限する。