1. 主要ページへ移動
  2. メニューへ移動
  3. ページ下へ移動

QES ブログ

記事公開日

Claude Codeのサブエージェントで、レビュー・テスト・ドキュメント作成を分担させてみた

  • このエントリーをはてなブックマークに追加

この記事のポイント

Claude Code のサブエージェント(役割ごとに独自のコンテキストで動く専用の AI アシスタント)を3つ作り、業務スクリプトのレビュー・テスト・ドキュメント作成を順番に分担させる方法を、実際の定義ファイルとともに解説します。

  • サブエージェントは Markdown ファイル1つで作れる:
    .claude/agents/ に name・description・tools・model と指示を書くだけで、使えるツールを絞った担当を用意できます。
  • 流れはカスタムコマンドで決める:
    前の担当の結果を次の担当に渡す手順をコマンドに書いておくと、毎回同じ順番で3つのサブエージェントを動かせます。
  • 分担は目的で選ぶ:
    筆者の検証(各2回)では、仕込んだ不具合11件の検出数は1つの会話にまとめて頼んでも同じでした。分担するとテストやドキュメントは詳しくなる一方、時間と出力量は約2倍になりました。

こんにちは!DXソリューション営業本部の近藤です。

Claude Code に「コードをレビューして、テストを書いて、ドキュメントも作って」とまとめて頼んだことはありませんか?
1つの会話に作業を詰め込むと、レビューの指摘、テストの実行ログ、ドキュメントの下書きがすべて同じ場所に積み上がっていきます。
「どの指示がどの作業に効いているのか分かりにくい」と感じた方もいらっしゃるのではないでしょうか。

Claude Code には、こうした作業を役割ごとに切り分けて任せられる「サブエージェント」という機能があります。
本記事では、レビュー担当・テスト担当・ドキュメント担当の3つのサブエージェントを自分で定義し、架空の業務スクリプトを順番に改善させるまでの手順をご紹介します。
題材のスクリプトとデータ、定義ファイル、コマンドはすべて記事内に載せていますので、そのままコピーして試していただけます。
あわせて、同じ作業を1つの会話にまとめて頼んだ場合と比べて、何が変わったのかもお伝えします。

サブエージェントとは:役割ごとに別のコンテキストで動くAI

サブエージェントは、特定の種類の作業だけを受け持つ、専用の AI アシスタントです。
メインの会話(普段やり取りしている Claude Code)から作業を任され、自分専用のコンテキスト(AI が一度に参照できる会話や情報の範囲)で作業し、結果の要約だけをメインに返します。

公式ドキュメントでも「各サブエージェントは、カスタムシステムプロンプト、特定のツールアクセス、および独立した権限を備えた独自のコンテキストウィンドウで実行されます」と説明されています(出典:カスタムサブエージェントの作成 - Claude Code Docs)。

サブエージェントでできること

できること 内容
コンテキストを分ける 調査やテストの実行ログはサブエージェント側にとどまり、メインには要約だけが戻る
使えるツールを制限する 「読むだけ」「テストを実行してよい」など、役割ごとに権限を変えられる
指示を使い回す 役割ごとの指示をファイルとして保存し、毎回同じ条件で呼び出せる
モデルを選ぶ 役割ごとに使うモデルを指定できる

なぜ「任せる相手」を分けると便利なのか:
1つの会話にすべての作業を頼むと、前の作業の指示や結果が、次の作業のときも会話に残り続けます。
サブエージェントは作業ごとに新しいコンテキストで始まるため、担当する作業に必要な指示と情報だけで動けます。
ただし、サブエージェントの利用分もメインの会話と同じ使用量の上限に含まれる点には注意が必要です(出典:カスタムサブエージェントの作成 - Claude Code Docs)。

次のセクションでは、この仕組みを使って何を作るのかを具体的に見ていきます。

今回作るもの:3つのサブエージェントで業務スクリプトを改善する

今回は、架空の株価CSVを銘柄ごとに集計する Python スクリプトを題材に、レビュー・テスト・ドキュメント作成を3つのサブエージェントに分担させます。
データの銘柄名や数値はすべて架空のもので、実在の銘柄・企業とは関係ありません。

スクリプトには、動作確認の目安になるよう、筆者がわざと11件の不具合を仕込んでいます。
たとえば「騰落率の符号が逆になっている」「日付を文字列のまま並べているため、10月1日が9月30日より前に来る」「終値が空欄の行があると処理が止まる」といったものです。

3つのサブエージェントの役割

名前 担当する作業 使えるツール
code-reviewer コードを読み、不具合と改善案を指摘する Read・Grep・Glob(読むだけ)
test-engineer pytest のテストを作り、実行して結果を報告する Read・Grep・Glob・Write・Edit・Bash(書き込み先は指示で tests/ に限定)
doc-writer docstring と README.md を作る Read・Grep・Glob・Write・Edit(Bash なし)

