Claude Agent SDKの長時間実行:再開・冪等性・監視の実装パターン¶
対象 / ポイント
対象: 数十分以上の調査、移行、コード変更をClaude Agent SDKで運用する開発者
ポイント:
session_idとresumeは会話を再開できるが、業務状態の永続化を代替しない- 長時間処理は1本の無停止ループではなく、再実行可能なフェーズへ分割する
- 予算、権限、hooks、監視、停止手順をアプリケーション側で設計する
長時間エージェントの信頼性は「何時間連続で考えられるか」では決まらない。 プロセス停止、APIエラー、権限待ち、重複実行、途中成果物の破損から回復できるかで決まる。
現在のClaude Agent SDKにはセッション再開、hooks、使用量・コストイベント、OpenTelemetry連携がある。12 一方、旧記事に見られる「30時間自律稼働」「SDKが任意地点へロールバックするチェックポイント」といった前提は、一般的なSDK機能として扱うべきではない。
状態を3層へ分ける¶
| 状態 | 保存先 | 例 |
|---|---|---|
| 会話状態 | Agent SDKのセッショントランスクリプト | メッセージ、ツール結果、session_id |
| 業務状態 | 自分のDBまたは耐久ストレージ | フェーズ、入力版、処理済みID、承認、再試行回数 |
| 成果物 | バージョン管理またはオブジェクトストレージ | 変更ファイル、レポート、検証ログ、チェックサム |
Agent SDKの再開機能が扱うのは主に会話状態だ。 「どの顧客へ送信済みか」「移行の何件目まで確定したか」は、モデルの会話ではなくアプリケーションの業務状態として保存する。
session_id を保存して再開する¶
各実行の最後に届く ResultMessage から session_id を保存し、次のプロセスで ClaudeAgentOptions.resume へ渡す。2
from dataclasses import replace
import anyio
from claude_agent_sdk import (
ClaudeAgentOptions,
ClaudeSDKClient,
ResultMessage,
)
async def run_first_turn() -> str:
options = ClaudeAgentOptions(
allowed_tools=["Read", "Grep", "Glob"],
max_turns=8,
)
async with ClaudeSDKClient(options=options) as client:
await client.query("対象リポジトリを調査し、移行計画だけを作る")
async for message in client.receive_response():
if isinstance(message, ResultMessage):
return message.session_id
raise RuntimeError("ResultMessage was not received")
async def resume_turn(session_id: str) -> None:
base = ClaudeAgentOptions(
allowed_tools=["Read", "Grep", "Glob"],
max_turns=8,
)
options = replace(base, resume=session_id)
async with ClaudeSDKClient(options=options) as client:
await client.query("前回の計画を、検証可能なフェーズへ分割する")
async for message in client.receive_response():
if isinstance(message, ResultMessage):
print(message.result)
anyio.run(resume_turn, "保存済みのsession_id")
トランスクリプトはローカルディスクに保存され、プロセス再起動を越えて再開できる。 サーバー側へ永続化される会話IDではないため、別ホストへ移る場合は同じセッションファイルを共有する設計が必要になる。2
ClaudeSDKClient を開いたまま複数回 query() する方法は、同一プロセス内の対話に向く。 クラッシュ回復には session_id の保存と resume を使う。
長い仕事を冪等なフェーズへ分ける¶
1つの指示で「調査、変更、テスト、公開」まで走らせない。
discovered
→ planned
→ approved
→ implemented
→ validated
→ published
各フェーズは次の契約を持つ。
- 読み取る入力とそのバージョン
- 許可するツールと書き込み先
- 生成する成果物
- 成功を判定する検証
- 再実行時の挙動
- 次へ進むための承認
たとえば implemented を再実行しても同じ変更を二重追加しないよう、対象コミット、パッチID、成果物チェックサムを記録する。 外部APIへ作成要求を送る場合は、業務IDをidempotency keyとして使う。
アプリケーションのチェックポイント¶
チェックポイントは「モデルの頭の中を保存する機能」ではなく、再開に必要な事実を自分のストレージへ確定する処理として設計する。
{
"job_id": "migration-2026-071",
"session_id": "...",
"phase": "implemented",
"input_revision": "a4c91d2",
"artifact_uri": "s3://agent-runs/migration-2026-071.patch",
"artifact_sha256": "...",
"validation": "pending",
"attempt": 2
}
状態更新と外部副作用の間で停止しても回復できるよう、次の順序を使う。
- 実行予定を
runningとして記録する - 副作用をidempotency key付きで実行する
- 結果と外部IDを保存する
- 検証後にフェーズを完了へ進める
権限と停止条件¶
長時間実行では、1回の誤判断が連続して副作用を生む。
- フェーズごとに
allowed_toolsを変える - 調査ではRead、Grep、Globだけを許可する
- EditやBashには
can_use_toolまたはPreToolUse hookで条件を置く - 削除、公開、送信、購入は必ず人間承認へ戻す
- ターン、時間、コスト、変更ファイル数、外部API件数に上限を置く
上限到達は失敗ではなく正常な停止条件として扱い、現在状態と次の再開指示を保存する。
hooksで不変条件を守る¶
PreToolUse hookは危険な操作を実行前に止め、PostToolUse hookは結果の記録や検証へ使える。3
例:
- 許可ディレクトリ外のWrite、Editを拒否する
- 本番ブランチへの直接pushを拒否する
- DB設定値が安全範囲外なら変更を拒否する
- ファイル更新後に構文検査を実行する
- 外部送信前に宛先allowlistを確認する
プロンプトの「絶対にしない」だけでなく、決定的なコードで不変条件を強制する。
監視する指標¶
ResultMessage から、結果、ターン数、使用量、total_cost_usd、セッションIDを取得できる。 SDKが共有するClaude CodeランタイムはOpenTelemetryメトリクスとイベントを出力できる。2
export CLAUDE_CODE_ENABLE_TELEMETRY=1
export OTEL_METRICS_EXPORTER=otlp
export OTEL_LOGS_EXPORTER=otlp
export OTEL_EXPORTER_OTLP_PROTOCOL=grpc
export OTEL_EXPORTER_OTLP_ENDPOINT=http://collector:4317
最低限、次をジョブIDと関連付ける。
- 実行時間と現在フェーズ
- ターン数、トークン、コスト
- ツール呼び出し数、失敗数、承認待ち時間
- 変更ファイル数と検証結果
- 再試行回数と最後のエラー
session_idと成果物URI
アラートは「プロセスが落ちた」だけでなく、長時間進捗がない、同じツール失敗を繰り返す、コスト傾向が閾値を超えた場合にも出す。
Agent SDKとManaged Agentsを混同しない¶
Claude Agent SDKは、利用者側が運用するプロセスとファイルシステムで動く。 AnthropicのManaged Agentsは、セッションとサンドボックスをAnthropic側で永続化する別のサービスである。4
複数ホストでの永続セッション、サーバー側のスケジュール、マネージドなサンドボックスが必要ならManaged Agentsを比較対象にする。 Agent SDKのローカルセッションへManaged Agentsの保持仕様を当てはめない。
まとめ¶
- 会話状態、業務状態、成果物を別々に保存する
session_idとresumeは会話再開に使い、業務の確定状態はDBへ持つ- 長時間処理を検証可能で冪等なフェーズへ分割する
- hooksと上限で副作用を制御する
- コスト、ツール、進捗、成果物をジョブ単位で監視する
長時間エージェントの目標は止まらないことではない。 安全に止まり、どこまで確定したかを説明し、同じ副作用を重ねずに再開できることが本番運用の条件になる。