DevinをRoo Codeで置き換え、レビュー精度やコスト、速度を大幅に改善した話 〜その定量 & 定性成果から、設計思想まで〜
前回書いたDevinにコードレビューをさせ、コード品質と開発速度を同時に高める話が、ありがたいことに130以上のLike、はてなブックマークでも同程度の反応をいただきました。最近のトレンドを含めて、AIエージェントに対する関心の高さがわかります。
そこで今回は、これまで Devin で行っていたレビュー機能をどうRoo Codeで実現し、精度を引き上げたのか、その設計も含めてご紹介します。
また、Roo CodeでのAIエージェント・ワークフロー実装方法については、プロンプト付きでチュートリアルを公開しています。
誰でも作れる!Roo Codeを利用したAIエージェントやワークフロー実装のチュートリアル
本記事のRoo Codeを用いた取り組みや背景については、先日 technuma さんがLT『Devinにファーストレビューをさせ、コードレビューを効率化するには』 (Speaker Deck, connpass)にて発表されており、その内容に加えて具体的な設計と評価結果、今後の展望をお伝えできればと思います。
この記事が、皆さんのモデル改善や運用フロー最適化の一助になれば幸いです。
Devinによるレビューを振り返る
Workflow と Agent の違いを整理する
以下の表は、Anthropic 社の記事 Building effective agentsで示された整理を参考に、両者の要点を抜粋したものです。
Workflow | Agent | |
---|---|---|
定義 | あらかじめ固定された手順とツール呼び出しを順番に実行する仕組み | LLM が 動的に計画を立て、外部ツールを使いながらループする自律システム |
テストのしやすさ | 各ステップが決まっているため 局所的にテスト・メンテナンスしやすい | ループの副作用が絡むため ブラックボックス化しやすい |
補足:Anthropic 記事では「まずは最小限の Workflow で済むかを検討し、柔軟性が必要な場合のみ Agent に踏み込む」ことが推奨されています。
Devinの高い自律性と一枚岩構造の課題
Devin は完全自律型 Agent として設計されており、差分取得・追加情報探索・ツール実行までを内部で自己完結させます。言い換えると、Agent とその内部 Workflow の複雑性を Devin 側が肩代わりしている 状態です。この構造により初期の導入は容易ですが、個々の Workflow を切り出してテストしたり、細かく調整したりすることが難しくなります。
レビュー精度をさらに高めるためには、Workflow を独立した部品として充実させ、段階的に磨き込む手法が有効です。しかし Devin では Agent と Workflow が一枚岩で結合しているため、プロダクトチームがカスタマイズを重ねるにつれて、次のような限界が顕在化しました。
- テストしづらい:Workflow ごとに検証したい場合でも、副作用を切り分けにくい
- メンテナンスが難しい:調整可能なパラメータが限られ、改善サイクルが遅くなる
- 精度の頭打ち:Knowledge ベース拡張などで一時的に精度が向上しても、複雑性の増大に伴い品質が再び低下する
また、コードレビューでは主に、関係するファイルなどを自律的に読むといった操作が重視されます。言い換えるとこれ以外の機能、たとえばDevinの持っている開発環境は活用されておらず、本来の用途から外れている状態でした。
運用初期は順調でしたが、カスタマイズが進むにつれて 精度とメンテナンス性の両面で壁に当たりました。 この課題を解消するために、Devin の一枚岩構造を テスト可能な Workflow 群へ分割し、オーケストレーションで再構成 したのが Roo Code 版のアプローチです。
今回Roo Code でレビュアーを実装した結果、Devin を大きく上回るレビュー精度を確認できました。本記事では、その評価方法と結果、さらにエージェント設計の概要についてご紹介します。
導入後の成果とこれから
テックリード(私)が手動でチューニング→レビュー内容をまとめ分析・評価しました。
ベンチマークからバイアスを排除するため、Roo Code / Devinは互いにコメント内容を見ないよう工夫しています。
また、評価対象としては以下のようなPRを選定しました。
- 実際に障害の原因となったPR数件(人間が見落としており、なおかつ発見難易度が高いというもの)
- Devinが良い指摘をしていたPR5つ(性能比較をよりわかりやすくするため)
- その他、ランダムなPR数件(選定によるバイアスを排除するため)
定量その1 レビュー内容の精度
指標 | Devin | Roo Code |
---|---|---|
レビュー精度 | 48.48% | 73.48% |
再現率 | ― | 7〜8割ほど |
1レビューあたりのコスト改善 | ― | コストが1/2に低下 |
1レビューあたりの所要時間改善 | ― | 30%高速化 |
- レビュー精度:対象PRへの指摘のうち、正しかった指摘割合の平均
- 再現率:Devinの良い指摘を再現した割合
レビュー内容の精度やコストから、予想以上にDevinのレビュー精度を上回っていることがわかります。
また、レビューの速度についても、Devinと同等 / ほとんどの場合、Devinよりも高速でした。(ローカル環境がそのまま使えるため、環境セットアップの時間が省略されているのもポイントですね)
定量その2 サイクルタイム
レビュー精度という数値のみを追いかけてしまうと、「指摘は鋭いがレスポンスが遅い」といった数値ハック・局所最適に陥るリスクがあります。
開発フロー全体の健全性 を測るために、2 つ目の軸としてサイクルタイム という健康指標を導入しています。これから組織で展開する際に、精度にのみ注目し他を見落とすことがないよう、合わせて指標を追っていきます。
計測には technuma さんが個人開発したリードタイム計測ツールをGLOBISで利用しています。GLOBISではFindy Team+を利用していましたが、殆どのチームではサイクルタイムのみを追っており、その他の機能を利用していなかったため、載せ替えました。
定性評価 & 何ができるのか?
指摘事項約50件を手動で評価しました。内容に対する所感としては
- 払える注意の総量が著しく多いテックリードのようなレビュー精度です。
- 以下のような、文脈込みでのレビュー性能も良い精度を出しており、実際にバグになり得た箇所をしっかりと拾えています。
- 以下のような、文脈込みでのレビュー性能も良い精度を出しており、実際にバグになり得た箇所をしっかりと拾えています。
- また、人間が純粋に目視で見つけづらいものも難なく発見することができるのも強みです。Devinもチューニングしましたが、以下のような指摘はあまり再現しないため、かなりの可能性を感じています。
- 一例(モデル内で):
admin.errors.add(:email, I18n.t(".organizations.admins.invitations.form.error.existing_email"))
は、相対パスではなく絶対パスにするべきです。(I18n.t("
後の.
などから察知したパターンです)
- 一例(モデル内で):
何を考え、どう設計したのか
基本設計
Devinの弱点を振り返る
Roo Codeへの移行には以下の理由がありました。
- 一つの巨大なAgentに対してテストをする必要があり、チューニングが難しい(指数関数的に難しさが上がる)
- 一つ一つのチューニングの結果が出ているのかを計測しづらい
- あるチューニングを行った際に、今までチューニングした他の性能が失われていないかを保証しづらい
- また、複雑なチューニングをし続けることで、かえって平均的な性能に戻ってしまった
- Devinは自動でKnowledgeを読みに行きますが、Knowledgeが増えるにつれて裏目に出てしまうことが増えた。初期は単純にKnowledge数が少なく、(おそらく)自動参照の精度にかかわらずモデルの性能でカバーできていましたが、臨界点を迎えた印象です(図で表すと以下のような状態ですね)
- Devinは自動でKnowledgeを読みに行きますが、Knowledgeが増えるにつれて裏目に出てしまうことが増えた。初期は単純にKnowledge数が少なく、(おそらく)自動参照の精度にかかわらずモデルの性能でカバーできていましたが、臨界点を迎えた印象です(図で表すと以下のような状態ですね)
弱点を克服した設計
上記の振り返りを含めて、以下を要件としました。
- <メンテナンス性>知識や手順、観点などといったチューニングが、テスト可能 (testable)な大きさに分けられている(専門性ごとに人格が分けられており、互いに干渉しない)
- また人格として独立をさせることで、(それぞれの人格に依頼し結果を統合するのみで良いため)チューニング項目が増えた場合でも性能が保証しやすくなるといった利点も見込んでいます。
- <体験>開発者は人格を指定せず、裏で自動的に適切な人格に振り分けられている
上記を実現するために、Roo Codeを選びました。
特に初期の段階では試行錯誤が多いのですが、自然言語で設計できるおかげで高速にフィードバックループを回すことができました。(実はRubyでAgentを実装したところ、そちらでもDevinの精度を上回ったのですが、ワークフローを少し変えるだけでも修正が多くなってしまう難点がありました。プラクティスが確定した状態でコードを書くのは良いものの、初期は自然言語で記述できることが強みだと思います。)
Roo Codeで設計したものを以下に図解しました。Anthropicの記事におけるOrchestrator-Workers workflowに近いものになります。
上記のうち、以下をモードとして実装(プロンプトの作成を)しています。
- 適切なモードを選定するモード
- それぞれチューニングしたモード
- オーケストレーター(Orchestrator)=複数のモードを統合する役割
- 適切なモードを選択する(サブタスク)
- それを元に、それぞれのモードに対しサブタスクを作成する
- サブタスクの結果が揃い次第、統合する
一見複雑に見えますが、それぞれのモードに必要なプロンプトは少なく、多いものでも(指示文に絞ると)300字ほどです。また、それぞれのモードの中には、以下のように固有の手順が定義されています。(一部簡略化しています)
考え方
巨大な単一エージェントとして実装するとなぜ辛いのか?
以下のようなエージェントを実装する場面を考えます
PRのレビューを行うエージェントを作る
gemのアップデートであれば、gemのバージョンごとの違いを比較し、リスクを分析→コード内を検索する
リファクタリングであれば、過去のコードと新しいコードを比較し、(…膨大なチェックリスト…)を満たしているかを検証する
bugfixであれば、バグの再現をし、修正前後でどう挙動が変わるのかをチェックする
単一のプロンプトでこれらを実現しようとすると、かなりの難易度になります。前述の副作用も無視できず、プロンプトが増えるほど、動作確認コストも指数関数的に増えてしまいます。(そして少し時間が経つと、もうメンテナンスをすることも辛くなってしまうはずです)
LLMの仕事をTestableにする
エージェントはその性質上、巨大な処理群となりがちです。巨大であればあるほどメンテナンスが難しくなります。例えばある性能をチューニングした場合、他の性能が低下してしまうかどうかを予測できず、メンテナンスコストが増えやすいというものがあります。
こうした①副作用の予測不能性、②チューニングのハードル上昇、そして③拡張性を克服するため、「小さなエージェントを実装→それらを組み合わせる」手法を利用しました。Anthropicの記事でもMaintain simplicity in your agent's designと推奨されている内容となり、複雑性をエンジニアリングする という観点では幅広く活用できるものだと思います。
LLMの仕事をメソッドとして扱う
エージェントと書くと、その手続き(自律性)に意識がいきます。必然的に中身が複雑に見えてしまいますが、代わりに入力と出力に注目するとシンプルです。
- LLMの仕事には、入力と出力がある(依頼→結果)
- LLMの仕事は分割ができ、分割後の仕事にも入力と出力がある
- →従来のプログラミングのプラクティスをある程度応用することができる。
古くから言われていますが、大きいものは複雑であり、小さく分けることで複雑性が減り制御可能になります。
入力と出力 / 仕事の分割はまさにメソッド化, クラス化にあたるもので、1つ1つの部品を確実なものにすることで、それらを組み合わせた大きい処理群を作ることができます。単一の巨大なモードが難しい理由も、まさに複雑性が高いためです。
おわりに
本記事では、Devinを用いたコードレビューの経験と課題を踏まえ、Roo Codeを活用してレビューシステムを再設計し、レビュー精度、コスト、そしてメンテナンス性とテスト容易性を改善した事例をご紹介しました。個別にチューニング・テスト可能なWorkflow(Roo Codeにおける「モード」)群へと分割し、それらをオーケストレーションするアプローチにより、複雑性の増大やチューニングの副作用といった課題に対応しやすくなり、改善サイクルを回しやすくなったと感じています。
今後も各モードのチューニングを進め、より開発チームに貢献できるレビューシステムを目指します。その過程で、私自身のテックリードとしての経験や、特定の技術・ドメイン領域に詳しいメンバーの知見など、これまで専門的だった知識・操作をWorkflowに落とし込み、AIレビューのさらなる可能性を追求しながら性能を伸ばしていきます。また、AI技術の最前線の知見も積極的に取り入れ、AIの得意な点・不得意な点を踏まえつつ、最適な活用方法を探求していきます。
この記事が、皆さまのチームでのAIレビュー導入の参考になれば幸いです。
最後までお読みいただき、ありがとうございました!
Discussion