🐈

エージェントが本番で黙って止まる4つの場面と、物理で防ぐパターン — AOS v0.2

に公開

エージェントは本番で「黙って」壊れる

ローカルで気持ちよく動いていた LLM エージェントを本番運用へ寄せると、だいたい次の場面で詰まります。

  • 黙って止まる — 途中で例外を飲み込み、何事もなかったように「完了しました」と返す
  • 痕跡がない — 「テストは通りました」と言うのに、ディスクには証拠が何も残っていない
  • 再起動で消える — 対話セッションの中でしか動かず、マシンを再起動すると継続性がゼロになる
  • 違反を自己申告しない — ルールを破った事実を、破った本人(エージェント)が報告しない

どれも「もっと丁寧にお願いする」では直りません。お願いが通らなかった瞬間に、そもそも壊れた状態が成立しない構造を、ホスト側で先に用意する必要があります。この記事の本題は、その「4つの壊れ方」に対応する 4つの物理パターン(§10.1〜§10.4)です。

なぜ「物理」なのか — v0.1 が引いた境界線

この発想自体は新しくありません。以前 AOS v0.1 の記事 で、エージェントを テキストのルールではなくホスト側の物理制約で縛る最小の枠組みを書きました。核は4つです。

  • §3.2 Three Zones — すべてのパスを Oracle(読取専用)/ Permitted(作業領域)/ Prohibited に分類する
  • §4.1 Hook Requirement — 書き込み・シェル実行を PreToolUse で実行前検査し、違反は exit 2 で止める
  • §4.3 Role Separation — 生成したエージェントに自分の成果物を採点させない
  • §4.4 Physical Evidence — 「完了しました」という会話ではなく、ディスク上の成果物を証拠にする

v0.1 はここまで、つまり 「何を守るべきか」の境界線を引きました。ただ、読んだ人から必ず出る質問が残ります — 「で、それを実際のツールでどう実装するの?」。冒頭の4つの壊れ方は、まさにこの 実装の空白から起きます。v0.2 はそこを埋めます。


v0.2 でやったこと:規範は据え置き、実装例を足す

v0.2 の方針は明快です。

  • §1〜§9 の規範(MUST / MUST NOT)は一切変更しない — 完全な後方互換
  • §10 Implementation Examples を新設 — 4つの本番パターンを、公開リポジトリの実コードへのリンク付きで掲載
  • §6 を Reference Implementation(単数)から Reference Implementations(複数)へ改題 — 未公開だった参照実装への言及を削り、実在・公開済みの physical-agent-patterns リポジトリを指すように差し替え

つまり「仕様の言葉を増やす」のではなく、**「仕様の言葉を、すでに動いているコードに接続する」**更新です。仕様だけが宙に浮かないようにした、と言い換えてもいいです。


§10.1 Manifest 宣言(§8・§9 に対応)

AOS 準拠ツールは、自分のゾーン境界を manifest.json で宣言します。これにより、別のエージェントが「このツールはどこに書いていいか/どこは触ってはいけないか」を起動前に知れます。

{
  "aos_compliant": "v0.2",
  "permitted_output_paths": ["docs/reports/"],
  "oracle_paths": ["evals/", "config/"]
}
  • oracle_paths は §3.2 の Oracle ゾーンに直結します。フックは実行時にここへの書き込みを止めます。
  • permitted_output_paths は Permitted ゾーン。ツールが出力してよい唯一の場所です。

肝心なのは **「宣言だけで準拠を名乗ってはいけない」**点です。manifest.jsonaos_compliant を書いても、実際にフック(または CI ゲート)が oracle_paths への書き込みを止めていなければ非準拠です(§8 末尾)。宣言と実行時強制はセットで初めて意味を持ちます。


§10.2 物理証拠パターン(§4.4 に対応)

AOS が防ぎたい典型的な失敗は **「エージェントは『動いた』と言うが、痕跡が何も残っていない」**です。

物理優先(physical-first)パターンは、証拠を完了の前提条件にします。後付けのログではなく、「証拠ファイルが存在して初めて完了を名乗れる」という順序です。

# 完了を宣言する「前」に証拠を書く(agent_with_evidence.py より)
evidence = {
    "task": task,
    "result": result_text,
    "timestamp": datetime.date.today().isoformat(),
    "model": model,
}
evidence_path.write_text(json.dumps(evidence, indent=2))
# ファイルが存在して初めて完了を出力する
print(f"[done] Evidence written: {evidence_path}")

