CLAUDE LABEN
BILLING — 6/15の課金変更まで残り1日。Agent SDK・headless・GitHub Actions・他社エージェントが別枠の月次クレジット($20/$100/$200・full APIレート・繰越なし)へ移行しますFABLE5 — Claude Fable 5(Mythosクラス)は一般提供で最高性能とされ、Claude Code v2.1.170以降で利用できます(6/9公開)SUBAGENTS — Claude Codeでサブエージェントがさらにサブエージェントを生成可能に。モデル・リージョン選択もより賢くなりましたENTERPRISE — Enterpriseのカスタムロールにadmin権限を追加。Owner権限なしで請求・プライバシー設定へアクセスできますPLUGINS — プラグイン検索とChrome・VSCode・ターミナル連携が改善。セッション・メモリ・権限まわりの不具合も修正されましたUI — フルスクリーン時のマウスホイール加速を無効化する設定を追加。/modelピッカーがモデルファミリーを正しく表示するよう修正BILLING — 6/15の課金変更まで残り1日。Agent SDK・headless・GitHub Actions・他社エージェントが別枠の月次クレジット($20/$100/$200・full APIレート・繰越なし)へ移行しますFABLE5 — Claude Fable 5(Mythosクラス)は一般提供で最高性能とされ、Claude Code v2.1.170以降で利用できます(6/9公開)SUBAGENTS — Claude Codeでサブエージェントがさらにサブエージェントを生成可能に。モデル・リージョン選択もより賢くなりましたENTERPRISE — Enterpriseのカスタムロールにadmin権限を追加。Owner権限なしで請求・プライバシー設定へアクセスできますPLUGINS — プラグイン検索とChrome・VSCode・ターミナル連携が改善。セッション・メモリ・権限まわりの不具合も修正されましたUI — フルスクリーン時のマウスホイール加速を無効化する設定を追加。/modelピッカーがモデルファミリーを正しく表示するよう修正
記事一覧/API & SDK
API & SDK/2026-06-14上級

Claude Agent SDK のツールを冪等にする — 二重実行を止める冪等性キーと Outbox の実装メモ

Claude Agent SDK のリトライやセッション再開で決済を二重処理する事故を防ぐ実装メモ。決定的な冪等性キー・Outbox・軽量ラッパーの3パターンを、動くコードと運用メトリクスつきで設計します。

claude-agent-sdk5idempotency2outboxreliability5production73

プレミアム記事

ある朝、決済エージェントのログに同じ請求書 ID が二回並んでいるのを見つけて、背筋が冷えました。

幸い金額が小さく、Stripe 側の Idempotency-Key が二重請求を弾いていたので実害はありませんでした。けれど原因をたどると、SDK のタイムアウト再試行で同じツールが二度呼ばれ、その間に自社 DB へのレコードだけは二件入っていた。Stripe が守ってくれなければ、顧客に二重で請求が飛んでいたところです。

エージェントが副作用を持つ処理を扱うようになると、この種の事故は静かに増えます。Claude Agent SDK はセッション再開やツールのリトライを内蔵していて、長時間タスクや一時障害に強い。その強さの裏側で、決済・メール送信・在庫減算のような「取り消せない副作用」だけは、開発者が冪等性を設計しないと二重実行のリスクが残ります。公式ドキュメントには API 単位の idempotency-key の記述こそありますが、エージェント全体としてどう冪等性を組むかはあまり語られていません。

ここでは、個人開発で運用していた決済エージェントを作り直したときの冪等性レイヤーを、そのまま使える形にまとめます。決定的な冪等性キー、Outbox、軽量ラッパーの3パターン。コピーして動くコードと、本番で何を計測すべきかまで踏み込みます。

なぜエージェントでは冪等性が一段むずかしいのか

普通の API クライアントでも冪等性は要りますが、エージェントには「失敗と成功の境界が曖昧」という事情が重なります。私が事故を起こして理解したのは、次の三つが同時に効いてくるという点でした。

一つ目はモデル応答の非決定性です。同じ意図でもツール引数の細部が揺れることがあるため、「同じ操作かどうか」の判定をモデル生成のキーに任せられません。二つ目は部分的成功です。ツールが成功した直後にループがクラッシュすると、次の起動でモデルは「まだ呼んでいない」と解釈して再実行します。三つ目は再開です。セッション再開やチェックポイントは状態を巻き戻すので、副作用側で重複を検知できないと素通りします。

