2
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?

AI開発チームを設計する ― 役割分担・権限分離・コンテキスト設計

2
Posted at

個人開発、インターンでの開発、研究での開発、あらゆる場面でAIを常に使っています。その際、以下のフローで開発をしてきました。

  1. 対話セッションを立ち上げて仕様や設計を詰めて仕様書を書く
  2. 仕様書を書けたら、タスク分割を設計する
  3. タスクを分割したら、自ら立ち上げた複数のセッションに仕様書とタスクを渡して実装させる
  4. 終わったら、AIに自動テストを走らせて、僕自ら受け入れ基準を満たしているかをチェックする
  5. 問題あれば実装に差し戻し、問題なければコミット&プッシュ、プルリクエスト提出をする

この開発フローにした理由として、コンテキストの膨大によって実装と検証の精度低下を防ぐことと、最終的に僕自身が説明出来ることを担保することの2つがあります。
確かに、この開発フローによって品質をある程度確保した開発を遂行できていると感じています。
しかし、以下の問題も感じていました。

  • 一々仕様書をセッションに渡すのがめんどくさい
  • さらにいえば、一々セッションを立ち上げるのもめんどくさい
  • ただ、サボって1つのセッションのみにすると、コンテキストの膨大によって実装と検証の精度低下を防げないというジレンマ

そこで、「1つの開発タスクにつき、1つのセッションで完結できるかつ、実装と検証の精度を落とさない開発フローを構築すること」を目的に、Claude Code でAI開発チームを設計してみました。
設計する上で、複数のサブエージェントの役割と権限をどう分けるかを特に意識していたので、それを書いていきます。

AI開発チーム構成

実践と改善を繰り返して、最終的には以下の構成になりました。

僕:開発責任者
└ プロダクトの価値、プロダクトゴール、新規機能やバグ修正などの要件(Why / What)の明確化と、重要な意思決定に責任を持つ

AI開発チーム
├ メインエージェント:テックリード役
│   └ 僕自身との議論、サブエージェントの指揮、開発フローの進行状態・判断の管理、判断が必要な事項の引き継ぎを担当する
└ サブエージェント:開発者役
│   └ 役割と専門性を分け、仕様設計から実装・統合・レビューまでを担当する
├ spec-designer ........ Why / Whatの確認、受け入れ基準の設定、設計、判断が必要な仕様変更や選択肢の整理
├ spec-updater ......... 承認済み事項の仕様への反映、状態更新、確定版への書き直し、機械的な整合修正
├ task-splitter ........ Howを、小さく独立した開発タスクへ分解
├ test-writer .......... 受け入れ基準からテストを先行作成し、Redを確認
├ implementer .......... 渡された仕様での実装可能性の検証と実装。僕自身への確認後の軽微な修正も担当
├ integration-tester ... 変更全体を統合した状態で、既存実装との整合や回帰を検証
└ reviewer ............. 完成の定義(DoD)を独立して検証し、品質報告と必要に応じた僕自身の確認手順を作成

このAI開発チームを組む過程で、4つのポイントが生まれました。

  1. 役割を仕様・実装・検証で分離する
  2. 実装の中でも工程を分ける
  3. 推論・判断と機械作業を分ける
  4. 全体を管理するAIに実作業をさせない

次節からは、この4つのポイントについて詳しく書いていきます。

AI開発チームを構成する4つのポイント

1. 役割を仕様・実装・検証で分離する

開発で扱うコンテキストは、大きく3つに分けられると考えました。

  • 仕様
    • spec-designer
    • spec-updater
    • task-splitter
  • 実装・統合
    • test-writer
    • implementer
    • integration-tester
  • 検証
    • reviewer

仕様フェーズで扱うべきコンテキストは、「何を(What)、何のために(Why) 作るのか」と「そのWhatとWhyを満たす受け入れ基準とは何か」です。

