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?

ループエンジニアリング・4つのデザインパターン

0
Posted at

自動工場(GitHub Issueを自律処理するAIを利用したループ)を作って運用しているうちに、ループエンジニアリングの形にいくつか種類があることが見えてきました。iOSのアーキテクチャをMVVMやTCAなど複数知っていると、アプリの目的に応じて選べるのと同じで、ループの型を知っていると、課題を見た時点で「これはあの型」と当てはめてから細部を考えられます。

この記事は、自分が使っている型と、調べて知った型を、簡単な図とユースケースで並べたものです。実装の話はしません。「うちの仕事はどの型か」を決めるための一覧です。1つの段階の中で回すパターン(生成と評価の分離など)は別の粒度なので、型としては並べず、各型のエッセンスとして触れます。

自動で止まらずに動かし続けるには、allowlist・ラッパー・hooks・検証規約といったハーネスエンジニアリングもかなり大事ですが、今回は省略します。そちらは自動工場の記事に書いています。

軸は3つ:ループの型、トリガーの型、実行場所と権限

ループの話をするとき、3つの軸が混ざりがちです。

  1. ループの型: システムとして、仕事をどう振って回すか
  2. トリガーの型: 何をきっかけに動くか
  3. 実行場所と権限: ローカルかクラウドか、誰の権限で動くか

この3つは独立しているので、掛け合わせで考えます。以下、順に並べます。

ループの型4つ:仕事をどう振るか

単純な定期実行

決まった時刻に、決まった入力に対して、毎回同じことをやります。分岐はありません。

項目 内容
向く仕事 決まった入力に対して、毎回同じ処理をすればいいもの
人のゲート 出力を見るだけ
良い点 作るのがいちばん簡単で、壊れにくい。何が出るか予測できる
トレードオフ 分岐がないので、想定外の入力もそのまま出力される。仕事の種類が増えたらこの型では持たない
毎週土曜の朝にスーパーのチラシから献立を出すルーティン、プロジェクトの進捗報告、依存ライブラリの更新確認、アラート監視

ルーティング型(決定的ルーター)

定期起動したら、まず1本のスクリプトを実行します。スクリプトは「今の時刻ならこの作業」「この状態ならこの作業」を返すだけで、判断は決定的です。AIは返ってきた仕事だけをやり、仕事がなければ終了します。

ループの作りは2通りあります。AIがスクリプトを呼ぶ形(AIは起動するが、仕事がなければすぐ終わる)と、スクリプトを先に呼んで仕事があるときだけAIを起動する形です。後者のほうがトークンは減りますが、自分のは前者です。

「ルーターや分岐はLLMに任せず、コードで切る」という考え方の、いちばん小さい形です。

項目 内容
向く仕事 状況で仕事が変わるが、分岐の条件は事前に書けるもの
人のゲート 仕事の種類ごとに決める
良い点 分岐がテストできる。仕事がなければすぐ終わる。入口が1つで済む
トレードオフ 分岐の条件は人が書くので、想定していない状況には対応できない。条件が増えるとスクリプトが仕様書のように育つ
その日のタスク管理。朝は今日やらなければいけないタスクを集めて一覧化、日中はメールやチャットを確認してタスクと判断したものを一覧に追加、夜は今日対応した内容のまとめを生成。時刻で仕事が変わり、日中の回は追加するものがなければ終了する

状態機械型(状態を共有の場所に置き、担当のループが拾う)

1件の仕事が複数の段階を流れ、段階ごとに別の生成と判断があります。状態を共有の場所に置き、段階ごとに担当のループが定期巡回して、自分の入力条件に合うものを拾います。状態の遷移は、許可した遷移だけを並べた表(遷移テーブル)で縛り、表にない遷移はできないようにします。

※自分はこれを自動工場という名前で構築しており、状態はGitHub Issueのラベルに置き、ラベルの遷移はラッパーが持つ遷移テーブルで縛っています。

型としてはBlackboard(共有の状態を見て、前提条件が揃った担当が拾う)に当たります。各段階の中では、決定的な処理をスクリプトがやり、解釈と起草だけをLLMがやります。

項目 内容
向く仕事 毎回同じ形で流れるが、途中に判断と生成があるもの
人のゲート 不可逆な操作の前。自動工場では仕様承認とPRマージの2箇所
良い点 落ちても次の巡回で拾える。誰が状態を変えても拾える。段階ごとに別のモデルや権限を使える
トレードオフ ラッパー、遷移テーブル、hooks、検証を揃えるのが重い。1件の経路が固定なので、手順が毎回変わる仕事には向かない
自動工場(Issue → 設計 → 実装 → PR)

この型の中に、2つのことを組み込んでいます。

  • 作る側とレビューする側を分ける。 実装するループとレビューするループは別のコンテキストで、レビュー側には書き込み権限を与えません。生成役の自己承認を避けるためです。評価の基準は、過去のレビュー指摘から作ったチェックリストにしておくと資産になります
  • ゲートの結果を仕組みに戻す。 承認ゲートでNGになった理由を溜めて、同じ理由が2〜3回出たら規約へ、機械で判定できるものはlintへ昇格させます

計画一括実行型(LLMが計画を1回書き、機械が決定的に実行)

エージェントが課題を見て、使うツールと順番と待ちをDAGとして先に全部決めます。あとは決定的に実行され、実行中はLLMを呼びません。中間結果は実行側に留まり、最終結果だけがエージェントに返ってきて、それを確認して報告します。

※DAGは、A・B・C・Dという決定的な処理を事前に用意しておいて、「今回はAのあとにCを使う」と決めた作業の並びのことです。使う処理と順番と依存だけが決まっていて、ループはありません。

