はじめに
アドプラットフォーム事業部で開発を担当している室岡です。
既存のGoのOSS内で参照しているaws-sdk-goパッケージをCopilot Agent mode(以下、Agentモード)を使用してメジャーアップグレードした事例をご紹介したいと思います。
LLMを利用した開発の参考になれば幸いです。
※ Copilotの使用法そのものの説明は割愛いたします。
開発過程
開発対象
下記のGoのアプリケーションになります。
こちらは、database/sqlパッケージのAthena用ドライバです。
他にもAthena用ドライバは存在しますが、パフォーマンス面において改良を加えています。
長らく、aws-sdk-goのv1を使用し続けていたため、Agentモードを使用してv2へ変更を試みました。
使用した開発環境
- Copilot Agent mode
- Claude 3.7 Sonnet
ステップ:1 とりあえずはじめてみる
下記のようなプロンプトでAgentモードによる修正を開始しました。
プロンプト
github.com/aws/aws-sdk-goを使っている箇所をすべてgithub.com/aws/aws-sdk-go-v2を使うように変更して ただし、 - github.com/aws/aws-sdk-goのv1からv2へのアップグレードで必要は変更以外はしないでください - 可読性が良くなるためだけのリファクタリングは避けてください(必要なら別途実施するからです) - ビルドが通るようにしてください
Agentモードにより完了を告げられた後に(1回目)
Agentの作業が終わったとのことなのでテストを実行しようとしたところ、ビルドが通りませんでした…
エラーの内容を指摘して、再度Agentモードを実行します。
Agentモードにより完了を告げられた後に(数回目)
何度か試行を繰り返すうちにビルドは通るようになったものの、テストが通らない状態が続きました。
変更したソースを確認しても、具体的にどこを変更したのかが分かりにくいです。
- 何度かAgentモードによる修正を繰り返し、ビルドは通るようになったがテストが通らない
- 変更したソースを見ても、なぜそのような変更をしたのかがわかりづらい
さらに、何度もやり直したり、最初から指示をし直したりしましたが、結局、一度挫折してしまいました。
また、変更箇所を見ると、単にv1からv2への置き換え以外にも修正が行われているようでした。
つまり、LLMが考える理想のコードへのリファクタリングとv2への更新を同時に実施してしまっていたのです。
そこで、今までの変更は破棄し、まずLLMにリファクタリングを行わせ、その後でv2へのアップグレードを行うことにしました。
ステップ:1(2回目) v1のまま、まずリファクタリングをする
もう一度最初から仕切り直して、今度はv1のまま、LLMが考える理想のソースへ一旦リファクタリングを施します。
プロンプト
こちら、goからsqlパッケージを介してAthenaにアクセスするパッケージです。 あなたが考えるリファクタリングをしてください。 条件 - 参照しているgoのパッケージのアップグレードはしない。 - テストも含めてすべてのビルドが通るようにして。
結果として、比較的すんなりビルドとテストが通るように修正してくれたと思います。
- クエリ判定の整理
- 正規表現を定数化し、内部用(小文字)のqueryTypeと外部用(大文字)のQueryTypeを定義。それぞれの判定関数(getQueryType, isDDLQuery, isSelectQuery, isCTASQuery, GetQueryType)が追加される。
- 結果モードのチェック追加
- コンテキストから取得した結果モードが有効かどうか、isValidResultMode関数で確認する処理を追加。
- コンテキストキーの型安全化
- 単純な文字列から、独自のcontextKey型とジェネリクスを用いた値取得関数(contextValue)が使われるように変更。
- エラーハンドリングの改善
- エラー定数(ErrDatabaseRequired、ErrSessionRequired、ErrInvalidResultModeなど)とwrapError関数を活用してエラー処理を統一。
- Goのバージョンと依存関係の更新
- go.modをGo 1.18にアップデートし、不必要な依存の整理・追加を行う。
LLMがどのような意図で実装したかは比較的わかりやすい変更でした。依頼していないPublic関数や変数が追加されるなど、筆者の設計方針とは異なる部分もありましたが、どうしても譲れない部分は変更し、総じて良い修正になったと感じています。
ステップ:2 その後、v2に変更している
プロンプト
github.com/aws/aws-sdk-goを使っている箇所をすべてgithub.com/aws/aws-sdk-go-v2を使うように変更して ただし、 - github.com/aws/aws-sdk-goのv1からv2へのアップグレードで必要は変更以外はしないでください - 可読性が良くなるためだけのリファクタリングは避けてください(必要なら別途実施するからです) - ビルドが通るようにしてください - go test ./…がと通るようににしてください - 外部へのインファーフェイスは変えないでください
リファクタリングをしないまま実施するよりも完成度は高くなりました。aws-sdk-goのAthena機能を素直に利用しているAPIモードについては、ほぼ一度で問題なくビルドとテストが通ったと思います。
Agentモードの修正の問題箇所
ただ、まだ下記の点に関しては問題が残っており、手動で修正しました。
- 独自仕様の複雑な箇所に対するv2対応の精度が十分ではない
- 独自のinterfaceを設けてなんとかビルドを通すようにしている
独自仕様の複雑な箇所に対するv2対応
下記のDL/GZIPモードはspeee/go-athena独自の仕様ですが、そのアップグレード対応は不十分でした。
- QueryResultをaws-sdk-goのathenaのAPI経由ではなく、S3からCSVファイルをダウンロードして取得するDL Modeの修正
- QueryResultをaws-sdk-goのathenaのAPI経由ではなく、S3からGZIPファイルをダウンロードして取得するGZIP Modeの修正
独自のinterfaceを設けてなんとかビルドが通るようにしている
また、テストを通すために強引に?おれおれinterfaceを作成していました。ビルドとテストを通すためのLLM的な最適解だったのでしょうが、speee/go-athena内はあくまでもawsのAthenaを使用するためのものなので、このパッケージ内でinterfaceを定義する必要を感じません。最終的にaws-sdk-goで定義されているinterfaceを見つけ出し、ビルドとテストの両方が通るように修正して完成しました。
下記のように、複数の要素が組み合わさった難題は、現状のLLMではまだすんなりと解決できなかったようです。
- aws-sdk-goのv1とv2でAthena APIのinterfaceが大きく変わったこと
- speee/go-athenaの独自仕様
今回の開発でわかったこと
- 網羅率が高いテストは必須
- LLMモデルの考える理想の設計とあなたの考える理想の設計は異なる
- 独自のロジックでかつ複雑なものに対しては、自動では対応しづらい傾向
- 開発しているのはLLMではなくあくまでもあなた自身
- LLMモデルはあくまでも予測でソースを書いている
- Agentは実行の一端を担ってくれるが、完璧ではない
- 最大の長所はやる気がない場合に着手するハードルを圧倒的に下げる
網羅率が高いテストは必須
今回のように、既存のアプリケーションに新たな修正を加える場合には、網羅率の高いテストが不可欠だと思います。
LLMモデルの考える理想の設計とあなたの考える理想の設計は異なる
上記で述べた通り、LLMは「Goのアプリケーションとしてこうあるべき」という観点をもとに修正を加えます。自分たちでは気づかない点を指摘してくれることもありますが、自分たちの想定するポリシーと合わない変更が含まれる場合もあります。
プロンプトに改めて指示をするか、手動で一部修正するなどして進めていく必要があります。
また、独自のロジックでかつ複雑なものに対しては、やはり自動で対応しづらい傾向があると感じました。
開発しているのはLLMではなくあくまでもあなた自身
このあたりは、今後のLLMやAgentの精度向上により改善される可能性もありますが、
- LLMモデルはあくまでも予測でソースを書いている
- AgentはテストやOSコマンドを実行する一端を担ってくれるが、最終的には開発者による確認が必要
という性質上、必ずしも完璧ではありません。
最終的には、やはり開発者が修正内容を理解し、コミットする必要があると思います。
最大の長所はやる気がない場合に着手するハードルを圧倒的に下げる
筆者としては、今回のgo-athenaのv2への移行は以前から必要性を感じていながらも、なかなか着手できずにいました。そんな中、実験的にAgentモードを利用してみたところ、数回のトライアルでビルドが成功したのをきっかけに(テストまでは通りませんでしたが)、最終的にアップグレードを完了できました。
- 別タスクを進めながら開発を任せられる
- 手軽にいろんな設計を試すことができる
仕事を早く進めるうえで「まず着手すること」は非常に重要ですが、それを大いに後押ししてくれると感じました。
以上になります。