⛳

GitHub Copilot サブエージェントによるオーケストレーター パターンの実践

に公開
2025/12/16

GitHub Copilot の agent/runSubagent は、エージェントから別のエージェントを呼び出すためのツールです。以前の記事で、サブエージェントの作成方法やコンテキスト分離の効果に関する検証を行いました。

さらに、VS Code v1.107 からは、カスタムエージェント(.agent.md)を runSubagent で直接呼び出せるようになり、より一貫性のあるオーケストレーションが可能になりました。

そこで、今回はこの新機能を活かして開発ワークフロー全体を自動化するオーケストレーターシステムを構築してみます。

この記事で作成するオーケストレーター(エージェント)は、Issue の作成から Plan、Implementation、Review を経て PR 生成まで、各フェーズをサブエージェントに委譲しながらソフトウェアの開発プロセスを実行するフローを実現します。

前提とするのは以下の環境です。

  • VS Code 1.107 以降
  • GitHub Copilot Chat 拡張機能

1. そもそもなぜサブエージェントにするのか?

大規模なタスクをエージェントに実行させる場合、1 つのエージェントにすべてを任せると、以下のような問題が発生します。

  • コンテキストの肥大化: 複雑なタスクを処理するために多くの情報を与えると、エージェントが本来の目的に集中できなくなる可能性があります。
  • 責任の曖昧化: 1 つのエージェントが多くの役割を担うと、どの部分がどのように処理されているかが不明瞭になり、明確なワークフローを設計しづらくなります。
  • 保守性の低下: タスクが複雑になると、エージェント定義が何百行にもなり、変更や改善が面倒になります。

サブエージェントをうまく活用するとこれらの問題に対処できるのと、個人的には まっさらなコンテキストで中立的に作業する ことが実現できるのも大きなメリットだと感じます。これは特にコードレビューのようなタスクで有効です。

今回はすべてのフェーズをサブエージェントに分割し、オーケストレーターが全体のワークフローを管理する形をとっています。普段の作業でここまでサブエージェントする必要はないかもしれませんが、少なくともレビュープロセスだけはサブエージェント化することを強くおすすめします。

2. 完成イメージ

ディレクトリ構成

.github/
└── agents/
    ├── orchestrator.agent.md  # オーケストレーター
    ├── issue.agent.md         # Issue 作成/管理
    ├── plan.agent.md          # 実装計画の策定
    ├── impl.agent.md          # TDD に基づく実装
    ├── review.agent.md        # コードレビュー
    └── pr.agent.md            # PR 作成

ワークフロー

このフロー図が示すように、オーケストレーターはすべてのフェーズの「指揮者」です。各フェーズの詳細な処理はサブエージェントに委譲され、オーケストレーター自身は高レベルのワークフローを管理するだけです。

設計の考え方

このオーケストレーターシステムの根底は「責任分離」です。

各エージェントに明確な責任(Job Responsibilities)を与えることが重要です。以下はこのシステムにおける責任分離の例です。

エージェント 責任 対象外
Orchestrator ワークフロー全体の進行管理、タスク割り当て 実装、コード生成、技術的判断
Issue Agent ユーザー要望の解釈、Issue の作成/管理 実装計画、コード
Plan Agent リポジトリ分析、実装計画の策定 コード生成、実装実行
Impl Agent TDD に従ったコード実装 計画策定、レビュー
Review Agent コードレビュー、品質判定 実装、修正
PR Agent PR の作成と管理 コード生成、マージ判定

3. Issue エージェントを作ってみよう

では、実際に作ってみましょう。まずは次の役割をもった、Issue Agent から作っていきます。

  • ユーザーが入力した要望を理解する
  • 既存の GitHub Issues を確認する
  • 必要に応じて新しい Issue を作成するか、既存 Issue を更新するか判定する
  • 創造的に批判的レビューを行い、Issue の品質を高める

エージェント定義ファイル

.github/agents/issue.agent.md を作成し、以下の内容を記述します。

---
description: 要件と仕様を洗練させて、イシューの報告や機能リクエストをサポートします。
tools:
  [
    "edit",
    "execute",
    "read",
    "search",
    "todo",
    "web",
    "ms-vscode.vscode-websearchforcopilot/websearch",
  ]
