※「ChatGPTと育てる、自分専用AI基盤」Season 1 第11回です。
前回は、開発のたびに私が「承認します」と返し続ける状態をやめるため、Standing Delegationを作った話を書きました。
→ 第10回:AI開発のたびに「承認します」と打つのをやめた
安全で可逆なroutine作業は、既存のguardが通る限りAI側で続ける。本当に人間にしか決められない境界でだけ止まる。
これで承認回数はかなり減りました。でも、ゼロにはなりません。
秘密情報、production、不可逆操作、権限境界、重要なsemantic apply。そういう場所では、やはり人間の意思が必要です。
そして、その境界へ来るたびにChatGPTから長めの確認文が出て、私は内容を見て「承認します」あるいは「PR #xxx の standard merge を承認します」と返します。
前回よりずっとましです。でも、ここまでシステムを作ったなら、もう少し使いやすくできそうでした。
ボタンでよくない?
そこでChatGPT上に「承認」「拒否」「更新」を出すInteractive Control UIを作りました。
ただし、ここで一つだけ絶対にやらないと決めたことがあります。
ボタンに権限を持たせないことです。
- 欲しかったのは管理画面ではなく、意思決定の入力面だった
- 最初のカードはKnowledge MCPのproduction deployだった
- ボタンを押した瞬間にdeployしてはいけない
- Approval Action Packetに、承認対象を閉じ込める
- 15分前のカードでも、現在状態をもう一度見る
- 「UIはAuthorityではない」を仕組みにした
- 最初は、ボタンがChatGPTに出なかった
- 「開発を続けて」ボタンも作った
- UIの裏側ではAuthorityをさらに固めていた
- 人間を消すのではなく、人間の仕事を変えたかった
- Season 1で最後に作ったのは、AIの機能ではなく人間との境界だった
- Season 1 Finale
- 連載ナビ
欲しかったのは管理画面ではなく、意思決定の入力面だった
AI基盤を作っていると、つい管理画面を作りたくなります。Run一覧、Workspace一覧、PR一覧、Worker状態。大きなダッシュボードを作れば、何となく完成度が上がったようにも見えます。
でも、今回欲しかったのはそれではありませんでした。
人間が本当に判断しなければならない時に、何を承認しようとしているのか、現在どの状態なのか、拒否するのか、最新状態をもう一度見るのかを、Chatの文章より少し分かりやすく入力できればいい。
そのためInteractive Control UIは、最初から大きな管理画面ではなく小さなApproval Cardとして作りました。
最初のカードはKnowledge MCPのproduction deployだった
最初の実用対象に選んだのは、Knowledge MCPのproduction deployです。
理由は単純で、すでに境界が明確だったからです。現在versionがある。target versionがある。Gitのexact SHAがある。candidateやrollbackの考え方がある。deploy後にhealthを確認できる。
つまり「何を承認するのか」を一つのpacketとして固定しやすい。
カードには、現在version→target version、ready/blocked、main SHA、approval packet SHA、承認、拒否、更新を持たせました。
見た目としてはかなり普通の承認カードです。でも中身は、単なるボタンではありません。
ボタンを押した瞬間にdeployしてはいけない
もし実装を単純にするなら、承認ボタン→deploy()で終わります。
でも、これはやりませんでした。
カードを表示してからボタンを押すまでの間に、状態が変わる可能性があるからです。mainが進んだかもしれない。別のworkspaceが動き始めたかもしれない。Runner jobが走っているかもしれない。target versionがすでにdeploy済みかもしれない。
表示した時点では安全でも、押した時点では古いかもしれません。
第4回からずっと出てきた問題です。
「さっき見た状態」と「今から変える状態」は同じとは限らない。
だから、ボタンはdeploy命令ではなく、「この内容を承認する」というOwner intentだけを返すようにしました。
Approval Action Packetに、承認対象を閉じ込める
UI-0で作った中心がApprovalActionPacketでした。
packetには、必要に応じてaction ID、action type、target service/resource、exact target version/SHA、expected current state、risk/approval class、expiry、idempotency key、replay protection、rollback readiness、verification expectationsを持たせます。
カードの「承認」は、このpacketに結びついています。
つまり「何かを承認した」ではありません。
「このaction IDで、このtarget SHAで、この状態を前提にした、この操作を承認した」です。
状態が変われば、その承認は古くなります。
15分前のカードでも、現在状態をもう一度見る
初期実装ではpacketに15分のfreshness boundaryを持たせました。ただし15分以内なら無条件で安全という意味でもありません。
execution前にはサーバー側で、HEADとorigin/main、repository clean、active workspace、git-main lease、Runner job/mutation、target source versionなどを再確認します。
さらにKnowledge MCPの実runtime versionは、UI packetの情報を信用せず、実行直前に別経路で読み直す前提にしました。
実際、runtime revalidation toolの返り値は明示的にexecution_authorized=falseでした。
UI側の再検証が通っただけでは、まだ実行権限にはならない。これはかなり意図的です。
「UIはAuthorityではない」を仕組みにした
今回の設計を一言で言うと、こうです。
UI
→ Ownerの意思を入力する
Authority / Policy / Live State
→ その操作を今実行してよいか決める
Executor
→ 実際に実行する
UIは一番上の入力面です。安全性の本体ではありません。
ボタンの色が緑でも、server-sideでstaleなら止まる。「承認」と表示されていても、scopeが変わっていれば止まる。二回押されても、idempotency / replay protectionで同じmutationを二重実行しない。UIが壊れても、普通のChatによる承認へ戻れる。
つまり、便利なUIを追加しても、それを信頼境界にはしませんでした。
最初は、ボタンがChatGPTに出なかった
こういう話を書くと、きれいに一発で動いたように見えます。実際は、また普通に詰まりました。
Development MCPへ新しいUI toolsを追加し、runtime側では61 toolsが登録されていました。ところが、その時開いていたChatGPTのconnector schemaは古い58-tool surfaceをcacheしたままでした。
サーバーにはある。テストも通っている。runtime registrationも確認できる。でも、このChatからは新しいrendererが見えない。
こういう時、以前なら「たぶん呼べるはず」と無理に進めたくなります。でも今回は、見えていないtoolをあることにして呼びませんでした。
ボタンをfakeしない。
普通の文章承認は残っているのでfallbackで進める。connectorがrefreshされた時に本物をdogfoodする。
この判断も、Season 1で何度も繰り返してきた「現実の状態を優先する」の延長でした。
「開発を続けて」ボタンも作った
Approval Cardを作ったあと、もっと日常的に便利なボタンも欲しくなりました。
それが、「開発を続けて」です。
長い開発では、safe checkpointでChatGPTが止まり、私は次のターンで「開発を続けて」と送ることがよくあります。だったら、これもボタンでいい。
そこで開発を続けてカードを追加しました。
ここでもボタンには実行権限を持たせていません。押すとChatGPTへ固定文開発を続けて。を送るだけです。
その後、ChatGPTが現在のlive stateを読み、Standing DelegationとAuthorityの範囲で何を続けるかを判断します。
そしてこのボタンは、connector refresh後に実際にdogfoodできました。UIからChatへ開発を続けて。が入り、そのまま既存の開発フローへ戻る。
小さい機能ですが、使ってみるとかなり楽でした。
UIの裏側ではAuthorityをさらに固めていた
ちょうどこの頃、UIとは別にAuthority Layerも強くしていました。
CapabilityをA0/A1/A2/A3へ分類し、未知のCapabilityはfail closedでA3側へ倒します。
実際のdogfoodでは、A1のlocal/reversibleなsandbox.pythonはOwner interventionなしで成功しました。
一方、A3のprotected actionでは、exact target、action ID、contract SHA、Run ID、replay fingerprintまで束ねたOwner decision packetを作り、承認されない限りaction countすら増やさず止めています。
A2のbounded external actionについては、productionでは0のまま、in-memory rehearsalだけで、scope外、stale、rate超過、cost超過、prior cost evidence不足、global kill switch OFFがすべてhard denyになることを確認しました。
さらにprovider、channel、brand、project単位のexecution revocationも追加しました。
ここまでやって、Authority Layerは「AIができることを増やす層」ではなく、できることを狭める層として完成しました。
これはUIと相性がよかったです。
UIは楽にする。Authorityは緩めない。二つを同じ機能にしなかったからです。
人間を消すのではなく、人間の仕事を変えたかった
Season 1の初め、人間はかなり多くの作業をしていました。コードを運ぶ。SSHする。テストする。WordPressへ貼る。SNSへ出す。PRを確認する。「承認します」と返す。
少しずつ、その中間作業を外してきました。
最後まで残したかったのは、何を目指すか。どの境界を越えてよいか。本当に取り返しがつかないことをしてよいか。という判断です。
Interactive Control UIは、その人間の判断を消す仕組みではありません。むしろ、判断以外の摩擦を減らす仕組みでした。
「承認します」と正確な文章を打つ代わりに、内容を見てボタンを押す。ただし、押したからといって安全確認は省略されない。
この形まで来たことで、Personal AI PlatformのHuman-in-the-loopはかなり整理されました。
Season 1で最後に作ったのは、AIの機能ではなく人間との境界だった
第1回では長期記憶が欲しかった。第2回ではコードを直接触ってほしかった。第3回では強い実行権限を分離した。第4回では変更を確定する境界を作った。第5回では公開の境界を作った。第6回からは仕事の流れそのものをLoopにした。そして第9回では複数Chatまで並列化しました。
ここまでAI側を強くして、Season 1の最後に残ったテーマは、「人間をどこに残すか」でした。
Standing Delegationでroutineな往復を減らし、Authorityで実行可能範囲を機械的に狭め、UIで本当に必要な意思入力を楽にする。
これで、最初に作ろうとしていた「自分専用AI基盤」は、一度かなりまとまった形になりました。
Season 1の最終回では、Knowledge MCPから始まったこの開発が、どうしてここまで大きくなったのか。そして、当時どこを「いったん完成」と感じていたのかを振り返りました。
Season 1 Finale
→ 第12回:記憶から並列開発まで。自分専用AI基盤は、いったんここまでできた
Season 1は第1回〜第12回で一区切りです。Season 2は別番号体系で、いったん作った基盤を「疑う」ところから続きます。
連載ナビ
- 第1回:ChatGPTに長期記憶が欲しくて、Knowledge MCPを作った
- 第2回:ChatGPTにコードを書かせるだけでは足りなかった。Development MCPを作った
- 第3回:AIに自分自身を再起動させたら止まった。Development Runnerを分離した
- 第4回:ChatGPTからPRを作り、安全にマージできるようにした
- 第5回:記事を書くだけでは自動化にならなかった。Publishing MCPを作った
- 第6回:MCPをいくつ作っても、AIは自律化しなかった。そこでLoop Engineを作った
- 第7回:AIが途中で止まっても、続きを再開できるようにした
- 第8回:作業自動化と「自律するAI」は何が違うのか
- 第9回:複数のChatGPTに同じシステムを開発させたら、普通に衝突した
- 第10回:AI開発のたびに「承認します」と打つのをやめた
- 第11回:AIに「承認」ボタンを作った。でも、ボタンに権限は渡さなかった ← 今回
- 第12回:記憶から並列開発まで。自分専用AI基盤は、いったんここまでできた
- 連載一覧


コメント