「200 OK」を合格にしない、AIエージェントのツール契約テスト
AIエージェントへ社内APIを渡す開発責任者は、「呼べた」ではなく「正しい条件で、重複なく、完了を確認できた」まで試す必要があります。本稿では、一つの書き込みツールを本番へ出すための契約テンプレートとテストを作ります。
ツールの説明文を仕様にしない
説明文が丁寧でも、実行側は入力、権限、再試行、成功の証拠、回復方法を保証する必要があります。
HTTPの200 OKはリクエストが成功したことを示しますが、POSTの応答内容は処理結果または適用後の状態を表し得ます。[1] したがって、通信成功だけを「発注完了」や「返金完了」とみなさず、業務上の後条件を別に定義します。
OpenAIも、戻り値とエラー動作を定義し、可能なら冪等にし、引数・権限をアプリ側で確認するよう案内しています。[2] 冪等とは、同じ要求を再送しても副作用が重複しない性質です。
コピーできるツール契約
所有者はAPIと業務ルールを管理する開発者です。業務責任者が成功・禁止条件を確認します。
tool_contract:
name: create_purchase_order
owner: procurement-platform
input:
required: [supplier_id, item_id, quantity, request_id]
additional_properties: false
authorization:
actor_scope: procurement-write
supplier_must_be_approved: true
side_effect: purchase_order_created
idempotency_key: request_id
success_evidence: [purchase_order_id, status]
success_when: status == "created"
ambiguous_failure: reconcile_then_stop
approval_required_when: amount_exceeds_internal_limit
JSON Schemaでは、requiredで必須項目を指定し、additionalProperties: falseで宣言外の項目を拒否できます。[3]
契約には次の五点を必ず入れます。
- 前条件:誰が、どの対象へ、どの権限で実行できるか
- 入力境界:必須、型、列挙値、上限、追加項目の扱い
- 副作用:どの外部状態が変わるか
- 完了証拠:IDと状態をどこから取得するか
- 再試行規則:重複防止キーと、結果不明時の照合先
六つの契約テストを通す
実APIまたは副作用を再現する環境で、次を自動化します。
| テスト | 入力・状況 | 合格条件 |
|---|---|---|
| 正常系 | 承認済み仕入先、正しい権限 | PO IDとcreatedを返す |
| 余分な項目 | 未定義のbank_accountを追加 | 実行前に拒否する |
| 権限違反 | 読み取り専用主体 | APIを呼ばず拒否する |
| 重複実行 | 同じrequest_idを二回送る | POは一件、同じIDを返す |
| 曖昧な失敗 | 作成後に応答をtimeoutさせる | 照合してから停止し、再作成しない |
| 後条件不成立 | HTTP 200、status: rejected | 成功扱いせず例外キューへ送る |
OWASPは、高影響の操作で判断と実行を分け、承認を主体・ツール・対象・引数・時刻・期限へ結び付け、可能なら冪等にするよう推奨しています。[4] 実行側がこの制約を強制するかを試します。
発注ツールで試す
たとえば、エージェントが在庫不足を見て発注案を作る場面を考えます。モデルはquantity: 20とrequest_id: restock-481を提案し、人が金額と仕入先を承認します。実行側は承認済み仕入先、権限、数量上限を独立して検証してからAPIを呼びます。
APIが処理後にtimeoutした場合、同じ要求をすぐ作り直してはいけません。まずrequest_idで発注先を照会します。既存POがあればそのIDを採用し、なければ同じキーで再送します。結果を照合できないときはunknownとして止め、人へ渡します。
完了条件は、六テストが通り、失敗時にsuccess / rejected / unknownのいずれかへ必ず分類され、unknownが自動再試行されないことです。
よくある失敗と適用境界
- 型検証だけで終える:正しいJSONでも、権限外の操作は防げません。
- 例外を文章で返す:後段が成功と誤読します。エラーコードと再試行可否を固定します。
- timeoutを失敗と決める:処理済みなら重複が起きます。先に業務状態を照合します。
- approval済みだけを見る:対象や引数が承認時から変わっていないか照合します。
副作用がなく、公開情報を読むだけの低リスクツールすべてに同じ重い契約テストを課すという場合には向きません。その場合も入力schemaとエラー分類は残し、書き込み・外部送信・金銭・権限変更を伴うツールから厳格化します。
明日から使える実装チェックリスト
- [ ] 一つの書き込みツールを選んだ
- [ ] 前条件、入力、副作用、完了証拠を契約へ書いた
- [ ] 宣言外の入力を拒否する
- [ ] 実行側で権限と承認内容を再確認する
- [ ] 重複防止キーがある
- [ ] timeout後の照合APIがある
- [ ] HTTP成功と業務成功を分けた
- [ ]
unknownを自動再試行しない - [ ] 六つのテストをリリース条件にした
まず最も危険なツール一つで契約を書き、timeout後の重複テストを実行してください。ここで二件作成されるなら、モデルを改善する前にツール境界を直す必要があります。
参考資料
- RFC 9110: HTTP Semantics
- OpenAI API: Programmatic Tool Calling
- JSON Schema: Object
- OWASP Cheat Sheet Series: AI Agent Security
本記事はAIを活用して作成し、公開前に自動レビューを実施しています。情報の確認日:2026-10-04。
著者
ELYSAI編集部