
MLOps
イベント

マガジン
技術ブログ
チューリングの MLOps エンジニアの岩政です。 以前、Databricks の Declarative Automation Bundles を用いた機械学習データセット作成基盤の構築をまとめました。この記事はその続きにあたるので、まだご覧になっていない方は先に読んでいただけると嬉しいです。 https://zenn.dev/turing_motors/articles/46b5560dce0e3a この中で「4.5.2 Python のライブラリの依存解決を高速にする」を紹介しました。 Databricks の Serverless compute では、依存パッケージのインストー
はじめに こんにちは、AIテクノロジーグループの検索チームです。 昨年公開した エニグモのAI活用を支える「AIテクノロジーグループ」について紹介します! では、グループ全体の体制と各チームの役割を紹介しました。 本記事ではそのなかの検索チームに焦点を当て、日々どんなシステムを運用し、どんな案件を進めているかをもう一段詳しくお伝えします。 検索チームは名前のとおり BUYMA の検索システムを担当していますが、それだけではありません。 データサイエンティストが開発したモデルを安定して動かす MLOps と、生成AIを使ったシステムの実装・PoC も担っています。検索基盤から機械学習の本番化、AI の実装までを同じチームが見ることで、インフラからアプリケーションまで一気通貫で課題を解けるのがこのチームの特徴です。 対象読者としては、検索・MLOps・データ基盤まわりのエンジニアの方を想定しています。検索エンジニアという職種は専門性が高く、会社によって担当範囲が大きく違うものと思われます。BUYMA の検索チームが実際に何をしているか、その具体性を示し、この領域のイメージを持ってもらうことが、この記事の目的です。 検索チームの役割 検索チームの業務は、次の3つの柱で整理できます。グループ紹介記事で触れた内容を、本記事では案件の粒度まで落とします。 BUYMA の検索システムの運用改善 大小あわせて8つの検索システムを運用し、その中核である商品検索では、ユーザーが探している商品を見つけられる状態を維持する。 MLOps データサイエンティストが開発したモデルを、求められるレイテンシ・可用性・セキュリティを満たす形で本番に載せ、繰り返し改善できるサイクルをつくる。 AIシステムの開発・PoC 生成AIをはじめとするサービスを使い、BUYMA 向けの AI 機能を実装し、PoC で終わらせず運用に載るところまで持っていく。 検索チームの3つの柱。検索、MLOps、生成AIの実装・PoC 担当範囲は検索エンジンそのものにとどまりません。検索API、商品データの投入、中間DB(MySQL)、クラスタ、監視、CI/CD まで、検索と機械学習サービスが動くための一式を見ています。 これらの基盤は Google Cloud(以下、GCP) 上で運用しており、GKE、Cloud Run、Vertex AI などを組み合わせて構成しています。 検索システムの運用改善 検索システムの運用改善では、まず「検索が止まると何が起きるか」、次に「なぜ本体から独立できたか」、最後に「独立したからこそ進んでいる Elasticsearch への載せ替え」の順で書きます。検索を止めないことが前提で、そのうえで基盤を進化させる、というのがこの領域の進め方です。 1. 検索が止まると、発見も購入も止まる BUYMA は世界中のファッションアイテムを購入できるマーケットプレイスです。 出品中約630万点のなかから、ユーザーが「これだ」と思える商品にたどり着く。その入口が検索です。キーワードやカテゴリ、ブランド、価格などの条件を組み合わせて探す体験が、発見と購入を支えています。 ピーク時の検索リクエストは約400 RPS に達します。検索が止まると、画面は残っていても、購入までの導線が途切れます。 サービスの主軸を担っている、という実感はここにあります。 絞り込みやファセット、並び順を含めた現行の検索体験を維持したまま、基盤を進化させていく必要があります。 検索チームが管理している検索システムは、大小あわせて8つあり、規模も用途もさまざまです。本記事ではそのうち、ユーザーの発見と購入に直結する商品検索に絞って書きます。 商品検索では、GKE 環境の更新、中間DBの MySQL、検索API、インデックス更新までを一体で見ています。いまは検索を止めない運用と基盤更新が中心で、検索結果の精度をよりよくしていくのはその先です。 検索システムの変遷については、以前の刷新の記録もあります。 BUYMAの検索システムを刷新したお話 2. GCP 移設と同時に境界を設け、BUYMA 本体から独立できた 2024年7月に、大小あわせて8つの検索システムをすべて GCP へ移設しました。移設と同時に、BUYMA 本体との境界も設けています。 【当時の課題】 移設前は、検索の大きな変更が BUYMA 本体(Rails / PHP 側)のリリースサイクルに引きずられやすい構造でした。検索エンジンのインデックスの洗い替えなどを、本体と切り離して進めにくい状態です。 【設けた2つの境界】 参照 : 本体は検索エンジンの実装を意識せず、検索APIのインタフェースを通じて検索を利用する 更新 : 商品データの更新は、MySQL を挟んで検索側へ渡す 検索APIと検索エンジンは、検索チームのリポジトリとデプロイで完結します。この境界があることで、検索側の基盤変更が BUYMA 本体のリリースを待つ必要がなくなりました。 参照は検索API、更新はMySQL 8つすべてが同じ切り出し方になっているわけではありません。 商品検索をはじめとする主要な検索は、検索APIを境界に独立した構成 で運用しています。残りのシステムは GCP 上で動いていますが、本体との結合の度合いはそれぞれ異なります。 【独立して進めるようになったこと】 独立した検索では、 検索領域だけの案件を、検索チームの裁量で企画・検証・リリースしやすくなった ことが大きいです。マイクロサービス化の効果は、運用が楽になることだけではありません。 たとえば次のような業務を、本体の大規模リリースに乗せることなく進められます。 検索クラスタの構成変更やスケール インデックスの投入パイプラインの刷新 検索APIの置き換え 検索エンジンそのものの検証と段階的な載せ替え 辞書やマッピングの更新を、検索を止めずに反映する仕組み 通常は BUYMA 本体が従来どおり検索APIを呼べばよく、裏側の実装は検索チームが差し替えられます。デプロイは検索側で完結します。インタフェースやデータの投入口を変えるときだけ、本体側のリクエスト処理や更新処理まで検索チームが担います。専門性の高い検索の問題を、検索ドメインの中で完結して解ける状態です。検索を独立したプロダクトとして扱える、というのがいまの進め方の前提です。 3. Solr から Elasticsearch への載せ替えを、検索チームのペースで進める 独立して案件を進められるようになった具体例が、現在進行中の Solr から Elasticsearch への移行です。 【当時の課題】 商品検索を支えているのは Apache Solr です。GCP 上で同一データを持つ2クラスタ、合計24ノードの冗長構成です。スケールや運用の柔軟性を上げたくても、本体と結合したままではエンジンごと変える判断は現実的ではありませんでした。 いまは同じ GCP 上で、Elasticsearch への置き換えを検証・構築しています。 【移行で外せない要件】 出品中約630万点の商品を対象にした全文検索 ブランド・カテゴリ・価格などのファセット 現行に近い並び順・グループ化 ピーク約400 RPS でも、ユーザー向けの応答速度を維持すること インデックスの洗い替えのために検索を止めないこと 【解決へのアプローチ】 エンジン選定 フルマネージドの検索サービスも検討しましたが、ファセットや複雑なソートを現行どおり載せるには、カスタマイズの余地が足りませんでした。既存の GCP 環境との統合のしやすさも踏まえ、Elasticsearch を GKE 上で運用する方針にしています クラスタ構成 Solr では安定運用のために必要だった2クラスタの冗長構成を、Elasticsearch では1クラスタにまとめる想定です 検索APIの刷新 検索APIとデータ投入も検索システム側で作り直しています。本体向けのインタフェースは現行に合わせつつ、裏側は Solr 前提の実装から切り離します。現行の検索APIは Python で、CPU 使用率が高く、アクセスが増えると 20〜30 インスタンスが起動し、コストも増えやすい状態です。新しいAPIは Go に書き換え、Cloud Run 上に設置済みですが、本番トラフィックの切替はこれからです クエリの見直し Solr 向けのクエリをそのまま写したところ、見た目の検索結果は近づけたつもりでも、本番相当の負荷をかけるとおよそ200 RPS で頭打ちし、ノードの CPU が飽和しました。現行の検索体験は残したまま何度もクエリの組み立てを見直し、ピーク約400 RPS の要件に乗せられたときは大きな達成感がありました 現行 Solr は同一データの2クラスタ。Elasticsearch は1クラスタにまとめる 検索がマイクロサービスとして独立しているからこそ、現行 Solr を止めずに並行して検証し、検索チームのペースで載せ替えを進められています。 MLOps:モデルを「定期的に、安全に」本番へ載せる 検索チームは、もともと検索エンジニアリングの専任でした。 推薦や機械学習の案件が増えるにつれて、モデルを本番で動かし続ける基盤、いわゆる MLOps も担当するようになりました。 実験を本番の定期ジョブに載せ、運用を回す 【役割分担】 データサイエンティストは、施策の設計、特徴量、学習、評価を担います。検索チームは、その成果物がオンラインの推論でも、毎日・毎週のバッチでも、想定した品質で動き続けるための実行基盤を担います。 不正検知については、分析・導入判断の経緯を別記事でも紹介しています。検索チームの役割は、そうしたモデルを「検証で終わらせず、運用に耐えるサービス」にする側です。 対応例: 不正対策の機械学習導入までに検証したこと 【基盤の構成】 学習・推論は Vertex AI Pipelines(Kubeflow Pipelines)上のパイプラインとして定義し、前処理・学習・予測・評価などのコンポーネントはコンテナイメージとしてバージョン管理します。GitLab CI/CD でテスト、ビルド、デプロイまでつなぎ、推論結果を下流のサービスやバッチが受け取れる形で届けます。 パイプラインには、推薦や不正対策、定期バッチで回すスコア系など、オンラインの推論とバッチの両方を載せています。 データサイエンティストの実験を、CI/CD と Vertex AI Pipelines を経て形にする 【いちばん詰まったところ:バージョン整合】 パイプライン定義、コンポーネント、下流のジョブで共通ライブラリを使い回すときのバージョン整合です。片方だけ新しいイメージに載せ替えると、学習は通っても、推論側で想定どおり動かないことがあります。派手な障害ではないのですが、原因の切り分けに時間がかかるタイプです。コンポーネントとパイプラインのバージョンを分け、共通ライブラリの整合を取りながら回すようにしたことで、大きな安心感を得られました。 【この領域の面白さ】 機械学習システムは、一度出せば終わりではありません。データが変わり、モデルが更新され、しきい値も動きます。そのたびに同じ品質で出し直せる状態を維持します。レスポンス速度や可用性、セキュリティは、検索APIと同じ目線で設計します。 ここでの面白さは、アルゴリズムそのものというより、 実験を本番の定期ジョブに載せ、運用を回せる状態にすること です。 AIシステムの開発・PoC 以前は検索運用と MLOps が主でしたが、生成AIの API が実用的になったこともあり、AI を使ったシステムの開発や PoC も担当するようになっています。 テキストや画像を対象にしたチェック処理を本番に載せるほか、商品検索とつながる「AIでさがす」にも関わっています。 生成AIによる感情分析・各種チェック 【対象にしているもの】 BUYMA は、出品者と購入者がメッセージを交わす CtoC の場でもあります。正当な商品のやりとり(在庫、サイズ、色味、配送追跡、公式サイトとの照合)と、スパム・フィッシング・外部誘導を切り分ける必要があります。 【ルールベースだけでは足りない理由】 ルールベースだけでは、新しい手口に追いつけません。逆に「外部URLがある」「BUYMA の外のサイトだ」だけで止めると、正常な購入会話まで不可となってしまいます。 【実装しているチェック】 検索チームでは Gemini を使い、次のようなチェックをマイクロサービスとして実装しています。 問い合わせメッセージのスパム・フィッシング判定 感情分析など、テキストのトーンやリスクを見る処理 画像に含まれる、外部サイトへの誘導につながりやすい要素の検出 【運用上の判断】 同期の API と、まとめて処理するバッチの両方があります。過検知と見逃しのどちらを許容するかは、カスタマーサポートや不正対策の運用チームとすり合わせます。モデルの世代が上がったときは、精度・速度・コストのバランスを見て載せ替えるかどうかを決めます。速いが高コスト、あるいは高精度だがレイテンシが合わない、といった上位モデルを見送る判断もここに含まれます。 【BUYMAドメインの制約】 検索で「現行の体験を維持したまま裏側を差し替える」のと同じで、生成AIでも、まずドメインの制約から設計します。ファッションの CtoC では、韓国・欧米の正規 EC の URL や配送会社の追跡リンクは日常的に登場します。その文脈を無視した汎用のスパム判定では、実運用には耐えません。 生成AIと商品検索の接点:「AIでさがす」 BUYMA の「AIでさがす」は、記事コンテンツを根拠にした提案へと進化しています。 ここは、検索チームが運用する商品検索APIと、生成AI側のキーワード生成・文書検索が接続する領域です。検索基盤が独立していることで、AI 側の変更と、商品検索エンジン側の変更を並行して進められます。 対応例: 「AIでさがす」サービスのリニューアル これから取り組むこと 検索チームとして、目の前にある大きな業務は次のようなものです。 Elasticsearch の品質確認と、Go 製検索APIを含めたトラフィックの段階的な切替 独立した検索基盤の上で、検索結果の精度をよりよくしていくこと 推薦・不正検知などの ML パイプラインを、より安定して回し、より載せやすくすること 生成AIのチェックや AI 検索を、既存の検索・ML 基盤と無理なくつなぐこと 「完成した基盤を保守する」フェーズではありません。切り離した検索プラットフォームの上で、エンジンも ML も AI も、まだ載せ替えと拡張の途中にあります。新メンバーには、アーキテクチャ設計から主導していただく余地が十分にあります。 インフラから API、データ、評価までを、同じチームで担っているのも醍醐味の一つです。 さいごに 検索チームは、出品中約630万点を支える商品検索をはじめ、BUYMA の検索を止めないことと、機械学習と生成AIを本番に載せることを並行して実施しています。 2024年の GCP 移設で検索APIを境界にして商品検索を独立させたことが、いまの Elasticsearch 移行のような「検索単体の大きな案件」を可能にしています。 現在は検索チームとしての幅を広げ、検索基盤・MLOps・生成AIまでを見ています。 今後はデータ基盤チーム等と統合し、よりプラットフォーム全体を見る体制へ変遷していく予定です。検索に閉じず、データを集め、モデルを回し、サービスとして届けるところまでを同じ視点で扱える場が、さらに広がっていくと考えています。 ここまで、いま私たちが担当しているものと、これから広がっていく業務の範囲を書いてきました。少しでも業務イメージが伝われば幸いです。 株式会社エニグモ すべての求人一覧 hrmos.co
はじめに こんにちは、データシステム部MLOpsブロックの 木村 と、推薦基盤ブロックの 上國料 です。 ZOZOでは2025年7月より、Claude Codeをはじめとする各種AI開発ツールを利用できる制度を開始しました。 corp.zozo.com 現在ではこの制度のもと、数百名にのぼる社員がClaude Codeを活用しています。 Claude Codeの活用が進むにつれ、スキルやエージェントといった開発資産がチームごとに蓄積されていきます。しかし、それらの資産がチーム内に閉じたままでは、組織全体で見たときに「AI開発が進むチーム」と「遅れるチーム」の差が広がる一方です。 この差を埋めるには、チームをまたいで開発資産を共有できる場が必要です。理想は、他チームの開発資産であっても、自チームの開発資産と同じようにいつでも参照・流用でき、それを起点に開発を始められる状態です。 本記事では、2025年下期から複数チームで運用してきた1つのClaude Codeプラグインマーケットプレイスについて紹介します。共同運用で直面した課題とその対策、そして得られた効果をまとめました。 本記事の内容は2026年8月時点の情報であることにご留意ください。 目次 はじめに 目次 背景 Claude Code プラグインマーケットプレイスとは 複数チームで運用するときに直面した課題 1. プラグインのグルーピングとメンテナンス責任が不明確になる 2. 共通ファイル(marketplace.json)の編集がコンフリクトし、登録漏れも起きる 3. 構造の誤りがレビューで見逃され、全チームに波及する 4. 目的に合致するスキルを検索で見つけられず、同じスキルが再発明される 5. 影響範囲が見えず、既存プラグインの修正が先送りされる 5つの課題への個別対策 1. チーム単位のディレクトリで責任範囲を分ける 2. 各プラグインのメタデータからmarketplace.jsonを自動生成する 3. 静的バリデーションで構造の誤りを検出する 4. やりたいことからスキルを逆引きできるようにする 5. @claudeの自動チェックで影響範囲への不安を減らす 複数チームで共有した効果 他チームの動きが見えるようになった 資産の横展開が生まれた 属人化が減り、誰でもすぐに始められるようになった 今後の展望 カタログの肥大化にどう向き合うか プラグインの追加・変更の周知コストをどう下げるか Claude Codeの進化の速さにどう追随するか 運用サイクルそのものを改善の対象にする まとめ 背景 Claude Code プラグインマーケットプレイスとは プラグインマーケットプレイス とは、Claude Code用の「プラグイン」を配布し、発見・バージョン管理・自動更新までまとめて行えるカタログのことです。 プラグイン自体は、以下のコンポーネントを1つのパッケージにまとめたものです。なお本記事では、CLIツールとしてのClaude Codeを指す場合は「Claude Code」、その基盤となるAIモデルを指す場合は「Claude」と表記します。 要素 役割 Skills Claudeが参照するガイドラインや、 /create-pr のようなスラッシュコマンドの実体 Agents 特定の作業を自律的にこなすサブエージェント Hooks 特定のイベント(タスク完了時など)で発火する処理 MCP Servers GitHubやNotionなど外部サービスと連携するためのサーバー設定 プラグインを使い始めるまでの手順は、 公式ドキュメント にもあるとおり、マーケットプレイスの追加と、そこからのプラグインの個別インストールという2段階に分かれています。追加した時点ではカタログを参照できるようになるだけで、プラグインはまだ1つもインストールされていません。 この2段階は、実際には次の2つのコマンドで実行します。 /plugin marketplace add <org>/cc-plugin-marketplace /plugin install my-plugin@cc-plugin-marketplace リポジトリ全体は次のような構成です。 リポジトリルート/ ├── .claude-plugin/ │ └── marketplace.json # カタログ全体の定義(全プラグインを列挙) └── my-plugin/ ├── .claude-plugin/ │ └── plugin.json # このプラグインのメタデータ └── skills/ └── ... マーケットプレイスの実体は、Gitリポジトリのルートに置く .claude-plugin/marketplace.json という1つのJSONファイルです。ここに配布する全プラグインの名前・リポジトリ内のパスなどを列挙します。 一方、各プラグインのディレクトリには .claude-plugin/plugin.json を置き、そのプラグイン自身のメタデータ(名前・バージョン・説明など)を記述します。つまり、プラグイン単位の情報はplugin.jsonに、それらを束ねるカタログ全体の情報はmarketplace.jsonに持つという2階層の構成です。marketplace.json側のpluginsエントリは、plugin.jsonの内容にsourceパスを加えたものです。 実際のファイルの中身は次のとおりです。 my-plugin/.claude-plugin/plugin.json : { " name ": " my-plugin ", " description ": " PR作成を支援するスキル集 ", " author ": { " name ": " Taro Yamada " } } ※ versionフィールドはあえて省略しています。省略するとClaude CodeはGitのcommit SHAをversionとして扱うため、マージがそのまま最新版の配信になります。 公式ドキュメント も、開発が活発な社内・チーム向けプラグインには、最もシンプルな構成としてこのパターンを紹介しています。 .claude-plugin/marketplace.json : { " name ": " cc-plugin-marketplace ", " plugins ": [ { " name ": " my-plugin ", " source ": " ./my-plugin ", " description ": " PR作成を支援するスキル集 " } ] } 複数チームで運用するときに直面した課題 もともと各チームは、それぞれ個別にスキルやエージェントを開発し、チーム内だけで使っていました。それを、前述の .claude-plugin/marketplace.json の仕組みを使って1つのプラグインマーケットプレイスにまとめ、複数チームで共同構築・運用する形に切り替えました。複数チームで1つのマーケットプレイスを共有するようになると、便利さの一方でいくつかの課題に直面しました。 私たちの場合、プラグインは開発からチームを越えて使われるまでに、次のような流れをたどっています。 複数チームが1つのマーケットプレイスを共有すると、この流れの各所で課題が起きやすくなります。いずれも参加チームとプラグインの数が増えるほど発生頻度が上がります。次節では、上記の流れの各段階に対応する5つの課題を順番に説明します。 1. プラグインのグルーピングとメンテナンス責任が不明確になる プラグインを「(1)開発する」段階で最初に直面するのが、マーケットプレイスのリポジトリ内でプラグインをどうグルーピングするかという問題です。マーケットプレイスには、PR作成支援のように全チームで使えるプラグインもあれば、パイプライン構築のように特定チームの業務に固有のプラグインもあります。これらを区別なく、次のようにフラットに並べると、利用者は自分に関係のないプラグインに紛れて目当てのものを見つけにくくなります。 リポジトリルート/ ├── .claude-plugin/ │ └── marketplace.json ├── plugin-a/ ├── plugin-b/ ├── plugin-c/ └── ... さらに深刻なのはメンテナンス責任の所在です。あるプラグインが壊れたとき、それを直す責任がどこにあるのかが、ディレクトリ構造上どこにも表現されていません。plugin.jsonのauthor情報をたどれば作者は判明しますが、そのプラグインがチーム内利用を想定したものか、全チーム向けの共通利用を想定したものかまでは読み取れません。その結果、壊れたまま直されない状態が続いたり、他チームのプラグインだと気付かずに手を入れてしまったりします。 2. 共通ファイル(marketplace.json)の編集がコンフリクトし、登録漏れも起きる 「(2)PRで反映する」段階でまず起きるのが、marketplace.jsonのコンフリクトです。前述の通り、Claude Codeの仕様でmarketplace.jsonには全チームの全プラグインの情報が1ファイルに列挙されています。そのため、Aチームが自分のプラグインを更新するPRも、Bチームが新しいプラグインを追加するPRも、最終的に同じファイルを編集することになります。マージのタイミングが重なればコンフリクトし、各チームが自律的に開発を進めるほどコンフリクトの頻度も上がります。 加えて、plugin.jsonとmarketplace.jsonは名前や説明といった情報を重複して持つため、手動で編集する場合は両方の内容を一致させ続ける必要があります。特に、新しいプラグインを追加した際にmarketplace.json側への登録を忘れると、そのプラグインは誰からも発見されません。 3. 構造の誤りがレビューで見逃され、全チームに波及する 続く「(3)検証する」段階では、設定ファイルの構造的な誤りを見逃してしまいます。誤りの種類はさまざまです。 plugin.jsonの必須フィールドの欠落 JSONの構文エラー プラグイン名の重複 スキル定義(SKILL.md)やagentのフロントマターの不備 hooks.jsonの構文エラー こうした誤りはdiffの見た目には現れにくく、レビュアーの目視チェックだけでは防ぎきれません。 壊れた設定が一度マージされると、そのマーケットプレイスを参照している全チームの全利用者に波及します。たとえばmarketplace.jsonがJSONとして壊れていると、 /plugin marketplace update がマーケットプレイス全体で失敗し、誰も新しいプラグインを取得できなくなります。「自分のプラグインしか触っていないのに、マーケットプレイス全体が更新できなくなった」という事故は、共有リポジトリならではのリスクです。 4. 目的に合致するスキルを検索で見つけられず、同じスキルが再発明される 「(4)見つけて導入する」段階では、そもそも目的に合致するスキルを見つけられないことが問題になります。1つのプラグインが複数のスキルを含むこともあるため、探す単位はプラグインではなくスキル単位になります。マーケットプレイスはもともと、スキルをさまざまなチームで参照できるように作ったものです。しかし運用が進むにつれてスキルの数そのものが増え続け、検索して見つけ出すコストが高くなっています。 見つけられないと、すでに同じものがあることに気付かないまま自分で作ることになり、別チームで同じスキルが再発明されます。 検索で見つけられない原因は、スキルの数だけではありません。SKILL.mdのdescriptionは開発者が実装や設計の観点で書くため、「PRのレビュー観点を多段階でチェックする」のような文言になりがちです。しかし利用者が検索するときの言葉は「レビューしたい」「PRを作りたい」のような、やりたいこと寄りの言葉です。descriptionをそのまま検索対象にしても、利用者の言葉とは一致せず、目的のスキルにたどり着けません。 5. 影響範囲が見えず、既存プラグインの修正が先送りされる 最後の「(5)改善する」段階では、既存のプラグインへの修正が先送りされがちです。最大の理由は、「自分の修正が他のスキルや呼び出し元を壊すのではないか」という不安です。たとえばSKILL.mdのdescriptionや引数の形式を変えると、それを前提に動いている別チームのスキルやワークフローが壊れかねません。マーケットプレイスを介して他チームがどう使っているかは見えないため、この不安を確かめる術がなく、些細な改善でも先送りされます。加えて、「これくらい満たしていれば導入してよい」という基準もないため、着手するかどうかの判断はそのつど個人の裁量に委ねられています。 5つの課題への個別対策 ここからは、それぞれの課題にどう対処したかを順番に紹介します。段階ごとに性質の異なる課題があるため、構造化・自動化・CIによる強制といった、異なるアプローチを組み合わせて対処しています。 1. チーム単位のディレクトリで責任範囲を分ける 以前はチームやプラグインの区別なく、1つのディレクトリにすべてのプラグインをフラットに並べていました。各プラグインの責任は、それを作ったチームが持つことにし、その責任をディレクトリ構造で表すという設計原則のもと、リポジトリをチーム単位のディレクトリに分けました。構成は次のようになっています。 ├── .claude-plugin/ │ ├── marketplace.json # 自動生成(直接編集禁止) │ └── marketplace-meta.json # マーケットプレイス自体のメタデータ ├── common-plugins/ # 全チーム共通のプラグイン │ └── plugin-a/ ├── xxx-plugins/ # xxxチーム所有 │ └── plugin-b/ ├── yyy-plugins/ # yyyチーム所有 └── zzz-plugins/ # zzzチーム所有 各チームがメンテナンスするプラグインは、そのチームのディレクトリ配下に置きます。この基準によって、プラグインの置き場所を見ればメンテナンス責任者が一意に決まります。common-plugins/への配置は、複数チームでの利用が見込まれるかを基準として、PRレビュー時に判断しています。 このようにチームごとに自由にディレクトリを分けられるのは、marketplace.jsonの各プラグインエントリが、プラグインの場所を相対パス(sourceフィールド)で持っているためです。実際のエントリは、次のようにチームごとに異なるディレクトリを指せます。 { " plugins ": [ { " name ": " plugin-a ", " source ": " ./common-plugins/plugin-a " } , { " name ": " plugin-b ", " source ": " ./xxx-plugins/plugin-b " } ] } プラグインをどこに置いてもmarketplace.json側でパスを合わせれば参照できるため、決まった1箇所に並べる必要がありません。ただし、この相対パスで参照できるのはmarketplace.jsonと同じリポジトリ内のプラグインだけです。別リポジトリのプラグインをGitHubソースなどで参照する方法もありますが、CIやリポジトリ設定をチームごとに分散させたくなかったため、今回は1つのリポジトリにまとめる構成を選びました。 もう1つの設計原則が、プラグインの粒度です。共通プラグインでは、関連性のない役割を1つのプラグインに詰め込まないというルールを設けています。一方、各チーム固有のプラグインは、どこまで細かく分けるかをチームの裁量に委ねています。たとえば、PRの作成・レビュー・管理のように互いに関連する役割は1つのプラグインにまとめます。一方、コードレビューを支援するスキルとインフラのコスト調査を支援するスキルのように、互いに無関係な役割は別々のプラグインに分割します。プラグインの数が増えても、自分が使わないプラグインのスキルが意図せず発火したり、そうしたスキルの説明文がコンテキストを圧迫したりする事態を避けられます。 2. 各プラグインのメタデータからmarketplace.jsonを自動生成する 各プラグインのplugin.jsonを正とし、marketplace.jsonは機械的に再生成する構成にしました。各プラグインのplugin.jsonを合成してmarketplace.jsonを生成するスクリプトを、CIから呼び出しています。開発者がやることは、自分のプラグインディレクトリの中でplugin.jsonを書くことだけです。 再生成はGitHub Actionsで自動化しています。PRを作成すると、ワークフローがplugin.jsonの変更を検知し、marketplace.jsonを再生成して、botコミットとしてPRブランチにpushします。 再生成スクリプトの要点を抜粋すると、次のとおりです。 #!/usr/bin/env bash set -euo pipefail META = " .claude-plugin/marketplace-meta.json " MARKETPLACE = " .claude-plugin/marketplace.json " # 各チームディレクトリ配下のplugin.jsonを、パス順にソートしてから収集する plugin_entries =$ ( find . -maxdepth 1 -type d -name ' *-plugins ' -print0 | xargs -0 -I {} find {} -path ' */.claude-plugin/plugin.json ' -print | sort | while IFS = read -r plugin_json ; do plugin_dir = " ${plugin_json % /.claude-plugin/plugin.json } " jq --arg source " $plugin_dir " ' . + {source: $source} ' " $plugin_json " done | jq -s ' . ' ) # marketplace-meta.jsonの内容に、収集したプラグイン一覧をマージする jq --argjson plugins " $plugin_entries " ' . + {plugins: $plugins} ' " $META " > " $MARKETPLACE " やっていることは、各チームディレクトリ配下のplugin.jsonをパス順に集めて、マーケットプレイス全体の情報と合成するだけの単純な処理です。 工夫の1つは、marketplace.jsonを部分的に更新せず、毎回すべて作り直す構成にしている点です。既存のplugin.jsonの集合から都度組み立て直すため、プラグインを削除したときの消し忘れが起きません。更新を重ねても、marketplace.jsonの内容が現状のplugin.jsonからずれていく心配もありません。この前提のもとでは、marketplace.json自体に直接手を入れることはできません。しかし名称のような、個々のプラグインには属さないマーケットプレイス全体の情報は、どのプラグインのplugin.jsonにも属さないため、生成元となる原本がありません。そこで、そうした情報だけをマーケットプレイスの構築時に marketplace-meta.json へ書いておきます。プラグインを追加するたびに書き換える必要はありません。 .claude-plugin/marketplace-meta.json : { " name ": " cc-plugin-marketplace ", " metadata ": { " description ": " 複数チームで共有するClaude Codeプラグインマーケットプレイス " } , " owner ": { " name ": " Claude Code Marketplace Maintainers ", " email ": " maintainers@example.com " } } スクリプトが収集したプラグイン一覧をこのファイルにマージし、marketplace.jsonを生成しています。 もう1つの工夫は、plugin.jsonの情報をパス順にソートしてから合成することで、副次的にコンフリクトを起きにくくしている点です。各プラグインのエントリはパス順の決まった位置に並ぶため、複数のPRがそれぞれ別のプラグインを追加しても、生成されるmarketplace.jsonの差分は配列内の別々の行に現れます。たとえば、 aaa-plugins/ チームのPRと zzz-plugins/ チームのPRが並行していても、前者は配列の先頭付近、後者は末尾付近にエントリを挿入するため、互いの差分は重なりません。末尾への追記のように複数のPRが同じ行を取り合うことがないため、マージ時にコンフリクトが起きにくくなっています。 3. 静的バリデーションで構造の誤りを検出する marketplace.jsonやplugin.jsonのように、目視でのレビューでは見逃しやすいファイルの構造的な誤りは、CIで自動チェックして検出しています。対象は次のとおりです。 JSON構文 必須フィールドの欠落 プラグイン名の重複 SKILL.mdやagentのフロントマターの不備 hooks.jsonの構文 こうした構造チェックは、CIのワークフローで実行しています。チェック自体は、Claude Code公式のCLIコマンド claude plugin validate にほぼすべて委譲しています。自作しているのは、公式コマンドがカバーしない次の2点だけです。 READMEを見ればプラグインの使い方がすぐわかるよう、README.mdの存在を確認する チームディレクトリにplugin.jsonはあるのに、marketplace.json側へ登録されていないプラグインがないかを検出する これらに加えて、 claude plugin validate はsourceフィールドの値がマーケットプレイスのルート外を指す ../ のようなパスになっていないかも検証します。プラグインはインストール時にキャッシュディレクトリへコピーされる仕様のため、ルート外を指すsourceは構文の誤りというより、動作しないか意図しない場所を参照してしまうリスクです。他の項目とは性質が異なるため、個別に触れました。 4. やりたいことからスキルを逆引きできるようにする スキルを「やりたいこと」から逆引きできる「スキルインデックス」を、ブラウザから確認できるようにしました。Claude Codeに直接探させることもできますが、Webページなら作業を始める前にさっと眺められますし、カテゴリタブを眺めているだけで「こんなスキルがあったのか」という偶然の発見もあります。 実際の画面は次のとおりです。検索窓にやりたいことを入力するほか、「やりたいこと」のカテゴリタブやチームでの絞り込みからも探せます。 上のスクリーンショットの時点で、対象となるスキルは73件にのぼります。これだけの数があると、利用者は目当てのスキルのdescriptionを覚えていられません。それでも、自分がやりたいことをそのまま打ち込むだけで目当てのスキルにたどり着けるのが、この仕組みの価値です。たとえば「PRのレビュー観点を多段階でチェックする」というdescriptionを知らなくても、「レビューしたい」と検索すればヒットします。検索する言葉が思いつかないときは、「Git・PR・レビュー」のようなカテゴリタブから探すほうが早いです。 この検索を支えている仕組みは、次の図のとおりです。 ポイントは次の2点です。 各スキルに、そのスキルが使われそうな場面を表す短いタスクフレーズ(想定作業)を複数持たせ、検索ではこのフレーズを最も重く評価する 想定作業フレーズとカテゴリは、日次のGitHub Actionsが生成する。SKILL.mdの内容に変更があったスキルだけを対象に、LLMを使わない通常のスクリプトとClaudeを組み合わせて更新する たとえばPR作成を支援するスキルには、次のようなassumed_work_ja(想定作業)とcategoryを持たせます。 { " id ": " common-plugins:create-pr ", " name ": " create-pr ", " assumed_work_ja ": [ " PRを作成する ", " 変更をpushしてレビュー依頼する ", " コミットしてPRを出す " ] , " category ": " git-pr " } 利用者が「PR出したい」で検索しても、descriptionの原文と一致していなくても、この想定作業フレーズ経由でヒットします。categoryは検索の照合には使わず、「Git・PR・レビュー」のような大まかな分野を表すラベルとして、画面上のタブ絞り込みに使います。 生成された想定作業フレーズは、検証・レビューを経てマージされると、GitHub Pagesとして自動で再公開されます。ホスティング先にGitHub Pagesを選んだのは、検索自体が埋め込みやLLM推論を使わないクライアントサイドのキーワードマッチングで完結しており、静的サイトのホスティングで十分だったためです。 5. @claudeの自動チェックで影響範囲への不安を減らす 静的バリデーションのCIは、設定ファイルの構造の正しさは保証します。しかし、スキルの中身の変更が既存の利用者や呼び出し元を壊さないかまでは検出できません。組織横断でスキルを使えるようにした分、開発者は自分のスキルが他チームでどう使われているかを把握できないため、入出力の形式を変えるような変更をしても、どこかで悪影響が出ていることに気付けません。そこで、GitHubのPRコメントで@claudeと打つだけで、この見えない影響範囲を機械的にチェックする仕組みを作成しました(ローカル実行も可能です)。チェックは2軸です。 ひとつは破壊的変更チェックです。検出対象は次のとおりです。 スキルのname・descriptionのトリガー条件・引数形式・出力契約の変更 agentの入出力契約やstatus codeの変更 hooksやMCP設定の変更 SKILL.mdから参照されるreferencesやscriptsの削除など、既存の利用者・呼び出し元を壊す変更 もうひとつはマーケットプレイス規約チェックです。記述面では、SKILL.mdの行数やdescriptionのフォーマットを確認します。Progressive Disclosure(本文を小さく保ち、詳細はreferencesなど別ファイルに逃がす設計)といった規約も対象です。安全面では、allowed-toolsの過剰付与、MCPのサービス分離、シークレットの直書きといった規約への準拠も確認します。 この仕組みには割り切りがあります。プラグインの良し悪しは文字列のレビューだけでは判断しきれず、結局は導入して動かしてみないとわかりません。そのためレビューで品質を保証しきることは目指さず、「最低限動くか」「規約に沿っているか」「既存のものと重複していないか」という入口の最低ラインだけを機械的に保証し、あとは導入して確かめる方針です。品質を最終的に担保しているのは、これまでどおり必須のPRレビューです。破壊的変更が起きていないことを自動で確認できれば、修正への心理的ハードルは下がります。チェック結果がGitHub上に投稿されるため、レビュアーは自動チェック済みであることを踏まえてダブルチェックでき、レビュー負担が減ります。運用件数が増えても、この負担軽減の効果は大きいと考えています。 現状は、ひとまず初期の導入として、上記の最小限の観点のみチェックできるように実装した段階です。それでも「壊れていないことは自動で分かる」という安心感は、日々の修正のしやすさに直結しています。実際、これまでのマージ済みPRのうち、既存プラグインの改善・修正を目的としたものは新規追加より多く、全体の6割近くを占めています。プラグインは作って終わりではなく、運用しながら継続的に手が入れられています。CIによる機械的な保証と、心理的なハードルを下げるコミュニケーション寄りの工夫、その中間に位置する仕組みだと捉えています。運用しながらリファクタし、リポジトリ独自のルールが固まってきたらチェック項目として組み込んでいく予定です。 複数チームで共有した効果 約10か月にわたり運用したところ、複数チームで1つのマーケットプレイスを共有した効果が見えてきました。 他チームの動きが見えるようになった 以前は、チーム内でどんなスキルやエージェントを作っているかが、チームの外からはわかりませんでした。スキルインデックスという共通の窓口ができたことで、他チームのスキルを見つけてSKILL.mdを読めるようになりました。たとえば、定例をAIで代替する取り組みを進めているチームがあります。そのチームのスキルの中身を読むと、どんなハーネスを使い、どんな工夫をしているのか、どこをAIに任せているのかがわかります。自分のチームに持ち込むとしたらどんな工夫を付け加えられそうか、そこまで考えられるようになりました。 資産の横展開が生まれた 以前は、それぞれのチームがAI活用の方法を1から考えている状態でした。workflowやloop、Routinesといった機能の使いこなし方も、チーム内の詳しい人に聞かなければわからず、知識が特定の人に偏っていました。マーケットプレイスを複数チームで管理するようになったことで、他チームの工夫を自分のチームの工夫として取り込みやすくなりました。その恩恵として、他チームが作った共通プラグインをそのまま使ったり、各チーム固有の工夫でも横展開しやすくなったりしています。 たとえば、GitHub・Confluence・Slack・Jiraを横断して過去事例を検索するスキルを、あるチームが作りました。このスキルは検索を担う4つのエージェントを独立したファイルへ切り出す構成にしていたため、別チームが障害調査を支援するスキルを作る際に、この4つの検索エージェントをそのまま呼び出して使えました。ゼロから検索の仕組みを作り直す必要はありませんでした。 また、定期実行するAIエージェント機能のRoutinesや、loop、GitHub Actionsのワークフローで呼び出すスキルも、このリポジトリに置いて共有する運用にしています。以前は、こうしたよくあるスキルをどのリポジトリで管理すべきか所在が定まっていませんでした。それが、誰かが音頭を取ったわけでもなく、マーケットプレイスに置けばよいという運用に自然と落ち着きました。 チームごとに開発資産を抱え込んだままだったら、これらの事例は生まれなかったはずです。共有の場があるからこそ、1チームの工夫が他チームの出発点になっています。 属人化が減り、誰でもすぐに始められるようになった 新しく入ったメンバーのオンボーディングも、マーケットプレイスによって変わりました。以前は、スキルがそれぞれのローカル環境に散らばっていたため、SKILL.mdの書き方やプラグインの構成をゼロから調べながら自分で作る必要があり、導入コストが高くなりがちでした。マーケットプレイスに既存のスキルがまとまっている今は、まずインストールして動きを確認するところから始められます。実際に動くスキルを読みながら使い方や設計の型を掴めるため、自分で一から設計を考える前に土台をつかめます。 今後の展望 これまでの運用を通じて、今後取り組むべき課題も見えてきました。 カタログの肥大化にどう向き合うか プラグインはplugin.jsonとディレクトリを用意するだけで簡単に作れます。この手軽さは開発を促進する一方、使われなくなったプラグインが増えても気づきにくくなります。使われなくなったプラグインも検索結果に混ざり続けるため、スキルインデックスの探しやすさを保つ効果も薄れていきます。カタログ全体を俯瞰して現状を把握するコストは、プラグイン数に比例して大きくなります。またあるプラグインが複数箇所から参照されるようになると、依存関係も見えにくくなります。 依存関係が見えないままでは、共通のプラグインへの変更がどのチームの利用に響くのかを事前に判断できません。@claudeによる破壊的変更チェックはその一歩ですが、プラグインの品質そのものを保証する仕組みではなく、「これを満たせば安心して変更してよい」と言えるレベルの動作確認の仕組みには至っていません。今後はプラグインの動作確認用のスキルを整備し、新規追加時・リファクタ時それぞれで基準を明文化することで、仮説検証を繰り返しやすい環境を作っていきたいと考えています。 プラグインの追加・変更の周知コストをどう下げるか チーム内で完結するプラグインなら、追加や変更があってもチームメンバーに直接伝えれば済みます。しかし、他チームでも使えるプラグインとなると、その存在に気づいてもらうこと自体にコストがかかります。プラグインの追加や更新を知らせる専用のSlackチャンネルは用意しているものの、投稿は個人の判断に委ねられているため、周知そのものが形骸化しつつあります。 ベースブランチへのマージをトリガーに、この専用チャンネルへ自動で通知を流す案を考えています。ただし、更新のたびに毎回発火させると通知が埋もれてしまい、かえって見られなくなる懸念があります。どの粒度・タイミングで知らせるのが適切か、今後詰めていきたいところです。 Claude Codeの進化の速さにどう追随するか Claude Code自体の機能追加は速く、数か月前のベストプラクティスが過去のものになることも珍しくありません。新機能が次々と追加される一方で、それに合わせてスキルやワークフローの書き方を更新し続けなければ、マーケットプレイスの資産はすぐに古びてしまいます。新しい機能が出るたびに、その機能をどう使えばよいか調べ、動く形にするまで試行錯誤する時間がボトルネックになりがちです。 この変化のペースに個々のチームがそれぞれキャッチアップするのは非効率です。新しい機能が出るたびに、スキルやloopをすぐ作って試せる仕組みを、マーケットプレイス側で用意しておきたいと考えています。雛形やスクリプト生成を支援することで、「使ってみる」までのハードルをさらに下げていく予定です。 運用サイクルそのものを改善の対象にする 最後は、運用の進め方そのものです。プラグインはplugin.jsonとディレクトリさえ用意すれば作れるため、プラグインを作る速度はこれからも上がり続けます。一方、それを複数チームで安全に運用し続けるための仕組みづくりは後回しになりがちだという感覚があります。本記事で紹介した5つの課題への対策も、最初から仕組み化されていたわけではなく、困りごとが顕在化してから後追いで整備してきたものです。前述のカタログの肥大化や周知コストの課題も、まだ「今後詰めていきたい」段階にとどまっており、同じ構図の繰り返しだと感じています。作る側の障壁を低く保ったまま、運用する側の障壁だけを先回りして整えるのは難しいというのが実感です。マーケットプレイスの運用に、整備して終わりという区切りはありません。課題を見つけるたびに仕組みで対処し、また新しい課題が出てくるというサイクルです。このサイクル自体をどう効率化するか、つまり運用サイクルそのものをエンジニアリングの対象にすることが次のテーマだと考えています。 本記事で紹介した工夫は、これまでの運用で得られた1つの到達点にすぎません。今後も運用しながら課題を見つけ、改善を重ねていきます。 まとめ 本記事では複数チームで1つのClaude Codeプラグインマーケットプレイスを育てる取り組みを紹介しました。 複数チームでの共同運用では、責任の所在の曖昧さやカタログの不整合などさまざまな課題に直面しましたが、多くは構造・自動化・CIの工夫を組み合わせることで仕組みとして解決できました。 結果として、marketplace.jsonを自動生成する構成にしたことで、コンフリクトや登録漏れが起きにくくなりました。チーム単位のディレクトリ構成で、プラグインのメンテナンス責任も明確になりました。構造の誤りも、CIが利用者へ届く前に検出できます。スキルインデックスによって目的のスキルも検索で見つけやすくなり、@claudeの自動チェックで既存プラグインの修正への心理的ハードルも下がりました。 運用開始前は、チーム間の変更のコンフリクトや壊れた設定が全チームに波及することを懸念していました。しかし2025年下期の運用開始から約10か月が経過し、大きなトラブルなく運用を続けられています。 本記事で紹介した知見が、複数チームでのマーケットプレイス運用を検討している方の参考になれば幸いです。技術仕様は Claude Codeの公式ドキュメント を参照して執筆しました。 ZOZOでは、一緒にサービスを作り上げてくれる方を募集中です。ご興味のある方は、以下のリンクからぜひご応募ください。 corp.zozo.com

