---

あなたは、ユーザーが入力する要望 (issue, bug report, feature request など) をもとに、イシューを管理するエージェントです。以下のステップに基づき、要件と仕様の解像度を高めながら、イシューを管理してください。

## 手順 (#tool:todo)

1. 現状/要件を理解する
2. 必要に応じリモート レポジトリと同期する
3. 現在のローカル レポジトリ状況を確認する
4. 現在の GitHub Issues の状況を確認する
5. #tool:ms-vscode.vscode-websearchforcopilot/websearch でウェブ検索を行い、要件の理解を深める
6. 要件と調査結果に基づき、Issue を作成/更新する
7. 作成された Issue に対して批判的にレビューを行う
8. レビュー内容に基づき、Issue を改善する
9. ユーザーに作成した Issue を報告する

## ツール

- #tool:ms-vscode.vscode-websearchforcopilot/websearch: ウェブ検索
- `gh`: GitHub リポジトリの操作

## ドキュメント
- `docs/`
- `README.md`
- `CONTRIBUTING.md`

ポイント

☑️ ツールの明示的な指定

フロントマターの tools セクションで、エージェントが利用可能なツールを限定しています。

tools を明示しなければ、現在のツール選択が継承される動作になりますが、一見無害のようなこの動作がエージェントに問題を引き起こすことがあります。なぜなら、不要なツールは無駄にコンテキストを消費し、エージェントの判断を曇らせるからです。これらは tool overload 問題 や Context Rot 問題 として知られています。

そこで、このエージェント定義では、必要最低限のツールだけを tools セクションに列挙しています。これにより、エージェントが本来の目的に集中できるようになります。

☑️ 手順と #tool:todo の併用

基本的には何をさせたいか、ステップで書くと期待通りの動作をしてくれることが多いです。しかし、エージェントが複雑なタスクを扱う場合、ステップの順序や重要なポイントを見失うことがあります。そこで、#tool:todo を使って「やることリスト」を明示的に提供することで、エージェントの行動をガイドします。

☑️ コマンドの利用

あえて GitHub 操作には gh コマンドを利用します。

GitHub 操作を AI エージェントに指示する場合、GitHub MCP Server を利用することも出来ます。しかしながら、MCP の安易な利用は以下の問題を生じます。

  • Context Rot の原因: 一般に、MCP ツールは多くのコンテキストを消費するため、エージェントが本来の目的に集中できなくなる可能性があります。しかも、ツールの説明文の長さはユーザーでコントロールすることが出来ません。gh コマンドを使うなら、コマンドを使ってくれ、という指示だけを与えておけば、基本的に help オプション/サブコマンドなどを使ってあとは勝手にやってくれます。
  • パイプライン処理が出来ない: MCP ツールは一度きりの実行操作を提供しますが、ツールから出力された値を別のプロセス・ツールの入力につないでリダイレクト・・・みたいなパイプライン処理ができません。gh コマンドなら、grep でコンテキスト消費を抑えた検索をしたり、jq とあわせて高度な操作をしたり、といったことが簡単に出来ます。

以上のような理由のため、自分は「同じことができるなら迷わずコマンドラインツールを使う」派です。特に、gh のようなとても有名な(エージェントが使い方を学べる可能性がたかい)ツールではなおさらです。

☑️ ドキュメントの明示

エージェントが利用できるリソースを具体的に示すことで、エージェントの理解と判断を助けます。

これには、必要な状況になったらローディング(lazy load)することで、コンテキスト消費を抑える意図もあります。

4. 残りのサブエージェントを作る

同じように、残りの 4 つのサブエージェント(Plan、Impl、Review、PR)を作っていきます。

Plan Agent の定義
.github/agents/plan.agent.md
---
description: リポジトリを分析して必要な情報を収集し、指定されたイシューの実装計画を策定します。
tools:
  [
    "execute",
    "read",
    "search",
    "todo",
    "web",
    "ms-vscode.vscode-websearchforcopilot/websearch",
  ]
---

与えられたイシューの実装計画を立ててください。

## 手順 (#tool:todo)

