バイセル Tech Blog

バイセル Tech Blogは株式会社BuySell Technologiesのエンジニア達が知見・発見を共有する技術ブログです。

バイセル Tech Blog

Agent Skillsによる負荷試験の民主化への歩みと学び - 前編

はじめに

こんにちは。テクノロジー統括本部 買取1グループに所属している宮川(kurogenki)です。

現在はバックエンドエンジニアとして、出張訪問買取システム「Visit」の開発・運用をしています。

この記事では、チームで形式が定まっていなかった負荷試験計画をAgent Skillsで誰でも作成可能にしたことと、その過程で得た知見についてお話しします。

課題とその背景

バイセルはM&Aによりグループ会社が増え、ユーザー数も拡大しています。それに伴い、システム負荷への課題感が高まってきました。

私のチームでも、直近のAPI改修でリクエストの増加が大きく見込まれ、負荷試験が必要だと判断しました。しかし、私自身は負荷試験の計画作成が初めてで、そもそも何から着手すればいいのかが分からない状態でした。

そのため、以前担当したことがある人に聞いてキャッチアップするところから始めました。ただ、聞いてみると人によってフォーマットがバラバラで、計画・評価が属人化しており再現性がない状況でした。

負荷試験はチームにとって初めてではなく、大きな機能のリリース時に今後も繰り返すことが予想されます。であれば、負荷試験の一連の流れを改めて定義すべきだと考えました。

さらに、形式を決めたことでAIに任せられる領域も出てきたため、Skill化を進めることにしました。

課題解決のための仮説

負荷試験の計画作成でやっていることを分解してみると、手順は大きく次の3つで、主に変わるのは対象APIとトラフィック量だけだと気づきました。

  • ソースコードを読んでAPI仕様を把握する
  • New Relicで本番トラフィックを調査し、RPSを試算する
  • シナリオを設計し、計画書にまとめる

※ チームでNew Relic APMをプロダクトに導入していたため、各種メトリクスの取得が可能でした。

この手順を明文化し、手順どおりに実行できる部分をAgent Skillsに任せれば、2つのことが見込めると考えました。

  • 暗黙知を明文化し、再現可能な計画作成プロセスをチームに提供できる
  • 計画作成のリードタイムを短縮できる

全体アーキテクチャ

負荷試験のプロセスを「計画作成」「実施」「結果評価」の3フェーズに分けました。計画と評価はそれぞれSkill化し、実施(k6の実行)だけは手動で行う構成としました。 試験対象の環境はSTGとPRDのどちらも想定され、特にPRDへの負荷試験は時間帯を考慮する必要があると考えたためです。

負荷試験 Skill アーキテクチャ(2 Skill × 8 Agent)
負荷試験 Skill アーキテクチャ(2 Skill × 8 Agent)
【計画フェーズ — 本記事で扱う範囲】
【計画フェーズ — 本記事で扱う範囲】
load-test-plan Skill
load-test-plan Skill
Step 1
ユーザー入力の収集
Step 1...
※ 並列実行。待機中にメインが gcloud でインフラスペック取得
※ 並列実行。待機中にメインが gcloud でインフラスペック取得
Step 2
[code-investigator Agent]

GitHub URLでAPI仕様・
変更差分を調査
Step 2...
Step 2
[rps-investigator Agent]

New Relic CLIで本番
トラフィック実測データ取得
Step 2...
gcloud CLI
インフラスペック取得
gcloud CLI...
Step 3 RPS試算(ユーザーと対話しながら)
Step 3 RPS試算(ユーザーと対話しながら)
Step 4 ソースコード解析
Step 4 ソースコード解析
Step 5 テンプレート埋め込み → plan.md ドラフト生成
Step 5 テンプレート埋め込み → plan.md ドラフト生成
※ 並列実行。両方の結果を統合して plan.md を修正
※ 並列実行。両方の結果を統合して plan.md を修正
Step 6
[sre-reviewer Agent]

シナリオ・目標値を
SRE観点でレビュー
Step 6...
Step 6
[pdm-reviewer Agent]

