LLM をソフトウェア開発に組み込む
この記事では、私(@spinute)がソフトウェア開発の中で最近どのように LLM を使っているかを紹介します。
ChatGPT に質問したり、GitHub Copilot を使ったり、知的で実用的な AI サービスがいくつか登場する中で、自分の普段の作業の中にどのように LLM を組み込むかを試してきました。
最近では、ブランチの作成、コミットメッセージの作成、プルリクエストの作成など、書いたプログラムの内容を言葉にする作業は基本的に AI に任せ、自動化しています。
そのために、使っているソフトウェア(PR Agent, bento)や設定を具体的に紹介します。
また、プログラムを書く際にも、LLM にコードを書かせたり、レビューを頼んだり、質問したりを繰り返しながら作業を進めています。
最近は Cursor という VSCode を拡張したエディタを主に使っているのですが、Cursor に関する記事はすでに割とたくさんあるので、この記事では軽い紹介に留めます。
開発の流れ
私は普段の仕事の開発では、作るものが決まったあと、ざっくり以下の流れで開発作業を進めています。(これは簡略化していて、作業の複雑さや流れに応じて、設計に時間を取ったり、イテレーションを重ねたりすることもあります。)
- プログラムを作成
- ブランチを作成
- コミット
- プルリクエストを作成
- レビューを受けて、CI/CD を通してリリース
ブランチの命名、コミットメッセージの作成、プルリクエストの記述といった作業は、書いたプログラムと情報的には重複が多く、AI に任せてしまえると感じていたのでここ1年ほどいろいろなツールを試してみていました。
今ではプログラムの作成以降の作業は多くの場合 AI に任せています。
プログラムを作り終え、プルリクに乗せたい変更を git add した後、後述のスクリプトを使って create_branch.bash && commit.bash && git push origin HEAD && gh create pr --web
のようにすると、ブランチの作成、コミット、プッシュ、プルリクエストの作成と上記一連の処理はコマンド一発で済みます。
ブランチの作成を AI に任せる
プログラムを書き終えているとします。
この作業をプルリクエストにするために、ブランチを作成します。
ブランチの名前は基本的に変更した内容を要約したものになっていて、プログラムの変更内容を元に AI に生成させればそれなりに納得できるものが得られます。
LLM を利用するためには bento を使っています。
bento は @catatsuy さんが作っているのを見かけて使い始めたツールです。OpenAI API のシンプルなラッパーになっていて、UNIX 哲学に沿った作りになっていて柔軟性が高いです。
catatsuy さんはこのように使っているそうです。https://zenn.dev/catatsuy/articles/1b64fc13d2e0b9
bento ではプロンプトを簡単に差し替えられるので、作業しているチームのルールに合わせたブランチ名のフォーマットなどを指定しています。
実際には、こんな感じのスクリプトを使っています。(fish, bash, zsh など使い分けるのが面倒なので最近はシェルスクリプトは AI に書かせています)
# create_branch.bash
diff=$(git diff -w --staged)
if [ -z "$diff" ]; then echo "No changes to commit"; exit 1; fi
prompt="generate a branch name by exactly 4 words without any additional text or formatting. ex. do_something_funny_foobar"
branch_name=$(echo $diff | bento -model "gpt-4o" -prompt "$prompt" -single)
if [[ ! "$branch_name" =~ ^[a-zA-Z0-9_]+$ ]]; then echo "Invalid branch name format"; exit 1; fi
git co -b $branch_name
LLM はたまに狂った出力を返してくることがあるので、出力フォーマットを軽く validation しています。
コミットメッセージの作成を AI に任せる
コミットメッセージも上のものと同様に bento を使って作っています。
# commit.bash
diff=$(git diff -w --staged)
if [ -z "$diff" ]; then echo "No changes to commit"; exit 1; fi
if [[ $(echo $diff | wc -c) -ge 10000 ]]; then echo "Git diff exceeds 10000 tokens"; exit 1; fi
message=$(echo $diff | bento -commit -model "gpt-4o")
git commit -m "$message"
catatsuy さんはメッセージを提案してもらった上で確認しているそうですが、私はコミットメッセージにはあまりこだわっていないことが多いので、そのまま自動でコミットしてもらうようにしています。
(git なんでイマイチだったら戻すことはできますし、ほとんどの場合そのまま採用しているため、デフォルトではそのまま進めてもらっていいかなと思っています。)
採用しなかったツール
GitLens にもこの機能がありますが、基本的に GUI から使用することを想定した作りになっているようです。GUI, GitLens を使っている方にとっては有用かもしれません。
私は主に CUI で Git を操作しているのもあって、これは採用できませんでした。
なお、最近は Cursor を使っていて、プログラムの作成もかなり AI に任せられることが増えてきているのを感じています。
指示を出してレビューをする、事業やプロダクトのことを考える、暇を潰すといった作業に人間のリソースを充てるようになっていく流れの必然性を感じています。
コミットメッセージやブランチ名については、及第点のものが作成されます。
人間がこだわればより高品質なものを作れるとは思うのですが、個人的にはブランチ名やコミットメッセージはそれほど重要視していません。
自分が読み書きする主戦場はプログラムやプルリクエスト・issue の単位であって、ブランチ名やコミットメッセージはあくまで補助的な情報だと考えています。
プログラムは実際に動くソフトウェアの一次情報として高い水準での正しさや理解しやすさ、メンテナンス性が要求されます。
また、プルリクエストはソフトウェア作成におけるコミュニケーションの単位、ソフトウェアの機能変更における単位であって、どのような意図で何をしたのかが明確にわかることが求められます。
これらの主要単位に対し、コミットメッセージやブランチ名はあくまで補助的なものだと考えています。
そのため、AI が作成したそれなりクオリティのものでも、自分はすでに満足できると考えており、これらの相対的に重要ではない作業を自動化できるメリットを取るべきだという判断をしています。
また、AI がうまく理解できるプログラムを書くことの重要さはこれから増していくはずです。
コミットメッセージやブランチ名を正しく明確に AI がつけられるようなプログラムを作成する癖がつき、普段の作業のなかで常にこの訓練の機会を手にするメリットもあると考えています。
PR Agent
(以下書きかけ🙏)
- プルリクエストの内容を踏まえてレビューや解説、改善提案やドキュメント作成などをやってくれる
- CI で動く
- 日本語じゃないと頭にすっと入ってこない人がいそうなので日本語で出力
- description と review は実用的
- improve はポンコツ。ベストプラクティスや高速化のためのコメントとしてかなり嘘をつくので、嘘を見抜けない人は混乱してしまいそう
- テストやドキュメント書いてくれるといいなと思いつつそのへんは発展途上
ローカルで OpenAI の API を叩くためのクライアントとしては https://github.com/catatsuy/bento を使います
opencommit, aicommit, gptcommit などのツールも試してみたのですが自分のやりたいことと微妙に噛み合わず、やりたいことはシンプルだったので自分で作っても良かったのですが、Twitter でちょうどいい薄さのクライアントライブラリを catatsuy さんが作っているのを見かけたのでこちらを使うことにしました(大感謝!)
簡単に使えること、自分やチームのフォーマットに合わせるためにプロンプトを調整できること、インタラクションナシで実行できること(-y オプション的な)などを求めていたのですが、既存のツールにはそれらを完全に満たすものを見つけられませんでした
このツールを使うと、CI の中でプルリクエストのレビューを自動で行うことができます
コミット内容の要約、レビュー、改善の提案などの機能がありますが、
- 内容の要約は十分実用的。コード上に乗っていない背景知識や注意事項は別途補う必要があり、プルリクエストのテンプレートでここはカバーしています
- レビューは役に立つことがある。簡単なコーディングミスを見つけてくれることがあります。人間のレビューと比べると安価にニアリアルタイムに提供されるのが嬉しいポイントです
- 改善提案については結構雑なことを行ってくる印象です。高速化のための手法や Ruby の標準的な書き方など、でたらめなことを結構言うので活用するには読み手のリテラシーが必要です
こうして、コードを書いてどのコードを元にプルリクエストを作成するかを決めれば、ブランチ名を決め、ブランチを作り、コミットメッセージを決め、コミットを作り、プルリクエストを作り、プルリクエストの中身を埋めてくれるところまでを全自動で行ってくれます。また、プルリクエストに対して1分以内に簡易的なレビューが自動で投稿されます。
プログラムを書くと spec を書いてくれたり、仕様書を書くとプログラムをそれに合わせて修正してくれたり、そういった世界もかなり現実に近づいている気がします。
(もしすでに実用に近いものがあればぜひ試してみたいので教えていただきたいです)
Discussion