メインの Claude Code は、この3つに順番に仕事を渡し、前の担当の結果を次の担当に引き継ぐ「取りまとめ役」になります。
レビュー結果をもとにテストを作り、レビュー結果とテスト結果をもとにドキュメントを作る、という流れです。

検証環境(2026年10月時点)

  • OS:Windows(VS Code の統合ターミナルは PowerShell)
  • Claude Code:VS Code 拡張機能(v2.1.296)。拡張機能の利用には VS Code 1.94.0 以降が必要です(出典:Use Claude Code in VS Code - Claude Code Docs)
  • 権限モード:オートモード(公式ドキュメントでは「自動モード」、auto)。比較した4回とも同じ
  • Git for Windows(Git Bash を含む):インストール済み
  • モデル:Sonnet 5.5(effort は Medium)
  • uv 0.13.1、Python 3.12.15、pytest 9.1.1

準備:作業フォルダとCLAUDE.mdを用意する

サブエージェントを作る前に、題材のスクリプトを置く作業フォルダと、プロジェクトのルールを書いた CLAUDE.md を用意します。
フォルダ構成は次のとおりです。

stock-report/
├── CLAUDE.md                     ← プロジェクトのルール
├── pyproject.toml
├── .gitignore                    ← git に登録しないファイル
├── .python-version               ← 使う Python のバージョン
├── .claude/
│   ├── agents/                   ← サブエージェントの定義ファイルを置く
│   │   ├── code-reviewer.md
│   │   ├── test-engineer.md
│   │   └── doc-writer.md
│   └── commands/
│       └── quality-pipeline.md   ← 3つを順番に動かすコマンド
├── src/
│   ├── __init__.py               ← 空のファイル
│   └── stock_report.py           ← 題材のスクリプト
├── data/
│   └── prices.csv                ← 架空の株価データ
├── tests/
└── docs/

題材のファイルを用意する

次の5つのファイルを、フォルダ構成のとおりに作成します。
スクリプトには動作確認用にわざと不具合(固定のパスなど)を入れています。書き換えずにそのままコピーし、業務では使わないでください。
空の src/__init__.py と、tests/・docs/ フォルダも作っておきます。

pyproject.toml

[project]
name = "stock-report"
version = "0.1.0"
description = "株価CSVを銘柄ごとに集計するスクリプト(ブログ検証用のダミー題材)"
requires-python = ">=3.12"
dependencies = []

[dependency-groups]
dev = ["pytest>=8"]

src/stock_report.py

import csv

DATA_FILE = "C:/Users/tanaka/work/data/prices.csv"


def load_prices(path=DATA_FILE):
    f = open(path, encoding="utf-8")
    reader = csv.DictReader(f)
    rows = []
    for row in reader:
        rows.append({
            "date": row["date"],
            "code": row["code"],
            "name": row["name"],
            "close": float(row["close"]),
            "volume": int(row["volume"]),
        })
    f.close()
    return rows


def group_by_code(rows, result={}):
    for row in rows:
        result.setdefault(row["code"], []).append(row)
    return result


def sort_by_date(rows):
    return sorted(rows, key=lambda r: r["date"])


def change_rate(rows):
    first = rows[0]["close"]
    last = rows[-1]["close"]
    return (first - last) / first * 100


def moving_average(rows, window=5):
    result = []
    for i in range(window, len(rows)):
        values = [r["close"] for r in rows[i - window:i]]
        result.append(sum(values) / window)
    return result


def average_volume(rows):
    return sum(r["volume"] for r in rows) / len(rows)


def build_report(rows, codes):
    groups = group_by_code(rows)
    report = []
    for code in codes:
        items = sort_by_date(groups.get(code, []))
        ma = moving_average(items)
        report.append({
            "code": code,
            "name": items[0]["name"],
            "start": items[0]["close"],
            "end": items[-1]["close"],
            "change_rate": round(change_rate(items), 2),
            "ma5_latest": round(ma[-1], 1),
            "avg_volume": int(average_volume(items)),
        })
    return report


def write_report(report, path):
    f = open(path, "w")
    writer = csv.DictWriter(f, fieldnames=report[0].keys())
    writer.writeheader()
    writer.writerows(report)
    f.close()


if __name__ == "__main__":
    rows = load_prices()
    report = build_report(rows, ["9991", "9992", "9993"])
    write_report(report, "report.csv")
    print("完了")

data/prices.csv(UTF-8 で保存します)