ユーザー行動パターン・
ビジネス影響をレビュー
Step 6...
Step 7 ユーザーレビュー
Step 7 ユーザーレビュー
Step 8 k6コード生成
Step 8 k6コード生成
成果物: plan.md(計画書)
成果物: plan.md(計画書)
成果物: k6シナリオコード(.ts)
成果物: k6シナリオコード(.ts)
plan.md + k6シナリオコード
plan.md + k6シナリオコード
【実施フェーズ — 手動実行】
【実施フェーズ — 手動実行】
k6 負荷試験の実施(手動)
k6 負荷試験の実施(手動)
Step 1 plan.md に基づき k6 シナリオを STG 環境で実行
Step 1 plan.md に基づき k6 シナリオを STG 環境で実行
Step 2 CSV 形式で実行結果を出力
Step 2 CSV 形式で実行結果を出力
成果物:k6 CSV(レイテンシ・エラー率・VU等の実測データ)
成果物:k6 CSV(レイテンシ・エラー率・VU等の実測データ)
k6 CSV + plan.md
k6 CSV + plan.md
【評価フェーズ — 後編で扱う範囲】
【評価フェーズ — 後編で扱う範囲】
load-test-evaluation Skill
load-test-evaluation Skill
Step 1 ユーザー入力の収集(対象シナリオ名)
Step 1 ユーザー入力の収集(対象シナリオ名)
Step 2 plan.md からの自動取得(目標値・監視対象インフラ)
Step 2 plan.md からの自動取得(目標値・監視対象インフラ)
Step 3 k6 CSV 解析
Step 3 k6 CSV 解析
※ Step 4 は metrics-collector と screenshot-collector を並列実行し、両方の結果が揃ってから Step 5 へ進む
※ Step 4 は metrics-collector と screenshot-collector を並列実行し、両方の結果が揃ってから Step 5 へ進む
Step 4
[metrics-collector Agent]

Cloud Monitoring API (v3) から
Cloud Run / SQL / Spanner メトリクス取得
Step 4...
Step 4
[screenshot-collector Agent]

playwright-cliで
Google Cloudコンソールの各種ダッシュボードを
スクリーンショット取得
Step 4...
Step 5 result.md ドラフト生成(テンプレート埋め込み)
Step 5 result.md ドラフト生成(テンプレート埋め込み)
Step 6
[sre-reviewer Agent]

Pass / Fail 判定 + MUST / SHOULD / NICE_TO_HAVE 分類
Step 6...
※ MUST/SHOULDの項目がある場合、bottleneck-analyzerを実行
ない場合はStep 8へ
※ MUST/SHOULDの項目がある場合、bottleneck-analyzerを実行...
Step 7(条件付き)
[bottleneck-analyzer Agent]

New Relic Transaction の内訳(databaseDuration / externalDuration / app_ms)で
ボトルネック層(app / db / external / infra)を確定
→ 該当箇所を gcloud logging, NRQL etc.で調査
Step 7(条件付き)...
Step 8 result.md 最終版生成(SRE レビュー + bottleneck-analyzer のエビデンス反映)
Step 8 result.md 最終版生成(SRE レビュー + bottleneck-analyzer のエビデンス反映)
Step 9 ユーザーレビュー
Step 9 ユーザーレビュー
成果物: result_YYYYMMDD.md(結果レポート)
成果物: result_YYYYMMDD.md(結果レポート)

計画フェーズのポイントは、Step 2とStep 6の2箇所でAgent同士が並列に動くところです。code-investigatorがソースコードを調査している間に、rps-investigatorはNew Relicから本番トラフィックデータを取得しています。この待機中にメインのSkillがgcloudコマンドでインフラスペックも取得する流れです。

Step 6ではsre-reviewerとpdm-reviewerが並列でレビューし、両方の結果を統合してplan.mdを修正します。最終的にStep 7でユーザーが目を通し、Step 8でk6のシナリオコードを生成して完了。成果物はplan.md(計画書)とk6シナリオコードの2つです。

工夫したポイントの紹介

計画書テンプレートの設計

計画書のテンプレート(plan.md)には、プレースホルダー({{PLACEHOLDER}}のように変数として埋め込む形式)を配置しました。各Stepでこのプレースホルダーを埋めていく方式です。

以下はテンプレートの一部を抜粋したイメージです。

## RPS試算根拠

### 参照エンドポイント
{{RPS_REFERENCE_ENDPOINTS}}

### 観測期間・データソース
{{RPS_OBSERVATION_PERIOD}}

### 見積もりパターン
{{RPS_ESTIMATION_PATTERNS}}

## シナリオ設計

### テスト対象エンドポイント
{{SCENARIO_TARGET_ENDPOINTS}}

### 負荷パターン
{{SCENARIO_LOAD_PATTERNS}}

## 目標値

### レイテンシ
{{GOAL_LATENCY}}

### エラー率
{{GOAL_ERROR_RATE}}

テンプレートを用意した狙いは3つあります。

  • プレースホルダーがあることで、AIが「書くべきこと」を明確に認識でき、出力の品質が安定する
  • フォーマットが統一されていることにより、レビュアーの負荷が下がる
  • 確認したい項目を変えたい場合はテンプレートを修正するだけで済む