Azure Functionsのサーバーレスエージェントランタイムには、Dynamic Workflowという名前でexperimentalの実装が入っています。

ポイントは、LLMが判断するタイミングが実行前の1回に固定されていることです。トークンが減り、実行が決定的になり、途中で方針を変える自由がなくなります。変えたければ、結果を見てもう1回DAGを作る2周目を実施します。

項目 内容
向く仕事 手順は内容で変わるが、決めたら手順どおりに進めばいいもの
人のゲート 最後の「送る・変える」操作は自動で実行せず、人に返す
良い点 トークンが少ない。実行が決定的で、落ちても再開できる。手順が毎回違う仕事を自動化できる
トレードオフ 途中で方針を変えられない。登録済みのツールにない操作はできない。計画が間違っていると、実行が正確でも救えない
インシデントの調査(ログ・メトリクス・デプロイ履歴を並列で集めて、30秒待って、相関して報告する)、問い合わせ対応、届いたメールへの一次対応

※LLMが組み合わせられるのは、あらかじめ決定的なツールとして登録したものだけです。ツールとその説明文が、この型の資産になります。

この型にも、結果を仕組みに戻す回路が要ります。実行が終わって人が対処した結果と、エージェントが出した計画や報告を突き合わせて、外れていたら計画役の指示を更新する。Microsoftの牛尾剛さんはNewbeeの動画で、チームのSREエージェントがインシデントの解決後にこれをやっていて、更新のPRをエージェント自身が作る形にしていると話していました。計画をLLMに任せる型ほど、この回路がないと同じ間違いを繰り返します。

トリガーの型:何をきっかけに動くか

ループの型とは独立した軸です。

トリガー 仕組み 向く 落とし穴
タイマー(定期巡回) cron、ルーティン、クラウドのタイマー機能 取りこぼしの回収、自己修復。落ちても次の巡回で拾える 即時性がない。仕事がなくても起動する
イベント(Webhook) Issue作成、PR更新、メール受信、Teams投稿 即時に反応したいもの 連打時のキューイング、bot自身のイベントでの誤爆、フィルタの肥大化
キュー Service Bus、SQS、Redis 同時実行数の制御、リトライ、失敗分を別に溜める仕組み(DLQ)が要るもの 個人や少人数では過剰
人の起動 対話、コマンド、メンション 判断を人が始めたいもの、探索 起動だけは人に依存する。人が起動しなければ動かない
状態変化(差分検知) 共有の状態を見て、差分があれば動く 状態機械型。誰が変えたかを問わず拾える 巡回と組まないと変化を見逃す

自動工場はClaude Desktopのルーティン(タイマー)とGitHubトリガー(イベント)の両方で動かしています。

人への出力:判断が要るなら通知、記録だけなら置いておく

出力の形も型に入れたくなりますが、軸を増やすと広がりすぎるので、人のゲートの一部として扱います。決め方は1つで、「人が動かないとループが進まないか」です。

  • 承認待ち、失敗して止まった、質問がある、確認して欲しい、のように人の判断や操作が要るもの → Slackなどに通知する。人が見に行かないと止まったままになる
  • 日次のまとめ、処理結果の集計、ログ、のように記録だけのもの → ファイルやIssueに置いておく。見たいときに見る

人間もループの一部なので、人に渡すときのインターフェースも設計対象です。通知には「回答するとこの後に何が起きるか」と「人間側の追加操作は不要であること」を書かせています。これがないと、人が状況を推測して修正するといった余計な運用が生まれます。

実行場所と権限:ローカルかクラウドか

3つ目の軸です。ローカルのコーディングエージェントは、ユーザートークン(人間が触る前提の権限)で動きます。自動化をこれでやると、乗っ取られたときの範囲が広いというリスクは意識しておく必要があります。クラウド側は使い方によりますが、権限を絞ることが多く、一時的に上がって消える実行環境が使えて、ローカルPCに依存しないため場所や時間を選びません。

自分の自動工場はローカルとサブスク枠で回しているので、財布が死なない安心と引き換えに、この軸では弱い側にいます。次の目標はここです。

ユースケース:型 × トリガーで、仕事を置く

3軸が揃うと、仕事の置き場が決まります。

仕事 ループの型 トリガー 人のゲート
週次レポート 単純な定期実行 タイマー 出力を見る
時刻と状態で変わる定型作業 ルーティング型 タイマー 仕事ごと
Issue → 設計 → 実装 → PR 状態機械型(工場) イベント+タイマー 仕様承認、マージ
インシデントの一次調査 計画一括実行型 イベント(アラート) 報告後の対処
届いたメールへの一次対応 計画一括実行型 イベント(メール受信) 送信
レビュー指摘からのルール更新 単純な定期実行 タイマー(週次) 更新の採否

チームや部署でやり方が違うので、実装をそのまま渡すことは考えていません。渡すのは「うちの仕事はどの型で、何をきっかけに動くべきか」を決めるための、この表のほうです。

おわりに

数年後には、ここに書いたトリガー、状態の保存と再開、通知といった仕組みの部分は、サービス側に吸収されていると思っています。Azure Functionsの.agent.mdは既に「Markdownを1枚置いてデプロイ」ですし、Cloudflareもホスティングされたエージェントの基盤を出しています。

残るのは、どのツールを許可するかという資産と、どこに人のゲートを置くかという判断と、一度自分で組んだ人の目です。型の一覧は、その3つを持ち運ぶための形だと思っています。


この記事はZennにも投稿しています。

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?