date,code,name,close,volume
2026/9/24,9991,ダミー商事,1520,152000
2026/9/25,9991,ダミー商事,1532,153370
2026/9/28,9991,ダミー商事,1524,154740
2026/9/29,9991,ダミー商事,1539,156110
2026/9/30,9991,ダミー商事,1559,157480
2026/10/1,9991,ダミー商事,1554,158850
2026/10/2,9991,ダミー商事,1564,160220
2026/10/5,9991,ダミー商事,1582,152590
2026/10/6,9991,ダミー商事,1570,153960
2026/10/7,9991,ダミー商事,1595,155330
2026/10/8,9991,ダミー商事,1603,156700
2026/10/9,9991,ダミー商事,1617,158070
2026/9/24,9992,サンプル電機,3480,86000
2026/9/25,9992,サンプル電機,3450,87370
2026/9/28,9992,サンプル電機,3425,88740
2026/9/29,9992,サンプル電機,3435,90110
2026/9/30,9992,サンプル電機,3395,91480
2026/10/1,9992,サンプル電機,3380,92850
2026/10/2,9992,サンプル電機,,94220
2026/10/5,9992,サンプル電機,3365,86590
2026/10/6,9992,サンプル電機,3330,87960
2026/10/7,9992,サンプル電機,3342,89330
2026/10/8,9992,サンプル電機,3324,90700
2026/10/9,9992,サンプル電機,3302,92070
2026/9/24,9993,テスト証券,842,410000
2026/9/25,9993,テスト証券,845,411370
2026/9/28,9993,テスト証券,843,412740
2026/9/29,9993,テスト証券,847,414110
2026/9/30,9993,テスト証券,848,415480
2026/10/1,9993,テスト証券,842,416850
2026/10/2,9993,テスト証券,847,418220
2026/10/5,9993,テスト証券,849,410590
2026/10/6,9993,テスト証券,852,"411,960"
2026/10/7,9993,テスト証券,851,413330
2026/10/8,9993,テスト証券,855,414700
2026/10/9,9993,テスト証券,857,416070

.gitignore

仮想環境や、Python が自動で作るキャッシュ(__pycache__/)などを git に登録しないためのファイルです。
これがないと、あとで git diff を確認するときに、キャッシュファイルの行が混ざります。

.venv/
__pycache__/
.pytest_cache/
report.csv

.python-version

uv が使う Python のバージョンを 3.12 に固定するためのファイルです。
Python 3.15 からは既定の文字コードが UTF-8 になったため(出典:PEP 686)、新しいバージョンで実行すると、文字コードに関わる不具合の結果が記事と変わります。

3.12

uv をインストールする

今回は Python の環境管理に uv(Python のパッケージとバージョンをまとめて管理するツール)を使います。
筆者の PC には uv が入っておらず、最初の uv sync が「用語 'uv' は認識されません」というエラーで止まりました。
Windows では、公式の手順に沿って PowerShell で次のコマンドを実行するとインストールできます(出典:Installation | uv)。

powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"

git も使うため、入っていない場合はこの時点で Git for Windows もインストールしておきます。
インストール後は VS Code ごと開き直し、作業フォルダで次のコマンドを実行します。
VS Code を開いたままだと、その中で動く Claude Code に新しい設定が反映されず、あとでテストを実行するときに uv や Git Bash が見つからない可能性があるためです。
2行目のコマンドで「OK」と表示されれば、スクリプトを読み込める状態です。

あわせて git で初期状態を保存しておくと、何度か試すときに元に戻しやすくなります。
また、初めて git を使う PC では、commit の前に名前とメールアドレスの設定(git config --global user.name と git config --global user.email)が必要です。

uv sync
uv run python -c "import src.stock_report; print('OK')"
git init
git add .
git commit -m "初期状態"
VS Code のターミナルで uv sync を実行し、Python 3.12.15 の仮想環境と pytest がインストールされ、動作確認で OK と表示された画面

CLAUDE.md にプロジェクトのルールを書く

CLAUDE.md は、Claude Code が起動時に読み込むプロジェクトの説明書です。
サブエージェントも、起動時に CLAUDE.md を読み込みます(出典:カスタムサブエージェントの作成 - Claude Code Docs)。
そのため、3つのサブエージェントに共通するルール(使うツール、触ってはいけないファイル、計算の定義)は、ここにまとめて書いておきます。

# stock-report

## プロジェクト概要
株価CSV(data/prices.csv)を読み込み、銘柄ごとの騰落率・5日移動平均・平均出来高を集計して report.csv に出力するスクリプト。
マルチエージェント検証用の題材であり、データはすべて架空(実在の銘柄・企業とは関係ない)。

## 技術スタック
- Python 3.12
- パッケージ管理: uv(pip は使わない)
- テスト: pytest

