0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

自己改変するAIエージェントを「外部アンカー」で安全に回す ― builder≠checker / 統治膜 / fail-closed

0
Last updated at Posted at 2026-07-26

自律エージェントに「毎日自分を改善させる」と、最悪 自分の安全装置を自分で緩める
それでも自己改善を回したい。どう安全に成立させるか ― という実装メモ。

TL;DR

  • 夜間に自走し、かつ 自分自身を毎日改善する 自分用の内部オペレータを作った。
  • 自己改変は諸刃。賢くするほど「自分のガードレールを自分で外す」事故余地が増える。
  • 効いた安全の核は6つ:
    1. builder ≠ checker ― 作るモデルと検めるモデルを 別系統 にする
    2. 決定的な床 (L0) ― テスト一式が緑でなければ検証にすら進ませない
    3. 統治膜 (governance membrane) ― 能力は自己改善してよいが、ガードレールは自分で触れない
    4. fail-closed ― 明示OK以外はすべて却下(曖昧・エラー・timeout = 不合格)
    5. 不可逆操作には追加ゲート+人間の窓 ― 公開・本番は別格
    6. 単一の親ループにしない ― 多数を組むときは疎結合+薄い観測層(賢い塊より境界で守る)
  • そして実地の証拠: 別系統の検証役が、builder が「緑」と思った成果から 安全穴を何度も発見 した。机上論ではない。

背景: 自己改善は諸刃の剣

「提案 → 実装 → 検証 → 採否」を回すエージェントは珍しくない。問題は 検証を誰がやるか
作った本人(同じモデル)が「OKです」と言うのは、自己採点でしかない。さらに自己改変まで許すと、
極端には「検証を甘くする変更」を自分で入れて、以後すべてを素通りさせられる。

だから設計の出発点はこう置いた:

賢いエージェントより、「自分の安全装置を自分で外せないエージェント」を作る。


原則1: builder ≠ checker(別系統で敵対検証)

作るのは Claude 系。検めるのは 別系統の codex (GPT)
同じモデル族は同じ盲点を共有する。別系統にすると、片方が見落とす欠陥をもう片方が捕まえる。

artifact = builder.implement(task)      # Claude 系が実装
if not L0(artifact): reject             # まず決定的チェック(後述)
verdict = checker.review(artifact)      # codex(別モデル)が「敵対的に」レビュー
if verdict != "PASS": reject            # 明示PASS以外は通さない

ポイントは、検証役を 「承認する人」ではなく「間違いを探す人」 として使うこと。
プロンプトも「これは正しい前提でレビューして」ではなく 「反証せよ。確信が持てなければ却下寄りで」


原則2: 決定的な床 (L0) を先に置く

LLM の判断は揺れる。だから まず機械判定(プロジェクトのテスト一式 ― pytest / npm test /
make test 等。あれば lint・型も)を緑にしてから、その上で LLM 検証を 二次パス として重ねる。
安いゲートが先(コスト順)。

通常の検証ループでは、L0 が落ちている間は検証役を呼ばない(トークンの無駄)。
L0 は「正しさの床」であって天井ではない ― 機械で言い切れない部分を別系統 LLM が補う、という二層。
(自己改変フローだけは両方を走らせ、最後に「テスト緑 かつ 別系統 PASS かつ 膜の外」のときだけ採用する。)


原則3: 統治膜(governance membrane)

ここが自己改変エージェントの肝。

エージェントは自分の 能力(機能)は毎日改善してよい。
だが自分の ガードレール(検証ゲート・公開判定・承認ロジック)は 自分で変更できない
変えるには人間の明示許可が要る。

SAFETY_CORE = {
  検証ゲート(verify),
  設定(denylist / 公開判定 / tier 判定),
  オーケストレータの公開キュー経路,
  そして ―― 自己改善ゲート「自身」のコード,
}

if change.touches(SAFETY_CORE):
    require_explicit_human()     # silence(沈黙承認)では絶対に通さない
else:
    allow_autonomous()           # 能力改善は自走でよい

罠: 膜は「自分自身」も守らなければ穴になる

最初の実装では、自己改善のゲート(「これは安全か」を判定するコード)を膜の に置いていた。
すると論理上、エージェントは「ゲートを緩める変更」を入れてゲートをすり抜けられる ― 再帰的な穴
別系統の検証役にこれを指摘され、「自己改善ゲートのファイル自体」も膜に入れる ことで塞いだ。

自分の安全装置を、自分のループで書き換えられないようにする。これが統治膜の本質。


原則4: fail-closed(曖昧はすべて却下)

検証役が timeout / 空応答 / エラー / 「PASS とも REFUTE とも言わない出力」 を返したとき、
それを すべて「却下」 にする。明示的な合格があるときだけ通す。

