$ cat posts/20260712-k55u3w.mdx
AIエージェントに『自分でプロンプトを打たせる』— ブログにループエンジニアリングを組み込んだ
はじめに
AIエージェントの使い方というと、多くの人は「チャット欄に指示を打つ」ことを思い浮かべる。自分もそうだった。だが最近、その前提を疑う考え方に出会った。「やさしいループエンジニアリング入門」(aki.ts、LINE DC Generative AI Meetup #8)というトークだ。この記事の内容は、以下のスライドを参考にしている。
結論から言うと、ループエンジニアリングとは 「自分をプロンプトを打つ人から外し、代わりにプロンプトを打ってくれる仕組みを設計すること」。トークではこれを組織マネジメントに例えていた。良いリーダーは部下の作業に逐一口を出さない。目標・レビュー体制・引き継ぎを整えて、自分がいなくても回る状態を作る。エージェントに対しても同じことをやろう、という話だ。
この記事は、その考え方をこのブログ(gtn74.com)のメンテナンスに実際に組み込んで、回してみた記録。
ループエンジニアリングの4要素
トークでは、ループを4つの部品で設計すると整理していた。
| 要素 | 意味 |
|---|---|
| トリガー | ループをいつ start させるか |
| 停止条件 | いつ終わらせるか(目標達成/使用量超過/人間のキャンセル) |
| 作業サイクル | 実行 → 結果確認 → 修正の繰り返し。メモリ必須 |
| 検証 | 機械的に成功を判定する仕組み。これが最重要 |
特に効くのが4つ目の検証だ。エージェントに「いい感じにして」と頼んでも、何をもって完了かが曖昧だと永遠に終わらない(あるいは早々に「できました」と嘘をつく)。テストが通る、lintエラーが0、ビルドが成功する——こういう exit 0 で機械的に判定できる基準があって初めて、ループは人間が見ていなくても自走できる。
そして、この仕組みが成立するには前提条件がある。トークでは4つ挙げられていた。
- 反復性 — 同じことが繰り返し必要になる
- 失敗の機械的検出 — 不正な状態を自動で棄却できる
- エージェント完結 — 途中で人間の判断が要らない
- 成功の客観的定義 — 「好みの問題」が残らない
逆に言えば、この4条件を満たさないタスクをループにするとハマる。
このブログに組み込んだもの
ブログのメンテナンスは、この4条件にきれいに当てはまる。記事を1本足すたびに、lint・型チェック・ビルド(検索インデックスやRSSの生成を含む)が全部通るかを確認する必要がある。毎回同じで、失敗はコマンドで検出でき、判定は exit 0 で客観的だ。
そこで、4要素をそれぞれ実体のあるファイルに落とし込んだ。
| 要素 | 実装 |
|---|---|
| トリガー | /loop-blog-health(手動)/ /loop 30m /loop-blog-health(定期) |
| 停止条件 | 検証オールグリーン / 5イテレーション到達 / 同一エラー2連続 / 人間のキャンセル |
| 作業サイクル | スキル loop-blog-health(手順書)。状態は loop-memory.md に追記 |
| 検証 | npm run lint / tsc --noEmit / npm run build / frontmatter検査 |
ポイントを3つ補足する。
メモリを外部ファイルに持たせた。 エージェントの文脈はイテレーションをまたぐと失われる。だから作業サイクルの状態(前回グリーンだったか、どのエラーで詰まっているか)を loop-memory.md という1枚のファイルに書き出させ、毎回それを読んでから始めさせる。これがないと「さっき直したはずのものをまた壊す」ループに陥る。
検証は独立した目にやらせる。 修正した本人が「直りました」と言うのは信用しづらい。そこで最終確認だけは blog-verifier という別のサブエージェントに委譲する。lint・型・ビルドを回してグリーン/レッドだけを報告する係で、修正はしない。作業者とレビュアーを分ける、組織マネジメントの比喩そのままだ。
フックで即座に突き返す。 ファイルを編集するたびに型チェックを走らせる PostToolUse フックを仕込んでおいた。壊れた瞬間にエージェント自身へエラーが返るので、傷が浅いうちに直る。
あえてループの外に置いたもの
ひとつ意図的に対象外にしたのが「記事の文章の質」だ。これは主観的で、前提条件の4番目「成功の客観的定義」を満たさない。lintのようにexit 0で「良い文章」を判定することはできない。だからスキルの禁止事項に「記事本文を勝手に書き換えない」と明記して、ループが手を出せないようにした。ループに向くのは客観的に判定できるものだけ、という線引きを守るための歯止めだ。
使い方
トリガーは2通り。
単発で回す(記事を追加した直後など):
/loop-blog-health検証を1周して、全部グリーンならメモリに記録して終了。失敗があれば最小の変更で直して再検証する。
定期実行で回し続ける(緑になるまで放置):
/loop 30m /loop-blog-health/loop が30分ごとに /loop-blog-health を叩き続ける。ここで混乱しやすいのが、/loop と /loop-blog-health は別物だということ。前者がタイマー、後者が中身だ。/loop-blog-health 自体は「1回分の作業手順」で、繰り返しはさせない。繰り返しは /loop に任せる。
実際に回してみたら、2件見つかった
仕組みを作っただけでは意味がないので、さっそく単発で1周させてみた。結果はこうだ。
tsc --noEmit ... グリーン
npm run build ... グリーン(検索インデックス・RSSまで生成OK)
npm run lint ... レッド
frontmatter ... レッド(2記事)
lintは、ESLintの設定ファイルが無くて対話プロンプトで固まっていた(そもそも設定が未導入で、しかも使っていた next lint はNext.js 16で廃止予定という二重の問題)。frontmatterは、別プラットフォームから移植した2記事が、このブログの規約(date / description / lang)を満たさないまま公開されていた。
ここで面白かったのが、ループがこの2件を勝手には直さなかったことだ。lintの設定方針は「設計判断」だし、記事のdescriptionを書くのは「編集作業」で、どちらも前述の線引き(客観的に判定できるものだけ)の外側にある。だからループは無理に修正せず、メモリに記録して人間向けのレポートを出して止まった。空回りして環境を壊すより、ここで人間に投げ返すのが正しい。停止条件と禁止事項がちゃんと効いた瞬間だった。
その後、方針を人間(自分)が決めてから、機械的に直せる部分——ESLintの導入と、frontmatterの date/lang 補完——をやらせた。再検証で全部グリーンになり、ループは停止条件を満たして終了した。
まとめ
- ループエンジニアリング = 自分をプロンプト実行者から外し、回る仕組みを設計すること
- 部品は4つ: トリガー / 停止条件 / 作業サイクル(メモリ必須) / 検証(最重要)
- 成立には4条件(反復性・機械的な失敗検出・エージェント完結・客観的な完成定義)が要る
- ブログの健全性チェックはこれにぴったり当てはまる。exit 0 で判定できるのが効いている
- 主観が入る「文章の質」は意図的にループの外に置いた。線引きが仕組みの信頼性を作る
- 実際に回したら、直せるものは直し、判断が要るものは人間に返してきた。止まり方まで設計するのがキモ
「AIに任せる」は「丸投げする」ことではなく、「どこまでを任せ、どこで止めて人間に返すかを設計する」ことなんだと、手を動かしてみて腑に落ちた。次は検証項目にリンク切れチェックあたりを足していきたい。