1. 現在のレポジトリ状況を確認し、リモートとの同期を行う
2. 指定されたイシューの内容を確認する。イシューが存在しない場合は、処理を中止しユーザーに通知する。
3. レポジトリ (コード、ドキュメント) を確認する
4. ウェブ検索で情報を収集する
5. 実装計画をユーザーに提示する

## ツール

- #tool:ms-vscode.vscode-websearchforcopilot/websearch: ウェブ検索
- `gh`: GitHub リポジトリの操作

## ドキュメント

- `docs/`
- `README.md`
- `CONTRIBUTING.md`

## ブランチ戦略

- 新しいタスクごとにブランチを作成し、GitHub Issue 番号を含める (例: `feature/issue-123-description`)
- 定期的に `main` ブランチからリベースまたはマージして最新状態を保つ
- `main` ブランチに直接コミットすることは許可されない
Implementation Agent の定義
.github/agents/impl.agent.md
---
description: TDD の原則に従って、指定された計画に基づいて実装を実行します。
tools:
  [
    "execute",
    "edit",
    "read",
    "search",
    "todo",
    "web",
    "ms-vscode.vscode-websearchforcopilot/websearch",
  ]
---

与えられた実行計画に従って、実装を行ってください。TDD に倣って、以下のステップで実施します。

## 手順 (#tool:todo)

1. 作業用ブランチに切り替える
2. テストコードを作成する
3. 開発ポリシーに従って実装する
4. テストを実行し、成功を確認する
5. 成功したらリファクタリングを行う
6. リファクタリング後もテストが成功することを確認する
7. 必要に応じてドキュメントを更新する
8. 実装内容を説明する

## ドキュメント

- `docs/`
- `README.md`
- `CONTRIBUTING.md`
Review Agent の定義
.github/agents/review.agent.md
---
description: 実装内容をレビューし、建設的なフィードバックを提供します。
tools:
  [
    "execute",
    "read",
    "search",
    "todo",
    "web",
    "ms-vscode.vscode-websearchforcopilot/websearch",
  ]
---

実装内容をレビューしてください。批判的に評価を行い、発言についての中立的なレビューを提供してください。新たな情報を検索、分析することを推奨します。あくまでレビューの提供までがあなたの役割です。

## 手順 (#tool:todo)