自分が求めるアウトプットに合わせて、適宜AIにテンプレートの修正を依頼していきました。「この項目がほしい」「この並び順のほうがレビューしやすい」といった調整を繰り返し、今の形に落ち着いています。

「自動化すべき箇所」と「人間の判断を入れるべき箇所」を分ける

設計で意識したのは、すべてを自動化しないことです。

RPS試算の参照エンドポイント選定や目標値の設定には、ドメイン知識やビジネス判断が必要です。ここをAIに任せきると、見当違いな根拠で計画が進んでしまうリスクがあるように感じました。

そこで、ワークフローの中に意図的に「人間がレビューするポイント」を設けました。

具体的に人間のレビューを入れたのは以下の箇所です。 - コード調査対象モジュールの確認: どのモジュールを調査対象にするかを確認する - RPS試算の参照エンドポイント確認: 比較APIが決まった段階で、そのAPIのトラフィックをRPSの根拠にしてよいかを確認する - 目標値の確認: レイテンシやエラー率の目標値が妥当かを最終的に人間が判断する

完全自動化を目指すのではなく、「どこに人間を挟めば全体の品質とレビュー効率が上がるか」を考えて設計しました。

前段のステップでレビューを通すことで、最終アウトプットのレビュー負荷を下げ、途中で軌道修正できる分、最終アウトプットの精度自体も高まると感じています。

マルチAgent設計

load-test-plan Skillでは4つのAgentを使い分けています。

Agent 役割 呼び出しタイミング
code-investigator GitHub URLからAPI仕様・呼び出し元・認証方式を調査 Step 2(並列)
rps-investigator New Relic CLIで本番トラフィック実測データを取得・整理 Step 2(並列)
sre-reviewer シナリオ・目標値をSRE観点でレビュー Step 6(並列)
pdm-reviewer ユーザー行動パターン・ビジネス影響をPdM観点でレビュー Step 6(並列)

Agentを複数に分けた理由はコンテキスト圧迫の防止専門性の分離の2つです。

New Relic CLIのレスポンスはTIMESERIES(時系列で値を返す)を含む大量のデータになります。これをメインの会話に流すとコンテキストが肥大化し、後続ステップの出力品質が落ちました。そこでAgent内でデータ処理を完結させ、メインにはサマリだけを返す構成にしています。

また、最初は複数の調査を1つのAgentに任せて出力が不安定でしたが、Agentを分離した結果、安定しました。この試行錯誤から得た学びは「学びと考察」セクションで詳しく触れます。

メトリクス・インフラスペックの取得

計画作成で使う外部データは、CLIツール経由で自動取得しています。

New Relic CLI では、推測ではなく実測に基づいてRPSを試算したく、本番トラフィックの実測データを取得しました。 平日と休日で案件数の多寡も考慮した上で、調査対象の期間は直近14日間としました。

最初に動かした段階では、Claudeが調査してきたVUに妥当性がない状態でした。 しかし、k6のシナリオフォーマットを先に決めていたので、「比較APIが決まり次第、そのAPIのピーク時のユーザー数をVUとして仮で置く」というデフォルトの基準を設けました。 また、VU数はユースケースによって変動しやすいため、RPS試算部分で人間によるレビューを意図的に設けました。

※ VU(Virtual Users)はk6が並列に動かす仮想ユーザー数で、負荷量の大きさを決める基本パラメータです。

gcloud CLI では、STG環境とPRD環境のインフラスペックを自動で取得・比較しています。 「STGで試験したけど、PRDはスペックが違った」というミスを防ぐためです。Cloud RunやCloud SQLのCPU・メモリなどの実際の値と、環境間の差分を計画書へ記載する仕組みにしました。

作成したAgent Skillsでの計画による成果

今回のSkillを、既存API刷新に伴う負荷試験の計画作成に適用しました。

刷新前後のAPIの変更点は以下の通りです。

  • 取得対象テーブル数: 2 → 4
  • JOINの本数: 0 → 3本
  • 集計処理: なし → GROUP BY / HAVING

テーブル数が倍になり、JOINと集計処理も加わったことで、レスポンスタイムへの影響が懸念される変更内容でした。

RPSの試算では、New Relicで直近14日間のトラフィックを観測し、推定ピークRPSを算出しました。

負荷シナリオは3段階で設計しています。

シナリオ 内容
ベースライン 現行の通常トラフィック
x2 ピーク時想定
x5 将来的な成長を見込んだ上限

各段階の負荷量は「なんとなく倍にする」ではなく、業務シナリオに基づいた根拠を添えています。目標値(レイテンシ・エラーレート)は、sre-reviewer Agentによるレビューを通して妥当性を確認しました。