Stripe のような成熟した SDK は Idempotency-Key を受け取ってくれますが、自社 DB への INSERT、メール送信、社内 API は自前で冪等性を作る必要があります。私は「ツールを全部冪等にしてから本番に出す」を自分のルールにしていて、この順序を逆にすると必ずどこかで事故が起きると実感しています。

パターン1: 決定的な冪等性キーを入力から導出する

冪等性キーに必要な性質はただ一つ、「同じ意図の操作なら、何度生成しても同じ値になる」ことです。その場で UUID を振っては意味がないので、操作の入力からハッシュで決定的に導出します。

# idempotency_key.py — 同じ意図から決定的に同じキーを導出する
from __future__ import annotations
import hashlib
import json
from typing import Any
 
 
def stable_idempotency_key(
    session_id: str,
    tool_name: str,
    logical_args: dict[str, Any],
    *,
    version: str = "v1",
) -> str:
    """決定的な冪等性キーを生成する。
 
    logical_args には「意図」を表す最小限の引数だけを渡す。
    timestamp や retry_count を混ぜると、再試行のたびにキーが変わって破綻する。
    """
    # 辞書順を固定して正規化(引数の順番が違っても同じキーにする)
    canonical = json.dumps(logical_args, sort_keys=True, separators=(",", ":"), default=str)
    raw = f"{version}|{session_id}|{tool_name}|{canonical}"
    digest = hashlib.sha256(raw.encode("utf-8")).hexdigest()
    return f"idem_{version}_{digest[:32]}"
 
 
if __name__ == "__main__":
    k1 = stable_idempotency_key(
        "sess_abc", "charge_payment",
        {"customer_id": "cus_001", "amount_jpy": 2480, "invoice_id": "inv_555"},
    )
    k2 = stable_idempotency_key(
        "sess_abc", "charge_payment",
        {"invoice_id": "inv_555", "amount_jpy": 2480, "customer_id": "cus_001"},
    )
    assert k1 == k2  # 引数の順番が違っても同じキー

キー生成に time.time() やランダム要素を混ぜると、再試行のたびにキーが変わって冪等性が崩れます。リトライ回数のような内部メタデータも同罪です。「意図」だけを抜き出してキーに含める——これが鉄則です。

version フィールドは、将来キー生成ロジックを変えたくなったときに旧キーと衝突させないための安全弁です。私はこれを怠ったことがあり、キー形式の変更時に DB クレンジングで一晩を溶かしました。最初から付けておくと安いコストで済みます。

セッション ID は、エージェントを起動する呼び出し側で発番して渡すのが素直です。ClaudeSDKClient はセッションを内部管理しますが、外部の永続化層と共有するには明示的な ID を握っておく必要があります。

import uuid
from claude_agent_sdk import ClaudeSDKClient, ClaudeAgentOptions
 
session_id = f"sess_{uuid.uuid4().hex}"
options = ClaudeAgentOptions(
    system_prompt="あなたは決済処理エージェントです。",
    extra_context={"session_id": session_id},  # ツール側から参照できるようにする
)

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

この記事の続きを読む

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

この記事で得られること
リトライやセッション再開でも値が変わらない『決定的な冪等性キー』を入力から導出する設計と全コード
Outbox パターンでエージェントループと外部APIのトランザクション境界を揃え、二重請求を構造的に消す方法
重複検知率・Outbox滞留・キー衝突率という3つの運用メトリクスと、その閾値設計の実例
Stripe による安全な決済 · いつでもキャンセル可能

この記事を購入する

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

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

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

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

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

関連記事

API & SDK2026-05-08
Claude Agent SDKでサーガパターンを実装する — 補償トランザクションと冪等性の設計
Claude Agent SDKで複数ステップのワークフローを安全に組み立てる実践ガイド。補償トランザクション・冪等性キー・部分失敗時の状態復元を、本番環境で動かしてきた構成パターンとともに紹介します。
API & SDK2026-05-07
Claude Agent SDK の Transactional Outbox 実装 — 「副作用の取りこぼし」を本番でゼロにする設計
Claude Agent SDK で発生する「DBには書かれたのにメール/決済/通知が飛ばなかった」事故を防ぐため、Transactional Outbox パターンを Postgres と Cloudflare Queues を例に本番品質で実装する手順をまとめます。
API & SDK2026-04-24
Claude API を Python で本番運用する — レート制限・リトライ・タイムアウトの設計
Claude API を本番サービスに組み込むなら、429・503・Read timeout とどう付き合うかが品質を決めます。私が実運用で落ち着いたリトライとタイムアウトの設計方針を、コード込みで整理しました。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →