freeeの開発情報ポータルサイト

Coding Agent へのタスク依頼を最適化する方法: Pull Request 作成 Workflow

はじめに

こんにちは、タイガーチームでエンジニアをしている横塚といいます。 この記事では Coding Agent へのタスク依頼を最適化していく過程を step-by-step で一緒に見ていきます。

お題は「Pull Request の作成」です。

  • コードは既に書いている
  • コミット済みで git の work-tree はクリーンな状態

この状況から Coding Agent (Cline, Roo Code, Goose CLI, GitHub Copilot Agent, Claude Code etc…) に高品質な Pull Request を作成してもらうことを目指します。

TL;DR:

  • Coding Agent によるワークフローの最適化には、シンプルなプロンプトチューニングのみでは不十分
  • 事前に確定できる処理はスクリプトに任せ、LLM には柔軟性が求められる処理に専念させる
  • スクリプトと LLM の相補的な組み合わせにより、コストパフォーマンスと実行時間、安定性を改善できる

まずはここから

まずは最もシンプルな方法で Pull Request を作成してもらいましょう。

あなたは GitHub Flow で開発するシニアエンジニアです。
現在のブランチの内容を元に Pull Request を作成してください。

たった二行のプロンプトですが、Coding Agent はいい感じに振る舞ってくれるでしょう。

git branch や git diff を実行したり、GitHub MCP サーバーのツールを呼び出して、Pull Request を作成してくれることは想像に難くありません。

しかし、この方法で作られる Pull Request の Description は言うなれば「品質ガチャ」状態です。指示するたびに実行するコマンド、参照する情報が代わり、結果として出力はまちまちになることでしょう。

第一段階: プロンプトチューニング

あなたが Pull Request の Description を書く時の手順を想像してください。それをなぞるような形で指示を出すことで、出力はあなたのそれに近づきます。

例えば、このようなプロンプトを考えてみました:

あなたは GitHub Flow で開発するシニアエンジニアです。
現在のブランチの内容を元に Pull Request を作成してください。

1.`git branch` を実行して現在のブランチ名とデフォルトブランチ名を調べてください
2. `git logs $DEFAULT_BRANCH..$CURRENT_BRANCH` を実行して、コミット履歴を調べてください
3. `git diff $DEFAULT_BRANCH..$CURRENT_BRANCH` を実行して、現在のブランチでの変更内容を調べてください
4. 変更内容の性質(機能追加、バグ修正、リファクタリングなど)を判定してください
5. 変更内容を元に Pull Request の Title と Description を生成してください
6. `git push origin HEAD` を実行して、remote に現在のブランチをプッシュしてください
7. GitHub MCP サーバーのツールを呼び出して Pull Request を作成してください

このくらい明確に指示をあたえると、Coding Agent は手順通りにコマンドを実行し、Pull Request を作成してくれるでしょう。

そして品質もかなり安定するはずです。

おっと、Pull Request を作る時はテンプレートを参照するべきでした。以下のように修正しましょう

-5. 変更内容を元に Pull Request の Title と Description を生成してください
+5. 変更内容を元に Pull Request の Title を簡潔な日本語で生成してください
+6. リポジトリに Pull Request のテンプレートがある場合は、それを参照して Description を生成してください。テンプレートは .github/ に存在することが多いです

これで Coding Agent はテンプレートに沿って Description を書いてくれるでしょう。

いや、待ってください、もう一つ大事な開発ルールを失念していました。Description には開発の根拠となる URL も含める必要があります。Coding Agent はどうやってその URL を知るのでしょうか?教えてあげる必要がありますね。

-1. `git branch` を実行して現在のブランチ名とデフォルトブランチ名を調べてください
+2. 現在のブランチ名からバックログのチケットのキーを抽出してください

課題: 手順の多さ

こうして PR 作成プロンプトのステップ数は膨らんでいきました…

手順が多いことは複数の観点で問題です。

  • ターン数が多い
    • function calling というのは実は一回のレスポンスで複数返せます。しかし、前述のようなプロンプトを与えた場合、Coding Agent はほぼ一つの手順を一つのレスポンスで実行することになるでしょう
    • つまり手順が 7 step ならリクエスト/レスポンスの往復はそれ以上の回数必要になります
  • 時間がかかる
    • LLM による推論は比較的遅い処理といえます。streaming で出力することが多いですが、あれは体感待ち時間を短縮するテクニックなのです
  • お金がかかる
    • LLM は呼び出すだけでお金がかかります。手順が多いとその分コストがかさみます。チリツモです
  • 失敗しやすい
    • 手順が多いと Coding Agent が手順を飛ばしたり、間違った手順を実行する可能性が高まります
    • 90% 成功する手順を 10 回繰り返せば 60% 以上の確率で一回は失敗します

