更新日:2026年7月9日

9分で読めます

AIエージェントでGitLabのレート制限システムを移行した方法

GitLabの3人チームが、GitLab Duo Agent PlatformをはじめとするAIツールを活用し、レガシーなレート制限システムを安全性を損なわずに移行した事例を紹介します。うまくいった点や、そこから得た教訓についても詳しく解説します。

ここ数週間、GitLabの小さなチームがある実験に取り組んでいました。レガシーなレート制限システムの一部を、安全性を犠牲にせずにAIエージェントで移行できるのか、という実験です。

結論を先に言うと、答えはイエスです。AIエージェントは確かに機能します。同時に、普段の仕事の進め方にある弱点を浮き彫りにすることもあります。今回の取り組みでは、エージェントそのものよりも、チーム体制、レビューのループ、そしてオブザーバビリティの方が重要でした。以下では、GitLabとGitLab Duo Agent Platformなどのツールを使ってどのように作業を進めたか、何がうまくいったか、ループとは何でどこがうまく機能しなかったか、そして同じことを再現する方法を紹介します。

背景

GitLabでは長年、本番環境に2つのレート制限の仕組みが存在していました。121個のキーを持つアプリケーションレベルのGitlab::ApplicationRateLimiterと、それとは別のRackレベルのシステムです。今回の目標は、これらをlabkit-ruby内の単一の実装に統合することでした。可観測性があり、テスト可能で、どこでも同じ方法で運用できる状態にすることです。モノリスへのすべてのリクエストがこの仕組みを通るため、障害の発生パターンは可視化され、かつ元に戻せる必要があります。

このプロジェクトのチーム(ポッド)は、GitLabのメンバー3名と数体のAIエージェントで構成されていました。API PlatformチームのスタッフバックエンドエンジニアであるMax Woolfがモノリス側を担当し、ロールアウトの大部分を実行しました。Scalabilityチームで働くBob Van Landuytはgem(labkit-ruby)を担当し、アーキテクチャの設計を主導しました。私はスコープ管理を担い、初期のlabkitコードの一部を書きました。他に数名のエンジニアが加わり、コンテキストを吸収しながらコードとレビューに貢献してくれました。

エージェントはコンテキストを読み取り、仕様書のドラフトを作成し、範囲を限定した変更を実装し、テストを書き、マージリクエストの事前レビューを行いました。GitLab Duo Code Reviewが、マージリクエストのコード品質を高く保つ役割を担いました。一方、スコープ、アーキテクチャ、ロールアウト、そして最終レビューは人間が担当しました。

私たちが実践した厳格なループは次の通りです。エピックを読む→仕様書を書く→仕様書に対して敵対的レビューを行う→ブロッカーが解消してから初めて実装する→明確な根拠をもって検証する→マージリクエストに対して敵対的レビューを行う→人間によるレビューへエスカレーションする→マージする。敵対的レビューは、人間が介入するまでの解決ラウンドを2回までに制限していました。プロジェクト全体では、14件の仕様書と30件を超えるマージリクエストをlabkit-rubyに投入しました。実際には、このループの厳密さは担当者によって多少異なりました。Bobは、共有可能な形にする前に、仕様書とレビューのサイクルを何度も一人で回すことがよくありました。

ループの図解

このループは、聞くとかなり手間がかかるように見えるかもしれません。しかし、レガシーコードに対してであれば、私はこのループの実行をエージェントに任せて信頼できます。

うまくいったこと

コホート1は、最も緊張感のあるテストでした。pipelines_createnotes_createuser_sign_inを含む、トラフィックの多い5つのキーが対象です。2026年5月4日に1%→10%→50%とロールアウトし、2026年5月5日に100%まで展開しました。その日のBobの実況コメントは、私たちの運用モデルを端的に表しています。

「ロールアウトはすべて完了しました。これまでのところ、applimiterとlabkit実装のレート制限はすべて一致しています。ただ、トラフィックがあまり多くないだけかもしれません。制限を超えるトラフィックを意図的に発生させてみようと思います。」

これこそが良いロールアウトの姿であり、エージェントに任せるべきではない種類の判断です。新システムが旧システムと一致していること自体は成功を意味せず、単に何も引っかからなかっただけという可能性もあります。

コホート2では、モノリス内83箇所、Enterprise Edition(EE)内12箇所を含む、次の95箇所の呼び出しサイトを、単一のフィーチャーフラグのペアに集約しました。この統合を行わなければ、ロールアウトには95個のフラグを個別に切り替え、約190件のYAML編集が必要になっていたはずです。エージェントは、コードベース全体にわたるこの種の機械的な展開作業を非常に得意としています。人間はこれが非常に苦手です。

ループが機能しなかった点

このループには、いくつかの見落としがありました。

1つはシャドーモードでの見落としです。コホート2は数日間シャドーモードで稼働し、旧実装と一致していました。観察モードから強制モードへの切り替えは、何も起きないはずでした。しかし、小さな不具合が発生しました。

新しいアダプターは、未認証の1つのコードパスで識別子を静かに欠落させていました。3つのString値が2つのプリミティブなスロットに詰め込まれ、誤った値が識別子を上書きしてしまったのです。ごく一部のユーザーが、短時間だけ一般的な失敗エラーを目にすることになりました。

シャドー比較は、実際にはこのキーの差異をフラグとして検出していました。しかし、構造的な衝突と通常の不一致を区別するラベル体系を用意していなかったため、100%まで展開する間、その信号はダッシュボード上に埋もれたままになっていました。

私たちはすぐに強制モードのフラグをオフにしました。Bobは、この構造的な問題を一文で言い当てました。