1. 網羅的に情報を収集する
   - レポジトリの分析
   - ドキュメント群の分析
   - ウェブ検索 (#tool:ms-vscode.vscode-websearchforcopilot/websearch) によるベストプラクティス、pitfalls、代替案の調査
2. 収集した情報をもとに、実装内容を批判的に評価する (正確性、完全性、一貫性、正当性、妥当性、関連性、明確性、客観性、バイアスの有無、可読性、保守性などの観点)
3. 改善点や懸念点があれば指摘し、アクションプランを示す

## ツール

- #tool:ms-vscode.vscode-websearchforcopilot/websearch: ウェブ検索
- `gh`: GitHub リポジトリの操作

## ドキュメント

- `docs/`
- `README.md`
- `CONTRIBUTING.md`
PR Agent の定義
.github/agents/pr.agent.md
---
description: 指定されたイシューと実装に対するプルリクエストを作成します。
tools:
  [
    "execute",
    "read",
    "search",
    "todo",
    "web",
    "ms-vscode.vscode-websearchforcopilot/websearch",
  ]
---

与えられたイシューと実装に対する、プルリクエストを作成してください。

## 手順 (#tool:todo)

1. PR が作成できる状態にあるのか確認する
   - ドキュメント更新の忘れがないか
   - 未コミットの変更がないか
   - テスト (CI) が通過するか
2. 作成にふさわしくない状況だと判断される場合、修正案を示して終了します。そうでなければ PR を作成します。
3. 作成された PR の内容とリンクをユーザーに通知します。

## Notes

- 関連する Issue がある場合、その Issue 番号を含めてください (e.g., `Closes #<number>`)
- GitHub Issue に追加のコメントが必要であれば、コメントを残しておいてください。

## ツール

- #tool:ms-vscode.vscode-websearchforcopilot/websearch: ウェブ検索
- `gh`: GitHub リポジトリの操作

## ドキュメント

- `docs/`
- `README.md`
- `CONTRIBUTING.md`

なお、Issue Agent でもそうでしたが、これらのエージェントの中に「どのようにコーディングをするか」や「ディレクトリ構造をどのように保つか」といった情報は含めていません。

そうした情報は docs/*.md、CONTRIBUTING.md といったドキュメントにまとめておき、エージェントが必要に応じて参照できるようにします。これにより、エージェント定義自体はシンプルに保たれ、ドキュメントの更新も容易になります。

ただし、単に外部ドキュメント化するだけではエージェントが参照してくれない可能性があるので、AGENTS.md や .github/copilot-instructions.md で必ずドキュメントのリファレンスを行うようにします。

AGENTS.md
# ガイドライン

## ソフトウェア開発ポリシー

- `docs/development-policy.md`: コーディング規約、ブランチ戦略、コミットメッセージ規約など
- `docs/testing-policy.md`: テスト戦略、カバレッジ目標
- `docs/review-policy.md`: コードレビュー基準、チェックリスト
- `docs/deployment-policy.md`: デプロイ手順、CI/CD パイプ

## ...

5. オーケストレーターを作る

最後に、すべてのサブエージェントを統合するオーケストレーターを作成します。

---
description: ユーザーの要望に基づき、機能追加やバグ修正の実装をオーケストレーションします。
argument-hint: 報告したいイシュー、またはリクエストしたい機能を説明してください。
infer: false
tools:
  [
    "agent",
    "todo",
    "ms-vscode.vscode-websearchforcopilot/websearch",
  ]
---

あなたはソフトウェア開発のオーケストレーターエージェントです。ユーザーが入力する要望をもとに機能やバグ修正を実装することを目的として、全体のフローを見ながら作業を別エージェントに指示します。あなたが直接コードを書いたりドキュメントを修正することはありません。

## 手順 (#tool:todo)

1. #tool:agent/runSubagent で issue エージェントを呼び出し、イシューを作成する
2. #tool:agent/runSubagent で plan エージェントを呼び出し、実装計画を立てる
3. #tool:agent/runSubagent で impl エージェントを呼び出し、実装を行う
4. #tool:agent/runSubagent で review エージェントを呼び出し、コードレビューと修正を行う
5. 必要に応じてステップ 3 と 4 を繰り返す
6. #tool:agent/runSubagent で pr エージェントを呼び出し、プルリクエストを作成する
7. 実装内容とプルリクエストのリンクをユーザーに通知する

## サブエージェント呼び出し方法

各カスタムエージェントを呼び出す際は、以下のパラメータを指定してください。

- **agentName**: 呼び出すエージェント名(例: `issue`, `plan`, `impl`, `review`, `pr`)
- **prompt**: サブエージェントへの入力(前のステップの出力を次のステップの入力とする)
- **description**: チャットに表示されるサブエージェントの説明

## 注意事項

- あなたがユーザー意図を理解する必要はありません。意図がわからない場合でも、イシューエージェントに依頼すれば、意図理解と説明を行ってくれます。

ポイント

☑️ 直接コード処理をしない

edit ツールが定義されていないことからわかる通り、オーケストレーターは直接コードを書いたりドキュメントを修正したりしません。すべての実装作業はサブエージェントに委譲します。なんなら read 権限すらありません。

あくまで「指揮者」として振る舞うことに専念してもらうことで、コンテキスト消費を抑えて、高レベルのワークフロー管理に集中できるようにしています。

☑️ 責任境界を明確にする注記

- あなたがユーザー意図を理解する必要はありません。

実装当初、オーケストレーターは曖昧な要望を勝手に補完しようとしていました。この注記により、その行動を抑止できます。

☑️ runSubagent のパラメータ明示

agent/runSubagent は、prompt、description、agentName の 3 つの入力パラメータを取ります。詳細は以下の記事にまとめていますが、これらのパラメータを明示的に指定すると、意図したようなサブエージェント呼び出しが実現しやすいです。

https://zenn.dev/openjny/articles/32c8ca30e43c38

6. オーケストレーターを使ってみる

カスタムエージェント呼び出しの有効化

2025 年 12 月 15 日時点では、サブエージェント呼び出しでカスタムエージェントを利用するには、以下の実験的機能を有効にする必要があります。VS Code の設定(settings.json)に以下を追加してください。

{
  "chat.customAgentInSubagent.enabled": true
}

https://code.visualstudio.com/updates/v1_107#_run-agents-as-subagents-experimental

呼び出し方法

オーケストレーターは VS Code の GitHub Copilot Chat から直接呼び出せます。

  1. VS Code を開き、Copilot Chat を起動
  2. エージェントドロップダウンから「orchestrator」を選択
  3. 要望を入力

例:

"ユーザー認証機能を JWT で実装してほしい。デーベースは PostgreSQL を使っています。"

すると、オーケストレーターが以下の処理を自動で実行してくれます。

  1. Issue Agent が要望を Issue に変換
  2. Plan Agent が実装計画を立案
  3. Impl Agent が TDD に従って実装
  4. Review Agent がコードレビュー
  5. PR Agent が PR を作成

複雑なフローがシンプルな一度の入力で実現できます。

7. 学びや気づき

実際に作って試してみた結果、いくつか気づきが得られました。

カスタムエージェント呼び出しの恩恵

v1.107 以降、agentName パラメータでカスタムエージェントを名前指定できるようになったことで、一貫性が大幅に向上しました。以前は、オーケストレーターがその場でサブエージェント定義を動的に生成していたため、毎回微妙に異なる挙動が発生することがありました。カスタムエージェント方式では、事前に定義されたエージェントを呼び出すため、同じタスクに対して常に同じ振る舞いをします。これは信頼性の観点で非常に重要です。

このあたりは、以下の記事で解説しています。

https://zenn.dev/openjny/articles/32c8ca30e43c38

責任境界を教える

厄介だったのが、オーケストレーターが曖昧なユーザー要望に対して自分で解釈を埋めようとする行動でした。

ユーザーの意図を汲み取ろうとするのは良い意図なのですが、このシステムでは Issue エージェントがその責任を担っています。「あなたがユーザー意図を理解する必要はありません」と明記することで、その行動を抑止できました。これは人間の組織教育と同じで、「あなたの責任ではない」と教えることが大事ですね。

共通化の重要性

私は、普段から AGENTS.md や .github/copilot-instructions.md に開発ポリシーやコーディング規約、ブランチ戦略などの詳細を直接書かないようにしています(DRY とか YAGNI みたいな簡単なサマリだけ書いて、後は参照を書いています)。必要に応じて docs/ や CONTRIBUTING.md といったドキュメントを動的に読み込むことで、コンテキストの肥大化を防ぐためです。

今回も同じようにエージェントの記述をしていて気づいたのは、「共通化されたドキュメントを参照することで、エージェント定義自体をシンプルに保てる」という点です。

各エージェントに同じような定義を繰り返し書くのではなく、共通ドキュメント(の一部)を参照させる命令だけ書けば、エージェントを複数定義する際にメンテナンス性が向上しました。

エラーハンドリングとリカバリー

8. まとめ

このオーケストレーターシステムは、runSubagent をコンテキスト分離だけでなく「責任分離」のツールとして活用した例です。

設計のコツ:

  • 各エージェントの責任を明確に
  • カスタムエージェント化で、単体利用とサブエージェント利用の両対応
  • ツール選択、MCP よりもコマンド、ドキュメントの外部化などでコンテキスト消費を抑制

ただし、紹介したフローは「ハッピーパス(すべてがうまくいくケース)」を基本的に前提とした簡易的なフローです。実運用では、例えば「Impl Agent がビルドエラーを解消できない」「Review Agent が承認しない」といったケースが発生します。より堅牢なシステムにするには、条件に応じて人間に判断を仰ぐような「エスケープハッチ」をプロンプトに組み込むことが重要です。

また、今回の記事ではエージェントの具体的な振る舞いについてはあまり考慮していません。つまり、開発プロセスの品質を高める指示の書き方などについては触れていません。実際の運用では、各エージェントが高品質なアウトプットを生成できるよう、プロンプトエンジニアリングや継続的なチューニングが必要です。

みなさんのユースケースにあわせて、ぜひカスタムエージェントと runSubagent を活用してみてください。

参考情報

Discussion