AIエージェントを使い始めた頃、最大の誤解は「一度うまく動けばずっと動く」だと思っていたことです。
実際はそうではありませんでした。エージェントは時間とともに品質が変化します。外部環境が変わる。ツールのバージョンが上がる。扱うデータの形式が変わる。何も変えていないのに、気づいたら期待した動作をしなくなっています。
ここでは Dolice Labs として個人開発で運営する4つのAI技術ブログサイトを、複数エージェントで自律運用してきた経験から、「なぜ品質が崩れるか」と「仕組みで防ぐにはどうするか」を、実際に動かしているコードとともに具体的に書きます。監視ダッシュボードを眺めるのではなく、崩れない設計をあらかじめ仕込んでおく、という話です。
自律実行が崩れる4つのパターン
まず、品質劣化がどこで起きるかを理解することが先決です。経験上、以下の4つのパターンに集約されます。
パターン1: 環境ドリフト
エージェントが依存するツールやAPIが静かに変わります。たとえば、gitコマンドのオプションが変わる、APIのレスポンス形式が変わる、認証トークンが期限切れになります。エージェント自体は何も変わっていませんが、外部環境との「ズレ」が蓄積して突然失敗します。私の運用では、月に1〜2回はこの種の「自分は何も触っていないのに落ちた」が起きます。直近では、固定していたセッションパスが変わってファイル書き込みが全滅した事例がありました。
パターン2: プロンプトの漂流
エージェントの指示(SKILL.mdなど)は生き物です。メンテナンスするたびに少しずつ変わり、気づかないうちに当初の意図から外れていくことがあります。特定の条件下で矛盾した指示が生まれ、エージェントが想定外の判断をするようになります。「週2本」と本文に書きながらスケジュールは「週1本」に変えた、という頻度のズレは典型例で、本文とcronのどちらが正かを毎回決めておかないと、エージェントが古い記述を信じて動きます。
パターン3: データの腐敗
エージェントが参照するデータ(記事一覧、設定ファイル、ログ)が時間とともに不整合を起こします。例えば、記事数のカウントが実態と合わなくなり、エージェントが誤った判断をするケースです。参照データのパスが _reference_data/ から reference_data/(先頭アンダースコアの有無)に変わっていたのに cat がエラーを握りつぶし、空のまま「成功」と記録していた、という無音失敗を経験しました。
パターン4: 成功体験の固着
これが最も気づきにくいパターンです。過去にうまくいった方法をエージェントが過度に信頼し、状況が変わっているのに同じアプローチを繰り返すことがあります。人間と同じ問題が、AIエージェントにも起きます。「前回はこのslugで復旧できた」が、今回は410で消した記事の再利用になっていてSEO上の自爆になる、といった具合です。
崩れる前に気づく — 観測すべき4つのシグナル
劣化は「ある日突然」ではなく、たいてい予兆があります。私が毎日見ているシグナルとしきい値を共有します。数値は運用規模で変わりますが、「絶対値」ではなく「前日比の変化率」を見るのがコツです。
| シグナル | 意味 | 警戒ライン(私の運用例) |
| 連続スキップ回数 | 同一タスクが候補なし等で連続スキップ | 3回連続でアラート(構造要因の疑い) |
| ログの空出力率 | 参照データcatが空のまま進んだ割合 | 1件でも空なら欠落ログ必須 |
| 検証ゲート失敗率 | push前ゲートで弾かれた割合 | 週20%超でプロンプト見直し |
| JA/EN件数差 | 日英記事数の乖離 | 差1以上で即停止(404の温床) |
特に「連続スキップ回数」は軽視されがちです。エージェントが3回続けて「適した候補がありませんでした」と返すとき、本当に候補が枯渇していることは稀で、ほとんどはマウント漏れやデータ陳腐化といった構造要因です。スキップを「正常な分岐」として流していると、静かに何週間も止まったままになります。
品質保証の4つの設計原則
「監視して問題を検知する」だけでは不十分です。品質は「崩れにくい設計」で保証するものです。
原則1: エージェントに自己申告させる
タスク終了時に「何ができて、何ができなかったか」をログに記録させます。成功だけでなく、失敗や不確実性も含めて。これにより、問題の早期発見が可能になります。
実装としては、SKILL.mdの末尾に記録フォーマットを固定で持たせるのが効きます。自由記述に任せると毎回粒度が変わってしまうので、項目を決め打ちにします。
# 実行ログの定型フォーマット(タスク終了時に必ず追記)
LOG="${WS}/_updated_article_log/antigravitylab/$(TZ=Asia/Tokyo date +%Y-%m-%d)_upgrade.txt"
{
echo "## $(TZ=Asia/Tokyo date '+%Y-%m-%d %H:%M JST')"
echo "- 対象: $SLUG"
echo "- 成功: 加筆・premium昇格・push"
echo "- 不確実: highlights の3項目目が抽象寄り"
echo "- スキップ理由(あれば): なし"
} >> "$LOG"
ログ日付は必ず TZ=Asia/Tokyo を付けます。素の date はUTCなので、深夜帯の実行で前日ファイルを上書きしてしまう事故が一度ありました。
原則2: 冪等性を前提に設計する
同じ処理を何度実行しても同じ結果になるよう設計します。エージェントの自律実行では、「失敗したら再実行する」というリカバリパターンが基本です。そのとき、再実行が副作用を起こさない設計が必要です。
# 冪等な書き込み: 一意なテンポラリ名 → 検証 → 本番反映
TMP="$HOME/upg_${SLUG}_$(date +%s).mdx" # 固定名にしない(前回残骸の混入防止)
build_article > "$TMP"
grep -q "premium: true" "$TMP" || { echo "build失敗"; exit 1; }
mv "$TMP" "$JA"
ファイル名を固定にすると、書き込みに失敗したとき前回の残骸が無言で混入します。slugとタイムスタンプを含む一意名にして、検証が通った場合だけ本番へ反映する。これだけで「途中で死んだ実行の残り物が次回に紛れ込む」事故が消えます。
原則3: 検証ステップを多段で組み込む
処理の「後」に検証ステップを入れます。1つではなく、独立した観点で複数重ねるのがポイントです。私の運用では push 直前に4つのゲートを直列で通します。
# 多段検証ゲート(1つでも落ちたら push しない)
python3 "${WS}/_documents/_quality_audit/_scripts/article_gate.py" "$JA" "$EN" || exit 1
python3 "${WS}/_documents/_quality_audit/_scripts/templating_gate.py" . --check "$JA" "$EN" || exit 1
python3 "${WS}/_documents/_quality_audit/_scripts/frontmatter_integrity.py" . || exit 1
python3 "${WS}/_documents/_quality_audit/_scripts/redirect_integrity.py" . || exit 1
# JA/EN 件数の最終確認(差1でも止める)
JA_N=$(find content/articles/ja -name "*.mdx" | wc -l)
EN_N=$(find content/articles/en -name "*.mdx" | wc -l)
[ "$JA_N" = "$EN_N" ] || { echo "件数不一致 JA=$JA_N EN=$EN_N"; exit 1; }
ここで重要なのは、ゲートとpushを同じシェル呼び出しにまとめないことです。gate && git push と一行に書くと、ゲートの出力を人間(あるいは次の判断ステップ)が確認する前に push が走ります。一度、ゲートが警告を出していたのに同一呼び出しで push してしまい、違反記事を公開した事故がありました。ゲートの結果を確認してから、別の呼び出しで push する。地味ですが、これが効きます。
原則4: 失敗を「辞典」として記憶させる
エージェントが失敗したとき、単なるエラーログではなく、再利用できる知識として残します。私は失敗を必ず3点セットで書きます。
| 項目 | 記録する内容 |
| 症状 | 何がどう失敗したか(観測された事実だけ) |
| 真因 | なぜ起きたか(仮説ではなく確認した原因) |
| 恒久対策 | 次回どう防ぐか(コード・チェック手順に落とす) |
この「失敗辞典」が100項目を超えたあたりから、同じ穴に二度落ちる頻度が目に見えて下がりました。エラーログは流れて消えますが、辞典は設計判断の根拠として残り続けます。Antigravity のメモリ機能や外部ファイルに置いて、タスク冒頭で必ず参照させるのがおすすめです。
実際に効いた対策3つ
理論は十分です。実際に大きな効果があった対策を3つ紹介します。
対策1: 「禁止リスト」を明示する
SKILL.mdに「やること」だけでなく「やってはいけないこと」を書きます。ポジティブな指示よりネガティブな制約の方が守られやすく、特に一度でも痛い目を見た制約は必ず入れます。
## 🚫 絶対禁止
- npm install の実行(ディスク消費でVM停止)
- AskUserQuestion の使用(スケジュール実行が停止)
- request_cowork_directory の呼び出し(ダイアログが出る)
- 存在しない記事への内部リンク記述(404の原因)
- ゲートと git push の同一呼び出しバッチ化
対策2: ハードコードをやめ、動的検出にする
パスやトークンをハードコードするとドリフトします。特にセッションをまたぐ場合、動的に取得する設計にします。
# ❌ ハードコード(セッションが変わると死ぬ)
WS="/sessions/old-session-name/mnt/Dolice Labs"
# ✅ 動的検出(常に正しいパスを取得)
WS="$(ls -d /sessions/*/mnt/Dolice\ Labs 2>/dev/null | head -1)"
これだけで、セッション変更のたびに設定を更新する作業がゼロになりました。
対策3: 「remote を正」として検証する
ワークスペースのミラーは古いことがあります。剪定対象の判定や件数チェックは、手元のミラーではなく git clone した最新の remote に対して行います。ローカルの設定ファイルを信じて消すべきでない記事を消す、という最悪の事故は、検証元を remote に固定するだけで防げます。
Antigravity 2.0 のマルチエージェント時代に、品質保証はどう変わるか
ここからは、いま起きている変化に絡めて書きます。Antigravity 2.0 はデスクトップ・CLI・SDK・Managed Agents API を備えたプラットフォームへと拡張し、複数エージェントの並列オーケストレーションが中核になりました。6/18 には Gemini CLI が Antigravity CLI へ統合され、自動化の載せ替えが現実の作業になっています。
単一エージェントから「エージェントの編成を管理する」運用に移ると、品質保証の重心も変わります。これまでは「1つのエージェントが時間とともに崩れる」問題でしたが、これからは「複数のエージェントが同じファイルに同時に触れて壊す」問題が主役になります。
私が並列運用で最初に効かせたのは、ファイル境界での分離でした。worktree やブランチでエージェントごとに触れる範囲を物理的に分け、同じ記事ディレクトリに2つのエージェントが同時に書き込まない設計にします。タスクは「自分が15分でレビューできる単位」に切り、受け入れ条件を3行で先に書いてから渡す。並列度を上げるほど、1タスクあたりの粒度はむしろ小さくする、というのが実感です。
バックグラウンドのスケジュール実行が増えると、前述の「連続スキップ」「無音失敗」が見えにくくなります。マルチエージェント環境ではなおさら、各エージェントに自己申告ログを書かせ、件数とゲート失敗率を横串で集計する仕組みが要になります。エージェントが増えるほど、人間の役割は「実装」から「観測点の設計」へ移っていきます。
今日から始める3ステップ
一気に全部を入れる必要はありません。費用対効果の高い順に並べると、次の3つから始めるのが現実的です。
- JA/EN 件数チェック(あるいは自分のドメインでの整合性チェック)を push 前に1行入れる。 最も安く、最も事故を防ぎます。
- 実行ログの定型フォーマットを決め、成功・失敗・スキップ理由を必ず残す。 観測できないものは改善できません。
- 失敗辞典を1ファイル作り、痛い目を見るたびに「症状・真因・恒久対策」で1項目ずつ足す。 半年で運用の地力が変わります。
品質保証は「設計」であり「文化」でもある
最後に、技術的な対策と同じくらい重要なことを書きます。
AIエージェントの品質保証は、一度設計すれば終わりではありません。エージェントと一緒に改善し続けるプロセスです。失敗したら原因を記録します。成功したらパターンを言語化します。定期的に設計を見直す。
それを続けると、半年後には「壊れにくく、自己修復できるエージェント」に育っています。最初から完璧なエージェントは作れません。でも、正しく育てることはできます。同じように個人開発で複数のプロジェクトを回している方の、設計の足場になれば嬉しいです。