ok = (returncode == 0
      and "VERDICT: PASS" in out
      and "VERDICT: REFUTE" not in out)
refuted = not ok          # 曖昧・失敗・無応答は全部 refuted

逆(fail-open)が古典的かつ致命的な穴:
「エラーが出なかった = OK」にすると、検証が壊れているのに素通りする。
検証役の応答が空でも timeout でも、安全側(却下)に倒す


原則5: リスクで段を分ける ― 不可逆操作には追加ゲート

すべてを同じ強さで止める必要はない。3段に分けた:

  • 可逆・低リスク(private な編集・ローカル commit)→ silence-consent:
    「期限(例: 翌朝11:00)までに人間が NO と言わなければ承認」。普段は黙っていてよい。
  • 不可逆だが委譲する(public 公開など)→ silence-consent で自律させる。ただし不可逆
    (一度 public にすると消せない = キャッシュ/インデックス)なので、実行直前に
    fail-closed の秘密スキャンを必ず通し、ダイジェストで強調して veto の窓を与える:
if action.is_public_exposure():          # 公開は不可逆
    hits = scan_secrets(repo)            # 公開前に必ず秘密スキャン
    if hits or cannot_fully_scan(repo):  # 秘密検出・列挙不能・読めないファイル
        block()                          # = すべて fail-closed で公開拒否
  • 常に人間のみ(保護リポジトリ・force-push・安全膜)→ silence では絶対に通さない。

要は、「黙っていれば進む」自律を 可逆な範囲に厚く 効かせ、不可逆には追加ゲート
ガードレールには必ず人間 ― と段を分ける。


原則6: 単一の親ループにしない(疎結合 + 薄い観測層)

安全な1体ができても、それを増やすときに 全部を1つの親ループに束ねてはいけない
単一の親は 単一障害点 であり、親自身が最大のリスクになる(そこが壊れると全部止まる)。

各エージェント/ループは 疎結合 に保つ(1本死んでも他は生きる)。上位に置くのは
観測と調停だけの薄い層 にとどめ、実行は各ループに委ねる。
つまり 「全体を観測(read-only)+実行は分散」。これが自律性と堅牢性を両立させる置き方だ。

賢い1つの塊より、境界で守られた多数の方が壊れにくい。

これは前章までの 統治膜 と同じ思想を、1体の中から システム全体 へ広げたもの ―
「中央に賢さと権限を集めない」。能力は分散させ、守りは境界に置く。


自己改変は隔離して行う

自分のコードを書き換える時は、本体を直接いじらない:

別 worktree で実装
   → テスト(L0)が全緑か
   → 別系統 checker が PASS か
   → 安全膜に触れていないか(変更ファイル全体で判定)
   → すべて満たせば本線に fast-forward merge + バージョン採番 + tag
   → マージ後にもう一度テスト。赤なら「マージ直前の状態」へ正確に巻き戻し

「実装中に本体が壊れている」状態を作らない。失敗は痕跡を残して捨てる。


効いた証拠(ここが本題)

「builder ≠ checker」は机上論ではない。別系統の検証役は、builder(実装側)が「緑」と思った成果から、
実際の安全穴を繰り返し落とした。代表的な型:

検証役が見つけた穴 なぜ危険か
pre-commit バイパス 「未コミット差分」しか見ない検査を、先にコミットしてすり抜け
fail-open 検証役の空応答 / timeout を「OK」と誤判定して通す
ゲートが自分を守っていない 自己改善ゲートのコードが膜の外(前述の再帰穴)
不可逆操作の検査漏れ 公開前スキャンが巨大/読めないファイルを「clean」扱い
revert が本体を破壊 失敗時の巻き戻しが、人間の未コミット変更まで消す

どれも「同じモデルがもう一度見る」では出にくい。
別系統 + 敵対プロンプト + fail-closed で初めて落ちた欠陥だった。


まとめ

自己改変エージェントを安全に回す最小セット:

  1. builder ≠ checker ― 別系統で敵対検証(同族の盲点を破る)
  2. 決定的な床 (L0) ― テストを先に、LLM 検証は二次パス
  3. 統治膜 ― 能力は自己改善可、ガードレールは人間のみ、膜は自分自身も守る
  4. fail-closed ― 曖昧・無応答・エラーは全部却下
  5. 不可逆操作は追加ゲート+人間の窓 ― 公開・本番は別格
  6. 単一の親ループにしない ― 多数を組むときは疎結合+薄い観測層(単一の親 = 単一障害点)

自律性は、検証の厳密さとセットでのみ 安全に増やせる。
「自分で自分の安全装置を外せない」こと ― それが、自己改変エージェントに最初に与えるべき性質だと思う。


この記事は、実際に運用している自律オペレータの設計から、機微な内部情報を除いてパターン部分のみを抜き出したものです。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?