実装・統合フェーズで扱うべきコンテキストは、「受け入れ基準を満たすために、どのように実装するか」と、「受け入れ基準を満たしていることを確認するために、どのようなテストが必要か」です。

検証フェーズで扱うべきコンテキストは、「実装された成果物を、受け入れ基準や完成の定義に照らして完成と判断してよいか」です。

これらコンテキストを1つのエージェントに混在させると、以下の状況が起こりやすいと考えています。

  • AIの採用した実装方針が正しいことを前提に、その実装を評価してしまう
  • 実装上の都合に合わせて、受け入れ基準や仕様を書き換えてしまう
  • AIが実装したコードを通すことを優先したテストを生成してしまう

そこで、仕様・実装・検証をそれぞれ別のサブエージェントに分け、各フェーズで必要な情報だけを渡し、そのフェーズの目的に集中させる構成にしました。

また、サブエージェントの間にある境界を超えてはならないというルールも設けています。例えば、spec-deginerはコードを書かない、implementerは仕様・受け入れ基準を変更しない、reviewerはコードを修正しないという形にしています。

仕様を決めるAI、実装するAI、受け入れ基準を満たすかを検証するAIを分けることで、コンテキストを絞りながら、実装都合で仕様や評価基準が書き換わらない構成にしています。

2. 実装・統合フェーズの中でも役割・工程を分ける

実装・統合フェーズは、単にコードを書く工程ではなく、「受け入れ基準を実装へ落とし込み、既存実装と統合できる状態まで持っていく工程」と捉えています。

そのため、実装・統合フェーズでは次の3つの役割に分けています。

  • test-writer
  • implementer
  • integration-tester

test-writer:受け入れ基準をテストへ落とし込む

test-writerは、仕様で定義された受け入れ基準から、実装前にテストを作成します。

ここで重要なのは、実装コードを見てからテストを書くのではなく、先に受け入れ基準からテストを作ることです。

これにより、

  • 実装都合に合わせてテストを書く
  • 実装したコードが通りやすいようにテストを緩める

といったことを防ぎやすくしています。

また、テストは実装前に一度実行し、期待どおりRedになることも確認します。

implementer:コードを扱う

implementerは、実際にコードを読み、変更し、実行して確認する役割です。

実装するAIというよりは、「コードに対する読み取り・変更・実行検証を担当するAI」に近いです。

ただし、implementerの中でも、いきなりコードを書かせるのではなく、工程を分けています。

大きくは、以下の3段階です。

  1. 技術的な事前検証
  2. 実装
  3. セルフチェック

1. 技術的な事前検証

仕様案と既存コードを読み、

  • 仕様と既存コードが衝突しないか
  • 変更対象外のコードや既存機能に影響しないか
  • 受け入れ基準に曖昧な点がないか
  • テストできない受け入れ基準がないか
  • 必要な依存が不足していないか
  • 実装規模が大きすぎないか

などを確認します。

ここではコードは変更しません。

仕様担当でも実現可能性は考えますが、こちらは「仕様として成立するか」ではなく、「今のコード上で技術的に成立するか」を確認する工程として分けています。

2. 実装

技術的に問題がないことを確認した後、承認済みの仕様とtest-writerが作成したテストをもとに実装します。

実装前には、自分でも対象テストがRedであることを確認し、その後コードを書いてGreenになることを確認していきます。

implementerは仕様や受け入れ基準を変更できないようにしています。その代わり、実装中に仕様との衝突や判断が必要な点を見つけたときは、僕(開発責任者)の判断に任せるようにしています。

3. セルフチェック

実装後は、以下のセルフチェックを行います。

  • テスト
  • 静的解析
  • 型検査
  • ビルド
  • 異常系や境界値などのAC外の観点
  • 完成の定義(DoD)の自己点検

ただし、セルフチェックを通ったからといって、implementer自身が「完成」と判断をしないようにしています。

