一晩でGitHubのプルリクを作る自律型AIコーディングエージェントの作り方

Dev.to / 2026/5/20

💬 オピニオンDeveloper Stack & InfrastructureTools & Practical UsageModels & Research

要点

  • 記事では、自律型AIコーディングエージェントを「取り込み→計画→実行→検証→パッケージ」という5段階の状態機械として説明し、GitHubのイシュー等のタスク入力をレビュー可能なプルリクエストへ変換します。
  • 重要な技術課題は言語モデルそのものではなく、その周辺にあるループとチェックポイント設計であり、計画・実行・検証を1つの巨大プロンプトにまとめると些細な修正以外では破綻すると述べています。
  • 検証(テスト/型チェック/リンタ)の結果とエラーテキストを次の編集へフィードバックし、リトライ回数を上限(例:3回)で制御することで、トークンを無限消費し続けたり壊れた修正を繰り返したりするのを防ぐべきだとしています。
  • 安全性のために、リポジトリ単位のきめ細かなトークンを使い、コード生成・実行は開発者PCではなく使い捨てコンテナ/VMで行い、mainへの影響を防ぐためにブランチ保護を前提にするべきだと提案しています。

就寝前に課題を登録します。「moment.js から日付ヘルパーを移行する。」目を覚ますと、ドラフトのプルリクエストができている――ブランチ作成、ファイル変更、テストはすべてグリーン、レビュー待ち。これが、自律型のAIコーディングエージェントの売り込み文です。そして意外なのは、そのほとんどが新しさに欠けることです。難しい問題はモデルではありません。モデルを取り巻くループです。つまり、誰も席に座っていないのに、タスクをレビュー可能なPRへと変換するハーネスです。

私たちはこのパターンを構築し、実際のリポジトリに対して実行しました。以下には、成り立ったアーキテクチャ、確実に安全だったGitHubの連携、そしてどのタスクは完了し、どのタスクは黙って失敗するのかについての正直な記録を示します。

夜間ループの構造

自律型のコーディングエージェントは、いくつかの遷移に言語モデルをつないだ状態機械です。マーケティングを取り除くと、次の5段階が残ります:

  1. 取り込み(Ingest) — タスク(GitHubのイシュー、キューロウ、ファイル内の1行)とリポジトリを取り出し、クリーンな作業ディレクトリに用意します。
  2. 計画(Plan) — 1回のモデル呼び出しでタスクとリポジトリの構成を読み取り、具体的な計画を出します。どのファイルをどう変更するか、どの順番で、そして「完了(done)」がどう見えるか。
  3. 実行(Execute) — 別のモデル呼び出しが計画に合わせてファイルを編集します。1つのまとまりとして、変更を一度に1つずつ行います。
  4. 検証(Verify) — テストスイート、型チェッカー、リンタを実行します。
  5. 梱包(Package) — コミットし、ブランチをプッシュし、プルリクエストを開きます。

最初の試行で多くの人が犯す間違いは、段階2〜4を1つの巨大なプロンプトに畳み込むことです:「ここにリポジトリがあり、ここにタスクがある。差分(diff)を出力して。」これは3行の修正なら動きますが、規模が大きくなると崩壊します。狭いステップをつなげることで、単一のプロンプトでは得られないものが手に入ります。つまり、各段階の間にチェックポイントを置き、エージェントがコミットを決断する前に作業を検査できるようにすることです。

段階4が、コーディングエージェントとコードジェネレーターを分けます。フィードバックループのないモデルは、コンパイルできないコードに対しても、あっさり「成功です」と報告してしまいます。エグゼキュータを検証器に接続し、テスト実行で失敗したときに実際のエラーテキストを次の編集へフィードバックします。リトライ回数には上限を設けます――3回が妥当な天井です。それでもなおグリーンに到達できない場合、エージェントは止まり、PRをドラフトとして開き、壊れたコードを押し付けたりトークンを燃やし続けたりせず、失敗を記録すべきです。

リポジトリへの書き込み権限を持つ自律型エージェントは、あなたが会ったことのない貢献者です。単一リポジトリにスコープした、きめ細かい個人用アクセス・トークンを渡してください。シェルに置いてある組織全体向けのトークンを使ってはいけません。実行はコンテナまたは使い捨てのVMで行い、ノートPC上では行わないでください。生成されたコードはnpm install と、他にもエージェントが必要だと判断したものを実行するからです。main のブランチ保護を有効にしておけば、最悪でも成立し得る結果はデフォルトブランチへの壊れたコミットではなく、「悪いプルリクエスト」になります。