Skillで作成した計画書を元に負荷試験を実施したところ、目標値を満たさない箇所がありクエリの改善が必要だとわかりました。改善後に再度試験を実施し、目標値をクリアしました。本番リリース時にも計画時に予測した程度のリクエストが発生したため、事前に負荷試験を実施し改善まで行えたことに意味があったと感じています。

また、計画作成で人間が手を動かして調査していた部分を今回のSkillで置き換えたため、Skillを実行しレビューをするだけで、計画書を作成できるようになりました。 具体的にどう置き換わったかは下記の通りです。

作業 Before(手動) After(Skill適用後)
変更箇所の把握 ソースコードを読み、変更差分を手動で調査 code-investigator Agentが自動調査
比較対象APIの選定 過去の知見を持つ人に聞いて判断 rps-investigator Agentが候補を提示 → 人間が確認
トラフィック測定 New Relicで手動クエリ・集計 rps-investigator AgentがCLI経由で自動取得・整理
インフラスペック取得 GCPコンソールを目視で確認 gcloud CLIで自動取得・STG/PRD比較
シナリオ・目標値のレビュー レビュアーに依頼し、口頭やドキュメントで確認 sre-reviewer / pdm-reviewer Agentが観点別に自動レビュー
計画書の作成 フォーマットなし、作成者ごとにばらつき テンプレートに自動埋め込み、構成・観点が統一

学びと考察

Agentに役割を持たせすぎない

今回の作業を通して「1つのAgentに役割を持たせすぎると、そのAgentに持たせている役割を全うさせることが難しい」と感じました。

「コード調査」と「New Relicからのメトリクス調査」を1つのAgentに任せていた時、片方で入れたルールを無視した出力をしてきました。 New Relicの調査ルールを守る一方で、コード調査で定義していたフォーマットの指示を無視する、といった状態です。

それぞれの調査をサブAgentに分離し、仕様理解やRPSの算出をメインAgentに任せたところ、数回の実行で確認した範囲では、それぞれのルールを守った出力が返ってくるようになりました。

この原因はコンテキストの肥大化や指示の競合が影響していると考えています。Agentにもコンテキストの限度があるので、それぞれのAgentに任せる責務を明確にして、責務ごとに守るルールや境界線を定義する。それを元にメインAgentが判断していくSkill設計が大事だと感じました。

レビューを戦略的に挟む

記事の前半で触れたように、本Skillでは 「出力の精度が低い箇所で意図的に人間のレビューを挟む」ということをしました。

最初は、RPS試算や既存仕様からの変更箇所の調査をすべてAIに任せて、レビューを途中で挟まず、最終アウトプットだけ人間が確認する形を取っていました。

しかし、いざレビューしてみると最初のフェーズの既存仕様からの変更点を間違えていました。 AIへのインプットを変えるなど試行錯誤を繰り返しましたが、人間が補助せずに既存仕様の変更を調査させ切ることは難しいと感じました。

既存仕様の変更点を間違えた状態で出力される成果物が間違っていることは明らかです。ただ、人間がレビューする際にはその間違っている箇所に閉じず、成果物全体を見てレビューをする必要があるので、レビューコストが高いと感じました。 全体的に数値の納得感がないものの、最終成果物の中から間違えている箇所を探すので、問題箇所の検出が大変でした。

意図的に人間によるレビューを挟んだことで、最終成果物をレビューする際に「ここまでは合っている」とレビューで確認する箇所を減らすことができたので大事に感じました。

最後に

今回の負荷試験計画のAgent Skills化を進める中で、AIの出力がブレやすい状態や、それをどう制御して出力を上げるかを体験し、自分の中で言語化することが出来ました。

完全にAIが作業をやり切れると楽ではありますが、AIの出力精度が安定しない領域もあり、すべてを任せ切るのは難しい場合が多いです。ただ、そこで「AIに任せることはまだ難しい」と諦めてしまうのはもったいなく感じます。

今回は人間がどう補助するかを考えて設計し、AIに任せる領域を見つけ出すことを経験できました。 今後AIと作業をしていく中でも応用できる経験に感じているので、他の業務でも積極的に活かしていきたいと考えています。

明日は弊チームTLのメントス (@m_t_tion1) による記事が公開されます。 この記事で計画した試験結果をAgent Skillsを活用しどう評価したか。その過程で得た知見や今後大切にすべきことについて言及しているので、ぜひそちらもご一読いただけると幸いです。

バイセルでは、一緒に働くエンジニアを募集しています。興味がある方は、以下よりご応募ください。

herp.careers