AI開発の進行管理を、自作ワークフローエンジンに任せてみた
はじめに
AIコーディングエージェントに実装を任せる場面が増える一方で、こんな指示を何度も繰り返していないでしょうか。
- まず調査して
- 方針を出して、いったん待って
- 実装して
- テストが失敗したら戻って直して
- 何度か失敗したら止まって
作業そのものはAIが進めていても、「次に何をさせるか」「完了とみなしてよいか」「失敗時にどこへ戻すか」は、依然として人間が判断しています。
つまり、人間がAIの外側でワークフローエンジンの役割を担っている状態です。
そこで、AI開発の進行管理をコードとして外出しするために、Go製のワークフローエンジン「Phasekeeper」を試作しました。
この記事では、Phasekeeperを作った背景と、AI開発のループを状態機械として扱うための設計、実際に作って見えた課題を紹介します。
想定読者
この記事は、次のような方を想定しています。
- AIコーディングエージェントを使った開発に興味がある方
- AIへ同じような指示や確認を繰り返している方
- AIによる開発作業を、一定のルールに沿って進めたい方
- 状態機械やワークフローエンジンをAI開発へ応用することに興味がある方
前提
この記事では、AIコーディングエージェントの具体例としてCodex CLIを使用します。ただし、特定のエージェントの機能を解説することが目的ではありません。
また、Phasekeeperはローカルで動かしている個人的な試作です。AI開発のあらゆるワークフローに対応する汎用基盤や、完成したプロダクトではありません。
この記事では、Phasekeeperの使い方よりも、次の設計上の考え方を中心に扱います。
- AIの作業と、ワークフローの進行判断を分離する
- 会話の中にある暗黙的な状態を、機械が読める形で外へ出す
- Retry、Rollback、Human Gateを明示的なルールとして扱う
人間が担っていた進行管理
AIと人間が一緒に開発するとき、それぞれが担っている仕事を分けてみます。
AIが担当するのは、主に次のような作業です。
- コードベースの調査
- 解決方針の作成
- コードの変更
- テストや検証
一方、人間はその外側で次のような進行管理をしています。
- 次の作業を指示する
- 作業が完了したか確認する
- Retryするか、停止するか判断する
- 問題が起きたときの戻り先を指定する
- 重要な方針を承認する
ここで気になったのは、個々の指示の難しさよりも、同じ種類の判断を繰り返していることでした。
「調査が終わったら方針作成へ進む」「方針は人間が承認するまで実装へ進めない」「検証に失敗したら実装へ戻る」といったルールは、会話ではなくコードで扱えるのではないかと考えました。
着想1:AWS Step Functionsの状態と遷移
この発想の一つのきっかけが、AWS Step Functionsです。
AWS Step Functionsは、Lambda、ECS、Batchなどの処理を、状態と遷移でつなぐオーケストレーションサービスです。成功・失敗による分岐、再試行、待機などを、アプリケーション本体から分離してワークフローとして定義できます。
今回参考にしたのは、個々のAWSサービスとの連携方法ではなく、処理を単なる順番ではなく「現在の状態」と「次の状態への遷移」として扱う考え方です。
AI開発にも、次のような状態と遷移があります。
調査 -> 再現 -> 方針作成 -> 実装 -> 検証 -> 記録
さらに、常に右へ進むとは限りません。
実装 -> 検証
^ |
| | 問題あり
+------+
この進行判断をAIとの会話から分離し、外側のEngineに持たせることにしました。
着想2:AI-DLCのHuman-in-the-Loop
もう一つのきっかけは、AWSが公開しているAI-DLCのサンプルです。
参考にしたサンプルでは、PhaseごとにAIが作業を進めながら、重要な判断では人間が参加します。
AIによる実行 -> Human Gate -> 次のPhase
|
人間が承認・判断
AIにすべてを自動で進めさせるのではなく、方針の承認や最終確認など、判断が必要な境界で人間を呼び戻す考え方です。
このHuman-in-the-Loopの考え方と、Step Functionsの状態遷移を組み合わせれば、AI開発の進行管理をAIの外側に置けるのではないかと考えました。
参考: AWS AI-DLC Decisions-Driven Development
Phasekeeperの概要
Phasekeeperは、Markdownで書かれたIssueを入力として受け取り、PhaseごとにCodex CLIを起動するローカルのワークフローエンジンです。
Issue.md -> Phasekeeper <-> Codex CLI
|
+-- 状態と遷移を管理
Codex CLI自体を変更するのではなく、その外側に進行管理を置いています。
現時点での主な特徴は次のとおりです。
- Go製
- ローカルで実行
- 状態をファイルに永続化
- 開発作業を固定されたPhaseに分割
- Human Gate、Retry、RollbackをEngineが制御
実装はGitHubで公開しています。
AIとEngineの責務を分ける
Phasekeeperで最も分けたかったのは、「現在のPhaseで作業すること」と「ワークフローの進行を判断すること」です。
AIの責務は次のとおりです。
- 現在のPhaseに指定された作業を実行する
- コードやテストを変更する
- 作業結果を構造化された形式で報告する
- 必要であればRollbackを提案する
Engineの責務は次のとおりです。
- 現在のPhaseを保持する
- Phaseの完了条件を確認する
- 状態遷移ルールを適用する
- Human GateやRetryを制御する
- Rollback時に後続Phaseの結果をリセットする
ポイントは、AI自身に次のPhaseを決めさせないことです。
AIは現在のPhaseを実行して結果を返し、Engineがその結果とルールを照合して、次へ進む、再試行する、前へ戻る、人間を待つ、停止するといった判断を行います。
会話の中にあった状態を外へ出す
Phasekeeperで最も試したかったのが、会話の中に暗黙的に存在していた状態の外出しです。
AIと人間だけで進めていると、次のような情報は会話の履歴に埋もれます。
- 現在はどのPhaseにいるか
- 直前の検証がなぜ失敗したか
- どのPhaseへ戻るべきか
- Retryは何回目か
- 人間の承認を待っているか
会話では、次のように表現される情報です。
「さっきverifyに失敗した」
「implementに戻ろう」
「3回目なので、いったん止めよう」
これらをmanifestやPhase Resultへ書き出し、Engineが読める状態にします。概念的には次のようなデータです。
state:
currentPhase: verify
control:
rollback:
toPhase: implement
retryLoop:
count: 3
gates:
aws_validation:
status: pending
重要なのは、単に状態を保存することではありません。
Engineが明示された状態と遷移ルールを読み、「次へ進めるか」「前へ戻すか」「人間を待つか」を判断できるようにすることが目的です。これによって、AI開発のループを会話の記憶だけに依存せず制御できます。
Phaseと完了条件
現在のPhasekeeperでは、一般的な開発作業を次の6つのPhaseに固定しています。
| Phase | 役割 |
|---|---|
analyze |
コードや要件を調査する |
reproduce |
問題を再現する |
propose |
解決方針を作成する |
implement |
コードを変更する |
verify |
テストや動作確認を行う |
document |
結果を記録する |
Engineはmanifestに現在位置と各Phaseの完了状態を保存します。AIから返されたPhase Resultを読み、必要なチェック項目が満たされた場合にだけ、次へ進めるかを判定します。
analyze -> reproduce -> propose -> implement -> verify -> document
^ | |
+-----------------------+-----------+
必要に応じてRollback
現時点では、設定だけで自由にPhaseを追加・変更できる汎用ワークフローエンジンではありません。まずは固定した開発フローの中で、状態と遷移を外出しすることを優先しています。
戻る・待つ・やり直すをコードにする
状態管理の効果が表れるのは、正常に次へ進むときよりも、途中で止まる、戻る、やり直すときです。
Phasekeeperでは、たとえば次のような制御を行います。
propose
|
v
Human Gate -- approve --> implement <--> verify
Rollback
|
v
Human Gate
|
v
document
Human Gate
方針から実装へ進む前や、検証が終わった後など、重要な境界では人間の承認を要求します。
Human Gateで人間が選べる操作は次のとおりです。
-
approve: 結果を承認して次へ進める -
retry: 現在のPhaseをもう一度実行する -
rollback: 指定したPhaseへ戻す -
stop: ワークフローを停止する
人間は常に細かな進行を指示するのではなく、明示された判断境界でだけ操作します。
Rollback
たとえばverifyで問題が見つかった場合、implementへ戻します。このとき、戻り先を変更するだけでなく、それ以降のPhaseで得られた結果もリセットします。
古い検証結果を完了済みとして残したまま再実装すると、状態に矛盾が生じるためです。
Retry
一時的な失敗や出力不足であれば、同じPhaseを再実行します。ただし、無制限に自動実行すると同じ失敗を繰り返す可能性があります。
そこで、Retryが一定回数を超えた場合は自動ループを止め、人間に続行するか判断してもらいます。
実際に動かして見えたこと
試作を動かしてみると、会話を読み返さなくても次の情報を確認できるようになりました。
- 現在どのPhaseにいるか
- Phaseの完了条件を満たしているか
- 次に許可されている操作は何か
- Retryを何回行ったか
- いつ、どのPhaseへRollbackしたか
- どのHuman Gateで承認されたか
失敗時の戻り先や、人間を呼び出す条件もコード上に明示できます。AIの応答に進行管理を委ねず、実行制御を再現可能な形に近づけられた点はよかったです。
一方で、状態を外へ出せばすべて解決するわけではありません。実際に作ったことで、「何を状態として残すべきか」という別の難しさが見えてきました。
現状には、少なくとも次の制約があります。
- Workflowは固定されている
- 一部のRetry状態はメモリ上にあり、再起動すると失われる
- 読み取り専用で作業させたいPhaseも、その境界はプロンプト上の契約に依存している
- ローカルで動く個人的な試作であり、汎用基盤として完成しているわけではない
特に、状態の永続化には設計上の判断が必要です。すべてを保存すると複雑になりますが、再起動後も判断に必要な情報を保存しなければ、ワークフローを正しく再開できません。
まとめ
Phasekeeperでは、AI開発における役割を次のように分けました。
- AIは、現在のPhaseの作業に集中する
- Engineは、状態、遷移、Retry、Rollback、Human Gateを管理する
- 人間は、明示された重要な判断境界で操作する
AIコーディングを改善しようとすると、モデルの性能やプロンプトの工夫に注目しがちです。しかし、その外側で人間が担っている実行制御にも、コードで改善できる余地があります。
Phasekeeperそのものを使うべき、というのがこの記事の結論ではありません。
普段AIに繰り返している指示を見直すと、そこには状態、遷移、完了条件、失敗時の戻り先といったワークフローが隠れているかもしれません。
自分がAIへ繰り返し出している指示は、コードにできないか?