呼び出し側は evidence_path の存在をチェックするだけで完了を検証できます。会話上の「やりました」は要りません。

実コード: physical-agent-patterns/patterns/02_physical-first/agent_with_evidence.py


§10.3 免疫ループ(§4.1・§4.5 に対応)

常駐したエージェントが、ワークスペース内の AOS 違反を検知し、修復シーケンスを起動するパターンです。ポイントは 検知(読取専用スキャン)と修復(書き込み)を分離することです。

# violation_detector.py — 修復を試みる「前」に報告を書く
violations = _scan(root)
report = {
    "timestamp": datetime.datetime.utcnow().isoformat(),
    "violations": violations,
}
report_path.write_text(json.dumps(report, indent=2))

検知器は違反レポートを JSON で書き出します(これ自体が §4.4 の物理証拠です)。修復プランナーはそのレポートを読み、既知の修正を当てるか、設計判断が必要なときは人間(Sovereign)へエスカレーションします(§4.5)。検知器が自分の発見を自分で修復しない、という分離が §4.3 のロール分離にもなっています。

実コード: physical-agent-patterns/patterns/03_immune-loop/


§10.4 systemd ランタイム(§4.4 の永続化に対応)

対話セッションでしか動かないエージェントは、再起動をまたいだ §4.4 を満たせません。systemd パターンは、エージェントを OS のプロセス supervisor に束ねます。サービスが実行境界を、タイマーがスケジュールを定義し、出力ファイルは再起動後も残ります。

# agent.py — 出力ファイルが「実行した」ことの証拠になる
output_path = OUTPUT_DIR / f"agent_run_{today}.md"
if output_path.exists():
    print(f"[skip] Output already exists for {today}: {output_path}")
    return output_path
# ... 実行して書き込む ...
output_path.write_text(content)
# physical-agent.timer(抜粋)
[Timer]
OnCalendar=daily
Persistent=true

冪等ガード(if output_path.exists(): return)が重複実行を防ぎ、証拠ファイルを唯一の完了記録として保ちます。Persistent=true は、スケジュールされた実行を逃した場合に次回起動時に発火させ、稼働時間に関係なく証拠要件を満たします

実コード: physical-agent-patterns/patterns/01_systemd-runtime/


4つのパターンと AOS 条項の対応

パターン 対応する AOS 条項 一言で
Manifest 宣言 §8・§9 どこに書いていいかを機械可読に宣言する
物理証拠 §4.4 証拠ファイルが完了の前提条件
免疫ループ §4.1・§4.5 違反検知と修復・エスカレーションの分離
systemd ランタイム §4.4(永続化) 再起動をまたいで証拠を残す

どれも特別な発明ではありません。エージェントを本番運用へ寄せると どこかで必ずぶつかるものを、再利用可能な形に切り出しただけです。


なぜ「実装例を仕様に入れる」ことにこだわったか

仕様書あるある、として **「規範は立派だが、誰も実装の出発点を持っていない」**状態があります。読んだ人が「正しいのは分かった。で、最初の1行は?」で止まってしまう。

v0.2 は、その距離をできるだけ縮めるための更新です。仕様の各条項に、クローンしてすぐ動かせる公開コードが紐づいている状態にしました。仕様自体は特定のランタイム(Claude Code / Cursor / 自前ループ)に縛られませんが、実装例があると 二度目の人が楽になるはずです。

なお §10 の4パターンはすべて physical-agent-patterns で公開しているので、git clone してそのまま読めます。


終わりに

AOS v0.2 は、新しい制約を足したバージョンではありません。「制約をどう実装するか」を、動くコードへのリンクで埋めたバージョンです。

「テキストのルールだけでは守らせられない」と感じている方の、実装のたたき台になれば幸いです。


AOS 仕様書(GitHub)

本記事で扱った「物理的ガバナンス」のアプローチは、AOS(AI Operating Standard) として仕様化・公開しています。v0.2 で実装例節を追加しました。

👉 AOS-spec — 仕様書(v0.2)
👉 physical-agent-patterns — 実装パターン集

仕様や実装例が参考になったら、⭐ スターを押していただけると次バージョンの策定の励みになります。Issue・PR も歓迎です。

Discussion