まだチケットを手動で書いてるの?!GitHub Actionsと生成AIでチケットの作成を自動化してみた話
はじめに
SHIFTでDevOpsリードエンジニア(自動化アーキテクト)をやっている片山 嘉誉です。
突然ですが皆さん、プロジェクト管理ツールは何を使っていますか?
有名なところで JIRA や Redmine がありますが、私が現在参画しているプロジェクトではGitHubが提供する Projects の機能を使っています。 GitHub Projectsではチケットを Issues で管理するのですが、今回はそのチケットの作成を自動化した話をしたいと思います。
基本的にGitHubでの話がベースにはなるのですが、生成AIの部分は他のプロジェクト管理ツールやCI/CD環境でも流用が効く話となるため、皆さんの環境に合わせてカスタマイズしてみてください。
まずは前提となるチケットの管理方法について話していきたいと思います。
※本記事は12/7(土)開催のソフトウェアテスト自動化カンファレンス2024でのセッション内容に基づいています。登壇資料もあわせてご覧ください。
チケットの作成方法について
子チケットを作成する例
皆さんはチケットをどのように管理していますか?
多くの場合は最終的な成果物単位で親チケットを作成し、作業を分割して子チケットにするのではないかと思います。 その子チケットの作り方は開発のスタイルやプロジェクトの方針によってケースバイケースであると思いますが、恐らくこのようなパターンになると考えています。
特にアジャイルの場合はスプリントと呼ばれる期間ごとに分割してチケットを作成するため、ウォーターフォールと比べて作成されるチケットの数は相対的に多くなると思います。
チケットの親子関係(チケットの構造)
少しイメージを共有するためにチケットの親子関係について図にしてみました。
今回の話は主に右側のチケットを数珠繋ぎで作成するパターンを想定しており、先行チケットの内容を踏まえて後続のチケットを作成する流れとなります。 これはアジャイル開発においてスプリント内のチケットを整理して、残作業を別のチケットに切り出す、という流れに沿ったものとなります。
子チケットを作成する、という意味では左側のパターンでも今回のツールは活用できますが、左は計画の段階で作業内容を明確化すると思うので、自動的に生成しても結局内容を全部精査することになると思います。
生成AIを使う以上、出来上がる成果物には間違いがあるので、それが許容できるようなシーンで使う必要があります。 現在のプロジェクトでは自動で作成されたチケットはリファインメントと呼ばれる作業内容を明確化するフェーズで内容を精査して作業の実態に都度合わせています。
生成AIを使うとチケットの作成はどうなる?
手動でチケットを作成した場合の課題として、打ち合わせ中に作業内容を検討していると話が脱線してチケットの範囲外の話をしてしまったり、作業を進める中で問題があった場合の想定が抜けていて、チケットの作業量を過小評価してしまう場合があります。
また、アジャイル開発ではバックログとしてチケットを作成してからリファインメントで内容を精査するまで時間が空くケースがあり、後から見直した際に何の話だったか思い出すところから始まってしまったりします。
それらを解消するため、今回作成したツールでは子チケットを作成したタイミングで親チケットの内容を参照し、親チケットの内容を踏まえて子チケットの内容を生成するようにしました。
親チケットの内容を参照することである程度生成AIの方で作業の意図を汲み取って内容を生成してくれます。 また、一般的にやるべき作業を出力してくれるので、実務に合わせて作業内容を見直す際にもそれほど手間にはなりません。 イメージとしては7~8割ぐらい精度でドラフトを作成してくれるようなものです。
何より打ち合わせ中にチケットを作成しても裏で勝手にチケットを更新してくれるので、新しく作成したチケットの方に話が脱線せず『取り敢えず生成AIが作ってくれる内容を踏まえて後で見直しましょう』と打ち合わせを中断させないところが良い点となります。
ツールの概要
チケット作成から自動更新までの流れ(簡易版)
まずは基本的な処理の流れを説明します。
GitHub ActionsはGitHubが提供しているCI/CD環境になるのですが、これはリポジトリ内の特定の場所にYAMLファイルを格納することで動作します。 YAMLファイルには「いつ(トリガー)」「どこで(実行環境)」「なにを(処理)」といった処理の流れを記載することができます。
今回の場合は子チケットが作成された事を契機に処理を開始させ、GitHub Actionsのランナーからチケットの更新を行うという流れになります。
生成AIでチケットを作成するツールの構成(詳細版)
もう少し具体的なツールの構成について説明します。
今回は複数のリポジトリから同じ処理を使い回しができるよう、アクションを管理する別のリポジトリを用意しています。 これはチケットを管理しているリポジトリから別リポジトリのアクションを呼び出す形で処理が行われます。
また、生成AIのAPIは社内からしかアクセスできないという制限があるため、GitHubが提供しているランナーは使うことができません。 そのため、自前で用意したセルフホステッドランナーを使用し、生成AIの実行とチケットの更新を実現しています。
生成AIのAPIを実行するための認証情報は呼び出し元のリポジトリで管理する必要があり、与えられた認証情報を基にアクションの処理が実行されます。
技術的な詳細
チケット作成のトリガー設定
トリガーの種類はたくさんあるのですが、今回はチケットの作成についてだけ紹介します。チケットに関わるイベントは「issues」を使用し、チケットが新規作成された場合はtypesに「opened」を記載します。チケットが更新された場合は「edited」、クローズされた場合は「closed」など、状態遷移に合わせて様々なトリガーが用意されています。
name: Generate Issue Content
on:
issues:
types: [opened]
permissions:
issues: write
contents: read
jobs:
generate-issue-content:
runs-on: [self-hosted, linux, x64]
steps:
- name: Generate Issue Content
env:
GH_REPO: ${{ github.repository }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
uses: organization/github-actions/generate-issue-content@v1
with:
repository: ${{ env.GH_REPO }}
issue_number: ${{ github.event.issue.number }}
ai_api_token: ${{ secrets.AI_API_TOKEN }}
親チケットの情報を取得する方法
チケットの情報を取得するためにはGitHub CLI(通称ghコマンド)を使用します。ghコマンドには様々な種類があるのですが、チケットの内容を取得するには「gh issue list」コマンドを使用します。「--state all」オプションと「--search "${issue_number} in:body"」オプションを使用する事で、子チケットの番号が本文に含まれるチケットの一覧を取得することができます。「--search」はあまり細かな条件を付与することが出来ないため、その後誤検知を防止するために改めて本文内に「- [ ] #${issue_number}」が含まれているかチェックを行います。
get_parent_issue_number() {
local -r repository="${1}"
local -r issue_number="${2}"
local -r issue_url="- [ ] https://github.com/${repository}/issues/${issue_number}"
local -r issue_path="- [ ] #${issue_number}"
gh issue list \
--state all \
--search "${issue_number} in:body" \
--json number,body \
--jq ".[] | select(.body | contains(\"${issue_url}\") or contains(\"${issue_path}\")) | .number" | head -n 1
}
生成AIの具体的なプロンプト
では、具体的なプロンプトを紹介します。
ポイントとしては、生成AIの回答内容を「本文だけ」と指定するところです。 こうする事で余計な解説などが返却されず、戻ってきたデータをそのまま使用することができます。 但し、例えば冒頭部分に「Issueの本文:」や「```」など余計な文字列が付与されるケースもあり、これらはシェルスクリプト側で削除する処理を実装しています。
また、親Issueへのリンクを参照欄に記載するようプロンプトで指定しており、位置を特定して文字列を挿入する、といったプログラムを書く必要が無いところも生成AIの良いところだと思います。
GitHubの親Issueから子Issueを作成したい。
以下の仕様に従い、子Issueの本文を作成して欲しい。
仕様:
- 回答は子Issueの本文だけにする。
- 子Issueのフォーマットは親Issueと同じ形にする。
- 親Issueのタイトルと親Issueの本文を基に子Issueで行う作業を推測する。
- 「達成条件」は子Issueが完了するための条件を1行で記載する。
- 「結果」と「残課題」「詳細」の欄は項目を削除して「- なし」とだけ記載する。
- 「参照」の欄は「- 親Issue: #${parent_issue_number}」を記載する。
子Issueのタイトル:
${child_issue_title}
親Issueのタイトル:
${parent_issue_title}
親Issueの本文:
\`\`\`
${parent_issue_body}
\`\`\`
先の例ではある程度テンプレートが決まっているという想定で各項目に記載して欲しい内容を具体的に指示していますが、より汎用的なプロンプトだとこの様になります。
GitHubの親Issueから子Issueを作成したい。
以下の仕様に従い、子Issueの本文を作成して欲しい。
仕様:
- 回答は子Issueの本文だけにする。
- 子Issueのフォーマットは親Issueと同じ形にする。
- 子Issueは作業を行う前の状態を想定して作成する。
- 各項目の初期値は「- なし」とする。
- 親Issueのタイトルと親Issueの本文を基に子Issueで行うタスクを推測する。
- 子Issueの本文に「参照」の項目を追加して「- 親Issue: #${parent_issue_number}」を記載する。
子Issueのタイトル:
${child_issue_title}
親Issueのタイトル:
${parent_issue_title}
親Issueの本文:
\`\`\`
${parent_issue_body}
\`\`\`
ポイントとしてはもし「参照」という項目が無ければ自動で追加して記載を行うような動作になります。
生成されたチケットの例
ここで実際に作成されたチケットの例を記載したいと思います。
親チケット(タイトル: テスト用のチケットを作成する。)
少し説明をしっかり書いておくことで、子チケットの内容も精度が上がります。
子チケット1(タイトル: テスト用のチケットを編集する。)
親チケットに書いてある仕様を理解し、編集しても本文がそのままであることを記載してくれています。
子チケット2(タイトル: テストチケットの本文を空にして、再度本文が生成されるか確認する。)
こちらは少しタイトルを長めにしていますが、タイトルの内容に従い確認内容を自動で生成してくれています。
さいごに
導入後の効果
このツールを導入した後、チームメンバーから『子チケットを作成するのが楽しくなった』という感想が出てきました。生成AIにはガチャのようなランダム要素があるため、どのような内容のチケットが生成されるのかというワクワク感が生まれたと思います。 また、親チケットに記載する内容を増やす事で生成される内容も正確になるため、生成AIに子チケットを作ってもらう前提で親チケットの内容をきちんと書くようになりました。これにより、後からチケットを見返した際により分かり易くなるという副次的効果がありました。
生成AIを使う上での苦労
生成AIを用いて仕事を自動的に終わらせたい、というのは誰しも思うところですが、成果物に高い精度が求められるような場所に生成AIによる自動化を適用するのはまだ難しいように感じています。 現状では意図したものが作成されているかレビューを行う必要があるため、何かのドラフトを作成するという用途であれば適しているように思います。
また、本ツールは当初GPT-3.5-turboで試作していたのですが、生成される内容が安定しないためGPT-4にモデルを変更して運用しています。その後運用コストを抑えるためにGPT-4oに乗り換えられないか試してみたのですが、「Issueのフォーマットは親Issueと同じ形とする。」という指示を思うように解釈してくれず、納得のいく結果を得ることが出来ませんでした。モデルによって出力される内容にはかなりバラつきがあるため、実現したい内容に合わせてモデルを選択することが大事です。
チケットの本文作成に適した生成AIモデル
今回ツールを作成するにあたって試した生成AIのモデルを記載します。
この中で私が実用レベルと判断できたのは「GPT-4」と「Gemini-1.5-pro」となります。 今回は紹介していませんが『チケットの本文からタイトルを1行にまとめる』というツールも作成しており、その場合は「GPT-4o」の方が精度が高かったです。
どのモデルが適しているかは正直やってみないと分からないという部分もあり、複数のモデルを試して結果を比較してみて適材適所で選んでいく必要があるように思います。
それではまた次の記事で!「スキ」と「フォロー」もお願いします!
お問合せはお気軽に
SHIFTについて(コーポレートサイト)
SHIFTのサービスについて(サービスサイト)
SHIFTの導入事例
お役立ち資料はこちら
SHIFTの採用情報はこちら