## 開発ルール
- パッケージの追加は `uv add`、開発用は `uv add --dev` を使う
- スクリプトの実行は `uv run python`、テストの実行は `uv run pytest` を使う
- コメント・docstring・ドキュメントは日本語で書く
- src/ の処理(ロジック)は、修正を指示されるまで変更しない。今回の作業範囲は「レビュー・テスト・ドキュメント」まで
- data/prices.csv は変更しない。テスト用のデータは tests/ の中で作る

## 計算の定義
- 騰落率(%)= (期間最終日の終値 − 期間初日の終値) ÷ 期間初日の終値 × 100
- 5日移動平均 = 当日を含む直近5営業日の終値の平均
- 日付は「YYYY/M/D」形式(月・日はゼロ埋めなし)

## ディレクトリ構成
- src/ : スクリプト本体(stock_report.py)
- data/ : 入力データ(prices.csv)
- tests/ : テストコード
- docs/ : ドキュメント

なぜ「計算の定義」を書いておくのか:
定義がないと、レビュー担当もテスト担当も「今のコードの動き」を正解とみなしてしまうおそれがあります。
騰落率や移動平均の正しい計算方法を CLAUDE.md に書いておくことで、各担当が同じ基準で「実装が定義とずれていないか」を判断できます。

なお、親フォルダに別の CLAUDE.md がある場合は、それも一緒に読み込まれます。
筆者の環境でも、作業フォルダの上の階層にあるブログ執筆用の CLAUDE.md が読み込まれていました。
試すときは、ほかの CLAUDE.md がない場所に作業フォルダを作るのがおすすめです。

サブエージェントを作る:定義ファイルを3つ書く

サブエージェントは、YAML フロントマター(ファイル冒頭の --- で囲んだ設定欄)付きの Markdown ファイルとして定義します。
プロジェクト専用にするなら .claude/agents/、すべてのプロジェクトで使うなら ~/.claude/agents/ に置きます(出典:カスタムサブエージェントの作成 - Claude Code Docs)。
今回はプロジェクト専用として、stock-report/.claude/agents/ に3つのファイルを作りました。

フロントマターで設定する項目

必須の項目は name と description の2つだけです。
今回はこれに tools と model を加えた4項目で作りました。

項目 必須 内容
name 必須 サブエージェントの名前。依頼するときにこの名前で指定できる
description 必須 どんな作業を任せる相手か。Claude はこの説明を見て、作業を任せるかどうかを判断する
tools 任意 使えるツール。省略すると、サブエージェントで使えるすべてのツールを引き継ぐ
model 任意 使うモデル(sonnet、opus、haiku など)

フロントマターの下に書いた本文が、そのサブエージェントへの指示(システムプロンプト)になります。
公式ドキュメントには、このほかにも disallowedTools(使わせないツール)や maxTurns(作業の最大回数)などの項目が載っています。

レビュー担当:code-reviewer.md

レビュー担当には、コードを読むためのツール(Read・Grep・Glob)だけを渡しています。
書き込みのツールを持たせないことで、指摘はできてもファイルを書き換えることはできない担当にしています。

---
name: code-reviewer
description: Pythonスクリプトを読み、不具合・例外処理の不足・計算ロジックの誤り・環境依存の問題を指摘するレビュー専門のエージェント。コードの変更は行わない。
tools: Read, Grep, Glob
model: sonnet
---

あなたは業務スクリプトのレビューを担当するエンジニアです。
ファイルの変更はせず、問題の指摘と改善案の提示だけを行います。

## 確認する観点
1. **入力データへの備え**
   - 欠損値・書式の違う値(カンマ付きの数値、日付の書式ゆれなど)が来たときに止まらないか
   - ファイルが存在しない、データが0件・少数件のときの扱い
2. **計算ロジックの正しさ**
   - CLAUDE.md の「計算の定義」と実装が一致しているか
   - 並び順・集計範囲・境界(最初と最後の要素)の扱い
3. **Pythonの落とし穴**
   - 可変デフォルト引数、ファイルを閉じ忘れる書き方など
4. **環境依存**
   - ハードコードされたパス、文字コード・改行コードの指定漏れ(Windowsで動かす前提)

## 進め方
1. CLAUDE.md と対象ファイルを読む
2. 関数ごとに上の観点で確認する
3. 指摘ごとに「どんな入力で、何が起きるか」を具体的に書く。実行して確かめていない内容は「推測」と明記する

## 出力形式
最後に、次の表だけを返すこと。

| No | 重要度(高/中/低) | 該当箇所(関数名・行番号) | 問題 | 起きる条件 | 改善案 |
|---|---|---|---|---|---|

テスト担当:test-engineer.md

テスト担当は、テストを書いて実行する必要があるため、書き込み(Write・Edit)とコマンド実行(Bash)も使えるようにしています。
その代わり、本文で「tests/ にだけ書く」「テストが失敗しても src/ を直さない」と範囲を決めています。
これは tools の設定ではなく指示による約束なので、書き込み先そのものを制限するものではない点に注意してください。

