Devin
Devin is an AI coding agent and software engineer that helps developers build better software faster. Parallel cloud agents for serious engineering teams.
https://devin.ai/
Photo by Bernie Almanzar on Unsplash
こんにちは。ウォンテッドリーでデータサイエンティストをしている林 (@python_walker)です。
この記事では、AI エージェント Devin の機能である Playbooks を活用し、データサイエンティストチームが管理するマイクロサービスで使用している Python バージョンの更新作業を効率化し、作業コストの削減を実現した取り組みについて紹介します。
チームの抱えていた課題
これまでの Python アップデートの手順
Devin Playbooks を利用した効率化
Playbooks とは何か
なぜ Playbooks を選んだか
Playbooks の活用法
結果
解決した課題
まだ残っている課題
まとめ
ウォンテッドリーでは、会社訪問アプリ Wantedly をはじめ、さまざまなプロダクトを開発・運用しています。その中には機械学習を活用したサービスも多く含まれており、そうしたリポジトリのメンテナンスは、私が所属するデータサイエンティストチームが一手に担っています。
機械学習関連のマイクロサービスでは主に Python を使用していますが、定期的に Python のバージョンを更新するにあたり、いくつかの課題がありました。
まず 1 つ目は 対象となるマイクロサービスの数の多さです。私たちのチームは 4 名で構成されていますが、そのメンバーで 28 個のマイクロサービスをメンテナンスする必要があります。Python は他の言語と同様におよそ1年ごとに旧バージョンが EOL を迎え新バージョンが公開されるため、セキュリティリスクを避けるためにも定期的なアップデートが欠かせません。また、チームの主な業務は Wantedly のマッチングの推薦を改善するための開発であるため、開発スピードに影響を与えずにメンテナンスを進める工夫が求められます。
2 つ目は機能に対する理解度のばらつきです。ウォンテッドリーはすでに 10 年以上事業を継続しているため、対象マイクロサービスの中には完全に保守フェーズに入り、普段ほとんどコードを触らないものも存在します。中には、開発に関わっていたメンバーがすでに誰もいないサービスもあり、その場合は 1 つ 1 つの保守コストが大きくなりがちです。特に機械学習システムでは、モデルの性能劣化が起きていないかを確認する作業が欠かせません。しかし、実際に確認しようとすると、動作方法や評価指標がすぐにわからない場面があり、これが大きな課題といえます。
この記事では、これらの課題に対して Devin を活用して効率化を進めた取り組みを紹介します。特に、1 つ目の課題に対して Playbooks 機能を活用した方法を中心にお話しできればと思います。
まず、Playbooks を導入する以前に、Python のバージョンアップ作業をどのように進めていたかを説明します。
実施していた手順は以下のとおりです。
pyproject.toml を編集し、対応する Python のバージョン範囲を拡大pyproject.toml を元に Lock ファイルを再生成Dockerfile 内の Python イメージのバージョンを更新こうした作業の 1 つ 1 つは小さなステップが多いものの、手順が多いため 人手で行うと地味に時間がかかる のが実情でした。特に Lock ファイルの再生成では、既存のバージョン制約のままでは生成できず、依存ライブラリのバージョン調整が必要になるケース も少なくありませんでした。
我々は上記の手順の内のいくつかを Devin によって自動化できないかと考えました。Devin は、米国スタートアップの Cognition AI, Inc. が開発した「完全自律型のAIソフトウェアエンジニア/AI開発エージェント」です。
Devin は、GitHub と連携することにより自然言語でタスクを与えるだけで自律的に作業して PR 作成までやってくれるため、エンジニアの生産性を大きく向上させられるツールだと言えます。
Playbooks は「カスタム system プロンプト」のような位置づけで、何度も発生する開発フローをテンプレート化することができます。
ウォンテッドリーでは Devin が開発組織全体に導入されており、もともと使える状態だったというのが一番大きな理由です。
さらに言うと、今回のようなメンテナンスタスクの場合、リポジトリを跨いで同じようなフローを使い回したいので、リポジトリごとに AGENTS.md を用意して任意のエージェントで作業させるよりも Playbooks を運用する方が適していると考えました。
我々は Playbooks を利用して Python アップデートの「動作確認より前の部分」を自動化しました。動作確認までやらせなかったのは、技術的な問題というよりも法務的な面が理由です。
以下が Python のアップデートに利用している Playbooks のプロンプトです。(一部公開できない部分は削除しています)
## Procedure
1. **step 1**: 対応するPythonのバージョンを変更する
pyproject.toml 内に定義されているPythonのバージョンを新しいバージョンを含める方向にスライドさせてください。
```toml
[tool.poetry.dependencies]
python = ">=3.10,<3.11"
```
のように記述されている場合には、以下のように変更します。
```toml
[tool.poetry.dependencies]
python = ">=3.11,<3.12"
```
どれだけの幅スライドさせるかは、タスクの依頼者の指示に従ってください。
2. **step 2**: Lockファイルの再生成
`poetry` コマンドを利用してLockファイルの再生成をしてください。手元のPythonのバージョンが pyproject.toml で指定した範囲に無い場合には、mise 等のツールを用いて必要なバージョンの Python を使えるようにしてからおこなってください。
```console
poetry lock
```
失敗する場合には、一度既存のLockファイル(poetry.lock)を削除してから再生成してみてください。
3. **step 3**: Linterを利用した確認
CIに設定されているコマンドを利用して、Lintを行ってください。エラーが出る場合には修正を行ってください。
4. **step 4**: ベースイメージの更新
まず Dockerfile に指定されているベースイメージを更新し、新しい Python のバージョンのイメージにしてください。例えば、`FROM python:3.10.15-slim` のように指定されている場合には `FROM python:3.11.13-slim` と指定してください。パッチバージョンはdockerhubなどで調べて最新のものを指定するようにしてください。わからない場合にはタスクの依頼者に確認してください。
次に、CIファイルで指定されているPythonのバージョンを上げてください。CIファイルはリポジトリの `.github` ディレクトリ以下にあります。
5. **step 5**: GitHub上でPull Requestの作成
新しいBranchを切ってここまでの変更を Commit してください。Commit は適切な粒度に分けておこなうようにします。完了したらGitHub上にPushしてPull Requestを作成してください。CIの結果を確認して、問題が発生していれば対応をお願いします。
通った場合には、タスクの依頼者に動作確認を依頼してください。
## Advice & Pointers
- ライブラリのバージョンが古くアップデートができない場合には、Python のバージョンを下げるのではなく、ライブラリ側のバージョンを上げる方向で修正してください
- 内製ライブラリのバージョンを上げないと、poetry.lock を再生成できないことがあります。pyproject.toml 内の `rev` を変更すれば解決しますが、何に変更すれば良いかはタスク依頼者に質問してください
- 利用している poetry のバージョンが1.x系から2.x系に上がった場合、poetry 起因で Lock ファイルの生成に失敗することがあります。その場合には pyproject.toml 内の `[tool.poetry]` のセクションに `package-mode = false` を追記することで問題が解消することがあります
- poetryのバージョンを上げるときには、コマンドライン引数の変更に注意してください。例えば、`--no-dev` オプションは 2.x 系では `--without dev` に変更されています
- 利用している poetry のバージョンを上げると、numpy などのライブラリで "not supporting PEP 517 builds" というエラーが発生して CI build が失敗することがあります。その際には、該当するライブラリのバージョンを上げることで解消をはかってください
- numpy については ">= 1.26" のようにバージョンを指定することによって問題が解消します
## Forbidden actions
- mainブランチへのcommit, pushは禁止です
- タスク依頼者の承認無しに、アップデート先のバージョンを変更することは禁止です
- e.g. タスク依頼者は Python 3.13 へのアップデートを依頼したが、勝手に 3.11 へのアップデートに変更した## Procedure や ## Advice & Pointers などの項目は、Playbooks を作成するときに表示されるテンプレートの項目をそのまま利用しています。手順は基本的には人間がやっていたものと同じですが、以下のような工夫を入れています。
この記事執筆時点で紹介しているプロンプトは最新のものですが、これで完成というわけではありません。チームでは定期的にこの Playbooks を使って Python バージョンアップデート作業を行っており、作業後には振り返りを行って うまくいった点・課題点を共有し、プロンプトを継続的に改善 しています。
Playbooks を使ったアップデート方法を何回かチーム内で運用してみました。これまでに我々が持っていた課題のいくつかは解決しましたが、依然として残っている課題もあります。
動作確認よりも上流のタスクについては、意図どおり 作業コストを大きく削減できた と感じています。これまでは、Lock ファイルを作り直す際に一部ライブラリのバージョンが上がることで、他の依存ライブラリとの不整合が発生し、その調整に毎回かなりの試行錯誤が必要でした。しかし、Devin を活用するようになってからは、こうした試行錯誤の多くを Devin の作業の中に閉じ込められるようになり、人間が対応する範囲が大幅に減りました。
また、Linter によるチェックも任せることで、コード上の修正が必要な箇所のいくつかは、人間が手動で動作確認を行う前に事前に潰せるようになりました。特に Polars は開発が非常に活発で、バージョンアップに伴ってインターフェースに破壊的変更が入ることがしばしばあります。Devin に mypy などの型チェッカーを使うよう指示していたため、例えば以下のようなコードのエラーは、動作確認を始める前に検出できていました。
import polars as pl
if __name__ == "__main__":
df = pl.DataFrame({
"name": ["Alice", "Bob", "Charlie"],
"age": [25, 30, 35],
"city": ["New York", "Los Angeles", "Chicago"]
})
df = df.groupby('name').len()
main.py:11: error: "DataFrame" has no attribute "groupby"; maybe "group_by"? [attr-defined]
Found 1 error in 1 file (checked 1 source file)Devin で対応しているのは動作確認より前の工程のみであり、それ以降の工程にはまだ課題が残っています。実行時にしか検出できないエラーは Playbooks の指示だけでは拾えませんし、対象が機械学習ジョブを扱うリポジトリであることから、機械学習特有の課題もこの段階で表面化します。
まず、実行時エラーが残っている場合、ジョブの実行時間が長いほどバグの特定に時間を要します。この点については、ユニットテストを充実させてバグ検出力を高め、できるだけ少ない実行回数で動作確認を完了できるようにすること が重要だと考えています。
次に、性能劣化のチェックは、冒頭で述べた「サービスに対する理解度のばらつき」という課題にも関係します。何を指標として確認すべきか、どの程度の値であれば問題ないのかといった基準を作業者が明確にするまでのコストが大きいため、まずは ドキュメント整備 や モニタリング体制の構築 によって、このコストを下げることが重要だと考えています。実際にこの課題に対してはすでに取り組みを進めており、Devin を活用した README の充実や、Looker を用いたモニタリング体制の強化などを行っています。
この記事では、Devin の Playbooks 機能を活用し、マイクロサービスのメンテナンスコストを削減した取り組みについて紹介しました。単純ではあるものの人間が行うと時間のかかる作業を Devin に任せることで、チームが機能改善や開発に充てられる時間を増やすことができたと感じています。一方で、まだ解決すべき課題は多く残っています。今後も継続的に改善を重ね、チーム全体の生産性向上に取り組んでいきたいと考えています。