追記: 2026年6月10日の最新情報
2026年6月10日にLangGraphとMastraの公式ドキュメントを再確認しました。LangGraphのInterruptsでは、interrupt()でgraph実行を止めるとpersistence layerに状態が保存され、同じthread_idを指定してCommand(resume=...)で再開する流れが説明されています。承認画面を作る前に、承認者へ見せるpayload、再開時に戻す値、同じ副作用を繰り返さないための実行済み判定を分けておく必要があります。
MastraのSuspend & resumeでは、workflowが停止した時の実行状態がsnapshotとして保存され、設定済みstorage providerによりdeployやapplication restartをまたいで保持されると説明されています。suspended runを復旧する実装では、getWorkflowRunById()やcreateWorkflowStateReader()で停止中のstep、resume label、step payloadを確認してからrun.resume()へ進める形になります。
そのため、LangGraphとMastraを比べる時は「人間承認があるか」だけでなく、run idやthread idの保存、承認payloadの監査、timeout時の扱い、resume後の二重実行防止まで含めて見てください。tool実行前のguardrailsはOpenAI Agents SDKの記事、人間へ入力を求めるUXはMCP Elicitationの記事も合わせて読むと整理しやすくなります。
このテーマをもう少し広げて見るなら、OpenAI Agents SDKのtool guardrailsを実務に入れる前に:handoff・built-in tools・人間承認の分け方 と MCP ElicitationをAIエージェントに入れる前に:form・URL・OAuth・人間承認の分け方 も合わせて確認してください。承認付きworkflowを、tool実行前のguardrailsやhandoff設計へ広げて確認できます。
3行まとめ
LLM応答後ではなく、tool実行や外部API呼び出しの直前で止める位置を決めます。
承認者が見るpayload、tool引数、理由、再開識別子、実行済み判定を保存します。
承認、却下、修正、期限切れを同じrunの続きとして戻す方法を決めます。
冪等性キー、payload hash、外部response IDで同じ副作用を繰り返さないようにします。
LangGraphとMastraの比較は、UIより先に状態遷移と副作用境界をそろえると判断しやすくなります。
- LangGraphとMastraはどちらも承認付きワークフローを作れますが、最初に決めるべきなのは「承認ボタンの見た目」ではなく、どの状態を保存し、どの位置で止め、どの入力で再開するかです。
- LangGraphはcheckpoint、thread、interruptを中心に、複雑な状態遷移や再開可能なagent graphを設計しやすい一方、state設計と副作用制御を丁寧に持つ必要があります。
- Mastraはworkflowのsuspend/resumeとagent approvalを分けて扱えるため、業務フローの承認ステップとtool実行前の承認をTypeScriptアプリに組み込みやすい構成です。
この記事は、LangGraphとMastraの優劣をランキングする記事ではありません。2026年5月31日時点の公式ドキュメントとnpmメタデータを確認し、AIエージェントアプリに人間承認を入れるときの設計判断を整理します。
AIエージェント全体の実装パターンを先に確認したい場合は、エージェントフレームワークカテゴリを入口にしてください。権限や監査ログを含む導入判断は、Securityカテゴリと合わせて読むと判断しやすくなります。
本文の事実確認には、公式ドキュメント、公式ヘルプ、関連する仕様・SDKドキュメントを使っています。実リポジトリでの性能ベンチマークや更新代行は、本文で明記した場合を除き実施していません。
この記事でわかること
入力、判断、承認待ち、承認結果、実行、ログ保存の流れを整理できます。
persistence、checkpoint、interrupt、thread_idを承認設計のどこで見るか確認できます。
workflow suspend/resumeとagent approvalを、業務承認とtool承認に分けられます。
停止、再開、却下、修正、サーバー再起動、retry、監査を同じ条件で検証できます。
単なる機能比較ではなく、保存状態、承認粒度、副作用制御、運用責務を判断するための記事です。
- LangGraphとMastraで承認付きワークフローを設計するときの共通モデル
- LangGraphのpersistence、checkpoint、interrupt、thread_idをどこで見るか
- Mastraのworkflow suspend/resumeとagent approvalをどう分けるか
- 承認待ち状態で保存すべきデータ
- 再開時にメール送信、DB更新、GitHub操作、外部API呼び出しを二重実行しない考え方
- PoCで必ず試すべき失敗ケース
- LangGraph寄り、Mastra寄りになりやすいユースケース
前提知識
| 項目 | 内容 | 見方 |
|---|---|---|
| 承認 | 人間が提案されたaction、payload、リスクを見て進行可否を決めます。 | |
| 権限 | AIが読めるファイル、呼べるtool、書けるDB、送れるAPIを別に制限します。 | |
| resume | 停止したrunを同じ文脈で続け、承認結果を次のstepへ渡します。 | |
| retry/re-run | 処理をやり直す操作で、LLM再推論により承認時と実行時の内容がずれる可能性があります。 |
承認、権限、再開、再実行を同じものとして扱うと、監査しにくいワークフローになります。
Human-in-the-loopは「最後に人間が見る」だけではない
human-in-the-loop、HITL、人間承認という言葉は便利ですが、実装時にはかなり雑に使われがちです。最終画面に「承認」ボタンを置くだけなら簡単です。しかしAIエージェントやworkflowが外部API、DB、GitHub、メール、決済、社内SaaSを操作する場合、承認の位置を間違えると「承認前にすでに実行済み」という事故が起きます。
実務で必要なのは、少なくとも次の4つです。
| 論点 | 決めること |
|---|---|
| 停止位置 | LLM応答後、tool実行前、外部API実行前、DB更新前、最終送信前のどこで止めるか |
| 保存状態 | 承認画面に出す情報と、再開に必要な情報をどこまで保存するか |
| 再開方法 | 承認、却下、修正、期限切れ、キャンセルをどうworkflowへ戻すか |
| 副作用制御 | 再開、再試行、worker再起動で同じ外部操作を繰り返さないか |
承認と権限は別物
人間承認を入れても、権限設計が不要になるわけではありません。AIエージェントが読めるファイル、呼べるtool、送信できる外部API、書き込めるDB、作れるPRは別に制限する必要があります。
特にMCPやtool callingを使う場合、tool自体はread-onlyから始めるのが実務では扱いやすいです。write系toolを入れる場合は、toolの説明、入力schema、実行前承認、実行ログ、ロール制御をセットで設計します。MCPの権限境界を整理したい場合は、MCPカテゴリも参照してください。
再開と再実行は違う
承認付きworkflowでは、resumeとretryを混同しないことが重要です。
resumeは、停止したrunを同じ文脈で続ける操作です。承認待ちのstate、tool引数、承認者、承認結果を使って、次のstepへ進みます。
retryやre-runは、処理の一部または全体をやり直す操作です。LLMへ再推論させると、承認時に人間が見たtool引数と、実際に実行されるtool引数がずれる可能性があります。承認対象を固定するのか、承認後に再生成を許すのかを明記しておかないと、監査しにくいワークフローになります。
承認付きワークフローの最小モデル
- 1入力
ユーザー入力、チケット、社内データ、イベントを受け取ります。
- 2判断
LLMまたはルールが次のaction候補を作ります。
- 3承認待ち
action候補、tool引数、payload、理由、再開識別子を保存します。
- 4承認結果
承認、却下、修正、差し戻し、キャンセルをworkflowへ戻します。
- 5副作用実行
承認済みのpayloadだけを外部API、DB、メール、GitHubなどへ実行します。
- 6結果保存
実行結果、外部response ID、承認ログ、実行済み状態を残します。
approve/rejectだけで始める場合も、修正、期限切れ、監査ログを後から足せるstateにしておくと運用しやすくなります。
LangGraphとMastraを比較する前に、共通の最小モデルを置きます。
- ユーザー入力、チケット、社内データ、イベントを受け取る
- LLMまたはルールが次のaction候補を作る
- action候補を承認待ち状態として保存する
- 人間が承認、却下、修正、差し戻し、キャンセルを選ぶ
- 承認されたactionだけを実行する
- 実行結果、外部レスポンスID、承認ログを保存する
承認待ち状態で保存するもの
承認画面に出す情報と、workflowを再開するための情報は似ていますが、同じではありません。
確認項目
| 保存対象 | 目的 |
|---|---|
workflow_run_id | どのrunを再開するかを特定する |
step_id / node_id | どこで止まっているかを特定する |
request_id | ユーザーや外部イベントからの依頼を追う |
pending_action | 実行予定の操作を人間が読める形で保存する |
tool_name / tool_args | tool実行前承認で確認する |
diff / payload | 変更差分や外部送信内容を固定する |
model_reason | LLMがそのactionを提案した理由を確認する |
approval_status | pending、approved、rejected、edited、expiredなどを管理する |
approved_by / approved_at | 監査ログに使う |
idempotency_key | 二重実行防止に使う |
external_response_id | 外部サービス側の実行済み結果を紐づける |
最小PoCでも、workflow_run_id、step_id、pending_action、approval_status、idempotency_keyは入れておく方が後で困りません。最初から完璧な管理画面を作る必要はありませんが、承認後に何を実行したのかを追えないPoCは、本番導入の判断材料になりにくいです。
承認結果はapprove/rejectだけでは足りない
社内の小さな補助ツールなら、承認と却下だけでも始められます。しかし顧客影響、金銭影響、公開操作、権限変更を含むなら、次の状態を用意した方が安全です。
状態の候補
| 状態 | 意味 |
|---|---|
approved | 提案されたactionをそのまま実行する |
rejected | actionを実行せず終了する |
edited | 人間がpayloadや条件を修正して実行する |
needs_revision | AIまたは担当者に再提案させる |
expired | 承認期限切れで自動停止する |
cancelled | 依頼自体を取り消す |
escalated | 別ロールの承認者へ回す |
承認結果が増えるほど実装は少し重くなります。ただ、approve/rejectだけで作った後に「修正して承認したい」「期限切れを扱いたい」「上長承認に回したい」となると、state設計を作り直すことがあります。最初の設計レビューでは、状態を表にしてからframeworkを選ぶのがおすすめです。
LangGraphで設計する場合
- 1State
request、pending action、tool args、approval status、idempotency keyを持ちます。
- 2Node
LLM判断、承認待ち、外部実行などの処理単位をgraphに置きます。
- 3Interrupt
副作用の直前で停止し、人間入力を待ちます。
- 4Checkpoint
threadごとのstateを保存し、再開や履歴確認に使います。
- 5Resume
承認結果を同じthreadへ戻し、次のnodeへ進みます。
外部APIを呼んだ後にinterruptすると、画面上は承認待ちでも外部世界では実行済みになり得ます。
LangGraphは、graph、state、node、edgeを使ってagent workflowを組み立てる発想が中心です。公式ドキュメントでは、persistenceによってgraph stateをcheckpointとして保存し、human-in-the-loop、memory、time travel、fault toleranceに使えると説明されています。
承認付きworkflowで見るべきキーワードは、State、checkpoint、thread_id、interrupt()、Command(resume=...)です。
Stateを承認可能な粒度で設計する
LangGraphでは、stateの設計が承認体験を大きく左右します。承認者が確認すべき情報がstateに入っていなければ、UI側で別のDBから寄せ集める必要があります。逆に、すべてを巨大なstateに詰め込むと、履歴確認や再開時の扱いが重くなります。
設計例
承認付きworkflowなら、例えば次のようなstate項目を検討します。
type ApprovalState = {
requestId: string;
userInput: string;
pendingAction?: {
type: "send_email" | "create_issue" | "update_db";
target: string;
args: Record<string, unknown>;
summary: string;
};
approvalStatus: "none" | "pending" | "approved" | "rejected" | "edited";
approvedBy?: string;
approvedAt?: string;
idempotencyKey?: string;
sideEffectStatus: "not_started" | "executed" | "failed";
externalResponseId?: string;
};
これは記事用の概念例であり、公式サンプルそのものではありません。重要なのは、承認画面に必要な情報、resumeに必要な情報、実行済み判定に必要な情報を分けて入れることです。
interruptは副作用の前に置く
LangGraphのinterruptは、graph実行を止め、人間入力を待ち、resumeで値を戻すための仕組みです。公式ドキュメントでは、checkpointer、thread ID、interrupt()、Command(resume=...)を使う流れが説明されています。interrupt時にはstateが保存され、同じthreadで再開します。
設計上の初期値は「副作用の直前でinterruptする」です。
注意点
// 概念例: 実際のAPI名や型は利用バージョンの公式Docsで確認してください
async function approvalNode(state: ApprovalState) {
const decision = interrupt({
question: "この操作を実行しますか",
action: state.pendingAction,
idempotencyKey: state.idempotencyKey,
});
if (!decision.approved) {
return { approvalStatus: "rejected" };
}
return {
approvalStatus: "approved",
approvedBy: decision.userId,
};
}
避けたいのは、外部APIを呼んだ後にinterruptする形です。画面上は「承認待ち」に見えても、外部サービスにはすでにメールが送られ、Issueが作られ、DBが更新されているかもしれません。承認は「やったことを見せる」ではなく、「これからやることを止める」ために置きます。
thread_idとcheckpointを運用ログに接続する
LangGraphのpersistenceでは、threadとcheckpointが重要です。承認UIや管理画面を作るなら、承認待ちレコードにgraphのthread IDやcheckpointの参照を持たせ、どの状態から再開するかを追えるようにします。
評価基準
最低限、承認画面から次を確認できるようにします。
| 確認項目 | 理由 |
|---|---|
| 対象ユーザー/依頼 | 承認対象の文脈を間違えないため |
| thread/runの識別子 | 再開対象を一意にするため |
| pending action | 実行予定の操作を確認するため |
| tool引数やpayload | 送信先や変更内容を固定するため |
| 前後のstate | 承認前後の差分を監査するため |
| 実行済み状態 | 二重実行を避けるため |
LangGraphがcheckpointを持っていても、業務上の承認ログまで自動で十分になるとは限りません。誰が、いつ、何を見て、何を承認したかは、アプリケーション側の監査ログとして設計します。
Mastraで設計する場合
| 項目 | 内容 | 見方 |
|---|---|---|
| Workflow suspend/resume | 申請、レビュー、送信前確認など、業務stepの節目で停止して外部入力で再開します。 | |
| Agent tool approval | agentがtoolを呼ぶ前に、tool名、引数、実行意図を確認して承認または却下します。 | |
| 業務判断 | この案件を次工程へ進めてよいかをworkflow承認として扱います。 | |
| 副作用判断 | このAPIをこの引数で呼んでよいかをtool承認として扱います。 |
workflow承認とtool承認を混ぜず、必要なら二段階承認として組み合わせます。
Mastraでは、workflowとagentを組み合わせてAIアプリケーションを作る発想が前面に出ています。承認付きworkflowでは、大きく2つの仕組みを分けて考えると整理しやすいです。
1つ目は、workflow stepを止めるsuspend/resumeです。申請、レビュー、承認、実行のような業務プロセスを止める用途に向きます。
2つ目は、agent approvalです。agentがtoolを呼ぶ前に、人間がtool名や引数を確認して承認または却下する用途に向きます。
Workflowのsuspend/resumeで業務プロセスを止める
Mastraのsuspend/resumeドキュメントでは、workflowを任意のstepで停止し、snapshotとして状態を保存し、後からresumeできる流れが説明されています。resumeDataを使って、承認結果や追加情報をstepへ戻せます。
向いている条件
業務フローとしては、次のような場面に合います。
| 場面 | suspend/resumeが向く理由 |
|---|---|
| 稟議/申請 | 承認待ち時間が長く、担当者や期限を管理したい |
| 文章レビュー | 人間が修正してから次stepへ進めたい |
| 顧客送信前確認 | 送信前にpayloadを固定して承認したい |
| 高コスト処理前確認 | 実行前にコストや対象件数を確認したい |
| 外部callback待ち | 他システムからのイベントで再開したい |
MastraはTypeScriptアプリと合わせやすいため、承認画面、API route、通知、DB保存と組み合わせる設計を考えやすいのが強みです。ただし、どのstorage providerにsnapshotを保存するか、承認者ロールをどこで見るか、期限切れをどう扱うかはアプリケーション設計として残ります。
Agent approvalでtool実行前に止める
Mastraのagent approvalドキュメントでは、toolにapprovalを要求し、tool callの実行前に承認または却下できる仕組みが説明されています。公式ドキュメントでは、破壊的操作、メール送信、支払い処理、高コストAPIなどを承認対象として挙げています。
これは「この業務案件を進めてよいか」よりも、「このtoolをこの引数で呼んでよいか」に向いた承認です。
表示する情報
| 承認対象 | 適した見せ方 |
|---|---|
| delete系tool | 対象ID、対象件数、復旧可否を表示する |
| email送信tool | 宛先、件名、本文、添付、送信理由を表示する |
| payment系tool | 金額、通貨、顧客ID、冪等性キーを表示する |
| GitHub作成tool | repo、branch、title、body、diffを表示する |
| 外部API POST | endpoint、method、payload、リスクを表示する |
agent approvalは便利ですが、これだけで承認運用が完成するわけではありません。承認依頼を誰に通知するか、承認期限をどう扱うか、複数承認者の競合をどう避けるか、却下理由をどう残すかは別途設計します。
Workflow承認とtool承認を混ぜない
Mastraで特に大事なのは、workflow承認とtool承認を混ぜないことです。
「この顧客対応案を次工程へ進めてよいか」はworkflow承認です。判断対象は業務プロセスです。
「このSlack通知をこのchannelへ送ってよいか」「このGitHub Issueをこの本文で作ってよいか」はtool承認です。判断対象は具体的な副作用です。
両方必要なケースもあります。例えば、AIがサポート返信案を作るworkflowでは、まず返信方針を承認し、最後にメール送信toolの宛先と本文を承認する二段階構成が安全です。
LangGraphとMastraの比較表
| 項目 | 内容 | 見方 |
|---|---|---|
| 状態保存 | LangGraphはcheckpoint、thread、state historyを見ます。Mastraはworkflow run、snapshot、storage providerを見ます。 | |
| 停止位置 | LangGraphはnodeやgraph stateの粒度、Mastraはworkflow stepやagent toolの粒度で考えます。 | |
| 承認UIとの接続 | thread ID、run ID、step ID、承認DBをどう紐づけるかを先に決めます。 | |
| 残る責務 | 承認者ロール、通知、期限、payload固定、監査ログ、冪等性はアプリ側の設計として残ります。 |
複雑なagent stateを細かく制御したい場合と、業務workflowとして承認stepを明示したい場合で検証観点が変わります。
| 論点 | LangGraphで見ること | Mastraで見ること | 採用判断 |
|---|---|---|---|
| 基本モデル | graph、state、node、edge | workflow、step、agent、tool | 複雑な状態遷移ならLangGraph寄り、業務stepを明示したいならMastra寄り |
| 停止方法 | interrupt()で止め、resumeで戻す | workflowのsuspend()、agent approvalで止める | 停止位置がnode中心かstep/tool中心かで選ぶ |
| 状態保存 | checkpointer、thread、checkpoint、state history | workflow run、snapshot、storage provider | 過去stateの追跡やdebug重視ならLangGraphを詳しく検証 |
| 再開識別子 | thread IDやcheckpoint文脈 | run IDやstep ID | 承認UIとどの識別子を紐づけるかを先に決める |
| tool実行前承認 | interruptをtool前nodeに置く設計 | agent approvalとして扱いやすい | toolごとの承認を主役にするならMastraが素直 |
| 業務承認 | graph内の承認nodeとして表現 | workflow stepのsuspend/resumeとして表現 | 稟議やレビュー工程はMastraのworkflow表現が読みやすい |
| 再実行時の安全性 | state設計、checkpoint、冪等性キーが重要 | snapshot、run state、冪等性キーが重要 | どちらでも外部副作用制御はアプリ側責務 |
| 監査ログ | state historyだけに頼らず業務ログを持つ | workflow stateだけに頼らず業務ログを持つ | 承認者、承認理由、payload固定を別DBに残す |
| TypeScript統合 | JS版もあるが、公式確認時点ではPython docsの情報も多い | TypeScriptアプリ向けに組み込みやすい | チームの主戦場がTSならMastraの検証価値が高い |
| PoCの見どころ | 複雑な分岐、interrupt、checkpoint復旧 | workflow承認、tool approval、UI接続 | 同一仕様で小さく実装して比べる |
状態保存と再開の違い
LangGraphでは、checkpointとthreadの設計をよく見ます。あるrunがどのstateで止まり、どのcheckpointから再開されるのかを追えるかが重要です。複雑なagent graphや分岐、過去状態のdebugを重視するなら、LangGraphのpersistence設計をPoCで深く見る価値があります。
Mastraでは、workflow runとstepのsuspend/resume、snapshotの扱いを見ます。業務プロセスとして「このstepで承認待ち」「このstepからresume」を表現しやすいか、アプリのDBやAPI routeと接続しやすいかが評価軸です。
承認粒度の違い
LangGraphはnodeやgraph stateの粒度で承認を置きやすい構成です。複数agent、複雑な分岐、途中stateの編集、再開後のroute制御を細かく持ちたい場合に向きます。
Mastraはworkflow stepとagent tool approvalを分けて考えやすい構成です。業務承認はworkflowで、危険なtool実行はagent approvalで、と分担しやすいのが魅力です。
実装者が抱える責務は残る
どちらを選んでも、次はframework任せにできません。
- 承認UI
- 承認者のロール管理
- 通知
- 承認期限
- payload固定
- 実行済みログ
- 冪等性キー
- 外部サービスのresponse ID保存
- 監査ログ
- 障害時の手動復旧
このリストが重く感じるなら、最初のPoCはscopeを小さくしてください。例えば「GitHub Issueを作る前に承認する」だけなら、承認対象、payload、実行済みログ、GitHub response IDを確認できます。いきなり顧客メール、DB更新、決済まで広げると、framework比較よりも運用設計が先に破綻します。
再実行時の副作用をどう防ぐか
| 項目 | 内容 | 見方 |
|---|---|---|
| メール送信 | 送信APIの直前で止め、宛先、件名、本文hash、message IDを保存します。 | |
| Slack通知 | postMessage前で止め、channel、本文hash、timestampを保存します。 | |
| DB更新 | transaction前で止め、record ID、変更前後、transaction IDを保存します。 | |
| 決済 | payment API前で止め、amount、customer ID、idempotency key、payment IDを保存します。 | |
| GitHub作成 | create API前で止め、repo、title、body hash、Issue/PR番号を保存します。 | |
| 外部API POST | POST前で止め、endpoint、payload hash、external IDを保存します。 |
resumeできることと、副作用を二重実行しないことは別の設計課題です。
承認付きworkflowの実務リスクは、承認UIの実装よりも副作用の二重実行にあります。
| 副作用 | 危険 | 止める位置 | 保存するログ |
|---|---|---|---|
| メール送信 | 同じ顧客へ重複送信 | 送信APIの直前 | 宛先、件名、本文hash、message ID |
| Slack通知 | 同じ通知が連投される | postMessage前 | channel、本文hash、timestamp |
| DB更新 | 更新済みデータを再更新 | transaction前 | record ID、変更前後、transaction ID |
| 決済 | 二重課金 | payment API前 | amount、customer ID、idempotency key、payment ID |
| GitHub Issue/PR作成 | 重複Issue/PR | create API前 | repo、title、body hash、issue/PR番号 |
| 外部API POST | 相手システムに重複登録 | POST前 | endpoint、payload hash、external ID |
副作用前承認を原則にする
承認は、外部世界に影響が出る前に置きます。AIがtool引数を作った後、実行前に止めるのが基本です。
注意点
「承認画面で見た内容」と「実際に送った内容」を一致させるために、承認対象のpayloadを保存します。承認後にLLMへもう一度payloadを作らせる場合は、人間が承認した内容と実行内容が変わる可能性を明記し、再承認を挟むのが安全です。
冪等性キーと実行済みログを持つ
resume、worker再起動、ブラウザ再送信、queue retryでは、同じ処理が再度呼ばれる可能性があります。frameworkがstateを復旧できても、外部サービス側の副作用までは完全に守ってくれません。
保存するキー
少なくとも次のようなキーを保存します。
type SideEffectLog = {
workflowRunId: string;
stepId: string;
actionId: string;
idempotencyKey: string;
approvalId: string;
payloadHash: string;
status: "planned" | "executing" | "executed" | "failed";
externalResponseId?: string;
executedAt?: string;
};
外部サービスがidempotency keyを受け付けるなら使います。受け付けない場合でも、自分のDBに実行済みログを持ち、同じactionIdやpayloadHashでは二度実行しないようにします。
LLM再推論とresumeを分ける
承認後にLLMへ再推論させると、承認時に人間が見た内容と実行内容が変わる可能性があります。特にメール本文、SQL、API payload、GitHub PR本文、決済金額などは危険です。
基本は、承認画面で見せたpayloadを固定し、そのpayloadを実行します。修正が必要なら、人間がpayloadを編集してeditedとして承認するか、needs_revisionとしてAIに再提案させ、その後もう一度承認します。
実装前チェックリスト
| 項目 | 内容 | 見方 |
|---|---|---|
| 状態 | 承認待ちrun、step、payload、状態履歴を永続化できているか確認します。 | |
| 承認 | tool名、引数、送信先、LLMの理由、リスクを承認者が確認できるか見ます。 | |
| 再開 | 承認、却下、修正、差し戻しを同じrunへ戻せるか確認します。 | |
| 副作用 | 外部操作の直前で止め、冪等性キーと実行済みログを持っているか見ます。 | |
| 監査 | 誰が、いつ、何を見て、どのpayloadを承認したか追えるようにします。 | |
| UI/通知 | 承認依頼、期限切れ、却下理由、再通知を運用できるか確認します。 | |
| 失敗時復旧 | サーバー再起動、worker停止、中途半端な失敗から調査と手動復旧ができるか見ます。 |
PoCでは「承認できた」ではなく、止まり、戻り、拒否でき、二重実行しないことを確認します。
状態保存
| チェック | OKの目安 |
|---|---|
| 承認待ちrunを一意に識別できる | workflow_run_idやthread/run IDで再開対象を特定できる |
| 承認対象payloadを保存している | UIで見た内容と実行内容が一致する |
| 状態履歴を追える | 承認前、承認後、実行後の状態を確認できる |
| サーバー再起動後も再開できる | in-memoryだけに依存していない |
承認UI
| チェック | OKの目安 |
|---|---|
| tool名と引数が見える | 何を実行するか判断できる |
| 送信先と対象IDが見える | 誤送信や誤更新を避けられる |
| LLMの理由が見える | なぜ提案されたか確認できる |
| 承認、却下、修正、差し戻しを扱える | 実運用の判断に対応できる |
| 承認者と時刻が残る | 後から監査できる |
副作用
| チェック | OKの目安 |
|---|---|
| 外部操作の直前で止めている | 承認前に実行されない |
| idempotency keyがある | retryやresumeで二重実行しない |
| 実行済みログがある | 外部レスポンスIDを追える |
| 失敗時に手動復旧できる | 中途半端な状態を調査できる |
セキュリティとコスト
承認付きworkflowは、権限とコストの境界も明示する必要があります。
- read-only toolから始める
- write toolはtool単位で承認を要求する
- 秘密情報、APIキー、個人情報、非公開リポジトリ情報を承認画面やログへ不用意に出さない
- 外部API送信前にpayloadを確認する
- 高コストAPIや大量処理は対象件数と見積もりを表示する
- 承認ログは長期保存してよい情報だけに絞る
- LLMに送る情報と、社内DBに残す情報を分ける
特に社内コードや秘密情報を扱う場合、承認ログそのものが機密データになります。ログを便利にしすぎると、別の情報漏えいリスクが生まれます。
どちらを選ぶか
| 項目 | 内容 | 見方 |
|---|---|---|
| LangGraph寄り | 複雑な分岐、loop、node単位のinterrupt、checkpoint、state historyを重視する場合に検証価値があります。 | |
| Mastra寄り | TypeScriptアプリで申請、承認、実行の業務stepとagent tool approvalを分けたい場合に検証価値があります。 | |
| どちらでも必須 | 承認前停止、承認後再開、却下、修正、サーバー再起動、retry、監査を同じ仕様で試します。 | |
| 追加検証 | UI接続、storage、監査ログ、外部サービスの冪等性対応は自社要件で確認します。 |
どちらが絶対に優れているかではなく、止めたい粒度と運用したい承認プロセスで選びます。
LangGraphが向きやすいケース
次の条件が多いなら、LangGraphを優先候補としてPoCする価値があります。
- agent stateが複雑
- 分岐やloopが多い
- nodeごとにinterruptを入れたい
- checkpointやstate historyを使ってdebugしたい
- graphの途中状態を人間が編集して再開したい
- PythonエコシステムやLangChain/LangSmith周辺と合わせたい
LangGraphを選ぶ場合は、最初にstate schemaとcheckpointの見方を決めます。承認UIからどのthreadをresumeするか、どのstateを表示するか、どの外部操作が実行済みかを追えることが採用判断の核になります。
Mastraが向きやすいケース
次の条件が多いなら、Mastraを優先候補としてPoCする価値があります。
- TypeScriptアプリにworkflowを組み込みたい
- 申請、承認、実行の業務stepを明示したい
- workflow承認とtool承認を分けたい
- agentがtoolを呼ぶ前のapprovalを扱いたい
- UI、API route、通知、storageを同じTSスタックでまとめたい
- workflowの見通しをチームで共有したい
Mastraを選ぶ場合は、workflowのsuspend/resumeとagent approvalをどちらに置くかを最初に決めます。業務判断をworkflowで止め、危険な外部操作をagent approvalで止める二段階設計が、実務では扱いやすい出発点です。
どちらでも必ずPoCするシナリオ
机上比較だけで採用を決めるのは危険です。最低限、同じ仕様で次の7ケースを試します。
| ケース | 確認すること |
|---|---|
| 承認前停止 | 外部操作前に確実に止まるか |
| 承認後再開 | 同じrun/threadから続けられるか |
| 却下 | 外部操作をせず終了できるか |
| 修正して承認 | payloadを変更して実行できるか |
| サーバー再起動 | 永続化された状態から再開できるか |
| retry | 同じ副作用を二重実行しないか |
| 監査 | 誰が何を見て承認したか追えるか |
PoC結果は、検証・ベンチマークに置ける粒度で残すと後から比較しやすくなります。採用候補が増えた場合は、比較表の観点に合わせて、状態保存、承認粒度、副作用制御、コスト、運用負荷を並べると判断がぶれにくくなります。
失敗点とハマりどころ
副作用の後に止めると起きます。外部操作の前に止め、保存済みpayloadだけを実行します。
framework側のrunと承認DBのstatusを同期し、再同期できる管理手段を用意します。
tool名、引数、送信先、payload、LLMの理由、リスク、復旧可否を表示します。
payload hash、要約、識別子を中心にし、詳細payloadの保存範囲と閲覧権限を絞ります。
承認画面はAIの出力を信じるためではなく、AIの提案を人間が検査するために置きます。
承認待ちに見えて実行済み
最も避けたい失敗は、UIでは承認待ちなのに外部操作がすでに終わっている状態です。これは承認ポイントを副作用の後に置いた時に起きます。
対策は単純で、外部操作の前に止めます。承認対象payloadを保存し、承認後は保存済みpayloadだけを実行します。
stateとDBの二重管理がずれる
framework側のstateと、アプリ側の承認DBがずれることがあります。例えば、frameworkはrunを再開済みなのに、DB上はpendingのまま残るケースです。
対策として、承認DBにstatus、workflow_run_id、step_id、executed_at、external_response_idを持ち、workflow側の進行と同期させます。異常時に再同期できる管理コマンドも用意しておくと安心です。
承認画面に情報が足りない
承認者が「実行しますか」だけ見せられても判断できません。tool名、引数、送信先、payload、LLMの理由、リスク、実行後に戻せるかを表示します。
承認画面は、AIの出力を信じるための画面ではなく、AIの提案を人間が検査するための画面です。
ログが機密情報の置き場になる
便利な監査ログを作ろうとして、APIキー、個人情報、顧客情報、非公開コードを丸ごと保存してしまうのも危険です。
ログには、必要な識別子、payload hash、要約、承認者、承認時刻、外部response IDを保存し、本文や秘密情報は保存範囲を絞ります。詳細payloadを残す場合は、保存期間、閲覧権限、マスキング、削除手順を決めます。
実務で使うなら
- 1. read-only
情報収集だけを行い、AIが外部操作しない状態から始めます。
- 2. 手動実行
AIがaction候補を作り、人間が内容を見て手動で実行します。
- 3. 低リスクwrite
承認付きで低リスクなwrite toolを1つだけ実行します。
- 4. 実行ログ確認
idempotency key、実行済みログ、外部response IDを確認します。
- 5. 運用整備
承認UI、通知、期限切れ、却下理由、監査ログを整えます。
- 6. 対象拡大
止まる場所、戻る場所、追えるログを確認しながらtoolを増やします。
成熟度はできることの多さではなく、止まるべき場所で止まり、実行したことを追えるかで見ます。
最初の導入は、影響の小さいread-onlyまたは低リスクなwrite操作から始めます。
おすすめの順序は次の通りです。
- read-only toolで情報収集だけを行う
- AIがaction候補を作るが、実行は人間が手動で行う
- 承認付きで低リスクなwrite toolを1つだけ実行する
- idempotency keyと実行済みログを確認する
- 承認UI、通知、期限切れ、却下理由を整える
- 対象toolを増やす
AIエージェントは、うまく動くと一気に自動化範囲を広げたくなります。ただ、承認付きworkflowの成熟度は「できることの多さ」ではなく、「止まるべき場所で止まり、戻るべき場所へ戻り、実行したことを追えるか」で見た方が安全です。
法人導入やチーム運用では、権限設計、監査ログ、MCP/tool権限、承認者ロールのレビューが必要になります。具体的な導入相談や誤り指摘は、お問い合わせから送れます。
まとめ
承認対象、再開識別子、承認者、承認結果、実行済み判定を残します。
メール送信、DB更新、決済、GitHub操作、外部API POSTの直前で止めます。
承認、却下、修正、差し戻しをrunへ戻す方法を明確にします。
冪等性キー、payload hash、実行済みログで二重実行を避けます。
誰が、いつ、何を見て、どのpayloadを承認したか追えるようにします。
LangGraphでもMastraでも、承認UI、権限、通知、監査ログ、冪等性はアプリケーション側の設計として残ります。
LangGraphとMastraは、どちらも承認付きAIワークフローの候補になります。ただし、選定の出発点はframework名ではありません。
先に決めるのは、保存する状態、止める位置、再開方法、副作用の防ぎ方、監査ログです。
LangGraphは、複雑なagent graph、checkpoint、interrupt、state historyを使って細かい状態遷移を制御したい場合に検証価値があります。Mastraは、workflow stepとして業務承認を表現し、agent tool approvalと組み合わせたいTypeScriptアプリで検証価値があります。
どちらを選んでも、承認UI、権限、通知、監査ログ、冪等性はアプリケーション側の設計として残ります。PoCでは「承認できた」だけで終わらせず、却下、修正、再開、サーバー再起動、retry、二重実行防止まで確認してください。
仕様更新や実装検証の続報を追いたい場合は、ニュースレターで更新通知を受け取れます。
次に読むなら
参照した主な情報源
- https://docs.langchain.com/oss/python/langgraph/overview
- https://docs.langchain.com/oss/python/langgraph/persistence
- https://docs.langchain.com/oss/python/langgraph/interrupts
- https://mastra.ai/ai-workflows
- https://mastra.ai/docs/workflows/suspend-and-resume
- https://mastra.ai/docs/agents/agent-approval
- https://mastra.ai/blog/hitl-where-to-put-approval-in-agents-and-workflows
更新履歴
- 2026-05-31
LangGraph 1.3.2、Mastra core 1.37.1のnpm公開メタデータと公式ドキュメントを確認して初版を作成しました。
AI開発基盤は更新が速いため、確認日と対象バージョンを記事内に残します。
| 日付 | 内容 |
|---|---|
| 2026-05-31 | 初版。LangGraph 1.3.2、Mastra core 1.37.1のnpm公開メタデータと公式ドキュメントを確認して作成。 |