implementerはあくまで「完成の定義(DoD)を満たしているかの検証待ち」としてメインエージェントに返し、最終的な完成判定はreviewerに委ねます。

つまり、同じ実装担当の中でも、「調べる → 作る → 自分で確認する」という異なる目的を持つ工程に分けています。

integration-tester:個々の実装を統合状態で確認する

implementerが担当するのは、基本的に1回の呼び出しにつき1つのタスクです。

複数のタスクを並列で実装できる一方、個々のタスクが正しく動いていても、それらを組み合わせたときに問題が起きる可能性はあります。

そこでintegration-testerを別に置き、以下のことを確認するようにしています。

  • 複数タスクを統合した状態で問題がないか
  • 既存実装と矛盾していないか
  • もともと正常に動いていた既存機能が壊れていないか

ここまでを「実装・統合」の工程としています。

なぜ工程を分けるのか

同じ「実装」という括りの中でも、必要な思考はそれぞれ異なります。

  • 技術的な事前検証では、既存コードとの衝突や制約を探すことに集中する
  • 実装では、承認済みの仕様とテストを満たすコードを書くことに集中する
  • セルフチェックでは、自分が書いたコードに問題がないかを確認する
  • 統合では、個々の変更ではなく、変更全体と既存実装との関係を確認する

これらを1回の指示でまとめて行わせるのではなく、目的ごとに工程を分けることで、各エージェントがその時点で必要なコンテキストと判断に集中できるようにしています。

3. 推論・判断と機械作業を分ける

これは、仕様フェーズで呼び出す spec-designer と spec-updater の役割分担の話です。

もともとは spec-designer だけが存在しており、以下の作業をまとめて担当していました。

  • 仕様を考える
  • 選択肢を整理する
  • 僕自身の判断を反映する
  • 承認状態を書き換える
  • 確定版に整える
  • 表記ゆれや整合性を修正する

spec-designer には、Claude Opus 5.5を割り当てています。仕様を考えるには高度な推論能力や判断能力が必要であり、その役割に適したモデルだと考えたためです。

しかし実際に運用してみると、spec-designer の仕事には、高度な推論や判断を必要とするものと、すでに決まった内容を機械的に反映するだけのものが混在していることが分かりました。

ある機能開発では、spec-designer を合計5回呼び出していました。そのうち、高度な推論や判断を必要とする作業のために呼び出したのは2回でした。

具体的には、以下のような作業です。

  • 僕自身が書いた要件から仕様案を作る
  • 僕自身が書いた要件から受け入れ基準を考える
  • 複数の設計案について、メリット・デメリットを比較して整理する

一方、残りの3回は、主に機械的な更新作業のための呼び出しでした。

具体的には、以下のような作業です。

  • 「承認待ち」を「承認済み」に変更する
  • 僕自身が判断した内容を仕様書の該当箇所へ反映する
  • 僕自身の確認後に、仕様書を確定版として書き直す
  • 機械的に検出できる仕様書上の不整合を修正する

前者のような、高度な推論や判断を必要とする作業には、Claude Opus 5.5を割り当てて十分なトークンを使う価値があります。

一方で、後者のように判断をほとんど必要としない機械的な作業まで同じモデルに任せる必要はありません。そこで、こうした作業にはClaude Sonnet 5.5を割り当てる方が、コストパフォーマンスを高められると考えました。

そのため現在は、推論や判断が必要な作業は spec-designer、すでに決まった内容を機械的に反映する作業は spec-updaterに分けて運用しています。

つまり、役割を専門性だけで分けるのではなく、その作業にどの程度の推論や判断が必要かによっても分けるようにしています。

4. 全体を管理するAIに実作業をさせない

メインエージェントには、「僕自身との議論、サブエージェントの指揮、開発フローの進行、状態・判断の管理、判断が必要な事項の引き継ぎ」を担当させています。

つまり、メインエージェントの役割は、僕自身が開発全体の意思決定を行うための支援です。