第二段階: 決定的な処理はスクリプトに任せる

手順が多いことの問題点は理解できました。ではそれを解消していきましょう。

必要な情報は Agent ではなく開発者自身が収集して prompt を動的に生成するのです。

あなたは GitHub Flow で開発するシニアエンジニアです。
現在のブランチの内容を元に Pull Request を作成してください。

# Operations
1. 変更内容を分析して、Pull Request の Title を簡潔な日本語で生成してください
2. Template を参照して Pull Request の Description を生成してください
3. GitHub MCP サーバーのツールを呼び出して Pull Request を作成してください
# Status
現在のブランチ名: {git branch の結果をここに入れる}
デフォルトブランチ名: {git branch の結果をここに入れる}
## Commit Logs
{git logs の結果をここに入れる}
## Diff
{git diff の結果をここに入れる}
# PR Template
{リポジトリの Pull Request テンプレートをここに入れる}

必要な情報を全て事前に収集しておき、Coding Agent には「Operations」のみを実行させるようにします。(git push も自分でやるのが良いです)

すると Coding Agent は 2ターンほどで Pull Request を作成してくれるでしょう。

最終的な結果は大きく変わらないでしょうが、かかる時間とお金、そして失敗率は大きく改善されます。

次なる課題: プロンプトの動的生成

当然の疑問として「え、開発者が自分でコマンド実行するのは面倒じゃない?」「AI がもっと自動でやってくれたらいいのに」と思うでしょう。

しかしここはスクリプトの出番です:

  • 簡単なシェルスクリプトを書いて必要な情報を収集
  • テンプレートツールを使って、プロンプトを動的に生成
    • Ruby の ERB, Go Template, Python の Jinja2 など、色々選択肢はあります

スクリプトは一度書いてしまえば、何度でも使い回せます。更に Coding Agent と違って動作の予測可能性が高いです。Coding Agent のように「たまに」失敗することもありません。動作確認に時間とお金をかける必要もなくなります。

Goose の Sharable Recipes

もう一歩進んで Coding Agent に組み込まれた機能を使うのも良いアイディアです。

自分の知る限りでは GooseSharable Recipes が最もクールにこの課題を解決できます。

以下のような YAML ファイルを用意しましょう:

version: 1.0.0
title: Create GitHub Pull Request
description: 現在の作業内容からGitHub PRを作成するためのワークフローを実行します
instructions: |
  あなたは GitHub Flow による開発フローを実践しているシニアエンジニアです。

prompt: |
  # Task
  現在のブランチの内容でGitHub PRを作成してください。
  # Operations
  1. PR タイトルと PR 本文の生成
     - PR タイトルは Conventional Commits仕様に従って日本語で簡潔に作成
       - : `feat(auth/stg): Googleでのログインを追加`
     - PR 本文はテンプレートに従って作成
  2. GitHub PR作成
     - GitHub MCP サーバーを使用してPRを作成
     - 生成したタイトルと本文を使用
     - エラーが発生した場合はユーザーに報告してタスクを終了する
     - **IMPORTANT**: PR は必ず draft として作成する
  3. PR URL をユーザーに報告して完了
     - その他の情報は不要です
  # Current Status
  - リポジトリ: {{repository}}
  - チケットのURL: {{ticket_url}}
  - 現在のブランチ: {{current_branch}}
  - デフォルトブランチ: {{default_branch}}
  ## Commit Logs
  {{commit_logs}}
  ## Git Diff
  {{git_diff}}
  # PR Template
  {{pr_template}}

extensions:
  # GitHub MCP Server を有効にする(詳細は省略)
  # https://block.github.io/goose/docs/mcp/github-mcp

activities: []

parameters:
  - key: commit_logs
    input_type: string
    requirement: optional
    default: "N/A"
    description: "現在のブランチとデフォルトブランチの差分のコミットログ"
  - key: current_branch
    input_type: string
    requirement: optional
    default: "N/A"
    description: "現在の作業ブランチの名前"
  - key: default_branch
    input_type: string
    requirement: optional
    default: "main"
    description: "デフォルトブランチの名前"
  - key: git_diff
    input_type: string
    requirement: optional
    default: "N/A"
    description: "現在のブランチとデフォルトブランチの差分の内容"
  - key: pr_template
    input_type: string
    requirement: optional
    default: "N/A"
    description: "PR作成時に使用するテンプレートの内容"
  - key: repository
    input_type: string
    requirement: required
    description: "対象のGitHubリポジトリの名前 (例: `org/repo`)"
  - key: ticket_url
    input_type: string
    requirement: optional
    default: "N/A"
    description: "開発の根拠となるチケットのURL"