「この混乱を片付けたら、ApplicationLimiterを呼び出す際は名前付きの特性だけを使うようにして、配列スコープはもう使わないようにすべきだと思う。」

その場しのぎの修正は2日後にリリースされました。構造的なクリーンアップは、次のフェーズの対応リストに入っています。

この件は、仕様書作成、敵対的レビュー、実装、GitLab Duo Code Review、段階的ロールアウトというループのすべてのステップを通過していました。つまり、ループはこの問題を検出していたとも言えるし、検出できていなかったとも言えます。ここから学ぶべきことは「エージェントは危険だ」ということではありません。私たちにはオブザーバビリティがあったものの、重要な障害パターンを見分けられるオブザーバビリティではなかった、ということです。

5月15日、Maxはmasterに対して監査を実行し、Slackで私に連絡し、コホート6を新たに立ち上げました。

「移行にコホート6を追加しました。あちこちで見落とされていた細かい項目たちです(Bob、あなたのことじゃないよ)」

当初の計画では5つのコホートを予定していましたが、実際には6つ必要でした。

数日後、診断結果が判明しました。ClaudeがEE限定のレート制限をいくつか見落としていたのです。notification_emails、いくつかのEEレジストリエントリ、3つのWebhookキー、3つのサブ秒単位のpartner_*キー、そして一部の孤立したアダプター行です。121個中17個のキーが、これまでのコホートから漏れていました。それぞれには、どのコホートにもきれいに当てはまらなかった理由がありましたが、見えなくなっていてよい理由はどれもありませんでした。

私たちは、エージェントにも自分たち自身にも、キーの全リストに対する進捗をカウントし続けるよう求めていませんでした。

もう1つの見落としはRedisでした。redis-cluster-ratelimitingサービスは4シャード構成のクラスターとして稼働しています。当初のBobの見立ては正直なものでした。「余裕はあるが、利用率を完全に2倍にできるほどではない」。

5月初旬、以前遭遇した制約が再び現れました。

Bob:「以前遭遇したこのボトルネックは、このプロジェクトで新たに発生したものではなく、実際に存在するボトルネックだ。つまり、これを回避するにはインフラの変更が必要になる。」

Max:「うわ、まずいな。」

maxclientsを段階的に引き上げていきましたが、接続数を増やすとプライマリのCPUが飽和状態に近づくことが明らかになったため、10万ではなく7万5千接続で止めました。各シャードに1台のプライマリ、コマンド実行用のコアも1つだけです。スケールアップで対処できる余地はありませんでした。

エージェントが実際に変えたもの

エージェントによってボトルネックが移動したことを示す図

エージェントは、ボトルネックの位置を移動させました。エージェントが仕様書を作成し、厳格なループの中で実装を行うことで、コード生成はもはや遅い部分ではなくなりました。代わりに、レビューの処理能力、ロールアウトの判断、そして担当者の注意力が遅い部分になりました。これはずっと望ましい種類の課題ですが、今のところはやはり人間のリソースを消費しています。

この取り組みは、常に快適だったわけではありません。プロジェクトの中盤、Maxはこう書いています。

「良い面も悪い面もある。エージェントとやり取りしていて堂々巡りになってしまった。『自分でやった方が早かった』と感じる瞬間があって、正直いらいらした。」

その数週間前、Maxはこのプロジェクトを「GitLabでの中でも間違いなく学習曲線が急な経験の1つ」と評していました。エージェントと協働するのはスキルであり、そのスキルを身につけるための代償として、一人で作業した方が進んだであろう日々が発生します。

もう1つの変化は、「完了」の意味について正直になることでした。コホート1の終わりにBobが残したメモ(「レート制限ごとにフィーチャーフラグを用意するのはやり過ぎだ、次回以降の移行ではこのやり方はやめるべきだ」)は、エージェントには任せられない種類の判断の小さな一例です。エージェントは、頼めば95個のフラグ切り替えを喜んで生成します。それをやらないと決めるのは、人間の判断です。

現在の状況

6月中旬までに、6つのコホートすべてが100%まで展開されました。ApplicationRateLimiter内の121個のキーはすべて新しいフレームワークを経由するようになり、監査によってレガシーパスの利用はほぼゼロまで減ったことが確認されました。また、今後追加されるレート制限が静かにこの仕組みをバイパスできないよう、ガードレールも追加しました。

これでアプリケーションレベルの移行は完了です。次は、1日あたり約40億件のリクエストを処理する、より大規模な層であるRackAttackです。シャドー&強制モードのミドルウェアは現在開発中で、最初のマージリクエストは承認され、マージ待ちの状態です。

同じことを試したい場合は、GitLab Duo Agent Platformで仕様書の作成を支援し、Duo Developerでイシューの実装を進め、Duo Code ReviewでMRのマージを支援してもらうことができます。ですが、それは簡単な部分です。本当に重要なのは、あなたのチームにBobのような人がいるかどうかです。50%展開する前に、あえて1%の段階で新システムを壊そうとする人です。そして、Maxのような人がいるかどうかも重要です。周囲が「移行は完了した」と思っている時に、あえて監査を実行する人です。ワークフローも重要ですが、人はそれ以上に重要です。自分たちのレガシーコードでこれを試してみたい方は、今すぐ試してみてください。

AIエージェントは機能します。そして、エージェントとの協働の仕方を変えることも、同様に機能するのです。

ご意見をお寄せください

このブログ記事を楽しんでいただけましたか?ご質問やフィードバックがあればお知らせください。GitLabコミュニティフォーラムで新しいトピックを作成してあなたの声を届けましょう。

フィードバックを共有する

今すぐ開発をスピードアップ

DevSecOpsに特化したインテリジェントオーケストレーションプラットフォームで実現できることをご確認ください。