なお、Windows で Bash ツールが使えるのは Git Bash がインストールされている場合です。
Git Bash がない Windows では、代わりに PowerShell ツールが自動で有効になります(出典:ツールリファレンス - Claude Code Docs)。
本記事の手順では Git for Windows を入れるため、Bash ツールでテストを実行できます。

---
name: test-engineer
description: pytestのテストコードを作成・実行し、スクリプトが仕様どおり動くかを確かめるテスト専門のエージェント。テストは tests/ にだけ書き、src/ は変更しない。
tools: Read, Write, Edit, Bash, Glob, Grep
model: sonnet
---

あなたは業務スクリプトのテストを担当するエンジニアです。

## 守ること
- テストコードは tests/ の中にだけ作成・編集する。src/ と data/ は変更しない
- テストは `uv run pytest -v` で実行する(pip や python -m pytest は使わない)
- テストの期待値は CLAUDE.md の「計算の定義」に従う。今の実装の出力に合わせて期待値を書かない
- テスト用のCSVは pytest の tmp_path で作り、data/prices.csv には依存しない
- テストが失敗しても src/ を直さない。失敗は「不具合が見つかった」という結果として報告する

## テストの方針
- 関数ごとに、正常なケースと異常なケース(欠損値、カンマ付きの数値、データ0件・少数件、存在しないファイル)を用意する
- 日付の並び順・騰落率・移動平均は、手計算できる小さなデータで期待値を確かめる
- 各テスト関数には、何を確かめるかを日本語の docstring で書く

## 進め方
1. CLAUDE.md と対象ファイルを読み、テストする項目を洗い出す
2. tests/test_stock_report.py を作成する
3. `uv run pytest -v` を実行する
4. テストコード自体の誤り(import の間違いなど)だけを直して再実行する

## 出力形式
最後に、次の2つを返すこと。
1. 実行結果(成功 / 失敗 / スキップの件数)
2. 失敗したテストの一覧

| テスト名 | 確かめたこと | 結果 | 失敗の原因(推定される不具合) |
|---|---|---|---|

ドキュメント担当:doc-writer.md

ドキュメント担当は、ファイルを書き込めますが、コマンドを実行するツール(Bash)は持たせていません。
また、「処理の中身は1文字も変えない」「渡された結果以外の不具合を推測で書き足さない」と決めています。

---
name: doc-writer
description: スクリプトの README.md と docstring を作成するドキュメント専門のエージェント。処理の中身は変えず、説明の追加だけを行う。
tools: Read, Write, Edit, Glob, Grep
model: sonnet
---

あなたは業務スクリプトのドキュメントを担当するエンジニアです。

## 守ること
- src/ のファイルには docstring の追加だけを行い、処理の中身は1文字も変えない
- 日本語で書く。セットアップや実行の手順は uv を使う前提で書く(pip は書かない)
- 依頼文にレビュー結果やテスト結果が含まれていれば、それを「既知の不具合」として README に載せる。自分で新しい不具合を推測して書き足さない

## 作成するもの
1. **docstring**:すべての関数に Google Style の docstring(概要・引数・戻り値・発生しうる例外)
2. **README.md**(プロジェクト直下)
   - 概要(何を入力して、何を出力するか)
   - セットアップと実行方法(uv sync、uv run python、uv run pytest)
   - 入力CSVの形式と、出力 report.csv の項目説明
   - 計算の定義(CLAUDE.md と同じ内容)
   - 既知の不具合(依頼文で渡された場合のみ)

## 出力形式
最後に、次の2つを返すこと。
1. 作成・更新したファイルの一覧と、主な変更内容
2. docstring を追加した関数の数 / 全関数の数

定義するときに意識した3つのこと

意識したこと 定義ファイルでの書き方
担当範囲を重ねない description と本文に「何をするか」と「何をしないか」を両方書く
ツールは役割に必要な分だけ レビュー担当は読むだけ、コマンドを実行するのはテスト担当だけにする
結果の形をそろえる 最後に返す内容を表の形で決めておき、取りまとめ役が次の担当に渡しやすくする

定義ファイルが認識されたか確かめる

以前のバージョン(v2.1.197 以前)では、/agents コマンドで対話式の作成画面が開きました(出典:カスタムサブエージェントの作成 - Claude Code Docs)。
執筆時点のバージョンで /agents を実行すると、作成画面は開かず、Claude に作成を頼むか、.claude/agents/ のファイルを直接編集するよう、英語で案内が表示されます。

Claude Code で /agents を実行し、The /agents wizard has been removed と表示され、Claude に依頼するか .claude/agents/ を直接編集するよう案内された画面

