AIエージェント向けAPIを設計して分かった「自由にさせるための制約」
AIエージェントにソフトウェアを操作させるとき、どこまで専用機能を用意すべきでしょうか。
自然言語による操作画面、AI専用のAPI、MCPサーバー、用途ごとのツール。いろいろな方法が考えられます。
一方、私が開発しているデジタルサイネージ「Glypha」では、AIエージェント専用のインターフェースを用意していません。あるのは、人間も利用できるHTTP APIだけです。
Human
│ 目的を伝える
▼
AI Agent
│ コンテンツを制作してHTTP APIで送信
▼
Glypha
│ 検証
├─ 適合 → 描画
└─ 不適合 → 拒否
この単純な構造で実験してみると、AIエージェント向けソフトウェアでは、機能を増やすこと以上に「何を受け入れるか」を設計することが重要だと分かってきました。
この記事では、Glyphaの実験から得たAPI設計上の気づきを整理します。
Glyphaが提供するもの
Glyphaは、テキストと画像を表示するデジタルサイネージです。
管理画面、テンプレート選択、レイアウト編集といった一般的な機能はありません。罫線や矩形を描画する専用機能もありません。
コンテンツはHTTP APIに送信します。専用CLIはなく、例えば curl から次のように操作できます。
curl --fail-with-body -X PUT http://localhost:8080/content \
-F 'content=@content.json;type=application/json' \
-F 'assets=@logo.png'
この例では、表示内容を記述した content.json と、表示に使用する logo.png をmultipart/form-dataとして送信しています。
ただし、受け取ったデータをそのまま表示するわけではありません。
Glyphaはメッセージの構造と制約を検証し、描画可能かどうかを判定します。適合するメッセージだけを描画し、不適合なら拒否します。
Glyphaの機能は少ない一方、受け入れ条件は曖昧ではありません。
気づき1:AIに自由を与えるなら、境界は厳格にする
「AIエージェントに自由に作らせる」というと、入力も柔軟に受け入れる設計を想像するかもしれません。
しかし、実際には逆でした。
AIエージェントは、情報収集、文章作成、画像加工、プログラム作成など、Glyphaの外側では自由に手段を選べます。一方、Glyphaへ渡す最終成果物は、定められた構造と制約を満たさなければなりません。
自由に任せる領域
├─ 情報をどこから得るか
├─ 文章をどう作るか
├─ 画像をどう加工するか
└─ 必要な道具をどう用意するか
システムが保証する領域
├─ メッセージの構造
├─ 各要素の制約
├─ 描画可能性
└─ 不適合な入力の拒否
AIの途中経過を細かく制御するのではなく、システムとの境界で成果物を検証する構造です。
外側のやり方を固定しないから、AIエージェントは状況に応じて工夫できます。内側の条件を固定するから、Glyphaが保証すべき範囲は変わりません。
AIの自由度と、システムの厳格さは対立しません。厳格な境界があるから、その外側を自由にできます。
気づき2:「AIに分かりやすいAPI」より先に、失敗を明確にする
AIエージェント向けAPIでは、成功するリクエストの作りやすさに目が向きがちです。
もちろん、単純なHTTP APIや明確な仕様は重要です。しかし、それと同じくらい重要なのが、受け入れられない入力を曖昧に処理しないことです。
例えば、不正なメッセージを可能な範囲で描画してしまうと、AIエージェントから見た結果は不安定になります。
- 一部だけ無視されたのか
- 値が自動補正されたのか
- 描画エンジンの都合で見えないのか
- リクエスト自体が間違っているのか
これらを外側から区別しにくくなるためです。
Glyphaでは、契約を満たさないメッセージは拒否します。curl の例に --fail-with-body を付けているのも、HTTPエラーを成功として扱わず、レスポンス本文を確認できるようにするためです。
AIエージェントが試行錯誤する前提なら、失敗を隠して「それらしく動く」ことよりも、失敗した事実が明確であることに価値があります。
設計時には、少なくとも次の点を明確にしておく必要があります。
- 何を必須とするか
- どの値を許可するか
- 複数要素の組み合わせにどのような制約があるか
- どの条件なら描画可能と判断するか
- 不適合時にどのように失敗を返すか
気づき3:用途別の機能を増やさなくても、用途は増やせる
GlyphaをClaude Codeに操作させたところ、想定していなかった方法でコンテンツを作り始めました。
罫線を画像として作った
Glyphaには罫線を描く機能がありません。
Claude Codeは、罫線を含む画像を作り、その画像を表示要素として使いました。Glyphaに新しい描画機能を追加するのではなく、既存の「画像を表示する」という能力に変換したわけです。
必要な画像加工プログラムをGoで書いた
素材画像をGlyphaの仕様に合わせて加工する必要があったものの、適切な画像編集手段がない場面がありました。
するとClaude Codeは、Goで画像加工プログラムを作成し、それを実行して画像を用意しました。
Glyphaには画像編集機能がありません。Goでプログラムを書くよう指示したわけでもありません。AIエージェントが、成果物を契約に適合させるための道具を外側で作りました。
URLから表示コンテンツを作った
WebページのURLを渡してコンテンツ制作を依頼すると、Claude Codeはページから情報を取得し、内容を整理し、Glyphaが受け入れられる形式へ変換しました。
GlyphaにはWebページの取得機能も、URLからコンテンツを生成する機能もありません。
それでも、AIエージェントが外側で処理を行うことで、新しい用途を実現できました。
この3例に共通するのは、目的を達成するためにGlyphaの機能を増やしていないことです。
罫線が必要
→ 罫線描画APIを追加するのではなく、画像へ変換
画像加工が必要
→ Glyphaへ編集機能を追加するのではなく、外部で加工
URLから作りたい
→ URL解析機能を追加するのではなく、外部で情報を変換
ソフトウェアが持つ機能と、そのソフトウェアを使って実現できることは一致しないということです。
AIエージェントが外部で利用できる能力を組み合わせれば、システム本体の責任範囲を広げずに、用途だけを増やせる場合があります。
「便利なAPI」ではなく「小さく安定した契約」を作る
従来のAPI設計では、利用者のユースケースを列挙し、それぞれに必要な操作を追加していくことがあります。
AIエージェントが利用する場合も、用途ごとのAPIを作る方法はあります。しかし、用途を先回りして機能を増やし続ける必要があるのかは、考え直す余地があります。
Glyphaでは、用途ではなく、サイネージとして最低限保証する能力をAPIの境界にしました。
- テキストと画像を受け取る
- メッセージが制約を満たすか検証する
- 描画可能なものだけを描画する
- 不適合なものは拒否する
観光案内、ホテルの案内、イベント告知といった用途は、GlyphaのAPIには現れません。それらはAIエージェントが作るコンテンツ側の関心事です。
この分離には、次の利点があります。
システム本体の責任が増えにくい
URL取得や画像編集などを本体へ追加すると、対応形式、セキュリティ、障害処理、依存ライブラリなど、保守すべき範囲も増えます。
外部のAIエージェントに任せられる処理を分離すれば、Glyphaは表示と検証に集中できます。
AIエージェントを交換しやすい
GlyphaはClaude専用の処理を持っていません。HTTP APIの契約を満たせるなら、別のAIエージェントでも、人間が作ったクライアントでも利用できます。
新しい用途をAPI変更なしで試せる
新しい用途が、既存のテキストと画像で表現できるなら、Glyphaを変更せずに試せます。
制約は人間が決め、実現方法はAIに任せる
Glyphaの開発では、Alloyを使って構造と制約をモデル化しました。AIに実装を任せる際にもこのモデルを利用し、生成されたテストコードにはモデルで定義した条件が反映されていました。
ここでも、Glyphaを利用するときと同じ構造が現れました。
人間が決める
└─ 守るべき性質、構造、制約
AIに任せる
└─ 具体的な設計判断、実装、制作手順
AIへ細かな手順をすべて指示する代わりに、変えてはいけない条件を明確にする方法です。
AIエージェントが何をするかを完全に予測することは困難です。だからこそ、途中の全行動を列挙して制御しようとするより、システムへ入る時点で満たすべき契約を設計する方が扱いやすい場合があります。
AIエージェント向けAPIを考えるときのチェック項目
Glyphaの実験を一般化すると、AIエージェントが利用するAPIを設計するときには、次の点を検討できそうです。
1. AI専用インターフェースは本当に必要か
既存のHTTP APIが単純で、仕様が明確なら、そのまま利用できる可能性があります。AI専用の層を追加する前に、既存のインターフェースで不足する情報が何かを確認します。
2. システムが保証する最小の能力は何か
用途を列挙するのではなく、システムが責任を持つ範囲を決めます。
3. 入力の契約を機械的に判定できるか
構造だけでなく、要素間の制約や、実際に処理可能かどうかも判定対象になります。
4. 不適合な入力を明確に拒否できるか
暗黙の補正や部分的な成功は、AIエージェントの試行錯誤を難しくする可能性があります。
5. 本体へ追加しようとしている機能は、外側で変換できないか
画像加工、データ取得、形式変換などは、AIエージェントが外部で行い、結果だけを既存の契約に合わせられるかもしれません。
6. 特定のAI製品へ依存していないか
AIエージェントではなく、契約に依存する設計にしておけば、利用するモデルやツールが変わってもシステム本体を維持しやすくなります。
おわりに
Glyphaの実験から得た一番大きな気づきは、AIエージェントに自由に仕事をさせることと、システムの制約を弱くすることは別だということです。
外側では、AIエージェントが情報を集め、画像を加工し、ときには必要なプログラムまで作る。
内側では、システムがメッセージを厳格に検証し、契約に適合するものだけを受け入れる。
この責任分界があれば、システム本体を小さく保ちながら、AIエージェントの能力によって用途を広げられます。
AIエージェント向けソフトウェアで最初に設計すべきものは、豊富な機能一覧ではなく、小さく、明確で、失敗も含めて予測可能な契約なのかもしれません。