そのため、メインエージェントが持つべきコンテキストは、個々の実装の詳細ではなく、目標に対して開発全体が今どの状態にあるかだと考えています。

具体的には、以下のような情報です。

  • 今やっている開発の目標は何か
  • その目標に対して、どこまで進んでいるか
  • 完成している成果物は何か
  • 現在の障害や解決していないことは何か
  • 僕自身の判断が必要なものは何か
  • 次にどのサブエージェントへ何を引き継ぐべきか
  • 各サブエージェントの作業結果は何か
  • その作業結果を信頼できる根拠は何か

逆に、各サブエージェントの作業内容までメインエージェントが細かく把握すると、そのコンテキストは膨大になっていきます。

たとえば、implementerがどのファイルを読み、どの実装方法を検討し、どのコードをどの順番で変更したかまで、メインエージェントがすべて把握する必要はありません。

そうした実作業の詳細は、各サブエージェントの中で完結させます。

実際に、メインエージェント自身はコードや仕様を直接変更せず、コードベースの探索が必要な場合もサブエージェントへ依頼するようにしています。また、サブエージェントからメインエージェントへの報告も、詳細な作業過程ではなく、要約と成果物の場所を中心にしています。

人間の組織でたとえるなら、上司が部下の作業手順をすべて把握するのではなく、成果とその根拠、問題点の報告を受け取り、それをもとに次の指示や意思決定を行うイメージに近いです。

この役割分担を成立させるために、サブエージェント間やメインエージェントとの情報の受け渡しには、できるだけ成果物を使うようにしています。

たとえば、

  • 仕様は implenent.md
  • タスク分割は tasks.md
  • テスト内容とRedの確認結果は tests.md
  • 実装結果や検査結果は task-notes
  • 統合結果は integration-report.md
  • 最終的な品質検証は quality-report.md

といった形です。

これにより、次のエージェントやメインエージェントが、それまでの会話や作業過程をすべて引き継ぐ必要がなくなります。必要な成果物と、その結果を信頼するための根拠だけを受け取れば、次の作業へ進めます。

メインエージェントを「何でもやるAI」にするのではなく、あえて実作業から切り離し、実装や検証の詳細は専門のサブエージェントに任せる。

その結果、メインエージェントは実装詳細でコンテキストを膨大させることなく、目標に対してどこまで近づけているかを把握し、必要なフィードバックと意思決定の支援を行うことに集中できるようにしています。

まとめ

この記事では、僕がAI開発チームを構成するときに重視したポイントを4つ紹介しました。

AIが実装した機能に対して僕自身が責任持ってGOサインを下せるために、どのコンテキストをどのAIにどこまで持たせて任せたら良いかを考えて構成しました。

もちろん、現在の構成が完成形だとは考えていません。

実際に運用する中で、spec-designerが担当していた機械的な作業をspec-updaterに分離するなどの変更もしてきました。

今後も、サブエージェントが多すぎてメインエージェントの指揮コストが増えていないか、1つのサブエージェントに任せている仕事が多すぎないか、そもそも必要な推論や判断事項を伝え忘れていないかを見ながら調整していきます。

個人的に、AI開発チームを構成する上で重要なのは、単にAIへ仕事を分担させることではなく、どのコンテキストを、どのAIに、どこまで任せるかを設計することだと考えています。

そして、その設計をするためには、自分自身が技術やアーキテクチャを理解している必要があります。どこで役割を分けるべきか、どこまで権限を与えてよいか、どの結果を信頼してよいかは、最終的には人間側が判断しなければならないからです。

今の時代だからこそ、AIに何を任せ、何を任せないかを判断するために、これまで以上に自分自身が技術を理解する必要があると感じています。

だからこそ、AIに開発を無責任に丸投げするのではなく、自分自身が判断の根拠を持ち、必要であればその理由を説明できる状態で、AIと一緒に開発していきたいと思っています。

2
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
2
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?