定義ファイルが読み込まれたかどうかは、Claude Code に「使えるサブエージェントを一覧にしてください」と頼むと確認できます。
筆者の環境では、プロジェクト用の3つが、設定したツールと一緒に表示されました。
なお、Claude Code を起動したあとで .claude/agents/ フォルダを新しく作った場合は、再起動するまで読み込まれません(出典:カスタムサブエージェントの作成 - Claude Code Docs)。
一覧に出てこないときは、定義ファイルを見直す前に、まず Claude Code を再起動してみてください。

Claude Code にサブエージェントの一覧を尋ね、code-reviewer・test-engineer・doc-writer の3つが役割と使えるツールとともに表示された画面

3つの担当がそろったので、次はこれを順番に動かす仕組みを作ります。

3つのサブエージェントを順番に動かす:カスタムコマンドで流れを決める

3つのサブエージェントを毎回同じ順番で動かせるように、依頼の手順をカスタムコマンド(/ から始まる自作のコマンド)にまとめます。
.claude/commands/quality-pipeline.md というファイルを作ると、/quality-pipeline というコマンドとして使えるようになります。

$ARGUMENTS の品質を改善します。次の3ステップを順番に実行してください。
あなた自身はコードのレビュー・テスト作成・ドキュメント作成を行わず、各サブエージェントに任せてください。

1. code-reviewer サブエージェントで $ARGUMENTS をレビューする
2. test-engineer サブエージェントでテストを作成・実行する。依頼文には 1 のレビュー結果の表をそのまま含め、指摘された条件もテストに入れるよう伝える
3. doc-writer サブエージェントで docstring と README.md を作成する。依頼文には 1 のレビュー結果と 2 のテスト結果を含める

最後に、次の表で結果をまとめてください。

| No | 問題 | 重要度 | レビューで指摘 | テストで確認(失敗したテスト名) | README に記載 |
|---|---|---|---|---|---|

$ARGUMENTS には、コマンドのあとに入力した文字列(今回は対象のファイル名)が入ります。
作ったコマンドが入力候補に出てこない場合は、Claude Code を再起動してから試してください。

なぜ「前の結果を依頼文に含める」と書くのか:
サブエージェントはメインの会話の履歴を見られないため、ほかの担当が何をしたかを知りません。
メインが前の担当の結果を依頼文に入れて渡すことで、テスト担当はレビューの指摘をテストに反映でき、ドキュメント担当は見つかった不具合を README に載せられます。

なお、公式ドキュメントでは、カスタムコマンドは「スキル」に統合されたと案内されています。
既存の .claude/commands/ のファイルは引き続き使えますが、新しく作る場合は .claude/skills/ にスキルとして作る方法もあります(出典:Claude をスキルで拡張する - Claude Code Docs)。

コマンドを実行する

Claude Code の入力欄に、次のように入力して送信します。

/quality-pipeline src/stock_report.py
/quality-pipeline src/stock_report.py を送信し、Step 1 として code-reviewer にレビューを依頼して、Run in background と 1 agent が表示されている画面

送信すると、メインが「Step 1: code-reviewer にレビューを依頼します。」と宣言し、レビュー担当に作業を渡しました。
画面下部に「1 agent」と表示され、サブエージェントが作業中であることが分かります。

なお、筆者の実行では、test-engineer の最初のテスト実行が「No module named 'src'」という import エラーになりました。test-engineer がテストコード側の import を直して再実行したため、同じエラーが表示されても、そのまま見守って問題ありません。

動作を確認する:仕事が順番に渡り、結果がまとまる

実行結果を見ると、メインが3つのサブエージェントに順番に仕事を渡し、それぞれの結果を受け取っていることが確認できました。
筆者の環境では、送信から最後のまとめまで約4分でした。

メインが Step 1 で code-reviewer、Step 2 で test-engineer、Step 3 で doc-writer に依頼し、各担当から Subagent hand-back として結果が戻ってくる流れが表示された画面

画面から読み取れる流れは次のとおりです。

Step 1:code-reviewer にレビューを依頼し、結果(Subagent hand-back)を受け取る
Step 2:レビュー結果の表を依頼文に含めて、test-engineer にテストの作成と実行を依頼する
Step 3:レビュー結果とテスト結果を含めて、doc-writer に docstring と README.md の作成を依頼する

Step 2 の依頼文には「以下は code-reviewer のレビュー結果です」と書かれていて、メインが前の担当の結果を次の担当に引き継いでいることが分かります。
なお、「Subagent hand-back」は、オートモードでサブエージェントの結果を受け取るときの表示です。
ほかの権限モードでは、結果の受け取り方の表示が異なる場合があります(出典:ツールリファレンス - Claude Code Docs)。