このファイルを goose コマンドの実行時に指定するだけで、Coding Agent が「必要最小限な MCP サーバー」と「動的に組み立てられたプロンプト」で Pull Request を作成してくれます。

parameter の部分はコマンドを実行して収集します。最終的には以下のようなシェルスクリプトが完成しました:

#!/bin/bash

set -eu

repository=$(gh repo view --jq .nameWithOwner --json nameWithOwner)
default_branch=main # Get git default branch name
current_branch=$(git rev-parse --abbrev-ref HEAD)
commit_logs=$(git log "$default_branch..$current_branch" --pretty=format:"- %s (%an, %ad)" --date=short | jq -Rs '@json')
git_diff=$(git diff "$default_branch..$current_branch" | head -1000 | jq -Rs '@json')
pr_template="..." # Get the contents of pull request template

# Extract ticket key from current branch name
ticket_url="N/A"
ticket_key=sample # Replace with actual regex to extract ticket key
if [ -n "$ticket_key" ]; then
    ticket_url="https://backlog.example.com/$ticket_key"
fi

git push origin HEAD
goose run --recipe /path/to/recipe.yaml \
    --params "commit_logs=$commit_logs" \
    --params "current_branch=$current_branch" \
    --params "default_branch=$default_branch" \
    --params "git_diff=$git_diff" \
    --params "pr_template=$pr_template" \
    --params "repository=$repository" \
    --params "ticket_url=$ticket_url"

Points:

  • ticket のキーは正規表現で抽出
  • リポジトリによって、Pull Request Template のファイル名やデフォルトブランチ名が違う問題をスクリプトで容易に吸収できる
  • 大きすぎる差分を全部 LLM に渡すのは非効率なので truncate する

Goose の Sharable Recipes の凄さは以下全てを同時に満たせることです:

  • ワークフローのコード化
    • GitHub Repository を介してスムーズに他の開発者と共有できます
  • プロンプトの動的生成
    • recipe のパラメータを使って、プロンプトを動的に生成できます
  • 利用可能なツールの制限
    • 先に提示したレシピでは GitHub MCP サーバーのみを有効にしています
    • こうなると Goose はファイルの読み書きやシェルコマンドの実行もできなくなります!
    • 不要なツールを排除することで、コンテキストを小さく保つとともに、変なことを始めてしまうリスクも減らせます
  • シェルスクリプトとのシームレスな連携

その他の Coding Agent

Goose の Sharable Recipes を例に解説しましたが、大抵の Coding Agent は再利用可能なプロンプトを定義する機能を持っています。

これらのツールを使うことで近い体験が得られると思います。

とはいえさすがに任意の shell command の結果をプロンプトに埋め込むのは難しいはずで、シェルスクリプトの実行結果をクリップボードに入れて運搬するなどの作業は必要になるでしょう。

教訓

一番伝えたかったのは「単なるプロンプトチューニング以外にもできることがある」ということです。

Coding Agent を使う時は、プロンプトをチューニングすることも大事ですが、それだけでは不十分です。Workflow の要求や各ステップを精緻に定義し、決定的な処理が可能な部分はスクリプトに任せてしまうことで、LLM の弱点をカバーすることができます。

更にスクリプトの開発が Coding Agent によって圧倒的に楽になっていることも特筆すべきでしょう。これまでだったらあれやこれやとインターネットで検索しなければ実装できなかったような少々複雑なスクリプトも、LLM ならサラッと書いてくれます。

長期的なメンテナンスを考慮してもスクリプトの良さが光ります:

  • 動作確認が早い、安い
  • レビューが容易
  • テストが書きやすい

重要なのは、タスクをステップに分解して精緻化する論理的思考と、どのような処理がスクリプト化できるのか、しやすいかということを深く理解することです。

一方で全ての処理をスクリプトで記述しようとするのもアンチパターンです。大変で時間がかかりますし、一つ一つ丹念に組み上げたつもりのスクリプトに限って、外的環境の変化によって容易に瓦解したりするものです。Keep it simple を心がけましょう。

大事なのは LLM とスクリプトを相補的に活用することです。そうすると Coding Agent の力を最大限に引き出すことができるでしょう。

まとめ

本記事では、「Pull Request の作成」という身近な題材で、Coding Agent によるワークフローの最適化について考察しました。

単にプロンプトを調整するだけでは、多くの課題に直面します。結果の予測可能性が高いスクリプトと非決定的でありつつも柔軟な LLM を上手く組み合わせることで、Coding Agent の安定性と効率性を向上させることができます。