指を失わずにGitHubへつなぐ

エージェントがグリーンの作業ツリーを作った後、GitHub側の手続きは定型です。私たちが耐えられたのはこのパターンです:

  • タスクごとに1ブランチ、予測可能な名前で――agent/142-moment-migrationのように、イシュー番号に基づいて命名します。予測可能な名前にすると、再実行が冪等(idempotent)になります。ブランチが既に存在していれば、重複したブランチを作るのではなく更新します。
  • PRはドラフトとして開く そして自分をレビュアーに割り当てます。ドラフト状態は、変更がマージ準備できていないことをチーム全体に知らせ、反射的な承認を抑制します。
  • ボットが作成したPRにはすべてラベルを付けるagent-generated など。同ラベルは出自(プロベナンス)の追跡として機能し、差分がユーザーに届く場合にあなたが行うべき開示の根拠になります。
  • CIを動かす — エージェントのPRに対して、人間のPRとまったく同じようにCIを走らせます。CIは、エージェント自身の検証ステージでは完全には置き換えられない安全網です。なぜならCIは、エージェントのサンドボックスではなく、あなたが管理するクリーンな環境で実行されるからです。

gh CLIなら梱包が短く済みます:gh pr create --draft --base main --head agent/142。より豊富な制御――ラベルの追加、レビュアーの指名、PRの状態を読み戻すこと――を行うには、OctokitのRESTクライアントを依存関係として使うのが妥当です。

トリガーは2つのきれいな選択肢があります。午前2時にcronで起動して、夜間にタスクキューを捌く方法。あるいはGitHubのWebhookです。イシューにagent-readyというラベルを付けると、ラベリングのイベントが実行を開始します。Webhook方式は、タスクとトリガーがチームがすでに働いている場所に共に存在するため、より実際のワークフローに近いです。

うまく自動化できること――そして止まる場所

夜間エージェントが役に立つのは、機械的ではあるが面倒な作業です。依存関係を更新して後始末を直すこと、未テストのモジュールにテストカバレッジを追加すること、コードベース全体で非推奨のAPI呼び出しを移行すること、codemodを実行すること、設定ファイルを変換すること、古くなったドキュメントを整えること。これらのタスクは共通して1つの性質を持っています――「done」が客観的に検査可能です。テストスイートがパスする、型チェックがきれいに通る。それだけで、検証ステージは成功したと判断できます。

止まるのは、それと逆の種類の作業です。曖昧な依頼(「ダッシュボードを速く感じさせて」)、横断的なアーキテクチャ変更、プロダクトの判断に委ねられるもの、そして最も重要なのは、テストスイートが薄いリポジトリ内のタスクです。検証ゲートがないと安全性は担保できず、エージェント自身の出力に対する自信は、それ単体では「一つの根拠」としては不十分です。

これを実行する価値があるかを決めるのは2つの数字です。1つ目は1回あたりのコストです。各ステージは1回以上のモデル呼び出しで構成され、リトライが絡む非自明なタスクなら十数回、場合によっては数十回に達します。上限として、トークンや金額の天井を1実行あたりに設定してください。そうしないと、動けなくなったエージェントがあなたが寝ている間に請求が膨らむことになります。2つ目はPR受け入れ率です。生成されたPRのうち、実質的な書き換えなしでマージされる割合を指します。あなたが書き直すほうが多いなら、タスクのスコープが広すぎます。エージェントが確実に成功するまでスコープを絞り、その後は注意深くスコープを拡げます。

朝のレビューは譲れません。エージェントの仕事は、あなたが数分で判断できるプルリクエストを渡すことです。1時間かかっていたはずの作業の代わりにするためです。午前9時にあなたがうっかり承認してしまう、質の悪いPRはPRがないよりも悪い――だから、CIがグリーンで、あなた自身が読み終えるまでは、夜間に出てきた差分を「信頼できないもの」として扱ってください。こうした設計にしておけば、エージェントはあなたの代替にはなりません。扱うのは退屈な部分だけの、夜勤です。

Originally published at pickuma.com. Subscribe to the RSS or follow @pickuma.bsky.social for new reviews.