最後のまとめ表

3つの担当が終わると、メインがコマンドで指定した形式のまとめ表を作りました。
問題ごとに「レビューで指摘されたか」「どのテストで確認できたか」「README に載ったか」が一覧になっています。

3つのサブエージェントの結果をメインがまとめた表。問題ごとに重要度、レビューでの指摘、失敗したテスト名、README への記載が並んでいる

筆者が仕込んだ11件の不具合は、すべてこの表に含まれていました。
このほかにも「BOM 付きの UTF-8 ファイルを読めない」など、仕込んでいない問題も指摘されています。
テストは38件作られ、うち27件が失敗しました(Windows の既定の文字コード cp932 で実行した場合。環境変数 PYTHONUTF8=1 を設定すると25件で、差の2件は文字コードの指定漏れによるものです)。失敗は、見つかった不具合を示す結果です。

src/ のロジックが変わっていないか確かめる

今回は「レビュー・テスト・ドキュメント」までが作業範囲なので、スクリプトの処理が書き換えられていないかも確認します。
ターミナルで次のコマンドを実行します。

git diff --stat src/
git diff --stat src/ の結果。src/stock_report.py に 169 行の追加だけがあり、削除は 0 行であることを示すターミナル画面

結果は「169 insertions(追加169行)」で、削除はありませんでした。
ただし、--stat が示すのは行数の集計だけです。
処理を書き足す変更でも削除は0行になるため、中身は次のコマンドで確認します。

git diff src/

追加された行が、すべて docstring(三重引用符で囲まれた説明文)の中に収まっていれば、処理の中身は変わっていません。
筆者の環境でも、追加された169行はすべて docstring でした。

使ってみて分かったこと:1つの会話にまとめて頼んだ場合との比較

役割を分けた効果を確かめるため、同じ作業を「サブエージェントを使わず、1つの会話にまとめて頼む」方法でも試しました。
1つの会話にまとめて頼むときは、次の依頼文を使いました。
作業の範囲(src/ を直さない、計算の定義に従う)はそろえましたが、各担当の定義ファイルにある細かい方針は含めていません。

サブエージェントは使わずに、あなた自身で次の3つを順番に行ってください。
1. src/stock_report.py をレビューし、不具合・例外処理の不足・計算ロジックの誤り・環境依存の問題を、重要度・該当箇所・問題・起きる条件・改善案の表で示す
2. tests/test_stock_report.py に pytest のテストを作成して `uv run pytest -v` で実行する。期待値は CLAUDE.md の「計算の定義」に従い、テストが失敗しても src/ は直さない
3. すべての関数に docstring を追加し、README.md を作成する。1と2で見つかった問題は「既知の不具合」として README に載せる

この2回も、3つの定義ファイルを置いたままの同じ作業フォルダで実行しています。
実行記録を確認したところ、2回ともサブエージェントを呼び出す操作(Agent ツール)は一度も行われておらず、メインの会話だけで3つの作業を進めていました。

それぞれ2回ずつ実行した結果は次のとおりです(筆者の環境での結果で、条件によって変わる可能性があります)。

項目 1つの会話にまとめて依頼 3つのサブエージェントに分担
仕込んだ不具合の検出(11件中) 2回とも11件 2回とも11件
作られたテストの件数 22件・24件 29件・38件
追加された docstring の行数 74行・104行 147行・169行
所要時間(平均) 約2分 約3分50秒
出力の量(文字数・平均) 約2.0万字 約4.2万字
入力側のトークン(平均) 約52.8万 約66.7万
メインのコンテキストの使用量(平均) 約71k 約69k

トークン数は、Claude Code がPC内に保存しているセッションの記録から集計しました。
サブエージェントの出力トークン数は記録から正しく取り出せなかったため、出力の量は文字数で比べています。
メインのコンテキストの使用量は、/context コマンドの表示です。

結果から分かった3つのこと

1. 小さな作業では、見つかる不具合の数は変わらない
約80行・1ファイルの規模では、1つの会話にまとめて頼んでも、仕込んだ不具合は毎回すべて見つかりました。
メインのコンテキストも約71k(上限の約100万トークンのうち7%程度)しか使っておらず、情報が多すぎて精度が落ちるような状況にはなっていませんでした。

2. 分担すると成果物は詳しくなるが、時間と出力量は約2倍になる
テストの観点やドキュメントの内容は、2回ともサブエージェントに分担したほうが詳しくなりました。
担当ごとに専用の指示を持たせたことが効いていると考えられますが、各2回の結果なので、ほかの要因がある可能性もあります。
その分、時間と出力量はおよそ2倍になっています。
また、前の担当の結果をメイン経由で次の担当に渡す流れのため、メインのコンテキストはほとんど小さくなりませんでした。

3. 書き換えさせたくないものは、ツールの権限と事後の確認で守る
src/ のファイルを丸ごと上書きしようとする操作の扱いは、回によって分かれました。

  • 1つの会話にまとめて頼んだ1回目:オートモード(操作の許可を自動で判断する権限モード)に止められ、関数ごとの書き足しに切り替えた
  • 1つの会話にまとめて頼んだ2回目と、分担した1回目(doc-writer):止められずに丸ごと上書きした
  • 分担した2回目(doc-writer):最初から関数ごとに docstring を書き足し、丸ごとの上書きは起きなかった

どの回も、結果として処理の中身は変わっていませんでした。
ただ、指示や自動の判断に任せるだけでは、毎回同じ動きになるとは限りません。
書き込みが要らない担当には、レビュー担当のように書き込むツールを渡さない。
書き込みが要る担当の結果は、git diff src/ で中身を確かめる。
この2段構えにしておくと安心です。

使い分けの目安

方法 向いている場面
1つの会話にまとめて頼む 対象が小さく、1回で終わる作業。早く結果がほしいとき
サブエージェントに分担する 観点ごとに深く見たいとき。担当ごとに権限を分けたいとき。同じ手順を何度も繰り返すとき

今回の比較は小さな題材で各2回だけ試した結果です。
ファイル数が多い、1つの会話で長く作業を続けるといった条件では、結果が変わる可能性があります。

よくある質問

Q. Claude Code のサブエージェントはどこに作ればよいですか?

プロジェクト専用にする場合は .claude/agents/、すべてのプロジェクトで使う場合は ~/.claude/agents/ に Markdown ファイルを置きます。
必須の設定は name と description の2つです。

Q. /agents コマンドでサブエージェントを作成できますか?

公式ドキュメントによると、対話式の作成画面が開くのは v2.1.197 以前です。
執筆時点のバージョンでは、/agents を実行すると、Claude に作成を頼むか .claude/agents/ のファイルを直接編集するよう案内が表示されます。

Q. サブエージェントに分担させると、トークンや時間は増えますか?

筆者の環境で各2回試した結果では、1つの会話にまとめて頼んだ場合と比べて、所要時間と出力の量は約2倍、入力側のトークンは約1.3倍でした。
サブエージェントの利用分も、メインの会話と同じ使用量の上限に含まれます。

Q. サブエージェント同士は、お互いの結果を知っていますか?

サブエージェントはメインの会話の履歴を見られないため、ほかの担当の結果を直接は知りません。
本記事では、メインが前の担当の結果を依頼文に含めて次の担当に渡すよう、カスタムコマンドに手順を書いています。

まとめ:定義ファイル3つとコマンド1つで、役割を分担させられる

本記事では、Claude Code のサブエージェントを3つ作り、業務スクリプトのレビュー・テスト・ドキュメント作成を順番に分担させた手順と結果をご紹介しました。
学びは3つです。

  1. サブエージェントは Markdown ファイル1つで作れる:.claude/agents/ に name・description・tools・model と指示を書くだけで、役割を持った担当を用意できる
  2. 流れはカスタムコマンドで決める:前の担当の結果を次の担当に渡すよう手順に書いておくと、毎回同じ順番で動かせる
  3. 分担は「目的で選ぶ」:小さな作業なら1つの会話で十分。観点ごとの詳しさや権限の分離がほしいときにサブエージェントが役立つ

まずは、普段よく頼んでいる作業を1つ選び、読むだけのレビュー担当を1つ作ってみてはいかがでしょうか。

なお、次回は、作りたい構成を伝えるだけでサブエージェントの定義ファイルを設計・作成してくれるスキルを作る予定です。


また、QESでは、今回のようにコーディングエージェントに役割を分担させる仕組みづくりから、業務で使えるAIエージェントの開発までをご支援しています。
セキュリティ・ガバナンス設計からPoC・本番構築、運用と継続改善まで一貫して対応していますので、以下のリンクからサービスの詳細をご確認ください。

※このブログで参照されている、Claude、Claude Codeは、Anthropic PBCの商標または登録商標です。
※このブログで参照されている、Windows、Visual Studio Codeは、米国およびその他の国におけるMicrosoft Corporationの商標または登録商標です。
※Pythonは、Python Software Foundationの登録商標です。

  • このエントリーをはてなブックマークに追加

お問い合わせ

Contact

ご質問やご相談、サービスに関する詳細など、何でもお気軽にご連絡ください。下記のお問い合わせフォームよりお気軽に送信ください。

お問い合わせ

資料ダウンロード

Download

当社のサービスに関する詳細情報を掲載した資料を、下記のページよりダウンロードいただけます。より深く理解していただける内容となっております。ぜひご活用ください。

資料ダウンロード