有名テック企業の技術ブログを、ひとつのフィードで。
フィード
32件
Data&Analysis部の稲葉です。 キャディは2026年6月10日(水)〜12日(金)にパシフィコ横浜で開催されたSSII2026(第32回 画像センシングシンポジウム)にプラチナスポンサーとして協賛しました。また、キャディから3名が登壇しましたので、当日の様子をレポートします。 オーガナイズドセッション:産業界における生成AIの利活用 技術動向解説セッション:CADにおけるAI分野の動向と製造業への実適用 インタラクティブセッション 終わりに オーガナイズドセッション:産業界における生成AIの利活用 生成AIが産業界でどのように価値を生み、どのような条件で実運用に乗るのかを議論するセッションです。 キャディからは、オーガナイザーとしてシニアリサーチエンジニアの福原(@gatheluck)、また講演者として私、稲葉(@mi_spindel)が登壇しました。会場には約450名と、非常に多くの方にお越しいただきました。 登壇資料はこちらです。 speakerdeck.com speakerdeck.com 私からは、Data&Analysis部として取り組んでいる生成AI活用事例として製造業RAGを紹介しました。 (本当は、他にも様々な取り組みがあるのですが、また機会を見て紹介したいと思います。) また、この中で直面した課題の一つが「各LLM/VLMモデルが我々のドメイン特有のタスクをどこまで実行できているかが不明」というものでした。 そこで、製造業LLM/VLMベンチマークとしてManuDraw-Benchを独自構築し、比較評価したお話しをしました。 皆様からのたくさんの質問をいただきまして、ありがとうございます。当日は時間の関係で回答しきれませんでしたので、ここで回答したいと思います。 Question: CADでのDXFはパースせずに図面の見た目で拾ってしまった方が総合的なコストが安いという判断でしょうか? Answer:DXFなどベクター図面のまま処理した方が、QualityやCostの観点で良いタスクは存在していると思います。ただ、結局はimage encoderが必要なタスクはありますし、処理プロセスの種類が増えることによって運用負荷も増えますので、QCDを総合的に判断して技術選定をしています。 Question:会社の固有知識については基本的にはRAGで対応となると思うのですが、RAGでは対応しきれないのではないか、モデルの Fine Tuning が必要ではないかという意見も社内であり、意見が分かれています。 Fine Tuning まで実施したというような事例はあるでしょうか? Answer:Fine Tuningまで実施した事例があるかないかの詳細はお答えできないのですが、Fine Tuningを考える前に基本はナレッジ管理とGroundingで対応できないかを先に考えるべきだと思っています。また、Fine Tuningと言えど一定のデータ量は確保しなければならないですが、機密情報の漏洩を考えると個社ごとに調整をすることになりがちです。確保できるデータ量とその労力に対する効果を検討する必要があります。 Question:過去の故障事例などは、設計改善に使用可能なレベルで、原因情報が現場から上がってくるモノでしょうか?実は、原因をLLMが把握するところに課題はないでしょうか。 Answer:おっしゃる通りで原因とその対応が上がってくる仕組みを作ることが重要ですし、そこは課題です。その解決のためにも、キャディが提供しているような部横断のデータ基盤を構築しデータを紐づけることが必要になります。 Question:P15のVLMによる3次元点群予測は1点1点を文字列として出力しているわけではないのだと思いますが、Pythonスクリプト出力などでCADモデリングさせて、表面に点を生やしているのでしょうか? Answer:1点1点を点群を文字列として出力させているのではなく、メッシュモデルとして形状を面の組み合わせで出力させてから点群サンプリングをしています。おっしゃるようにPythonスクリプト出力などでCADモデリングする方法もありますが、コーディング能力や各LLM/VLMが扱える開発環境にも依存するため、このような方法を取っています。 Question:位置やサイズなど幾何的な理解の性能は、モデルの進化を待てばある程度上がってきそうなベンチの結果になっているのでしょうか? Answer:そのあたりは今後の傾向を見てみないと何とも言えないところですので、今後もトラッキングしていきます。ただ、自然画像や文字列で表現されている位置やサイズの理解は進化が見られます。 Question:3面図とアイソメ図でVLMからみた理解度にどれだけ差があるのでしょうか?VLMの訓練にメインで使われているであろう写真データには三面図的な見え方は珍しそうに思います。写真に近そうなアイソメ図の方が理解してくれたりするのでしょうか? Answer:とても良いご指摘です。三面図をそのまま与えるよりは、斜めから見たアイソメ図の方が形状の理解力は高い印象です。ただ、アイソメ図には寸法など必要な情報が抜けているので、処理プロセスのどこかでアイソメ図にリフトするとかデータを組み合わせて利用するとか工夫は必要にはなると考えています。 共に登壇いただいたエクサウィザーズの加藤様、LayerXの松村様、素晴らしい発表をありがとうございました。エクサウィザーズ様はやはり取り組まれていることの幅が広いですし、生成AIの性能だけでなくUI/UXやガバナンスといった活用推進の重要なポイントを俯瞰して抑えられているなと感じました。LayerX様はAgentありきの業務フローに変革していく強い意思を伝えながらも、結局は当たり前をやりきれるかという話に共感しました。 登壇の様子 技術動向解説セッション:CADにおけるAI分野の動向と製造業への実適用 昨今の3D基盤モデルなどの潮流を概観し、CAD解析技術の実プロダクト適用における「研究と実践」のリアルを解説するセッションです。 キャディから、Data Platform本部長の今井(@imaimai0)が登壇しました。こちらも500名近い方に聴講いただくことができました。 speakerdeck.com なぜ製造業においてCADが重要なのか、CADの活用において何がボトルネックになっているのか、最新研究の動向はどうなっているのかをお話ししています。 詳細は資料をご確認いただけると幸いですが、私からは特に、CAD(Geometric系)やMechanical Engineering系の研究開発をもっと盛り上げたいと思っていることをお伝えしたいです。 資料の中でもCVPRにおいてGeometric系の論文は5%程度というお話しがありましたが、製造業のGDPが日本の2割程度を占める巨大産業にも関わらず日本においても類似の研究開発が少ないように思います。我々もResearchチームの規模を拡大中ですし、共同開発や共同研究の機会も探しているところです。一緒に盛り上げていただける仲間を募集中です。 インタラクティブセッション 6/11(木)のブース出展では、多くの方にキャディブースへお越しいただきました。セッションを聴講して「話を聞いてみたい」と立ち寄ってくださった方もいらっしゃいました。 ポスター発表では、現在取り組んでいる研究開発テーマを紹介しました。注力しているテーマとして、以下の3点をご紹介しました。 設計資産全体を横断して検索するための、2D図面と3D CADモデルの埋め込み空間の統合 3D CADデータ内の加工に必要な特徴の認識 製造業ドメインに特化した独自の視覚言語モデル(VLM)評価ベンチマーク ManuDraw-Bench ManuDraw-Benchは公開されているのか?されないのか?といった質問をたくさんいただきましたが、権利の関係上公開は難しいです。ただ、業界の研究開発を促進したいと思っていますので、何かしら対応を考えていきたいとは思っています。 お話いただいた皆様、本当にありがとうございました! 終わりに SSII2026への協賛・参加を通じて、製造業領域におけるAIの研究開発の現状や、その中でのキャディのチャレンジについて知っていただく貴重な機会となりました。また、来場者の方との交流から、日々取り組む課題に対してもヒントを得られる非常に有意義な場でした。 運営の皆様、素晴らしい会をありがとうございました。 今後もキャディは技術的な挑戦を続け、画像センシング・コンピュータビジョン研究コミュニティの発展と、モノづくり産業のポテンシャル解放の両面に貢献していきたいと思っています。 また皆さんとお会いできることを楽しみにしています!
こんにちは!Data&Analysis部の今野です。 キャディは2026年6月8日(月)〜12日(金)にGメッセ群馬で開催されたJSAI2026(人工知能学会全国大会 第40回)にプラチナスポンサーとして協賛させていただきました。この記事では5日間にわたる開催期間中の当社ブースの出展報告や、聴講した技術セッションのレポートをお伝えします。 会場紹介 ブース紹介 聴講したセッションの感想 非構造データからの情報抽出 画像音声メディア処理:視覚言語理解とマルチモーダル生成 終わりに 会場紹介 まずは会場の様子を紹介します! 場内では複数のセッション・企業展示・ポスター発表が同時並行で実施されていました。企業展示では、多様な業界に跨る159社の企業が、生成AIに限らない幅広い機械学習技術の産業応用に関して紹介をしていました。私も色々なブースを訪れ、エンジニアの皆さんと意見交換をさせていただきました。 場内の案内図 大規模言語モデル等の生成AIとともにフィジカルAIも大きなテーマの一つとなっていて、実際に入口付近ではGMOインターネット株式会社のブースの前でヒューマノイドロボットが来場者を迎えていました。 入口から見た会場の様子 ブース紹介 次にキャディのブースについて紹介します! ブースでは、主に私たちが提供している「製造業AIデータプラットフォームCADDi」の中で使用されている機械学習技術や現在取り組んでいる研究開発テーマの紹介をしました。また本サービスのデモを通して、実際に製造業の現場の課題解決にどのように貢献しているかを実感してもらえるようにしました。 注力してR&Dを行っているテーマの中でも、設計資産全体を横断して検索するための2D図面と3D CADモデルの埋め込み空間の統合・3D CADデータ内の加工に必要な特徴の認識・製造業ドメインに特化した独自の視覚言語モデル(VLM)評価ベンチマーク ManuDraw-Benchの3点について紹介させていただきました。 ノベルティとしては、キャディが各所で出展する度に大人気の「データ活用カツ」や製造業をイメージしたマイクロファイバークロスをお配りしました。 図面が文書としての特徴と幾何学的な形状が融合した複雑なデータであることやその中に潜む活用しきれていない情報の価値であったり、テキストや画像と比べるとあまり一般的でない題材の3D CADに対してどのようなアプローチを課題に応じて選択しているかについて関心を持って頂くことができました。 イベント期間中、キャディのブースに立ち寄ってくださった皆さん、本当にありがとうございました! 聴講したセッションの感想 次に、聴講させていただいたセッションの感想を簡潔にまとめます。 非構造データからの情報抽出 株式会社リクルートの中田さんとSansan株式会社の山内さんがオーガナイザとして実施されたセッションです。 複数ページの請求書 ・医薬品データ・技術マニュアル ・有価証券報告書 など、多種多様な産業の実務に溢れる「非構造データ」から、いかに正確かつ網羅的に情報を抽出するかという共通の課題に対する検証結果が発表されました 。 問題設定及びそれに対して提案された手法は様々ですが、ほとんどの発表においてVLMが手法の中心に据えられていたことが印象的でした。引き続き物体認識やOCRに特化したモデルの有効性は変わらないものの、大規模言語モデルの推論能力を生かした情報の構造化はこの領域において避けては通れないものになっていると感じました。その中で、プロンプトの工夫・画像の前処理・ステップの分割・検索システムの統合など能力を最大限に引き出すための多岐に渡る手法が検証されていました。 図面という非構造化データからの情報抽出は我々の中心にある課題の一つで、日頃の取り組みと密接に関連したセッションであり、これから解析対象のカバレッジを拡張していくに当たり非常に示唆に富んだ内容でした。 https://pub.confit.atlas.jp/ja/event/jsai2026/session/acHLauKQ 画像音声メディア処理:視覚言語理解とマルチモーダル生成 本セッションでは、画像・音声・対話データといったマルチモーダル情報を対象に、人間の認知特性や数理的アプローチを組み合わせて処理のブラックボックスを解き明かし、生成・推論の「制御性と効率性」をいかに向上させるかという共通の課題が議論されました 。 特に印象的だったのは、東京大学の大坂さんによるVLMにおける視覚アクセス境界の存在を実証した研究です 。この研究では、思考のプロセスを言語化させるChain-of-ThoughtプロンプティングをVLMで行う際、モデルが「長く考えること」で視覚的な特徴抽出を拡張しているわけではなく、実際には言語空間内での記号的推論を延長しているに過ぎないという機構を示すものでした。 過去のテックブログでも紹介しているように、図面からより高度な情報の獲得を目指していくに当たり、VLMのメカニズムに起因する視覚情報に基づく推論の限界は我々も課題に感じており、この問題を新たな視点で捉えられる研究内容であるように感じました。 https://pub.confit.atlas.jp/ja/event/jsai2026/session/fQHM84pJ 終わりに 5日間にわたるJSAI2026への協賛・参加を通じて、AIに関するアカデミックな着目点や産業応用における最新の機械学習技術について幅広い知見を得られる貴重な機会となりました。また、会場での多くの交流や専門的なセッションから、VLMの可能性など我々が日々取り組んでいる課題に対してもヒントを得られる非常に有意義な時間でした。 スピーカーの皆さん、参加者の皆さん、運営の皆さん、素晴らしい会をありがとうございました。今後もキャディは技術的な挑戦や現場の課題解決に向けた取り組み、そして研究開発の内容を積極的に発信し、エンジニアコミュニティの発展の一助となれるような貢献を続けていきたいと思っています。 次回、また皆さんとお会いできることを心より楽しみにしています!
TL;DR Dependabotの脆弱性アラートをSlackに流し、Devin(AIコーディングエージェント)でトリアージ・修正を行うスキームを構築しました CVE脆弱性アラートを、チームで効率的に対応できるようになりました AIの活用で「セキュリティよくわからないから放置...」が「なるほど、そういう脆弱性なのか。これなら対応できそう」に変わりました はじめに 製造業データ活用クラウド CADDi Drawer開発チームの大道です。 突然ですが、みなさんのリポジトリにDependabotのアラート、溜まっていませんか? 「あ、また増えてる...まあ今は忙しいし、後で見よう」って思っちゃいません? npm install をした際のCriticalやHighの件数を見て、「嫌なものを見たな〜」という気持ちになりませんか? こうして「後で」が永遠に来ないまま、気づけばアラートが大量に溜まっている。そんな経験、ありませんか? この記事では、DependabotとDevin(AIコーディングエージェント)を組み合わせて、CVE対応が「回り続ける」仕組みを作った話を紹介します。セキュリティの専門知識がなくても「とりあえずやってみよう」と思えるような内容を目指しているので、気軽に読んでいただけたらうれしいです。 背景:なぜスキームを作ろうと思ったか 「気づいた人がやる」運用の限界 もともと私たちのチームでは、CVE脆弱性アラートへの対応は「気づいた人がやる」スタイルとなってしまっていました。 Dependabotからのメール通知は飛んでくるのですが、日々の開発メールに埋もれてしまい、気づかないことがほとんどです。たまたま気づいた誰かが善意で対応してくれる。でも、その「誰か」がいない日は、当然誰もやりません。「誰か」がやってくれたことに対する感謝も埋もれがちです。 放置するリスクは一定ある 実際、多くの脆弱性は到達可能性(Reachability)がなく、自分たちのコードから該当の関数を呼んでいないケースがほとんどです。この経験が積み重なると、「今回も大丈夫か」と思ってしまうのは、ある意味エンジニアとしての経験則でもあります。 ただ、最近はリスクを巡る状況も変わってきています。 AIの進化によって、攻撃用のコードを生成するハードルが大きく下がりました。以前であれば高度な知識が必要だったエクスプロイトの作成も、今ではAIを使えば比較的容易にできてしまう時代です。その結果、ゼロデイ攻撃のスピードは加速し、公開される脆弱性の件数自体も増加傾向にあります。 そして、もしセキュリティインシデントが起きてしまった場合、事業へのインパクトは計り知れません。顧客データの漏洩、サービスの停止、信用の失墜...。「大丈夫だろう」の一言では済まされない世界です。 だからこそ、エンジニアとしては微妙なストレスを抱えているのも事実ではないでしょうか。「たぶん大丈夫」と思いつつも、心のどこかで「もしこれがインシデントにつながったら...」とビクビクしている。そのストレス、放置しているアラートの数に比例して大きくなっていませんか? DependabotのPR自動作成機能に対する要望 Dependabotには検知した脆弱性に対して、自動でPRを作成してくれる便利な機能がありますね。 ですが、「もっとこうなったらよいな」と思うものもありました。 変更の妥当性を判断する情報が乏しい: 「このパッケージをx.x.xからy.y.yに上げます」としか書かれていない。破壊的変更があるのか、自分たちのコードに影響があるのか、PRを見ただけでは判断しづらい プロジェクト固有のルールを守ってくれない: 私たちのチームでは「lockfileの直接編集禁止」「overridesは原則使わない」といったガイドラインがありますが、Dependabotにそれを強制する術がない (もしかしたらRenovateなら設定を駆使すればこのあたりは回避する方法があるかもしれませんね) 結局、PRが来ても「これ、マージして大丈夫...?」と不安になり、確認コストが高くなりがちでした。 セキュリティの知見、チームで底上げしたい もうひとつ、スキームを作りたかった理由があります。 脆弱性対応は、最終的には人間が判断する必要があります。「この脆弱性は本当に自分たちのアプリに影響があるのか?」「Hotfixを当てるべきか、通常リリースでいいのか?」。こうした判断は、AIに丸投げするわけにはいきません。 そもそも、「どのような脆弱性なのか」がわからないという問題もあります。SQLインジェクション、XSS、プロトタイプ汚染...。名前は聞いたことがあっても、具体的にどういう攻撃手法で、どうガードすればいいのか。アプリケーションエンジニアとして、こうした知識は本来持っておいたほうがいいはずです。 そういった知見は、自分たちのアプリケーションに対してコードを書いたり、AIが書いたコードをレビューする際にも役に立つはずです。 ただ現実には、こうしたセキュリティの知識を、アプリケーションエンジニアが体系的に学ぶ機会はそう多くありません。業務の中で自然と身につく類のものでもない。だからこそ、CVE対応のプロセス自体を「学びの機会」にできないか、という思いもありました。 実際に組んでみたスキーム 全体のフローは以下のようになっています。 graph TD A[Dependabot検知] --> B{Severityがチームの既定値以上?} B -- No --> C[無視] B -- Yes --> D[Slack通知] D --> E[Code Ownerがアサイン] E --> F[担当者がトリアージ] F --> G{Hotfix必要?} G -- Yes --> H[即時対応・特殊フロー] G -- No --> I[通常修正] I --> J[AIレビュー実施] J --> K{Humanレビュー必要?} K -- Yes --> L[Human Review] K -- No --> M[Merge & Slack報告] L --> M それぞれのステップを見ていきましょう。 Step 1. まずSlackに流す ― 「気づく」の自動化 最初にやったのは、Dependabotのアラートを Slackに流すこと でした。 GitHub Actionsで1時間ごとに新規アラートをチェックし、Incoming Webhookで専用のSlackチャンネルに通知します。チームリーダーへのメンション付きなので、見逃しにくい仕組みです。 やっていること自体はシンプルですが、 「普段見ているインターフェースに情報を届ける」 というのが大事なポイントです。メールは埋もれますが、Slackは(良くも悪くも)みんな見ています。通知先を変えるだけで、「気づかなかった」という問題がほぼなくなりました。 Step 2. Devinにトリアージを依頼 ― 「理解する」のハードル低下 アラートに気づいたら、次はトリアージです。 ここで活躍するのがDevinです。Slackのスレッドから、こう打つだけです。 @Devin !triage_cve CVE-XXXX-XXXXX Devinは事前に設定したPlaybookに従って、以下のことを調べてくれます。 脆弱性の概要と深刻度: CVEの内容を平易な日本語でまとめてくれる 到達可能性(Reachability): 脆弱性のある関数を自分たちのコードが実際に呼んでいるかを調査 devDependenciesかどうか: 開発環境のみの影響なら緊急度が下がる Hotfixの必要性: 上記を踏まえて、通常リリースで良いか、Hotfixが必要かの判断材料を提示 SlackにDevinがトリアージ結果を投稿した様子 これが本当にありがたいのです。以前は「CVEの英語ドキュメントを頑張って読み解く」必要がありましたが、今はDevinが要点をまとめてくれるので、エンジニアは 「判断する」ことに集中 できます。 セキュリティに詳しくないメンバーでも、Devinのレポートを読めば「なるほど、これはdevDependenciesだけだから緊急度は低いな」「これは実際にリクエスト処理で使っているライブラリだから早めに対応しよう」と判断できるようになりました。 ただし、最終的な判断は必ず人間が行います。 これはエンジニア組織のルールとして、キャディ株式会社 共同創業者兼最高技術責任者 CTOの小橋から明確なメッセージが発信されています。AIは優秀ですが「責任」はとってくれません。 Slackのスレッドでやりとりされるので、迷ったらリーダーや有識者に相談するのもやりやすいです。 Step 3. Devinに修正も依頼 ― 「直す」の効率化 トリアージが終わったら、修正です。ここでもDevinに頼ります。 @Devin !Patch_cve DevinはPlaybookに定義された修正ガイドラインに沿って、PRを作成してくれます。 私たちのチームでは、以下のような修正ルールを定めています。 セマンティックバージョニングの範囲内で更新する: メジャーバージョンを勝手に上げない。 overridesは原則使わない: 親パッケージが指定した範囲内で一時的に引き上げるために使うのであればよいが、レンジ外のバージョンへ無理やり上書きすると、テストされていないパッケージの組み合わせになるリスクがある。 Dependabotにはこうしたプロジェクト固有のルールを守らせることが難しかったのですが、DevinならPlaybookに定義しておくことで遵守させることができます。これが、修正をDevinに任せている大きな理由です。 PRが作成されると、AIレビュー(Devin ReviewまたはCopilot Review)が自動で実施されます。もちろん、Humanのレビュアーも必ずアサインします。 Step 4. 週次定例でカバー ― 仕組みの穴を塞ぐ どんな仕組みにも漏れはあります。リーダーが休みでアサインが遅れた、Devinの修正がうまくいかなかった、親パッケージが未対応でそもそも直せない...。 こうした漏れを拾うために、週次の定例MTGで滞留しているアラートをチェックしています。 直接対応できないケース(間接依存のパッケージに修正パッチが出ていない場合など)は、チケットを起票して管理します。フィルターで一覧化し、定例MTGにて状況を確認しています。 そしてもうひとつ、この場で 対応してくれたメンバーをちゃんとレポートに載せる ようにしています。脆弱性対応は地味な作業です。やっても新機能のリリースのように派手に褒められることは少ない。だからこそ、「あなたが対応してくれたおかげで安全になりました」と可視化することが大切だと考えています。 振り返って重要だと思ったこと このスキームを運用してみて、いくつか大事だと感じたことがあります。 普段見る場所に通知する、それだけで変わる 正直、これが一番効果がありました。 メールからSlackに通知先を変えただけで、アラートへのリアクション速度が段違いに変わりました。人は「目に入るもの」には反応するんですよね。「気づきの導線設計」は、ツールの選定以上に大事かもしれません。 AIがセキュリティのラーニングコストを下げてくれた CVEの内容を理解し、影響範囲を調査し、修正方針を考える。以前はこの一連の作業が重くて、「できる人」に偏りがちでした。 AIが一次調査を肩代わりしてくれることで、セキュリティに詳しくないメンバーでも対応できるようになりました。AIは「判断するための情報収集コスト」を下げてくれる存在です。 「セキュリティの知見がないから自分には無理」というハードルが、チーム全体で下がったのは大きな変化でした。 でも、最後は人間が判断する AIが便利だからといって、すべてを任せるわけにはいきません。 Hotfixを当てるかどうかの判断 破壊的変更を含むアップデートの影響範囲の最終確認 本当にマージして問題ないかの判断 これらは人間の責任です。そして、AIのおかげで「判断に必要な材料を集めるコスト」が下がっているからこそ、人間が判断そのものに集中できるようになったとも言えます。 やった人をちゃんと認知する 繰り返しになりますが、脆弱性対応は報われにくい作業です。ユーザーに見える新機能を作るのとは違って、「何も起きなかった」が成果になります。 だからこそ、週次レポートで対応者を可視化する仕組みは大事にしています。「ありがとう」が自然に言える仕組みは、運用を続けるための燃料です。 おわりに 「脆弱性のアラート、見なかったことにしよう...」 この記事を読んでくださった方の中にも、そんな経験がある方がいるかもしれません。 でも、仕組みを作ってみて思ったのは、負債はちゃんと細かく返していったほうが、精神衛生上いい ということです。溜めれば溜めるほど重くなるし、見ないフリをしている間のストレスは意外と大きい。 完璧な運用じゃなくていいんです。「回り続ける仕組み」をまず作ること。そしてAIの力を借りれば、セキュリティという重たいテーマのハードルも、思ったよりずっと下がります。 この記事が、みなさんの脆弱性対応の第一歩になれば幸いです。
はじめに こんにちは。Reliabilityグループ QAエンジニアのmeguroです。 最近、開発現場でAI Agentがコードを書く場面が増えてきました。Claude CodeやGitHub Copilotを使えば、APIサーバーの実装が数分で完成します。テストコードも自動生成される。開発スピードは確かに上がっています。 しかし、QAエンジニアとして、あることが気になりました。 「AI Agentが生成したテストコードの品質は、どうやって担保すればいいのか?」 同じAI Agentなのに、時には網羅的なテストを書き、時には重要なケースが抜け落ちている。この品質のばらつきは、一体何が原因なのか。 QAとして、AI時代のテスト品質をどう管理すべきか。その答えを探すため、実験を行いました。同一のタスク管理APIを3パターンの仕様書で実装し、生成されたテストコードの品質を定量的に比較してみました。 結果は明確でした。 仕様書の書き方次第で、AI生成テストの品質が2〜3倍変わる。 AI Agentは「書かれたことは確実にテストする」が「書かれていないことはテストしない」という特性があります。 つまり、仕様の完全性が品質を決定するのです。 この記事では、その実験の過程と、品質を担保するための具体的な知見をお伝えします。 実験設計:同一APIを3パターンの仕様で実装 実験の概要 今回の実験は、特定の仮説を検証するのではなく、「AI Agentの特性から逆算して、品質を担保するために必要な要素を導き出す」という演繹的なアプローチをとりました。 AI Agentには「指示されたことは忠実に実行するが、行間は読まない」という特性があります。この前提(公理)から、「人間が暗黙的に行っている思考」をどの段階まで具体化して与えれば、納得する品質に届くのかを検証するため、以下の3段階のPoCを設計しました。 3つのPoC poc-1-minimal(最小限仕様) エンティティ定義 エンドポイント一覧 エラーマッピング表 認証・認可ルール poc-2-tdd(TDD手法追加) poc-1の仕様 + TDD手法の指示 実装順序の指定 具体的なテストコード例 poc-3-strategy(テスト戦略追加) poc-1の仕様 + テスト戦略ドキュメント 5つの品質指標の定義 検証すべき仕様項目の具体例 評価指標(5つの品質メトリクス) テストコードの品質を測るため、過去のバグを分析し、実際に見落とされがちな5つの指標を設計しました。 Schema Coverage(スキーマカバレッジ) 定義:レスポンスの全フィールドが検証されているか 計測方法:検証済みフィールド数 / 全フィールド数 目標:100% Post-Condition Coverage(事後条件カバレッジ) 定義:書き込み操作で「対象レコード・関連レコード・不変条件」の3点が検証されているか 計測方法:検証済み事後条件数 / 全事後条件数 目標:100% Error Mapping Consistency(エラーマッピング一貫性) 定義:HTTPステータスコードが全エンドポイントで一貫しているか 計測方法:実装済みエラーパターン数 / 全エラーパターン数 目標:100% Authorization Coverage(認可カバレッジ) 定義:全ロール×全エンドポイントの組み合わせがテストされているか 計測方法:テスト済み組み合わせ数 / 全組み合わせ数 目標:100% Abnormal Test Ratio(異常系テスト比率) 定義:4xx/5xxテストの割合 計測方法:異常系テスト数 / 全テスト数 目標:60%以上 実験結果:仕様の質が品質を決める さて、実際にAI Agentに実装させ、その実験結果を見ていきましょう。 定量結果サマリー 指標 poc-1 poc-2 poc-3 戦略 改善率 Schema Coverage 43% 61% 100% 2.3倍 Post-Condition Coverage 22% 39% 100% 4.5倍 Error Mapping Consistency 31% 90% 97% 3.1倍 Authorization Coverage 48% 80% 100% 2.1倍 Abnormal Test Ratio 53% 58% 48% 0.9倍 注目すべき3つの発見 結果を分析していて、特に興味深かった点を3つ紹介します。 発見1:TDD手法はError Mapping Consistencyで劇的改善(31%→90%) poc-2では、CLAUDE.mdに具体的なテストコード例を含めました。 その結果、AI Agentはこのパターンを全8エンドポイントに自動適用し、401テストが網羅的に生成されました。一方、poc-1では「認証なしは401を返す」とテキストで書いていましたが、テストは1エンドポイントにしか書かれませんでした。 学び:抽象的な指示(「全エンドポイントで認証テストを書く」)よりも、具体的なコード例の方がはるかに効果的です。 発見2:テスト戦略はスキーマ・認可で100%達成 poc-3のdocs/test-strategy.mdには、全32通りの検証パターンをマトリクスで指示しました。 結果、AI Agentはその表を見て「全8エンドポイント × 4ロール = 32パターン」のテストを自動生成してくれました。さらに、Schema Coverageについても、Protoの全フィールドを1つずつ検証するテストコードを生成しました。 学び:「何を検証すべきか」が具体的に列挙されていれば、AI Agentは漏れなく実装してくれます。 発見3:poc-1でも53%の異常系テストは書かれる 意外だったのは、最小限の仕様でも、異常系テストは過半数書かれていたことです。これは、エラーマッピング表(404/400/403/500の定義)を明示していたおかげでした。 ただし、一貫性に欠けていました。例えば POST /projectsには401テストあり PATCH /tasksには401テストなし 学び:「何をテストすべきか」の明示的な指示がなければ、AI Agentは恣意的にテストを選んでしまいます。 なぜAI Agentには異なる仕様が必要なのか? ここまでの結果を見て、「なぜこんなに差が出るのか?」と疑問に思われた方もいるかもしれません。 その理由は、人間とAI Agentの根本的な違いにあります。 人間とAI Agentの根本的な違い 人間の開発者: 仕様(80%完成) + 暗黙知 + 経験 + コミュニケーション → 完全な実装 AI Agent: 仕様(100%必須) → 実装品質 品質を担保するために意識すべき6つの観点 この実験を通じて明らかになったのは、「頭の中で考えている品質の視点」を、明示的に定義することの重要性です。 従来、エンジニアは「暗黙知」を持っていました。 人間の開発者なら、レビューやコミュニケーションで補えました。 しかし、AI Agent時代では、思考プロセスを仕様書に明記する必要があります。 以下、品質を担保するために意識すべき6つの観点と、実験で得られた知見を紹介します。 品質観点1: エラーハンドリングの一貫性 なぜ重要か エンドポイントごとにエラーハンドリングがバラバラだと、以下の問題が起きます ユーザー体験の不整合:同じ「認証なし」なのに、401と500が混在 監視設計の困難:どのステータスコードを監視すべきか曖昧 障害対応の遅延:本番で「これは404か500か?」の切り分けに時間がかかる 「全エンドポイントで一貫したエラーマッピング」を担保する必要があります。 従来の検証方法と課題 実装後にテストコードをレビュー 手動テストで各エンドポイントのエラーレスポンスを確認 → 8エンドポイント × 3エラーパターン = 24ケースを人手で確認 → 実装後に気づいたときは既に手遅れ 品質を設計で担保する 実験では、以下を事前に定義しました: ## エラーマッピング(全エンドポイント共通) | エラー種別 | HTTPステータス | 内部エラー | |-----------|----------------|-----------| | 認証なし | 401 | JWT検証失敗 | | リソース不存在 | 404 | sql.ErrNoRows | | DB障害 | 500 | その他すべて | ## テスト要件 - 全8エンドポイントで401テストを実装 - 全8エンドポイントで404テストを実装 - 全8エンドポイントで500テストを実装 実験結果: Error Mapping Consistencyが31%→97%に改善 エラーハンドリングの一貫性は、品質の基本です。実装前に表として定義することで、レビュー工数を削減し、品質を担保できます。 品質観点2: 事後条件の検証 — 副作用を見逃さない なぜ重要か 書き込み操作(POST/PATCH/DELETE)では、対象レコードだけでなく、関連レコードや不変条件も変化します。 典型的な見落とし - POST /projectsでProjectは作成されるが、作成者がMemberに追加されない - DELETE /projectsでProjectは削除されるが、関連するTaskが残ってしまう - 不変条件の破壊(例:オーナーが0人のプロジェクトが存在する) 「対象レコード」「関連レコード」「不変条件」の3点セットで検証する必要があります。 従来の検証方法と課題 テストコードで「レスポンスが200 OK」だけ確認 → DBの状態は検証されていない → 本番で「データが不整合」のバグ報告 → レスポンスが正しくても、DB状態が壊れている 品質を設計で担保する 実験では、事後条件を3点セットで定義しました ## 事後条件(POST /projects) 以下の3点をIntegration Testで検証すること: 1. 対象レコード: Project行が1件作成される(status=active) 検証SQL: SELECT status FROM projects WHERE id = $1 2. 関連レコード: Member行が1件作成される(role=owner, user_id=作成者ID) 検証SQL: SELECT COUNT(*) FROM members WHERE project_id = $1 AND role = 'owner' 期待値: 1 3. レスポンス: Proto全フィールドが含まれる 実験結果: Post-Condition Coverageが22%→100%に改善(4.5倍) 書き込み操作の品質は「レスポンスが正しい」だけでは担保できません。DB状態を直接検証する設計が必要です。 品質観点3: スキーマの完全性 — フィールド欠落を防ぐ なぜ重要か APIレスポンスで「主要なフィールドは返るが、一部のフィールドが欠落」というバグは頻発します。 典型例 - Protoにstatusフィールドを追加したが、ハンドラで返し忘れ - フロントエンドでundefinedエラー - 本番リリース後に発覚 「Protoの全フィールドがレスポンスに含まれる」を担保する必要があります。 従来の検証方法と課題 テストで主要フィールド(id, name)だけ検証 → 追加したフィールドは検証されない → 「主要な機能は動く」が「追加機能が壊れている」 品質を設計で担保する 実験では、全フィールドを明示的に列挙しました ## Contract Test要件 GET /projects/:id のレスポンスで、以下の全フィールドが非ゼロ値で返ることを検証: - id (string) - name (string) - description (string) - status (enum: active/archived) - owner_id (string) - created_at (timestamp) - updated_at (timestamp) テストコード例: assert.NotEmpty(t, project.ID) assert.NotEmpty(t, project.Name) assert.NotEmpty(t, project.Status) // ... 全7フィールドを検証 実験結果: Schema Coverageが43%→100%に改善(2.3倍) フィールド欠落は、型チェックでは検出できません。全フィールドを明示的に検証する設計が必要です。 品質観点4: 認可の網羅性 — 権限チェック漏れを防ぐ なぜ重要か 認可のバグは、セキュリティインシデントに直結します。 典型例 - オーナーだけが実行できるDELETE /projects/:idを、メンバーも実行できてしまう - 本番で「他人のプロジェクトを削除できる」バグ報告 - → セキュリティインシデント 「全ロール × 全エンドポイントの組み合わせ」を検証する必要があります。 従来の検証方法と課題 「オーナーは実行できる」だけテスト → 「メンバーは実行できない」はテストされない → 正常系だけでは、セキュリティホールを防げない 品質を設計で担保する 実験では、全組み合わせを表で定義しました: ## Authorization Coverage: 100% 全8エンドポイント × 4ロール = 32パターンを検証 | エンドポイント | 認証なし | 非メンバー | メンバー | オーナー | |--------------|---------|----------|---------|---------| | GET /projects | 401 | 200 | 200 | 200 | | POST /projects | 401 | 201 | 201 | 201 | | PATCH /projects/:id | 401 | 403 | 403 | 200 | | DELETE /projects/:id | 401 | 403 | 403 | 204 | (以下、Task/Memberエンドポイントも同様) 実験結果: Authorization Coverageが48%→100%に改善(2.1倍) 認可の品質は「正常系が動く」だけでは担保できません。全組み合わせを明示的に検証する設計が必要です。 品質観点5: リスクベースのテスト優先度 なぜ重要か すべてのバグが同じ重要度ではありません。 - 金銭的損失につながるバグ(決済、課金) - セキュリティインシデントにつながるバグ(認可、認証) - ユーザー体験を大きく損なうバグ(データ削除、不整合) 「リスクの高い領域ほど、異常系テストを厚くする」必要があります。 品質を設計で担保する 実験では、リスク評価を異常系テストのパターン数に変換しました ## リスク評価とテスト戦略 ### 高リスク領域: DELETE /projects(データ削除) 異常系テスト5パターン必須: 1. 他人のプロジェクトを削除 → 403 2. 存在しないプロジェクトを削除 → 404 3. DB障害時の挙動 → 500 4. トランザクション途中でタイムアウト → ロールバック確認 5. 外部キー制約違反 → 適切なエラーメッセージ 「重大度:高」という抽象的な表現ではなく、具体的なテストパターン数で優先度を表現します。 品質観点6: 暗黙知の明示化 なぜ重要か 「ベストプラクティス」「適切に実装」といった抽象的な要求は、人によって解釈が異なります。 典型例 - 「削除は適切に実装」→ 物理削除を実装 - → 監査ログ要件を満たせない - → 「適切」の定義が曖昧だった 「なぜそうするのか」を明示する必要があります。 品質を設計で担保する 実験では、「〜しない理由」も記載しました ## 削除の実装方針 ソフトデリートを使用すること 理由: - 監査ログ要件:誰が、いつ削除したかの記録が必要 - 誤削除時の復旧:ユーザーからの「間違って消した」問い合わせに対応 - データ分析:削除されたプロジェ
はじめに 10年以上前、単語を単なる記号ではなく、意味の近さを「距離」で表現する高次元ベクトルへと数値化する技術「Word2Vec」が登場しました。これが、AIの重要技術の1つである「埋め込み(Embedding)技術」が研究界で大きな注目を集める契機となりました。 その後、この技術は単語から文章、さらには画像へと適用の幅を広げ、AIは次第にそれらの「意味」を理解し始めます。類似する文章や画像を検索する精度は飛躍的に向上しましたが、当時はまだ、文章と画像を同じ尺度(共通のベクトル空間)で扱うことは困難でした。 その壁を打破したのが、2021年にOpenAIが発表した「CLIP」です。CLIPは文章と画像で共通の埋め込みを作成することに成功し、いわば両者の意味を繋ぐ「共通言語」を誕生させました。このマルチモーダル埋め込みの成功を皮切りに、現在は音声や3Dデータなど、あらゆる情報を共通の埋め込み空間で扱う研究が加速しています。 現在、製造業においてもこれらの技術は浸透しつつあります。画像埋め込みを用いた「図面類似検索」や、テキスト埋め込みを応用した「RAG(検索拡張生成)」などがその代表例です。しかし、現状では単一モーダルの活用が主流であり、マルチモーダル埋め込みの真の社会実装はまだ始まったばかりと言えるでしょう。 マルチモーダル埋め込みの研究分野での盛り上がりを鑑みれば、今後この領域が製造現場に社会実装されていくのは間違いありません。本記事では、マルチモーダル埋め込みの概要から最新の研究事例、そして製造業における活用の未来について詳しく解説します。 「埋め込み」とは? この節では、そもそも「埋め込み」「マルチモーダル埋め込み」とは何かを説明します。 「埋め込み」とは、一言で言えば「現実世界のあらゆる情報を、AIが計算しやすい『多次元空間上の座標(ベクトル)』に変換する技術」のことです。人間が言葉の意味を理解するように、コンピュータに「概念の近さ」を数値として教え込むプロセスだと考えると分かりやすいでしょう。 埋め込みを使うことで、次の3つのことを実現します。 1. 「記号」を「座標」に変える コンピュータは本来、数字しか扱えません。かつて、AIに「リンゴ」という言葉を教える際は、単に「101番」という背番号(ID)を割り振るだけでした。しかし、これでは「リンゴ」と「ナシ」が似ているという意味のつながりを計算できません。 埋め込み技術は、エンコーダーを使い、例えば「リンゴ」を [0.12, -0.54, 0.88, ...] という数百次元の数値の並び(ベクトル)に変換します。この数値は、その対象が持つ「甘み」「赤い」「果物」といった無数の特徴を凝縮した地図上の座標のようなものです。 2. 「近さ」で意味を測る データが座標(ベクトル)になると、データ同士の「距離」を計算できるようになります。 意味が似ているもの: 空間上で近くに配置される(例:「犬」と「猫」) 意味が異なるもの: 空間上で遠くに配置される(例:「犬」と「数学」) 3. 多様なデータを一箇所に集める(マルチモーダル) 最新の埋め込み技術の凄さは、テキストだけでなく、画像、音声、センサーデータまでも同じ空間に並べられる点にあります。 例えば図1のように、「犬が走っている」というテキスト、ゴールデンレトリバーの画像、「ワンワン!」という鳴き声、そして走る犬の動画。これらは入り口こそバラバラですが、それぞれの専用エンコーダーによって「ベクトル(数値の並び)」へと変換されます。 変換されたデータは、多次元の「埋め込み空間」の中に配置されます。この空間の最大の特徴は、「意味が似ているものほど、近くに配置される」という性質です。この例では、データ形式が違っていてもすべて「犬」という同一のコンセプトに関連しているため、AIの頭の中(空間)では同じエリアにギュッと集まります。 これにより、AIはデータ形式の壁を越えて、「これは『犬』という本質的な概念だ」と一貫して捉えることが可能になるのです。 図1 マルチモーダル組み込み 犬の例 埋め込みの歴史 埋め込み技術は、わずか10年余りの間に驚くべき進化を遂げてきました。ここでは、その進化の道筋を象徴する3つのマイルストーンを紹介します。「単語だけ」から始まった技術が、「画像と言葉の融合」を経て、「3Dシーンの丸ごとアライメント」へと到達する物語です。 Word2Vec ── 言葉に「座標」を与えた原点 Mikolov et al., 2013 2013年、Googleの研究チームが発表したWord2Vecは、「言葉の意味を計算できるようにした」という点で、自然言語処理の歴史を塗り替えました。 それまでの限界:One-hotベクトル Word2Vec以前、コンピュータに単語を教える方法は非常に素朴でした。「One-hotベクトル」と呼ばれる方式では、語彙数と同じ長さのベクトルを用意し、該当する単語の位置だけを「1」、残りをすべて「0」にします。 例えば語彙が5万語あれば、「リンゴ」は5万次元のベクトルの中で、たった1箇所だけ「1」が立っている状態です。この方式には2つの致命的な欠陥がありました。 次元の呪い: 語彙が増えるほどベクトルが膨大かつ疎(スカスカ)になり、計算効率が極めて悪い。 意味の不在: 「リンゴ」と「ナシ」のベクトルは完全に直交しており、距離を測っても「近い」とも「遠い」とも言えない。つまり、意味の類似度が一切計算できない。 Word2Vecの発想の転換 Word2Vecは、この問題をシンプルかつ強力なアイデアで解決しました。「ある単語の意味は、その周囲に出現する単語によって決まる」という言語学の仮説(分布仮説)に基づき、大量のテキストから単語の「使われ方のパターン」を学習したのです。 具体的には、ニューラルネットワークに以下の2つのタスクのいずれかを解かせます。 CBOW: 「昨日 ___ を食べた」→ 空欄に入る単語を、周囲の文脈から予測する。 Skip-gram: 「リンゴ」という単語から、その周囲に出現しやすい単語(「食べた」「赤い」「果物」など)を予測する。 このタスクを何億もの文章で繰り返すことで、各単語は数百次元の密なベクトル(分散表現)へと圧縮されます。「リンゴ」と「ナシ」は似た文脈で使われるため、自然と空間上で近くに配置されるのです。 なぜ衝撃的だったのか Word2Vecが世界を驚かせたのは、学習されたベクトルが「意味の足し算・引き算」を可能にしたことです。 「王様」−「男」+「女」=「女王」 この計算が成立するということは、ベクトル空間の中に「性別」「階層」といった意味の軸が自然に形成されていることを意味します。人間が明示的に教えたわけではなく、AIが大量のテキストから自ら意味構造を発見した ── この事実は、後の埋め込み技術すべての出発点となりました。 CLIP ── 画像と言葉の壁を壊した転換点 Radford et al., 2021 Word2Vecが「単語同士の距離」を測れるようにしたのに対し、2021年にOpenAIが発表したCLIP(Contrastive Language-Image Pre-training)は、さらに大胆な問いに挑みました。「画像と言葉の距離を測ることはできないか?」── CLIPの答えは、驚くほどシンプルでした。 4億枚の「画像+キャプション」で学ぶ CLIPは、画像用とテキスト用の2つの独立したエンコーダーを備えています。学習に使ったのは、インターネットから収集した4億セットの「画像とキャプションのペア」。この膨大なデータを使い、以下のルールでベクトル空間を鍛え上げます。 正しいペアは近づける: 犬の画像と「走る犬」というキャプション → ベクトルを空間上で近くに配置。 無関係なペアは遠ざける: 犬の画像と「青い車」というキャプション → ベクトルを空間上で引き離す。 これが「対照学習(Contrastive Learning)」です。正解と不正解を対比させながら空間を整えていくことで、画像とテキストが同じ座標系で「意味的に比較可能」になります。 「見たことがないもの」を理解できる CLIPの最も画期的な特徴は、「Zero-shot性能」と呼ばれる能力です。従来の画像認識モデルは、「犬」「猫」「車」などのラベルを事前に教え込む必要がありました。学習していないカテゴリは認識できません。 CLIPは違います。ラベルではなく「言語の概念そのもの」を学習しているため、一度も見たことがない物体でも、テキストで説明すれば識別できます。例えば「三角形の赤い標識」と入力すれば、学習データに含まれていなくても該当する画像を見つけ出せるのです。 この「データ形式を超えた意味の理解」こそ、マルチモーダル埋め込みの幕開けでした。 CrossOver ── 3Dシーンを丸ごと対応づける最前線 Sarkar et al., 2025 (CVPR 2025 Highlight) CLIPが画像とテキストの2つのモダリティを結びつけたのに対し、2025年にコンピュータビジョンの最高峰学会CVPR 2025でハイライト論文に選ばれたCrossOverは、さらに多くのモダリティへと対象を広げました。RGB画像、点群(Point Cloud)、CADメッシュモデル、フロアプラン、テキスト── これら5種類ものデータを1つの共通空間にまとめ上げ、3Dシーン全体をモダリティ横断で対応づける(アライメントする)フレームワークです。 従来手法の限界:「完璧なデータ」がないと動かない これまでの3Dマルチモーダル学習には、大きな制約がありました。「椅子」「テーブル」といったオブジェクト単位で厳密にラベルを付けたアノテーションが必要で、しかも全てのモダリティ(画像・点群・CADなど)が揃っていなければ学習できなかったのです。 しかし現実のAR/VRやロボティクス、建設モニタリングといった現場では、そんな理想的なデータが揃うことはほとんどありません。ある部屋は3Dスキャンデータしかない、別の部屋はCAD図面と写真だけ ── こうした「歯抜け」のデータが当たり前です。 CrossOverの3つの工夫 CrossOverは、3つの工夫でこの「現実の壁」を突破しました。 1つ目は、「シーンまるごと」で対応づけること。従来はオブジェクト1つ1つに丁寧なラベルを貼る必要がありましたが、CrossOverは「部屋全体」「フロア全体」といったシーン単位で異なるモダリティを結びつけます。いわば、家具を1個ずつ辞書登録するのではなく、部屋全体の写真を1枚見せて「ここにあるもの全部まとめて覚えて」と教えるようなイメージです。 2つ目は、データが歯抜けでも学習できること。5種類全てのデータが揃っている必要はありません。「この部屋は点群とテキストしかない」「あの部屋はRGB画像とCADだけ」── そんな不完全なデータでも、手持ちのモダリティだけで埋め込みを計算し、学習に組み込めます。 3つ目は、段階的に賢くなる学習戦略です。各モダリティに専用のエンコーダを用意し、最初は少ないデータの組み合わせから始めて、徐々に複雑な組み合わせへと学習を積み上げていきます。完璧なデータを待たずに、今あるデータから着実に知識を蓄積できるのです。 何ができるようになるのか CrossOverにより、データの形式を飛び越えた3D検索・解析が現実のものになります。 例えば、フロアプラン(間取り図)を検索クエリとして入力すれば、対応する3D点群データが検索結果として返ってくる。逆に、点群データから対応するフロアプランやCADモデルを見つけ出すことも可能です。さらに、明示的に学習していないモダリティの組み合わせ(例:フロアプラン ↔ テキスト)でも検索が機能する「創発的な汎化能力」が確認されています。 これはまさに、製造業や建築業が待ち望んでいた技術です。次の章では、この技術が製造現場でどのように活用されていくのかを具体的に見ていきます。 製造業における活用の未来 ここまで紹介してきたマルチモーダル埋め込み技術は、あくまで「要素技術」です。では、この技術が製造業の現場に入ると何が変わるのか? ── ここからは、最も実用化が近い「検索」の応用領域を見ていきます。 検索 ── 「探し方」が根本から変わる 製造業には、長年にわたって蓄積された膨大な図面・3Dデータ・仕様書が眠っています。しかし、その多くはファイル名や管理番号といった「メタデータ」でしか検索できません。番号を忘れたら最後、必要なデータにたどり着けない ── そんな経験のある方も多いのではないでしょうか。 マルチモーダル埋め込み技術は、この「探し方」を根本から変えます。データの本質的な「意味(特徴)」がベクトル化されることで、メタデータに頼らない、3つの新しい検索が可能になります。 クロスモーダル検索:形状で図面を探す 「データ形式の壁」を越える検索です。 設計担当者が、過去の類似製品の仕上がりを確認したい場面を想像してください。従来は管理番号を手がかりに過去資料を探し回る必要がありましたが、マルチモーダル埋め込みを使えば、開発中の3D CADデータをそのまま検索クエリとして入力するだけで済みます。AIが埋め込み空間上で「形状的・構造的に近い」過去の製品図面(画像)を瞬時に見つけ出してくれるのです。 管理番号が不明な古い部品でも、形状さえあれば「過去の類似品」を紐付けられる。これだけでも、設計の初期段階で過去の知見を活かしやすくなります。 マルチモーダル検索:「画像+テキスト」で絞り込む 1つのモダリティでは足りない場面に効く検索です。 例えば、「このフランジ(画像)と同じ形状で、かつ材質がステンレス(テキスト)のもの」を探したいとします。画像だけでは材質まで判別できませんし、テキストだけでは形状の微妙な違いを表現しきれません。 マルチモーダル検索では、画像の「視覚的な特徴ベクトル」とテキストの「仕様的な特徴ベクトル」を掛け合わせることで(ベクトル加算など)、両方の条件を満たすデータをピンポイントで特定できます。材質、硬度、耐熱性── 画像では見えない情報を言葉で補足することで、検索精度が格段に上がるのです。 AIチャット検索:現場の言葉でデータを引き出す 対話型インターフェースを介した検索です。 現場の作業員がタブレットに向かって「先週のライン停止時に、ベアリング付近を撮影した写真を見せて」と話しかける。あるいは「この3Dモデルの、取付穴が5つあるバリエーションをリストアップして」と指示を出す。── ユーザーの発話がテキストベクトルに変換され、データベース内の画像・3Dデータのベクトルと直接照合されることで、こうした自然な対話での検索が実現します。 複雑な検索コマンドを覚える必要はありません。専門知識がなくても「現場の言葉」で必要な技術資産にアクセスできるようになる点が、現場への浸透を考えると最大の強みです。 おわりに 本記事では、埋め込み技術の進化を「単語だけ」のWord2Vecから、「画像と言葉」を結んだCLIP、そして「3Dシーンを丸ごと対応づける」CrossOverへとたどりました。この10年余りで、AIが「意味」を捉える範囲は劇的に広がっています。 製造業にとって、この技術が意味するのは「データの探し方の根本的な変化」です。ファイル名や管理番号に頼っていた検索は、形状やテキストの「意味」で直接つながるようになります。ベテラン設計者の頭の中にしかなかった「あの時似たようなものを作った」という経験知は、埋め込み空間を通じて組織全体で共有できるデジタル資産へと変わります。 現時点では、製造業でのマルチモーダル埋め込みの社会実装はまだ始まったばかりです。しかし、研究の進展を見れば、この技術が現場に届くのは時間の問題でしょう。「形」と「言葉」の境界が消えたとき、製造業のデータ活用は新しいステージに入ります。 仲間を募集しています! キャディ株式会社では、本記事で紹介したマルチモーダル埋め込み技術をはじめ、AIモデル開発に全力で取り組み、ミッション「モノづくり産業のポテンシャルを解放する」の実現を目指しています。 この記事を読んで「自分ならこう解決する」「この技術、面白そう」と感じたエンジニアの方、ぜひご応募お待ちしております! 詳細は以下の採用ページからご覧いただけます! Data & Machine Learning / CADDi Tech Careers
こんにちは。キャディ株式会社でリサーチ組織の立ち上げを担っている福原です。 現在、私たちのResearchチームでは「Staff Research Engineer, 2D/3D Vision & Multimodal Understanding」のポジションを新たにオープンしています。これまでのテックブログでは、VLMの空間推論における限界や、3D CADモデルの幾何情報処理の難しさといった「私たちが直面している技術課題(What)」について発信してきました。 今回は視点を変えて、この挑戦的な技術領域で、どのようにして素早く価値を生み出し続ける研究開発が可能なのか、そしてなぜキャディでそれが実現できるのかについてお話しします。 製造業コンピュータビジョンの特異性 なぜキャディなのか:研究開発スピードの構造設計 技術ロードマップにおける3つの重点領域 3D形状の幾何学的・意味的理解の深化 2D図面と3D CADモデルの高度な対応付け マルチモーダル横断検索 求める人物像 製造業コンピュータビジョンの特異性 現在のコンピュータビジョン研究の主流は、RGB画像から3Dタスクを解くというアプローチです。自動運転、ロボティクス、AR/VRなど、多くの先端応用では、豊富なテクスチャ情報、照明の変化、背景のコンテキストといった視覚的手がかりを活用します。最新のVision-Language Model(VLM)も、このような「見た目の情報」を高度に理解することで、驚異的な性能を発揮しています。 しかし、製造業の現場では状況がまったく異なります。図面にも3D CADにも、色もテクスチャも背景も存在しません。そこにあるのは、ピュアな幾何学的情報のみです。 この違いは些細なものではありません。以前のテックブログでもお話ししましたが、言語処理タスクでは人間レベルに達するMLLMも、空間推論タスクでは60%の精度にすら届きません。建築図面のベンチマークでは、テキスト中心の質問応答では高精度を示す一方、空間認識では40〜55%程度という劇的な性能差が報告されています。既存の最先端モデルは、テクスチャなき幾何学の世界では「3歳児レベルの空間推論能力」に退化してしまうのです。 さらに、製造業では幾何学的特性に加えて物理的特性も同時に考慮する必要があります。ある形状が「見た目として正しい」だけでは不十分で、「製造可能か」「強度要件を満たすか」「加工コストは妥当か」といった物理的制約を満たさなければなりません。この点で、最近注目を集めているフィジカルAIの研究と技術的な親和性が高く、今後の研究トレンドとの接続も見えています。 つまり、製造業のコンピュータビジョンは、主流の研究結果をそのまま横に持ってきて使えるわけではない領域です。一見すると制約のように聞こえるかもしれませんが、逆に言えば独自性があるということでもあります。ビッグテックや巨大な外資企業が開発する汎用モデルは、確かにテキスト生成や一般的な画像認識では驚異的な性能を発揮しますが、テクスチャなき幾何学、製造ドメイン特有の制約、物理的特性といった領域では、汎用モデルをそのまま適用しても十分に機能しません。 これはリサーチエンジニアの視点では、既に確立された正解がないからこそ挑戦的で面白い技術領域であること、そして一瞬で成果が水泡に帰すリスクが、他の領域と比べて相対的に低いことを意味します。 製造業の実データは非公開のものが多く希少性が高いため、ビッグテックであっても容易に参入できる領域ではありません。加えて、扱う情報が様々なモダリティに跨る製造業の業務上の課題には学術的にもまだ確立された解決策が存在しないことも多く、データフォーマットや顧客が実現したい業務の個別性も高いという特徴があります。 汎用的なアプローチがそのまま正解にはならないからこそ、データや顧客の業務といったドメイン特化の深い知見と、製造業の実データを組み合わせた研究は、持続的な技術的Moat(競争優位性)を築きやすいテーマだと言えます。まだ解決すべき課題が山積しており、極めて挑戦的でエキサイティングな研究フロンティアなのです。これが、製造業AIの魅力です。 そして同時に、私たちを取り巻く環境は、かつてないスピードで変化しています。AI技術の進化は加速度的であり、新しい手法やモデルが日々登場しています。このような時代において、3年後、5年後に成果を出すというアプローチでは、市場や技術トレンドが大きく変わってしまう可能性があります。 私たちは、素早く価値を生み出し、検証し、次の価値創出につなげていく組織を目指しています。これは単なる目標ではなく、変化の激しい時代からの要請だと考えています。研究成果を小さく素早くリリースし、顧客のフィードバックを得て、次の研究テーマを磨き込んでいく。このサイクルを高速で回すことで、長期的な技術的優位性を築いていきます。 なぜキャディなのか:研究開発スピードの構造設計 では、なぜキャディにおいてこれほど高速な価値創出が可能なのでしょうか。 それは、単に「優秀な人材がいる」あるいは「リソースが潤沢である」という理由からではありません。研究開発のスピードを根本的に決定づけるのは、プロセスそのものをいかに速く回せる「構造」が整っているかです。 キャディの研究開発環境には、この構造を支える2つの大きな特徴があります。 1つ目は、自社でアプリケーションとデータプラットフォームを保有し、顧客の現場課題に深く入り込んでいることです。ビジネスメンバーが顧客と伴走し、見積、図面検証、製造プロセス管理といったコア業務の課題に日々向き合っています。この顧客との深い関係性が、机上の空論ではない「リアルな現場の知見」と「実データ」へのアクセスを可能にしています。 2つ目は、経営直下での研究開発の優先順位の高さです。キャディにおいて、独自のAI技術によるMoat構築は経営の最重要課題の一つです。そのため、CEO自らが研究開発の現場と連携し、技術検証や事業実装に向けたブロッカーを即断即決で取り除く体制が整っています。 これら2つの特徴により、私たちの環境では、一般的な研究組織が直面するボトルネックに対して、引けるレバー(選択肢)が圧倒的に多く、かつそれが機能する速度が速いのです。 例えば研究を進める上で壁にぶつかったとき、私たちには以下のような選択肢が即座に用意されます。 データが足りない → ビジネスチームと連携し、実際プロダクトを利用いただいている顧客に直接アプローチして新しいデータの整備をする ドメイン知識が足りない → 製造現場と直結したプロダクトを持つ強みを活かし、社内の専門家や実務者の知見へ即座にアクセスする 業界標準が曖昧で判断できない → 必要に応じて政府機関や業界団体と連携し、マクロな視点から課題を整理する リソースの壁に直面する → 経営層と連携し、課題と必要性を共有することで、人的リソースや計算資源の拡張の判断を仰ぐ ここで重要なのは、私たちが「誰とも関わらず研究だけに閉じこもれる温室」にいるわけではないということです。研究成果を事業価値に繋げるためには、PdMや他チームとの連携が不可欠であり、自ら主体的に動くことが求められます。しかし、そこには本質的ではない待ち時間や政治的な摩擦が極めて少なく、主体的に動くことで高速に研究開発のサイクルを回せる環境が存在します。 自分で動き、周囲を巻き込むことで、あらゆる問題が即座に解決していく。これは逆を言えば、「言い訳ができない環境」でもあります。研究成果を事業価値へとつなげ切る責任がある一方で、そのための障害は経営層や周囲のメンバーが全力で取り除いてくれます。 事業部と切り離された研究組織では、ともすれば大規模なリソース獲得の承認に数週間、社内部署の調整まで含めると数ヶ月といった遅延が発生しがちです。しかしキャディでは、そうした非本質的な遅延がほぼありません。リサーチエンジニアが本来向き合うべき技術検証と価値創出に、時間のほぼすべてを注ぎ込むことができる。この構造的な違いこそが、研究スピードを根本から変えているのです。 ここまで読んで、「それならアカデミアや大企業の研究所でも同じことができるのでは?」と思われるかもしれません。しかし、キャディの研究開発環境は独特のバランスの上に成り立っています。 アカデミアとの違いは、論文執筆は目的ではなく過程であり、実データでの検証と「顧客の課題解決」こそが最終的な価値基準である点です。 大企業研究所との違いは、意思決定のスピードです。事業実装までの判断が「週単位」で行われ、組織的なブロッカーは即座に解除されていきます。 スタートアップとの違いは、製造業という数兆円市場において、すでにグローバル4カ国に展開するSaaSプラットフォームと確固たる顧客基盤、実データを有している点です。 つまりキャディは、技術的な挑戦の深さ、スタートアップの意思決定スピード、事業基盤を持つ企業としての実装力という、通常はトレードオフになりがちな要素を併せ持つ、稀有な研究環境なのです。 技術ロードマップにおける3つの重点領域 このような環境で、私たちは具体的にどのような技術課題に挑んでいるのか。重点課題の中から、いくつかの領域をご紹介します。 3D形状の幾何学的・意味的理解の深化 まず一つ目の領域が、3D CADデータの純粋な幾何情報に対する深い理解です。 製造業のデータを扱うモデルには幾何形状や空間配置に関する高い認識力が求められますが、前述の通り既存の多くの基盤モデルはこの要件を満たせていません。私たちは、SaaSを通じて蓄積された大規模な3D CADデータを活用し、純粋な幾何情報から製造上意味を持つ特徴を認識できる表現を獲得する研究に取り組んでいます。 これは単なる形状の認識だけにとどまりません。3D CADの局所的な特徴(フィレット、ボス、リブ、穴など)を抽出し、「この穴はM6ボルトを通すためのもの」「このリブは強度を確保するためのもの」といった、設計者の意図や物理的な制約をモデルに推論させることが求められます。幾何学的な形状の認識だけでなく、強度や剛性、加工の実現可能性といった物理的特性も同時に扱う、フィジカルAI領域の先端的な挑戦でもあります。 このように3D形状に対する理解を深めることで、部品の3D CADモデルから加工難易度や適切な製造方法を自動推定することも可能になります。これにより、これまでベテランの暗黙知に依存していた見積業務の精度やスピードが飛躍的に向上し、SaaSプロダクトの強力なコア機能としての事業価値に直結します。 2D図面と3D CADモデルの高度な対応付け 二つ目の領域が、2D図面と3D CADモデルの高度な対応付けです。 多くの場合において、図面と3D CADは「部品単位」でしか紐付いておらず、それぞれが持つ詳細な情報の、システム上での密な関連付けは出来ていないのが現状です。 寸法などの詳細な情報は図面側に記載されていることが多い一方で、見積業務において、それらが3次元的にどう配置されているかの確認が必要になることが頻繁にあります。そのため、「図面上の情報を、3D CAD側の対応する適切なコンテキストに紐づけて処理をしたい」という実務的なニーズが存在します。 このようなプロセスを自動化するためには、2D図面と3D CADモデルの情報を相互に解釈し、高度に統合することが必須の要素技術となります。この技術の実現によって、図面と3D CADモデル間を横断したクロスチェックの効率化や、設計情報の整合性担保が可能になり、設計プロセスにおいて大きな事業価値を生み出します。 マルチモーダル横断検索 三つ目の領域が、あらゆる製造データをモダリティを超えて統合する検索・推論基盤の構築です。これには、3D CADや2D図面だけでなく、仕様書、過去の不具合報告、見積書といった自然言語のテキスト情報も含まれます。 最大の技術的挑戦は、純粋な幾何学的類似性(形状が似ている)と、セマンティックな類似性(用途や機能、関連する不具合の文脈が似ている)を両立させ、すべてのモダリティを統一された単一の埋め込み空間に整合させることです。 これが可能になれば、「この部品と類似した形状で、過去にどんな不具合があったか」「この図面形状を満たす最適な加工プロセスは何か」といった自然言語クエリでの高度な横断検索と推論が実現します。これまで個人の頭の中や各部署に散在していた暗黙知がシステム上で形式知化され、設計者や調達担当者の意思決定スピードを劇的に引き上げる事業価値をもたらします。 求める人物像 私たちは以下のような方と是非お話したいと考えています: VLM、3D Vision、マルチモーダル学習のいずれかで深い専門性を持つ方:トップ会議への投稿経験や、博士課程での研究実績など 「面白いモデルができた」で満足せず、事業価値まで執着できる方:研究と実装の間を往復しながら、顧客の課題解決に向き合える 研究スピードを上げるために、構造から変えることを厭わない方:AI活用、プロセス改善、組織設計にも興味がある 提供できる環境: 非本質的な摩擦を排し、研究成果を事業価値へと直結させる最速の社会実装環境 数兆円規模の巨大市場を動かし、独自の技術的Moat(競争優位性)を築く挑戦の場 変化の激しい時代において、最速のサイクルで価値を生み出し続けるアジャイルな組織 特許取得や学会発表をバックアップし、成果を社会へ還元するアウトプット支援 CADDiのリサーチエンジニアは、論文を書くだけでも、実装に専念するだけでもありません。仮説立案・モデル構築・SaaSへの組み込み・顧客検証までを一気通貫で担う「越境型」のポジションです。既存の基盤モデルが通用しない未踏の領域で、世界に先駆けて独自の技術的Moatを築き上げる。そして、その研究成果を圧倒的なスピードで数兆円規模の巨大産業へと実装していく。 あらゆる組織的摩擦が排除された「言い訳ができない」環境で、本質的な技術探求と事業価値創出のサイクルを最速で回し、自らの手でこのブレイクスルーを起こしたい。そう思われた方は、ぜひ一度カジュアルにお話ししましょう。エントリーを心よりお待ちしています。 募集要項: Staff Research Engineer, 2D/3D Vision & Multimodal Understanding カジュアル面談: 応募フォーム
RFC 8707 Resource Indicatorsの活用事例: マイクロサービス間のトークンの権限適正化 はじめに こんにちは、キャディ株式会社のControl Plane 部に所属している麻生です。 キャディでは、マルチテナントSaaSを提供しておりマルチプロダクト化を進めています。その上でアプリケーションを横断した機能をControl Plane として切り出して開発しています。 Control Plane 全体のアーキテクチャについては、以前のブログ記事「CADDi の Control Plane を支えるシステムたちの紹介」で紹介しました。是非こちらもご一読いただけると幸いです。 そのControl Plane において、ワークロード間の認証基盤として "M2M Token Issuer" を運用しています。これはOAuth 2.0 のClient Credentials Grant を用いた社内専用のトークン発行システムで、ユーザー操作を伴わないシステム間通信やバッチ処理で利用されています。 本記事では、M2M Token Issuer が発行するInternal Token を見直し、RFC 8707 Resource Indicators を適用して最小権限の原則を実装したエピソードを紹介します。 改修に至った課題 M2M Token Issuer は、まず動くものを素早く届けることを優先して構築した経緯があり、トークンの権限制御は最小限の設計にとどまっていました。 Client Credentials Grant では、ユーザーが認可の場にいないため同意プロセスがありません。その分、クライアントに許可された操作範囲をscopeで明示的に制約することが重要です。 社内システムでの活用が広がる中で、より安全な利用を促進するため、 「各クライアントに、どのサービスが、どのような操作を許可しているか」 これらを統制できるようにしたいと考えるようになりました。 設計と実装 RFC 8707 Resource Indicators の活用 RFC 8707 Resource Indicators for OAuth 2.0 に準拠する形にしました。これは、トークンリクエスト時にresourceパラメータでアクセス先を指定する仕組みを定義しています。これにより、発行されるトークンのaudにリクエストで指定したリソース識別子が設定されます。 Control Plane の機能は他チームの開発者に認知してもらうことも重要になりますが、RFCに準拠することで、新しい仕様でも社内の開発者に対する説明がしやすくなるというメリットがあります。 改修後のトークンリクエストとレスポンスは以下のようになります。 POST /oauth2/token --user "{Client ID}:{Secret}" -d grant_type=client_credentials \ &resource=urn:caddi-service01 \ &scope=delete { "sub": "{Client ID}", "aud": ["urn:caddi-service01"], "scope": "delete", "iat": 1234567890, ... } トークンを受け取るサービス側は、Istio の RequestAuthentication でaudを検証し、AuthorizationPolicy を用いて要求されたscopeが適切か検証します。自サービスのリソース識別子(urn:caddi-service01)と一致しないトークンは拒否されるため、他のサービス宛てのトークンでアクセスすることはできません。 複数resource を指定した場合の設計 原則は「1トークン = 1リクエスト」の都度取得ですが、技術的には複数のresourceを指定して1つのトークンに複数のaudを含めることもサポートしています。RFC上も、複数のaudを受け付ける仕様です。 POST /oauth2/token resource=urn:caddi-service01 resource=urn:caddi-service02 scope=delete { "aud": ["urn:caddi-service01", "urn:caddi-service02"], "scope": "delete" } ここでのポイントは、scopeがすべての指定resourceに対して共通(積集合)であることです。リクエストされたscopeは、指定されたすべてのresource に対して許可されている場合にのみ発行されます。 複数のresource に別々のscope を指定するケースについては、サポートしないこととしました。これらを提供可能にすると、トークンの権限範囲が広がります。これはトークンの権限適正化という元々の目的と合わないため、最小権限を実現することを優先しました。 この設計により、マイクロサービス間でリクエストがチェーンする場合にも、同一トークンを伝搬させて各サービスでaudとscopeの両方を検証できます。「このトークンは自サービス宛てであり、かつ要求された操作が許可されている」ことは各サービスが独立して検証できます。 ネットワークトポロジーに依存しない識別子 RFC 8707のresourceパラメータにはURIを指定します。Kubernetes 上でマイクロサービスを構築しているキャディにとって、最も直感的な選択肢はKubernetes クラスター内のサービスURL(http://caddi-service01.ns.svc.cluster.local)です。一方でキャディではControl Plane と、Data Plane / Application Plane を別のKubernetes クラスターに分割しており、クラスターを跨いでトークンをやり取りする場合、クラスター内URLはリソース識別子として一意性を担保できる保証はありません。 また、URLを使うとRFC 9728 OAuth 2.0 Protected Resource Metadata が取得できるエンドポイントと誤解されるリスクもあります。リソース識別子はあくまでトークンのaudに載せる論理的な名前であり、実際にアクセス可能なURLである必要はありません。 こうした背景からURLではなくURNを基本とする方針を採りました。ただし、厳格なフォーマットを強制するのではなく、ルールを提供し使う側に委ねる方式としています。 [MUST] URIフォーマット(URNを含む)であること [RECOMMEND] urn:{サービス名} のフォーマットを用いること [CAN] 一意性の担保のために必要に応じて、namespaceやパス情報を追加すること(例: urn:control-plane:caddi-service01) まとめ M2M Token IssuerのInternal Tokenに対して、RFC 8707 Resource Indicatorsを適用し、audとscopeによる最小権限の原則を実現しました。 設計ポイント 内容 resourceによるaud指定 RFC 8707に準拠し、トークンのアクセス先をリクエスト時に明示。サービス側でIstioによるaud検証が可能に scopeの積集合設計 複数resource指定時もscopeは共通。resource別のscope指定は最小権限の観点からサポートしない URNベースのリソース識別子 ネットワークトポロジーに依存しない論理名を採用し、クラスター横断でも一意性を担保 今後の展望 今回の記事はaudに焦点を当てて解説しましたが、scopeについても運用で考えることが多くあります。トークン発行者としてどこまでルールを作るか、今後も検討をしていくことになると思います。 またこれはM2M Token Issuer に限った話ではありませんが、Control Plane の機能は、Data Plane / Application Plane で活用されて価値を発揮します。 新しい機能を導入する上で、開発者に負担なく、かつ開発のアジリティに影響しないように、それでいて全体の生産性にインパクトをもたらす工夫に努めていく所存です。 結び M2Mトークンの認可設計は、ユーザー認証と比べて議論されることが少ない領域ですが、マイクロサービスが増えるほどその重要性は高まります。同じ課題に取り組む方の参考になれば幸いです。 Control Plane の開発に興味がある方は、ぜひ以下のページもご覧ください。 recruit.caddi.tech
こんにちは、Control Plane部認証認可グループの平岩です。私たち認証認可グループではバックエンドAPIにGoを多く採用しています。共通基盤である特性上高RPSに耐えられる必要があり、また安定して低いレイテンシでリクエストを処理することが求められます。本記事ではGoの標準パッケージである sql.DB の内部実装を、ソースコード(Go 1.26時点)を読みながら解説します。 はじめに sql.DB とは何か 内部実装の詳解 DB 構造体の主要フィールド クエリ実行の全体像 BadConn リトライの仕組み コネクションの取得: conn メソッド フェーズ1: idleコネクションがあれば再利用する フェーズ2: 最大接続数に達している場合の待機 フェーズ3: 新規接続の作成 コネクションの返却: putConn メソッド 非同期なコネクション作成: connectionOpener トランザクションとコネクション コネクションの定期削除: connectionCleaner DBStats: プールの状態を観測する コネクションプールの設定 4つの設定パラメータ デフォルト値の問題 各パラメータの解説 SetMaxOpenConns SetMaxIdleConns SetConnMaxLifetime SetConnMaxIdleTime まとめ はじめに GoでRDBを使うとき、何かしらのO/R mapperやライブラリを使うことが多いかと思います。ですが、内部的には標準パッケージの sql.DB が使われています。この sql.DB はコネクションプールの役割を持ち、4つの設定パラメータが存在します。これらの値をデフォルトのまま使うと本番環境でエラーやパフォーマンス問題を引き起こすことがあります。また、内部でリトライが行われるケースがあるなど隠蔽されている挙動も存在します。 本記事では前半で sql.DB の内部実装をソースコードを追いながら解説し、後半でそれを踏まえた設定の考え方を述べます。設定についてだけ知りたい方はコネクションプールの設定まで読み飛ばしてください。 sql.DB とは何か sql.DBの実態はコネクションプールであり、複数のgoroutineから安全に使えます(goroutine safe)。 sql.Openは引数の検証のみを行い、この時点ではデータベースへのコネクションを作成しません。実際にコネクションが作れることを確認するには (*sql.DB).PingContext を使います(詳細はOpening a database handle - The Go Programming Languageを参照してください)。 内部実装の詳解 DB 構造体の主要フィールド ここからは sql.DB の実装を見ていきます。以降のコードを読むにあたって、DB 構造体 の以下の4つのフィールドを把握しておけば十分です。 freeConn []*driverConn: idleコネクションのスライス。プールに戻った時刻 returnedAt の古い順になる connRequests connRequestSet: コネクションを待っているgoroutineの集合 connRequestSet はSetと言っているが実体はindexでの参照を付けたスライス numOpen int: 使用中とidleの両方を含む、現在openなコネクション数 cleanerCh chan struct{}: プールにあるコネクションを閉じるgoroutineへの通知用のchannel すべてのフィールドへのアクセスは mu sync.Mutex で保護されています。 クエリ実行の全体像 まず、 QueryContext を例として全体像を示します。他の QueryRowContext ExecContext PingContext も基本的に同じ流れですが、 QueryContext のみが Rows.Close() を明示的に呼んでコネクションを返却する責任がuser側にあります。 flowchart TD A["(*sql.DB).QueryContext"] subgraph retryScope ["retryの範囲(ErrBadConnの場合、最大3回リトライされる)"] B["(*sql.DB).retry"] Q["(*sql.DB).query"] C["(*sql.DB).conn"] E["(*sql.DB).queryDC"] end A --> B B --> Q Q --> C C -- エラー --> ERR[error を返す] C -- 成功 --> E E -- ErrBadConn --> B E -- エラー --> ERR E -- 成功 --> F[Rows を返す<br>コネクション所有権が Rows に移動] subgraph userCode ["user"] K["(*sql.Rows).Next() で最後まで読むか、(*sql.Rows).Close()を呼ぶ"] end F --> K K --> G["(*sql.DB).putConn"] BadConn リトライの仕組み sql.DB には無効な接続に当たった場合に自動でリトライする仕組みがあります。 このリトライのトリガーとなるのが driver.ErrBadConn です。godocには次のように書かれています。 ErrBadConn should be returned by a driver to signal to the sql package that a driver.Conn is in a bad state (such as the server having earlier closed the connection) and the sql package should retry on a new connection. To prevent duplicate operations, ErrBadConn should NOT be returned if there's a possibility that the database server might have performed the operation. つまり、 driver.ErrBadConn はコネクションがDBサーバ側から切断された場合などに返り、sql package側でリトライすべきエラーであるということです。 実際にリトライを制御する DB.retry を見ていきます。 database/sql/sql.go L1572-1584: const maxBadConnRetries = 2 func (db *DB) retry(fn func(strategy connReuseStrategy) error) error { for i := int64(0); i < maxBadConnRetries; i++ { err := fn(cachedOrNewConn) // 👈 (1) // retry if err is driver.ErrBadConn if err == nil || !errors.Is(err, driver.ErrBadConn) { return err } } return fn(alwaysNewConn) // 👈 (2) } (1) 最大2回、cachedOrNewConn のstrategyで試行します。このstrategyではまずidleコネクションを再利用しようとします。 (2) 2回とも driver.ErrBadConn だった場合、3回目は alwaysNewConn strategyで新規のコネクション作成を強制します。 コネクションの取得: conn メソッド retry から呼ばれる conn メソッドが、プール内のidleコネクションか新規の接続を返します。このメソッドはかなり長いため、全体を3つのフェーズに分けて読んでいきます。 flowchart TD A[connメソッド呼び出し] --> B{freeConnに<br>idleコネクションがある} B -- Yes --> C{コネクションが期限切れ} C -- No --> D[コネクションを再利用] C -- Yes --> E[driver.ErrBadConnを返す → リトライ] B -- No --> F{コネクション数が最大(maxOpen)に<br>達している} F -- Yes --> G[connRequestsで待機] F -- No --> H[新規接続を作成] フェーズ1: idleコネクションがあれば再利用する database/sql/sql.go L1331-1354: // Prefer a free connection, if possible. last := len(db.freeConn) - 1 if strategy == cachedOrNewConn && last >= 0 { // Reuse the lowest idle time connection so we can close // connections which remain idle as soon as possible. conn := db.freeConn[last] // 👈 (1) db.freeConn = db.freeConn[:last] conn.inUse = true if conn.expired(lifetime) { // 👈 (2) db.maxLifetimeClosed++ db.mu.Unlock() conn.Close() return nil, driver.ErrBadConn } db.mu.Unlock() // Reset the session if required. if err := conn.resetSession(ctx); errors.Is(err, driver.ErrBadConn) { conn.Close() return nil, err } return conn, nil } (1) freeConn の末尾を取得しています(LIFO)。コメントにある通り、同時に必要とする数よりも多いコネクションがあった場合、余分なコネクションはidle状態のままcloseされていきます。 (2) 取得した接続が maxLifetime を超えていた場合は driver.ErrBadConn を返し、リトライの対象になります。 フェーズ2: 最大接続数に達している場合の待機 database/sql/sql.go L1358-1426: if db.maxOpen > 0 && db.numOpen >= db.maxOpen { req := make(chan connR
こんにちは!Core SRE の 織田 英吾です。 キャディはクラウドネイティブ会議にブーススポンサーとして協賛させていただきました。 この記事では2日間にわたるイベント期間中のブースの様子や聴講したセッションの感想をレポートします。 ブース紹介 まずは、キャディのブースについて紹介します! ブースでは、 私たちが取り組む製造業にまつわる課題を知っていただくための「30秒図面捜索チャレンジ」を実施したり、おすすめの Claude Code Skills を共有するボードを用意しました。 以下が実際に寄っていただいた皆さんに記載いただいたボードの写真です。おすすめ Claude Code Skills や使っている機能などをたくさん教えていただきました。Skillsを自作されている方も多くいて、コードのレビューやドキュメント作成が特に多かった印象です。私が知らなかったものも多くあり、試してみようかと思いました。 私たちが提供している「製造業AIデータプラットフォームCADDi」のアプリケーションである「製造業データ活用クラウドCADDi Drawer」のデモも行いました。 デモを通して、製造業出身者や所属の方以外にも、製造業が抱える課題に共感していただくことができました。私自身、キャディが取り組んでいることの重要さを再認識することができた機会になりました。 名古屋での開催ということもあり、製造業出身や所属の方も多く、現場の声やペインポイントを聞くことができ、私が学ばせていただく機会にもなり、とてもいい経験をすることができました。 イベント期間中、キャディのブースに立ち寄ってくださった皆さん、本当にありがとうございました! 聴講したセッションの感想 次に、私や他のメンバーが聴講させていただいたセッションの感想を簡潔にまとめます。 「100マイクロサービスのTerraform/Kubernetes管理地獄から抜け出すためのAI活用術」 株式会社LegalOn Technologies の Ishigaki さんと Wada さんによる発表です。 本セッションでは、マイクロサービスの増加に伴って Kubernetes / Terraform 管理や設定変更、レビュー対応が大きな運用負荷になるという課題が紹介されました。その解決策として、定型的な変更作業は仕様化・ツール化し、AIエージェントを活用してサービス単位で並列に展開するアプローチが示されており、とても参考になりました。 特に印象的だったのは、AI にすべてを任せるのではなく、社内ルールやガイドラインを AI が参照しやすい形に整備し、人間が最終判断を担う設計にしていた点です。これにより、大量の PR 作成やレビュー支援、移行作業を効率化しながら、運用品質を保つ工夫がなされていました。 AI 活用の前提として、業務プロセスやナレッジを構造化しておくことの重要性を感じるセッションでした。(Core SRE 織田) 登壇資料: https://speakerdeck.com/markie1009/kubernetesguan-li-di-yu-karaba-kechu-sutamenoaihuo-yong-shu 「そのSLO99.9%、本当に必要ですか? 〜優先度付きSLOによる責任共有の設計思想〜」 株式会社TopotalのVTRyoさんによる発表を聴講しました。以前、SREKaigiでもVTRyoさんの発表を聞いたことがあり、とても参考になったので今回も楽しみにしていました。 本発表では、SREチームはDevチームのEnablingを突き詰めていくと、横断で複数のサービスを見ていくことが増えていくことで、運用しているサービスで何が起きているのか分からなくなる可能性が高くなりやすいと話されてました。実際に、VTRyoさんは自分たちはSREとしてサービスに価値を生み出していないのではないかと葛藤が生じたそうです。 そこで紹介されていたのが Product-Focused Reliability for SRE (PER)という考え方でした。自分は初めて聞いたのですが、SREチームが限られたリソースを有効活用するために、ビジネスやユーザーにとって最も重要なことに焦点を当て、優先順位をつけて活動することだそうです。 確かに、従来のSREはインフラやサービスそのものの安定稼働に責務を持つため、自然とDevはアプリケーション、SREはインフラという得意領域で境界が分かれてしまいやすいです。 PERの考え方は、SREの関心ごとをサービスからプロダクトの重要機能に移し、プロダクト中心にSLOを考えていくため、よりユーザーやビジネスの理解が重要になってきます。自分自身、SREが信頼性という指標を追っているのはユーザーの満足度とビジネスの成功度を上げるためだと思っているので、PERの考え方はとてもしっくりきました。 また、SREは日々のアラート対応に追われがちではありますが、それは本当にユーザーの離脱や解約につながっているのか?実は過剰な信頼性を追っているだけで、根本的な問題は機能不足なのではないか?、本セッションの問いとして投げかけられていた「そのSLO99.9%は本当に必要なのか」は定期的にSLOを見直す際に立ち返りたい問いだなと思いました。(Drawer SRE 松嶋) 登壇資料:https://speakerdeck.com/vtryo/is-that-99-dot-9-percent-slo-really-necessary-design-philosophy-of-shared-responsibility-through-prioritized-slos 登壇レポート キャディからCore SREチームリーダーの小林明斗が登壇しました。 セッション名:生成AI時代に信頼性をどう保ち続けるか - Policy as Codeの実践 概要:生成AIによりコードやIaCの変更量が増える中、人手のレビューやチェックリストだけでは信頼性リスクを見落としやすくなっています。本セッションで は、組織ポリシーのうち静的に評価できる項目をPolicy as CodeとしてCIや実環境に組み込み、人の認知に依存しすぎず信頼性を維持する設計を紹介し、ConftestやKyvernoの実装例を交え、誤検知対応、ポリシー強度、既存リソース是正など、形骸化しないガードレール運用の工夫を共有しました。 開発組織の変遷や SRE の歩みから入り Policy as Code の紹介、実装方法の共有がされていました。私はまだ入社3か月目なのもあり、キャディの私でも学べるセッションでした。 会場の席はほぼ埋まり、立ち見がでるほどの盛況ぶりで約100名の方が参加されていました! SNSでも「Policy as Code が気になっている」、「PRC のレビューが大変なのわかる」、「Policy 違反1,684件すべて修正完了はすごい」などたくさんの反響をいただきました。キャディから登壇者を出せてとても良かったです。 Policy 違反の Report に「Policy の詳細や OK/NG の例が記載された wiki」へのリンクを入れているらしい。これを見ることで Policy 違反が発生した時の開発者側での修正をやりやすくしてる感じっぽい。よさそう。#cloudnativekaigi #cloudnativekaigi_b— こたつ&&みかん (@kota2and3kan) 2026年5月15日 x.com 1684件すべて修正完了すごすぎる#cloudnativekaigi #cloudnativekaigi_b— yuki / ほにゃにゃ (@honyanyas) 2026年5月15日 x.com うおー、ポリシーに対するテストコード書けるのめっちゃいい。#cloudnativekaigi #cloudnativekaigi_b— たか (@_nogtk_) 2026年5月15日 x.com 登壇資料: speakerdeck.com 終わりに ブースへの来場・セッション聴講・懇親会と充実した2日間でした。クラウドネイティブな技術の進化は非常に速いですが、今回学んだ知見を業務に活かしていきたいと思います。 スピーカーの皆さん、参加者の皆さん、クラウドネイティブ会議の運営の皆さん、素晴らしいイベントをありがとうございました。今後もキャディは、技術的な挑戦や課題解決の知見を発信し、エンジニアコミュニティへの貢献を続けていきます。今後のイベントでもお会いできるのを楽しみにしています!
プログラミング言語を選ぶとき、開発効率や学習コスト、エコシステムの充実度など、考慮すべき要素は多岐にわたります。OSS パッケージを標的にしたサプライチェーン攻撃の増加や脆弱性に対するゼロデイ攻撃の発生といった状況を踏まえると、「アプリケーションが依存するライブラリをどう管理するか」も技術選定の重要な軸となっています。 私の所属する Control Plane 部の認証認可グループでは、2025年から、 Go の利用を本格化しました。技術選定時に挙げられていたメリットの一つが、まさに依存管理にあります。 本記事では、私たちが Go を選んだ背景と、1年間実際に開発してみて分かったことを振り返ります。 なぜ Go を選んだか 対象システムの特性 キャディの主流言語: TypeScript Go の特徴 1年間やってみてどうだったか 良かった点 メンテナンスコストの低さ AIコーディングとの相性 苦労した点 ライブラリに頼らないことのトレードオフ Go の慣習に慣れるまでのコスト 期待と現実のギャップ 採用した技術スタック まとめ なぜ Go を選んだか 対象システムの特性 キャディでは、製造業AIデータプラットフォームCADDi の基盤として「Control Plane」と呼ばれるシステム群を開発しています。Control Plane は、テナント管理や認証認可など、アプリケーションの機能から独立した管理層を担うシステムです。詳しくはこちらの記事で紹介しています。 開発言語を選ぶにあたって重要だったのは、Control Plane が持つ特性です。Control Plane は、1つの大きなサービスではなく、認証ゲートウェイ、トークン発行、テナント管理、認可といった、それぞれが明確な責務を持つ小さなサービスの集合体です。各サービスはシンプルな機能を提供する一方で、プラットフォーム基盤としての信頼性が求められます。 つまり、「小さなサービスを多数、手堅く作れること」が言語選定において重要な要件でした。 キャディの主流言語: TypeScript キャディのバックエンドでは TypeScript が主流です。TypeScript の開発エコシステムの充実度は群を抜いています。 また、フロントエンドとバックエンドを同じ言語で統一できるのも大きなメリットです。 一方で、依存管理の観点では、ライブラリの数が増えがちで、依存管理のコストが増大します。 Go の特徴 Go は Web API の構築に向いた言語です。標準ライブラリもサードパーティのライブラリもシンプルなものが多く、必要なパーツを組み合わせて開発するようなスタイルを取りやすいです。 こうした特性が、小さなサービスを数多く開発・運用する Control Plane とよくマッチすると判断しました。 1年間やってみてどうだったか 良かった点 メンテナンスコストの低さ Go を採用して最も良かったと感じているのは、メンテナンスコストの低さです。 Control Plane のアプリケーションは、一度作った後は数ヶ月単位で改修が入らないことも珍しくありません。そのような場合でも、セキュリティアップデートは定期的に適用する必要があります。このような作業は1つ1つは小さくても、積み重なると大きな負担になります。 Control Plane には、Go採用以前から開発・運用されている TypeScript(NestJS)アプリケーションがありますが、これと比較して Go アプリケーションはセキュリティアップデートが必要になる頻度が低いと感じています(およそ1/5程度)。 AIコーディングとの相性 Claude Code や Devin を用いたAIコーディングはキャディ社内でも主流となっていますが、構文がシンプルで書き手による差異が生じづらい Go は、AIが読み書きしやすいという点でもメリットがあります。また、コードフォーマッター(go fmt)やテストランナー(go test)が標準のツールチェインに組み込まれていて、かつ、高速に動作するという点も Go の強みです。 苦労した点 ライブラリに頼らないことのトレードオフ Go では依存ライブラリを少なく保って開発することができます。これは裏を返せば、基本的な処理を自前で実装する必要があるということです。例えば、以下のコードではサーバのグレースフルシャットダウンを行なっています。 ctx, stop := signal.NotifyContext(ctx, os.Interrupt, syscall.SIGTERM) defer stop() go func() { // e は Echo インスタンス if err := e.Start(":" + c.Port); err != nil && !errors.Is(err, http.ErrServerClosed) { slog.Error(fmt.Sprintf("error occurred when starting the server: %v", err)) } }() ... <-ctx.Done() ctx, cancel := context.WithTimeout(ctx, 10*time.Second) defer cancel() if err := e.Shutdown(ctx); err != nil { slog.Error(fmt.Sprintf("error occurred when shutting down the server: %v", err)) } このような、他の言語であればフレームワークが担ってくれるような処理も自分たちで書く必要がありました*1。 依存の少なさと自前実装の手間は、トレードオフの関係にあります。私たちはこのトレードオフを意図的に受け入れました。長期的な運用コストの低さのほうが、初期の実装コストより重要だと判断したからです。 Go の慣習に慣れるまでのコスト チームメンバーの多くは Go での開発経験がそれほど多くありませんでした。Go 特有の慣習やイディオム ── たとえばエラーハンドリングの作法や、パッケージ構成の考え方 ── に慣れるまでには時間がかかりました。言語仕様の学習コストは低くても、「Go らしいコード」がわかるようになるまでには別のハードルがあります。 期待と現実のギャップ Go の採用にあたっては、goroutine による並行処理のしやすさにも期待していました。しかし、現時点では並行処理を積極的に活用する場面はまだありません。現在の Control Plane のサービス群は、典型的なリクエスト/レスポンス型の API が中心であり、goroutine の恩恵を実感する局面がまだ訪れていないのが実情です。 今後、バッチ処理や非同期ワーカーのようなワークロードが増えてきた際に、この特性が活きてくると考えています。 採用した技術スタック Goコミュニティにおいて実績のある技術スタックの中で、薄めのものを選定しました。 通信: Connect フレームワーク: Echo ※アプリケーションによってはフレームワーク無しの場合も ORM: Bun JWT: lestrrat-go/jwx いずれも優れたライブラリですが、特に Connect は素の gRPC に比べてデバッグしやすく、重宝しています。 まとめ Go は万能な言語ではありません。例えば、Go の特徴の一つである明示的なエラー処理は、コードの冗長さと表裏一体です。しかし、小さなサービスを数多く開発・運用する Control Plane においては、Go のシンプルさが強みになりました。 技術選定は常に文脈次第であり、私たちの経験がそのまま他の組織に当てはまるとは限りません。それでも、「Control Planeを Go で作る」という選択は、私たちにとって正しかったと考えています。 今後も Go を活用しながら Control Plane を拡充し、CADDi のマルチテナントプラットフォームをより堅牢なものにしていきます。 Go を使った Control Plane の開発に興味がある方は、ぜひ以下のページもご覧ください。 caddi.tech tech.caddi.com *1:このサンプルコードは Echo v4 です。Echo v5 ではフレームワークにグレースフルシャットダウン機能が搭載されています。
はじめに こんにちは。キャディ株式会社でソフトウェアエンジニアとして製造業AI見積クラウドCADDi Quoteの開発を担当している松田です。 私たちのチームでは、新機能の開発時など、プロダクトに新しい概念を導入する際には、開発者のみならずPdMやQAといった他職種を交えて議論し、ユビキタス言語を定義しています。 ユビキタス言語とは、ドメイン駆動設計においてビジネスと設計の橋渡しをする共通言語です。ドメインエキスパートとエンジニアが、会話・コード・ドキュメントに渡って同じ言葉を使うことで、ビジネスと設計の間の翻訳コストの発生を防ぐことが目的です。 出典:エリック・エヴァンス著、今関剛監訳、和智右桂、牧野祐子訳『エリック・エヴァンスのドメイン駆動設計』翔泳社(2011) p.34より一部改変して筆者作成 私たちがこれまでにユビキタス言語として定義した用語の多くは、チームの業務において実際に用いられ、生きた言葉として価値を発揮しています。 その一方で、定義した用語が実際の議論やドキュメントの中でうまく定着せず、形骸化してしまうケースも経験しています。使われないユビキタス言語はなぜ生まれてしまうのでしょうか? この記事では、こうした経験をもとに、使われないユビキタス言語を生んでしまう7つのアンチパターンを紹介します。これらのアンチパターンは、「誰を巻き込むか」「どう考えるか」「定義後の運用」の3つの観点にまたがりますが、網羅的なものではなく、私が実際の運用の中で失敗や悩みを抱えたポイントに重点を置いています。ユビキタス言語という概念は知っているが、実践の中でつまずきを感じている方に読んでいただければと思います。 はじめに アンチパターン1: エンジニアだけで決めてしまう 問題 なぜ起きるか どうすればいいか アンチパターン2: ドメインエキスパートという概念に固執してしまう 問題 なぜ起きるか どうすればいいか アンチパターン3: ドメインエキスパートの言葉を無批判に受け入れてしまう 問題 なぜ起きるか どうすればいいか アンチパターン4: 英語名をAIに相談せずに決めてしまう 問題 どうすればいいか アンチパターン5: 理詰めで考えてしまう 問題 なぜ起きるか どうすればいいか アンチパターン6: 声に出した時の自然さを軽視してしまう 問題 なぜ起きるか どうすればいいか アンチパターン7: ユビキタス言語辞書の作成が目的化してしまう 問題 なぜ起きるか どうすればいいか おわりに アンチパターン1: エンジニアだけで決めてしまう 問題 ユビキタス言語の定義からして当たり前ですが、エンジニアだけで議論するのはアンチパターンです。私たちのチームではエンジニアもお客様を訪問したり、セールス、カスタマーサクセス、PdMといった他職種のお客様訪問レポートを読むなどして顧客理解に努めていますが、顧客理解という点においてPdMにはかないません。エンジニアだけで議論すると、PdMなどの他職種が持つ貴重な知見を設計に反映する機会を失うことになります。また、エンジニアはどうしても実装をイメージしながら議論してしまうので、用語が実装に引きずられがちにもなります。 この場合、PdMからするとユビキタス言語の存在自体を認識していないことになるので、エンジニアだけがユビキタス言語を使い、PdMは別の言葉でエンジニアと会話する状態になるでしょう。 なぜ起きるか 背景には、いくつかの思い込みがあります。 ひとつは、遠慮です。PdMなどの他職種は忙しいので、設計寄りの議論に巻き込むのは申し訳ないという気遣いが働くことがあります。 また、説明コスト回避の心理も働きます。ユビキタス言語という概念を他職種に説明しながら議論するのを面倒に感じ、エンジニアだけで決めてしまいたくなることがあります。 どうすればいいか タイムボックスを区切った上で、PdMなどの開発者以外のメンバーを集め、効率よく議論しましょう。 そのために有効な手法がイベントストーミングです。イベントストーミングは、複雑な業務ドメインを参加者のコラボレーションにより探索するワークショップ形式の手法です。参加者が付箋を出し合い、それらを構造化する作業を通じて、ドメインの全体像が見えてきます。 参加者がそれぞれの理解に基づいて付箋を貼る中で、同じ概念が人によって別の言葉で表現されている状況が可視化されます。メンバー間の言葉のずれを発見し、用語の統一を図る中で、自然とユビキタス言語が定義されていきます。 イベントストーミングの良いところは、ドメイン駆動設計やユビキタス言語といった概念の理解が薄いメンバーであっても、ファシリテーターの指示をステップバイステップでこなしながらワークに参加できるところです。ファシリテーターにとっても、ワークの進め方を一度身につけてしまえば、参加者に対する説明コストはそれほどかかりません。 また、イベントストーミングを終えると、ユビキタス言語だけでなく、要件やドメインモデルの全体像も見えてきます。要件に関する認識合わせの中で自然とユビキタス言語も整理される形となるため、時間効率も良いと言えます。 イベントストーミングについては、キャディのTech Blogでも紹介されていますので、ぜひご覧ください。 caddi.tech アンチパターン2: ドメインエキスパートという概念に固執してしまう アンチパターン1はエンジニアだけで閉じてしまうという問題でした。これから議論するのはその逆方向の問題です。理想のドメインエキスパートがいないなら、ユビキタス言語の議論をしても意味がないという心理に陥るケースです。 問題 ドメイン駆動設計では、ドメインエキスパートとの協働がユビキタス言語の前提とされています。 ドメインエキスパートとは誰なのでしょうか? 通常は、そのソフトウェアを利用するユーザーとなります。私たちキャディで言えば、製造業の現場で働く方々、とりわけ、業務全体を俯瞰し、業務プロセスの設計や変革をリードしている方々です。 そうすると、ユビキタス言語を定義する際には、実際のお客様を会議にお招きし、議論をする必要があるのでしょうか? 多くの場合、それは非現実的です。 このような場合に、ドメインエキスパートを呼べないのであれば、ユビキタス言語の定義をしても意味がないのでは? という議論が発生したり、悩みを抱えてしまうことがあります。これが2つめのアンチパターンです。 なぜ起きるか EvansのDDD本では、ドメインエキスパートと開発者が継続的に対話しながらユビキタス言語を洗練させていく様子が描かれています。しかし現実には、ドメインエキスパートは自身の担当業務で多忙であり、ソフトウェア開発のためだけに継続的な時間を確保してもらうのは困難です。 特にSaaSの場合、この難しさはより顕著です。SaaSにおいてサービス提供者と顧客は一対多の関係にあり、顧客の要望がすべてプロダクトに反映されるわけではありません。提示した意見がそのままプロダクトに反映されるならまだしも、ただ設計を洗練させるためだけに貴重な時間を割くのは、ほとんどのお客様にとって難しいでしょう。 どうすればいいか ドメインエキスパートという概念に固執するのはやめ、現実的な妥協をしましょう。 現時点で顧客の言葉遣いをよく把握している社内メンバーを探し、その人を知識の源泉として活用しましょう。私たちのチームの場合、幅広い顧客と日常的に接し、業界全体の課題を俯瞰的に捉えているPdMがドメインエキスパート役として最適なことが多いと考えています。教科書通りのドメインエキスパートを求めるのではなく、現実的にアクセスできる範囲内でドメイン知識を吸収しましょう。 アンチパターン3: ドメインエキスパートの言葉を無批判に受け入れてしまう 問題 ユビキタス言語を議論する際、PdMに「お客様はこれを何と呼んでるんですか?」と質問することがあります。ここで、議論に疲れていると、お客様が使っている言葉をそのまま採用したくなってしまう瞬間があります。 しかし、お客様の個別の業務の文脈においては意味が通じる言葉であっても、私たちが作ろうとするプロダクトの文脈にそのまま持ち込むと具体性が高すぎたり、逆に意味が曖昧であったりすることがあります。 私たちのチームでも、製造業の調達業務においてサプライヤー企業からバイヤー企業に対して提出されるさまざまな種類の見積資料をどう呼ぶかを議論した際に、この点が問題となりました。PdMに、リリース後最初の想定ユーザーとなるお客様がその資料を何と呼んでいるのかを質問したところ、お客様は単に「見積書」と呼んでいるとのことでした。そのお客様にとっては、さまざまな種類の見積資料のうち、「見積書」と言えばこれを指す、というのが暗黙の合意となっていたのでしょう。しかし、さまざまな企業のお客様を対象とするSaaSプロダクトの文脈においては、「見積書」という表現は曖昧であり、私たちが開発している機能のスコープとは全く性質の異なる資料までもがそこに含まれてしまう懸念がありました。 結局、私たちは、お客様が実際にそう呼んでいるかではなく、業務慣習の異なる他のお客様や、開発者も含めて誤解が生じないことを優先し、資料の内容が明確に分かる別の用語を定義することになりました。複数企業のお客様を対象とするプロダクトとして、曖昧性を避けることを優先した選択でした。 なぜ起きるか ユビキタス言語という概念を、ユーザーや非エンジニアが用いる言葉をそのまま使用して開発することだと思い込んでいることが原因です。 実際には、ユビキタス言語は、ドメインエキスパートと開発者の双方が批判的意見を提示しながら洗練させるものです。このことは、Evans本でも以下のように明記されています。 ドメインエキスパートは、ドメインについての理解を伝えるには使いにくかったり不適切だったりする用語や構造に意義を唱えるべきであり、開発者は、設計を妨害することになるあいまいさや不整合に目を光らせるべきである。 出典:エリック・エヴァンス著、今関剛監訳、和智右桂、牧野祐子訳『エリック・エヴァンスのドメイン駆動設計』翔泳社(2011) p.27 どうすればいいか ドメインエキスパートからのインプットを、ソフトウェア設計上の概念として利用可能な抽象度に洗練させる責任は開発者にあることを認識しましょう。ドメインエキスパートが提示した用語を使って設計やコーディングを行うイメージが湧くかを常に想像し、違和感があれば対案を提示しましょう。 開発者側から対案を提示する際には、その対案に対して開発者以外の参加者が納得感を持っているかどうかにも目を配りましょう。往々にして発生するのは、議論の場ではユビキタス言語が合意されたものの、結局、開発者以外のメンバーは独自の用語を使い続けているという状況です。言葉が揃っていないことで苦労するのは結局のところ開発者なので、開発者以外のメンバーも含めてちゃんと納得感を持って使ってもらえそうかには注意を払う必要があります。 アンチパターン4: 英語名をAIに相談せずに決めてしまう 問題 DDD本を執筆した当時のEric Evansも想像していなかったでしょうが、現代のソフトウェア開発では、ドメインエキスパートや開発者と並んで、AIもユビキタス言語の策定の参加者となり得ます。 とりわけAIが活躍するのは、英語名の提案です。日本語圏でドメイン駆動設計を実践する際、現実的な妥協として、ユビキタス言語は日英併記で定義し、会話やドキュメントといった自然言語では日本語名を、ソースコードでは英語名を用いるといった手法が取られることが多いと思います。 日本語話者が英語名を定義する際、日本語を直訳したような英語名となり、英語として存在しない、あるいはニュアンスが意図と異なる表現になってしまうことがあります。私がチームの一員として関わった例で言えば、生成AIの登場以前の話ではありますが、「受注」という概念の英語名を Received order としてしまったことがありました。軽くインターネット検索すると分かりますが、このような表現は英語として通常用いられないようです。 また、ボキャブラリーが貧弱であるがゆえに FooData や BarInformation といった曖昧で意味の薄い名称となってしまうこともあります。 英語名の定義の際に以上のような問題を回避するには、AIを活用することが有効です。 どうすればいいか 英語名に自信がない場合はAIに提案してもらいましょう。 英語名をAIに考えてもらう上で重要なのは、日本語名を単語ベースで渡して翻訳させるのではなく、日本語名とその意味合いの説明文(加えて、既に決まっている英語名があればそれも)を一覧化し、全体を見せた上で日本語名に対応する英語名を提案させることです。こうすることで、単なる直訳ではなく、用語のニュアンスや用語間の関連性も踏まえた上での回答が期待できます。 また、複数の候補を提案させ、それぞれについて、ニュアンスや英語としての自然さを解説させた上で、どれを採用するか人間が選ぶべきです。決定する際は、インターネット検索により、その単語が実社会で意図したとおりのニュアンスで使用されているかを確認するのも忘れないようにしましょう。これにより、AIが提案した英語名をそのまま採用したら、実は日本語名とニュアンスがずれていた、といった事故を防ぐことができます。 アンチパターン5: 理詰めで考えてしまう ここまで取り上げてきたアンチパターンは、誰を議論に巻き込むかという問題でした。続く2つのアンチパターンは視点を変え、どう考えるかという軸から、使われない用語が生まれる構造を見ていきます。 問題 ユビキタス言語を定義する際、論理的な整合性を追い求めるあまり、聞いた瞬間に意味が伝わりにくい用語が生まれることがあります。このような用語は、議論の参加者が最初に提示した用語がどれもぴたりとはまらず、ああでもないこうでもないと色々な別案を出していくうちに発生します。 用語の意味を論理的に説明して理解できるのであれば、一見問題のないように見えます。しかし、長々と説明しないと意味が伝わらない用語は、会話の中で使うたびに説明のコストが発生します。結果として、メンバーは無意識のうちにその用語を避けるようになり、日常の議論には登場しない「公式用語」として辞書に残るだけの形骸化したユビキタス言語になっていきます。 なぜ起きるか ドメインエキスパートの言葉遣いを観察することから出発するのではなく、演繹的に用語を定義しようとしているのが原因です。 母国語について考えれば分かるように、自然言語は、演繹的に定義されたものではありません。そうではなく、ある言葉が使われているという事実が先にあり、そこから帰納的に文法や言葉の意味が定義されているわけです。 自然言語のこういった性質を踏まえれば、ユビキタス言語を定義する際も、ある言葉が自然に使われているという事実を重視すべきです。しかしながら、自然に使われている用語を設計にふさわしい抽象度に洗練させていく中で、理論先行に陥ってしまうことがあります。 どうすればいいか 前提として、論理的に用語を定義することを全否定するわけではありません。ソフトウェアは人工的な創造物であり、現実世界に対応物のない抽象的な概念を扱わざるをえない場合があります。自然に使われている業務の言葉だけでは表現できず、抽象的な論理から出発して命名せざるを得ない場面は一定あります。 ですが、まず優先すべきは、実際の会話の中で自然に飛び交っている言葉から出発することです。ドメインエキスパートやPdMが議論の中で無意識にある言葉を使っているなら、その言葉が直感的に選ばれたことには何かしらの理由があります。理詰めで独自の用語を作り出す前に、ある言葉が直感的に選ば
製造業データ活用クラウド CADDi Drawerで SREを担当している佐藤です。 組織編成でCADDi Drawer専任のSREになったことを機に、長らく後回しにしていたDatadog MonitorのTerraform構成の再設計に取り組みました。複数チームの監視設定が単一リソースに混在しOwnershipが不明確なため、各チームが自律的に改善に踏み出せない状態でした。 本記事ではこの課題をOwnership単位のモジュール設計で解消した経緯と学びについて紹介します。 監視設定が抱える課題 単一リソースに積み上がった監視設定 Ownershipの不在によるアラート改善の停滞 Ownershipを明確化したモジュール設計 監視ロジックとOwner情報の分離 Owner情報の一元管理 ふりかえり よかったこと 苦労したこと 移行の現状と今後 おわりに 監視設定が抱える課題 キャディでは監視基盤にDatadogを採用しており、Datadog Monitorはすべて監視用の単一リポジトリでTerraform管理しています。 歴史的経緯により、監視すべき内容については検討できていましたが、Terraformモジュールとしてどう実装するかは整理されていませんでした。 このためDatadog MonitorのTerraform実装には以下のような課題を抱えていました。 単一リソースに積み上がった監視設定 Terraformモジュールの設計が難しい問題です。適切な抽象化の粒度を見極め、再利用可能な形でモジュール化するには、対象サービスや組織の全体像が見えていることが前提になります。 組織・サービスが急成長していた時期には監視対象が次々と増え、その都度設計を見直す余裕はありませんでした。この結果、再利用可能な形でのモジュール化は採用せず、既存の設定を拡張する形で対応し続けていました。 具体的には、監視対象のサービスが増えるたびに新規のモジュールやモニターを構築することはせず、既存の単一のDatadog Monitorに対象サービスを追加し続けていました。 Terraformのdatadog_monitorリソースでは監視条件をquery属性の文字列として定義しますが、サービスが増えるたびにOR条件を追記し続けた結果、以下のような状態になっていました。 logs( "status:error (service:SERVICE_A OR (service:SERVICE_B -message:\"noisy message\") OR service:SERVICE_C OR service:SERVICE_D OR (service:SERVICE_E env:production))" ).index("*").rollup("count").last("5m") > 100 組織規模が小さく、サービス数が2-3個の場合やサービス固有の除外条件が含まれていない場合にはこれでも上手くいきました。 しかし、サービス数が増え、サービスごとの監視条件が混在するようになると、とたんにコードからどのサービスがどの条件を持つのか読み解くことが困難な状態になりました。 また、問題の兆候は認識していましたが、全サービスに影響する監視設定の一括整備に踏み切るきっかけがなく、他のタスクを優先していました。 Ownershipの不在によるアラート改善の停滞 この課題に向き合うきっかけになったのが2025年に実施した組織編成です。 それまで全社横断でインフラ運用を担っていたSREチームから、サービス・プロダクトごとにSREが配置される形になりました。 私はCADDi Drawer専任のSREとして新たな役割を担うことになりました。 CADDi Drawerの信頼性向上に絞った視点で改めて監視設定を見ると、Datadog Monitorの複雑化に関する問題が浮き彫りになりました。 複数サービスの設定が混在したクエリへの変更は、git diff や terraform planでも影響範囲が掴みにくい状態でした。 Ownerの異なるチームが同じリソースを共有しているため、「他チームに影響しないか」という懸念が変更の腰を重くし、細かな改善がどんどん後回しになっていました。 クエリ実装の複雑さ以上に懸念になっていたのがSlackのアラート通知先の混在でした。 Datadog MonitorのSlack通知チャンネルの動的切り替えはクエリ条件以上に複雑になるため、Datadog Monitorごとに単一のSlackチャンネルに通知していました。 その結果、複数チームのアラートが同じSlackチャンネルに通知され、関係のないアラートであっても内容を都度確認する割り込みコストが発生していました。 SREチームで議論した結果、これらの問題の根本は、どのチームがどのモニターに責任を持つかが不明確というOwnershipの欠如にあると判断しました。 複数チームのサービスが1つのdatadog_monitorリソースを共有しているため、変更が他チームに影響するかどうかを確認せずに修正できません。 自チームの判断だけで変更に踏み切れず、誰も主体的に手を入れられない状態になっていました。 Ownershipを明確化したモジュール設計 これらの課題を解決し、Datadog MonitorのOwnershipを明確化するため、監視項目のTerraformモジュールを設計して移行しました。 監視ロジックとOwner情報の分離 従来の構成では、通知先や担当チームといったOwner情報がモジュール内に直接書き込まれていました。Owner情報が埋め込まれた構造では、呼び出す側がチームごとの情報を渡す設計にはできません。 具体的には以下のような構成でした。 terraform/ ├── modules/ │ └── monitor/ │ └── shared_monitors/ # 全サービス・全チームの監視設定が混在 └── environments/ ├── <google_project>-development/ │ └── main.tf # shared_monitorsモジュールを呼び出す └── <google_project>-production/ └── main.tf # shared_monitorsモジュールを呼び出す terraform/environments/<environment>/main.tf が shared_monitors モジュールを呼び出す構成です。このモジュールに全サービス・全チームの監視設定が集中していたことが、前述の問題の原因でした。 そこでこのモジュールを解体し、監視ロジックの情報に限定したモジュールを作成した上で対象サービス・通知先・担当チームといったOwner情報は呼び出し元から変数として渡す設計にしました。 具体的には以下のような構成です。 terraform/ ├── main.tf # environments をモジュールとして呼び出す ├── teams.tf # チーム情報を一元定義 ├── modules/ │ └── common/ │ ├── cloudrun-service/ # Cloud Run監視モジュール │ ├── alloydb/ # AlloyDB監視モジュール │ └── ... └── environments/ └── <google_project>-production/ └── service-a/ ├── locals.tf # 通知先・Owner情報を定義 └── main.tf # 各監視モジュールをOwner情報と共に呼び出す 監視項目の種類( cloudrun-service など)ごとにモジュールを定義し、 terraform/environments/<environment>/<service>/ というサービス単位のディレクトリから呼び出す構成です。 モジュール自体は監視対象のプロダクトを知らず、呼び出すディレクトリごとにOwnershipが決まるため、「誰がどのアラートに責任を持つか」がディレクトリ構造として表れます。 各モジュールに対するOwner情報を変数として以下のように設定することで、サービスごと・モニターごとのOwnershipを明確化できました。 # environments/project-production/service-a/main.tf module "cloudrun_service_monitor" { source = "../../../modules/common/cloudrun-service" service_name = "service-a" env = "production" owner_teams = local.owner_teams mention_slack_alert_ch = local.mention_slack_alert_ch mention_oncall = local.mention_oncall } この設計により、変更の影響範囲が自チームのスコープに収まり、他チームを巻き込まずに監視設定を改善できるようになります。移行後はこの設計方針をドキュメントにまとめ、社内で共有しました。設計を標準として明文化することで、チーム間の設計認識を統一し、今後の監視設定追加・変更にも一貫したOwnership管理を維持できるようにしました。 Owner情報の一元管理 監視対象ごとにDatadog Monitorが分割されることで、移行後はモニターの総数が増えます。多数のモニターを管理するにはタグ情報が欠かせないため、各Datadog Monitorへのタグ付けを徹底しました。 タグ自体は従来から設計に組み込まれていましたが、今回の移行を機に全Datadog Monitorへの適用を強化しました。 タグ情報の適用を強化する上で、通知先Slackチャンネル、担当チーム名といったOwner情報を各サービスの設定に個別に書き込むと、組織変更のたびに全サービスのファイルを修正する必要があります。また、複数の場所に分散して書くとチーム名やSlackメンションの表記ゆれも起きやすくなります。 そこで、チーム情報を teams.tf に一元定義しました。Datadog Teamリソースもここで合わせて作成します。 # teams.tf locals { owner_teams = { team_alpha = { name = "Dept A > Group A > Team Alpha" mention = "<!subteam^XXXXX>" # @team-alpha tag = "team:team_alpha" } team_beta = { name = "Dept B > Group B > Team Beta" mention = "<!subteam^YYYYY>" # @team-beta tag = "team:team_beta" } } } resource "datadog_team" "teams" { for_each = local.owner_teams name = each.value.name handle = each.key } 組織変更が起きた場合も teams.tf の修正だけで全サービスに反映されます。 ふりかえり よかったこと サービスごとに通知先を変更できるようになったことがメリットとしては大きいです。 チームごとにSlackチャンネルを切り分け、CADDi Drawer 関連のアラートのみに集中できる環境を整えたことで、業務への割り込みを最小限に抑えることが可能になりました。 datadog_monitor がOwnerごとに分割されたことで、PRレビューの負荷も下がり、自チームの判断だけで変更をマージできるようになりました。 モジュール化に伴い監視条件を変数として宣言的に記述する構成になったことで、各サービスの監視条件を個別に把握できるようになった点も嬉しいポイントです。 苦労したこと 最も苦労したのはDatadog Monitor移行に伴うPRレビューです。Datadog Monitorリソースの分割には destroy / create が伴う上、クエリの整理も必要だったため、大量の terraform plan の差分が発生しました。これをすべて人手で確認しきることは難しく、想定以上にレビューに時間がかかってしまいました。 今回は利用できませんでしたが、AIを活用したリソース移行の半自動化や設定差分の検出など、効率化の仕組みを今後の大規模移行に活かしたいと考えています。 移行の現状と今後 作業リソースやスケジュールの都合上、通知頻度の高いコンポーネントの移行を優先して完了させました。旧モジュールへの新規追加を禁止することでこれ以上の複雑化を防ぎつつ、通知先のチャンネル分離も継続して進めています。一方、一部のDatadog Monitorはまだ解体する必要があるものが残っており、引き続き整備を進める予定です。 設計方針はドキュメントとして共有しているものの、まだ十分に浸透できているとは言えません。設計の定着にはドキュメントだけでなく、ポリシーチェックをCIに組み込むような仕組みも必要だと感じています。今後は組織横断チームと連携しながら検討を進めていきます。 おわりに 組織の自律性を高める上で、監視設定のOwnershipも合わせて整備することが重要だと実感しました。Ownershipが明確であれば、自チームの判断だけで監視設定を改善でき、変更のスピードも上がります。 今回は組織編成がきっかけとなり、長らく後回しにしていた構成の再設計に取り組むことができました。 普段から監視設定を気軽に修正できる状態を維持し、組織や役割が変化した際には監視のOwnershipが適切に機能しているかを継続的に見直していきます。
機械学習エンジニアの竹本です。普段は、製造業の膨大なドキュメントを対象にしたRetrieval-Augmented Generation(RAG)の検証に取り組んでおり、その一環として社内検証向けのベンチマークデータセットを作成しました。同じ課題を抱えるエンジニアの方の参考になればと思い、本記事を書きました。 TL;DR 作りたい。でも動き出せなかった 当時の思い込みと、今の自分からの答え合わせ 1. LLM-as-a-Judgeに頼るしかないと思っていた 当時の状況 データセットを作ってみると 2. データセットを作れるのか? そしてCSやユーザーに頼っていいのか? 当時の状況 CSに相談してみると 3. 時間も工数もかかるのに、そこまでしてやる価値があるのか 当時の状況 データセットを作ったら検証速度が5倍に向上 作る過程で得られた想定外の価値 まとめ TL;DR 最初は、コストや体制の壁があり作成に動き出せなかった 制約を取っ払って考え、「作りたい」と声に出したら、動き出せた ベンチマークデータセットを作って、検証スピードが約5倍になった 作る過程そのものも、ユーザー理解を深めるきっかけになった 作りたい。でも動き出せなかった RAGの検証を進める中で、製造業の深いドメイン知識や個社特有の知識が求められる領域では、LLMによる評価だけでは精度を正しく判断しきれないと感じるようになりました。評価用のベンチマークデータセットが必要だと分かっていたものの、作成にかかる時間的コストの大きさと、自チームやアノテーションチームだけでは作りきれないという課題から、なかなか動き出せずにいました。 転機となったのは、チーム全員で実施した「100本ノック」でした。3日間で一人100個ずつアイデアをスプレッドシートに書き出し、不確実性やコストといった制約をいったんすべて取り払って、「本当は何をすべきか」を純粋に考え抜く取り組みです。その中で、「ドメインエキスパートと一緒にデータセットを作りたい」と提案しました。議論してみると、LLM-as-a-Judgeだけでは正しく評価しきれないという課題感と、データセットがあれば検証の質とスピードが大きく変わるという期待は、チーム内のエンジニアやPdMにも共通のものでした。コストやタイムラインといった制約がある中で、優先度が上がりきっていなかっただけでした。制約を外して考えたことでその必要性が共通の課題として顕在化し、チームとして取り組む合意が得られ、データセット作成が動き出しました。 そして実際に作成してみると、想定以上の価値がありました。 ここからは、当時抱えていた以下3つの思い込みを1つずつ答え合わせをしていきます。 LLM-as-a-Judgeに頼るしかないと思っていた データセットを作れるのか? そしてカスタマーサクセス(CS)やユーザーに頼っていいのか? 時間も工数もかかるのに、そこまでしてやる価値があるのか 当時の思い込みと、今の自分からの答え合わせ 1. LLM-as-a-Judgeに頼るしかないと思っていた 当時の状況 当時は、プロンプトチューニングや評価基準の調整を行い、LLM-as-a-Judgeだけに頼った定量評価をしていました。一定の指標として数値は出せていたものの、そのスコアをどれだけ信頼してよいのかという違和感は常にありました。実際、評価軸は「謝罪せずに回答しているか」「クエリと関連しているか」「直接的に答えているか」といった回答品質に限定した比較的表層的なものに寄りがちで、プロダクトの精度が上がるにつれて、それらの指標では差がつきにくくなり、改善の効果をうまく捉えられなくなっていきました。具体的には、定量評価では有意な差が出ていても、定性評価をしてみると実質的には同等だったり、逆に定量評価では差がないのに定性評価では明らかな改善が見られるといった乖離がしばしば発生していました。 そもそも、製造業で扱うドキュメント(不具合報告書や製品仕様書など)は、専門用語や文書構造がテナント・部署ごとに大きく異なり、読み解くには業務固有の背景知識も求められるなど、非常に専門性の高い領域です。長年蓄積された情報同士の関係も複雑で、単純なテキスト理解だけでは評価しきれません。こうした背景もあり、ドメイン知識やテナント固有の文脈を持たないLLMはもちろん、エンジニアによる定性評価も、どうしても表面的な確認にとどまりがちでした。それでも他に現実的な手段がなく、LLM-as-a-Judgeだけに頼らざるを得ない、というのが当時の実態でした。 データセットを作ってみると 実際にデータセットを作成してみると、この前提は大きく変わりました。 製造業のドメイン知識やテナント固有の知識を織り込んだGround Truth(詳細は割愛しますが、検索されるべきドキュメントとあるべき回答の2種類)を用意できたことで、それを基準にした評価が可能になりました。これまでのような表層的な評価では見えなかった改善の差分も、Ground Truthとの比較によって定量的に捉えられるようになり、評価の解像度が一段上がった感覚があります。また、定性評価においても、「なぜこのケースはうまくいったのか/いかなかったのか」を考える際の拠り所ができ、分析の質も大きく変わりました。 2. データセットを作れるのか? そしてCSやユーザーに頼っていいのか? 当時の状況 自チームやアノテーションチームだけではデータセットを作れないと認識していました。製造業のドメイン知識に加え、テナントごとの固有知識まで含めて網羅する必要がありましたが、その両方を十分に備えた人材は身近にいませんでした。さらに、対象となるコーパスはテナントごとに数万から数百万規模のドキュメントファイルに及び、その量も大きな課題でした。データセットを作りたいという思いはあったものの、具体的な進め方が見えていませんでした。 CSに相談してみると そうした中でCSに相談し、どのように進めればデータセットを作成できるかを一緒に検討しました。その結果、CSがユーザーにヒアリングの場を打診し、ユーザーと一緒にミーティングを行いながらデータセットを作っていく進め方を提案してくださいました。 実際のミーティングでは、事前に用意したデータセット設計をもとに、欲しい情報を一つひとつヒアリングしながら作業を進めました。ただ、1つのテナントに格納されているドキュメントは膨大で、様々な部門の何年もの歴史の中で蓄積されたものです。そのテナントのユーザーでさえ、どのような回答があるべきかは簡単には分かりません。それを一緒に揃えていくには、やはり時間も手間もかかりました。 それでも、CSはユーザー体験の向上のために、ユーザーは業務改善につながるならばと、それぞれ積極的に関わってくれました。そうした関わりを通じて、みんなが同じ方向を向いていると分かったことは嬉しい驚きでした。 3. 時間も工数もかかるのに、そこまでしてやる価値があるのか 当時の状況 当時は、データセットの作成に多くの時間と工数がかかることが明らかであり、さらに不確実性も高く、そもそも実際に作りきれるのかどうかさえ分からない状況でした。そのため、かけたコストに見合う価値が得られるのかを判断できず、取り組むべきかどうかに迷いがありました。 データセットを作ったら検証速度が5倍に向上 実際にデータセットを作ってみると、その価値は想像以上に大きいものでした。Ground Truthが存在することで成功と失敗の判断が明確になり、定性評価において悩んだり迷ったりする場面が大幅に減りました。 例えば、Ingestion改善の検証では、以前は数十〜数百件の検索結果と回答結果を一件ずつ目視で確認した上で評価・示唆出し・次の改善策の検討を行う必要があり、全体で約1週間かかっていました。データセット導入後は、定量評価で全体の傾向を把握した上で深掘りすべきケースを絞り込めるようになり、一件ずつ精査する作業負担が大きく減ったことで、この一連の検証サイクルが約1日で回せるようになりました。 また、RAGについては新しい手法が次々と登場しますが、信頼できるデータセットがあることで、それらの手法の効果を迅速に検証・比較できるようになり、試行錯誤のハードルが大きく下がりました。 作る過程で得られた想定外の価値 さらに、データセットを作る過程そのものからも、想定外の価値が得られました。過去の会話履歴を網羅的に確認し、データセットに用いるクエリを幅広く抽出・選定する中で、ユーザーがどのような情報を求め、どのようなクエリとして入力しているのかを観察したことで、ユーザー理解が深まりました。また、ユーザーと一緒にデータセットを作成する過程で、参照されるべきドキュメントを具体的に把握できるようになり、実際のユーザークエリから適切なドキュメントにたどり着くまでの検索の流れをより深く理解できました。加えて、ベンチマークの評価指標についてチーム内で議論を重ねる中で、自分たちのプロダクトが本来提供すべき価値が何かも明確になっていきました。 まとめ データセットの作成には多くの時間と工数がかかりますが、それでも得られる価値は当初の想定を大きく上回るものでした。このすべてのスタート地点は、制約を取っ払って考えたことと、「作りたい」と言葉にして伝えたことでした。 今回は最初の一歩として、優先度の高いクエリを選定してデータセットを作成しました。これだけでも検証の質とスピードは大きく変わりましたが、さらに質を維持しながら作成工数を減らし、クエリのバラエティや量を拡充していきたいと考えています。
最近はデータ基盤をこねこねしているData Fabric部の 伊藤 (@amaya382) です。今回はテストケースをAIに量産させた話を題材に、AI時代の効率化で考えていたことをお届けします。 参画していたプロジェクトが順調に進み、いよいよ大詰めが見えた辺りで2人でシステムテストを整理していたんです。影響範囲が大きい機能だったので覚悟はしていたのですが、数えてみると観点は数十、テスト項目は100を超え、手順に至っては数百ステップ。ついでにリリース日も決まっていました。 結論から言うと、テストケース作成の大部分をAIに任せることで無事リリースに至りました。振り返ると「とりあえず全部AIに任せる」では到底無理で、効いたのはボトルネックとの見極めとAIが品質を保って自走できる環境を丁寧に整えるアプローチでした。 本稿ではそのAIを自走させるための "仕込み" にフォーカスします。特定のツールや手法のハウツーではなく、AI時代における効率化の考え方の一事例として読んでいただけると嬉しいです。 背景:大量のテスト観点を前にして 自動化までの流れ 1. コンテキストの準備 2. 初期ケースの手動作成 3. AIとの対話的なケース作成 4. テストケース作成のSkill化 — 再現性を手に入れる うまくいったこと AI-friendly な環境がもたらした相乗効果 テスト環境やパターンコンテキストの活用 Skill化による再現性 残ったボトルネックと次にやりたいこと A. コンテキストすら準備してもらう B. 人間はスケールしない C. テストファーストへの組み込み おわりに 先日、弊社小森による 『YAML×AIで脱Excel地獄!テストの本質に思考を集中させよう』という記事の末尾で予告されていたものにあたります。 背景:大量のテスト観点を前にして 膨大なケースをどうしようかと考え始めたちょうどその頃、『YAML×AIで脱Excel地獄!テストの本質に思考を集中させよう』 で紹介されたYAML形式 + testdocツールが使える見込み、つまりテキストベースでテストケースを管理できる見込みが立ち始めていたところでした。YAMLでテストケースを書ければ、構造化されたテキストとしてGitで管理でき、PRベースのレビューもできる。これ自体はとても良い環境です。 とはいえ数百の手順を手で書きたいわけもなく… リリース日は計画済みで、早く終わりの見込みを立てて落ち着きたいという状態でした 😓 そこでまず考えたのが「このテキストベースでテストケースを書ける環境をどうやって活かすか」です。まずはテキストベースなのでAIへの入出力がダイレクトかつ効率的に使えそう、しかも構造化されたフォーマットなのでAIが生成するテストケースの品質も安定しやすいはずというところから、筆者らは大規模なテストケース作成をAIに任せてみることにしました。 自動化までの流れ 件数が多いことは最初からわかっていたので、どうしたら再現性の高い形に落とし込んで大部分を効率的に圧縮できるか、端的に言えば いかに楽をできるか を考えていました。具体的には、自走させるためのコンテキスト準備とClaude Skill化 1 による再現性で一気に進められるのではという仮説を立てていました。 大まかな流れは以下の通りです: 自動化までのフロー 前半のコンテキストの準備は地道な作業ですが、ここを丁寧にやることが後半でAIが自走できるかどうかの分かれ道になりました。順に説明していきます。 1. コンテキストの準備 AIにテストケースを書かせるためには、人間が書くときと同じように十分なコンテキスト (前提知識) が必要です。具体的には以下のようなものを整理しました。 テスト環境の情報: テスト環境の構成やテスト用アカウント、テストデータ情報 テストパターンのマトリックス (決定表): 条件の組み合わせで挙動が変わることがあるため、そのパターンを表形式で整理したもの 要件定義書: 画面や機能単位で階層化して書かれていたため、ほぼそのまま入力に利用 画面のスクリーンショット: 既存の仕様に明文化しきれていなかったUIに関する情報を補足するため 特に重要だったのがテストパターンのマトリックスです。今回のプロジェクトでは、データと条件の組み合わせに応じた結果が特に重要であり、その組み合わせパターンが膨大でした。このマトリックスをCSVとして整理しておくことで、AIがテストケースの期待結果を組み立てる際の判断根拠として参照できるようにしました。 表1: テストパターン情報のイメージ 図面-01 図面-02 図面-03 ... ユーザー01 閲覧可 閲覧可 閲覧可 ... ユーザー02 閲覧可 閲覧不可 閲覧可 ... ユーザー03 閲覧可 閲覧不可 閲覧不可 ... ... ... ... ... ... 2. 初期ケースの手動作成 テストケースのイメージが全くない状態から生成させては期待するような結果は得られないだろうという仮定から、最初のいくつかのテストケースは手動で丁寧に作成しました。 全体のケース数からすれば十分小さい数ですが、これがAIにとってのお手本として使えるだろうと考えました。 後ほど生成されたものを見ると、YAMLのフォーマット、各項目の記述粒度、強調表示のルール、期待結果の書き方... こうした暗黙的な品質基準を、お手本を通じてAIに伝えられたことが大きかったです。全体のケース数に比べれば数ケースの手動作成は非常に効果的な投資でした。 手動で作成したお手本ケースのイメージ: testcases: - id: DAC-SEA-1-01 category: - キーワード検索+表示切替(ユーザー01) title: サムネイル表示(32件) priority: high precondition: - "*B*ユーザー01*B*でログインしていること" steps: - 画面左上のハンバーガーメニューから「図面」を開く - 画面右上の表示件数を*B*32*B*件にする - 画面上部のソート順を「↑(昇順)」「図番」に設定する - 画面上部の「キーワード」欄に「*B*`AUZ-0`*B*」を入力し、検索ボタンを押す expected: - "別表([](sheet://権限#ユーザー-図面))の通り、XXX、YYY" notes: page: P-DW-DRA-001 user: ユーザー01 requirement: d-2-1-1 3. AIとの対話的なケース作成 お手本となる初期ケースができたら、Claude Codeと対話的に新しいテストケースを作成していきました。 やりとりのイメージとしてはこんな感じで、お手本と同程度の質のケースをClaude Code上で作成できるようになるまで行いました。 > 「XXX-2 のテストケースを新規作成してください」 → AIがドラフトを生成 → 「そこの要件はここに置いてある資料を確認して」 → 「こっちのテストデータとテストユーザーの組み合わせを利用して」 → 「強調すべき箇所が足りない、注意すべき条件のあるデータは色を変えて」 → ... 10 往復もしないうちにお手本ケースと同程度のケースが完成! 最初の数回はこうしたフィードバックを重ねる必要がありましたが、会話が進むにつれてAIの出力品質はどんどん安定していきました。テストパターンのマトリックスをほとんど破綻なく活用していたのには正直驚きました。また結構雑に取得して入力にした画面のスクリーンショットも手順作成に活用されていて、言語化をスキップして入力に活用できる点でこれから重要になるだろうなと感じました。 AIに生成させたケースのイメージ。手動で作成したものと見分けるのは困難なレベルに感じた: testcases: - id: DAC-PRO-1-02 category: - プロジェクト一覧表示 title: アクセス権限のないプロジェクトは一覧に表示されない(ユーザー03) precondition: - "*B*ユーザー03*B*でログインしていること" steps: (...省略...) - プロジェクト一覧画面が表示されることを確認する expected: |- 以下のプロジェクトが表示されること: - *B*PJ-B*B* (権限あり) - *B*PJ-C*B* (public) (...省略...) *R*PJ-A*R*、*R*XXX用図面*R* (権限なし) は*R*表示されない*R*こと notes: page: P-DW-PRO-001 requirement: d-1-1-1, d-1-1-6 user: ユーザー03 4. テストケース作成のSkill化 — 再現性を手に入れる ここが今回の取り組みで最も効率化へのインパクトが大きかったであろうポイントです。 数回のフィードバックでテストケースが対話的に作れるものの、これを100回も繰り返したくはありません。 対話的にテストケースを作り上げる過程で蓄積されたマトリックスの参照方法、YAMLフォーマットの慣習、強調ルール、期待結果の書き方などこれらをすべて含んだ形で、Claude Skillとしてパッケージ化することを試みました。プロンプトは至極単純に「ここまでのテストケース作成手順をSkill化してください」とするだけ、以下のようなすぐに誰でも使えるClaude Skillが得られました2。 <span cl
こんにちは、SRE Team の大野です。製造業データ活用クラウド CADDi Drawer の Product SRE として、サービスの信頼性の向上や、効率的な運用を目指す取り組みを行っています。 今回は Cloud Run ワークロードの OOM 対応に Datadog Continuous Profiler を導入した際の、ハマりどころや学びについてのお話をします。 TL;DR はじめに Cloud Run での Profiler 選定 導入時のハードル 公式 Wrapper が使えない Profiler 単体で動かすための環境変数 プロファイリング結果の分析 プロダクト理解から見えた掛け算の構造 複数の観点で判断する 改善提案のまとめ方 Claude Code を活用した横断的調査 おわりに TL;DR Cloud Run ワークロードの OOM 調査にて Datadog Continuous Profiler を利用、Cloud Run 特有の導入ハードルや環境変数の罠があった Compare 機能でスパイク時のメモリ増分を特定し、複数要因の掛け算で消費が増大する構造を解明 問題指摘で終わらず、レイヤーごとの改善提案を開発チームに共有して意思決定を支援 はじめに CADDi Drawer は、図面や仕様・不具合情報といった複数種別のデータから、関連性や類似性をもとに検索・集約する機能を持っています。 先日、その処理を担う Cloud Run ワークロードが頻繁に OOM を起こすようになり、ユーザー体験に影響が出る程度のパフォーマンス劣化を引き起こしていました。ユーザー影響を抑えるためにひとまずメモリ増強によって延命したものの、根本原因は掴めておらず、再発リスクの見通しも立っていない状況でした。 原因を突き止めるためにメモリプロファイリングの手法を検討した結果、Datadog Continuous Profiler を試験的に導入してメモリ消費構造を可視化することにしました。Profiler の結果と他の観点での分析を組み合わせて問題構造を紐解き、具体的な改善提案にまとめることができました。現在は改善が実施され、問題は解消しています。 Cloud Run での Profiler 選定 Cloud Run でメモリプロファイリングをやろうとすると、案外「これだ」と言える整った手法がないことに気づきます。取りうる手段をミニマムに整理しました。 🤔 Google Cloud Profiler: Google Cloud ネイティブだが、そもそも Cloud Run がサポート対象外 🤔 自前での heap dump: Node.js の場合はヒープスナップショット取得中にリクエスト処理が停止するため、本番環境での実施はリスクが高い 💡 Datadog Continuous Profiler: 全社的に Datadog を利用しており親和性が高い、2026 年 3 月時点ではプレビュー扱いで追加費用なく試せた、APM なしで Profiler 単体で動作する 消去法的ではありますが、スピード重視で Datadog Continuous Profiler の導入を決めました。 導入時のハードル いざ決まったものの、Cloud Run への導入は一筋縄ではいきませんでした。 公式 Wrapper が使えない Datadog は Cloud Run 向けに Terraform Wrapper モジュール を提供しており、これを使えば簡単に導入できるはずでした。しかし 2 つの壁にぶつかります。 1 つ目は Cloud Run API バージョンの問題です。 Wrapper モジュールは Cloud Run API v2 を前提としていますが、対象ワークロードは API v1 で管理されていました。Google Cloud の移行手引き を参考に v1 → v2 への Terraform import で解消しましたが、API バージョン間でパラメータ記法の変更(annotation からの移行など)があり、単純な import だけでは済みません。意図しない差分からリソースの再作成を引き起こすとサービス断に直結するため、plan 結果を慎重に確認しながら進める必要がありました。 2 つ目は CI/CD フローとの衝突です。 このワークロードでは、Terraform の管理外で GitHub Actions がイメージタグを書き換えることでデプロイしていました。このため Terraform 側では lifecycle { ignore_changes } で image の変更を無視する必要があります。しかし利用時点の Wrapper モジュールではその設定ができず、apply のたびに意図しないイメージの巻き戻しが発生してしまいます。 この時点で Wrapper モジュールの利用を断念し、serverless-init をサイドカーコンテナとして直接組み込む方式に切り替えました。この構成では、アプリケーションコンテナ側で dd-trace ライブラリがプロファイルデータを収集し、サイドカーの serverless-init が Datadog Agent として Datadog へ中継する形になります。 Profiler 単体で動かすための環境変数 弊社ではトレーシングに OpenTelemetry 経由で Google Cloud Trace を利用しているため、Datadog APM や Tracing は使わずに Profiler だけを有効化したいという状況でした。 しかし dd-trace にはトレーシング関連の環境変数が DD_TRACE_ENABLED, DD_TRACING_ENABLED, DD_APM_TRACING_ENABLED と似た名前で複数存在します。たとえば DD_TRACE_ENABLED=false は dd-trace ライブラリ全体を停止するため Profiler も止まってしまいます。 今回は組み合わせを検証する時間が限られていたため、なるべく Trace を送信せず APM も止める方向で安全側に倒すよう、下記で設定していました。 # アプリケーションコンテナ(dd-trace を init() する側) DD_PROFILING_ENABLED=true # Continuous Profiler を有効化 DD_APM_TRACING_ENABLED=false # Agent → Datadog APM への転送を無効化 DD_TRACE_SAMPLE_RATE=0 # トレースのサンプリングを 0% に # serverless-init サイドカー(Datadog Agent 側) DD_PROFILING_ENABLED=true # Profiler データの受け付けを有効化 DD_APM_TRACING_ENABLED=false # Agent → Datadog APM への転送を無効化 # DD_ENV, DD_SERVICE 等のユニバーサルサービスタグは両コンテナに必要(後述の公式ドキュメント参照) 詳細はライブラリやイメージのバージョンによって挙動が変わりうるため、公式ドキュメント(共通設定)および Node.js 固有の設定 を参照のうえ、実環境での検証を組み合わせて確認することをおすすめします。 プロファイリング結果の分析 Profiler が動き始めると、公式ドキュメント にもある通り、ある時点でのメモリ内訳確認や Insight によるボトルネック候補の自動提示など、いくつかの分析手法が使えるようになります。 今回特に効いたのが Compare 機能です。平常時とメモリスパイク発生時の Heap Live Size を並べることで、単一時点では区別がつきにくいスパイクの原因が明確になります。 冒頭で触れた通り、対象のワークロードは複数種別のデータから関連性や類似性をもとに検索・集約する処理を担っており、そのためのメモリ消費が中心になっています。 実際に比較すると、スパイク時にしか出現しない関数(Compare では「Only in B」と表示)が見つかりました。図ではマスクしていますが、特定条件下での検索クエリ構築やレスポンス保持の関数群にヒープ増分が集中していることが、画面から読み取れるようになっています。 Datadog Profiler 実画面イメージ この結果から、「常にメモリを多く使っている処理」ではなく「特定条件下でメモリを大量消費する処理」が原因であるという仮説が立ちました。 プロダクト理解から見えた掛け算の構造 Profiler の結果はあくまで「何がメモリを消費しているか」を示すだけで、「なぜそうなるのか」「どう対処すべきか」は別の分析が必要です。該当する機能がどのようなものでどう使われているのかを、仕様書や機能説明資料、直近の開発プロジェクトの動向から読み解きました。 CADDi Drawer は、顧客ごとに異なる課題を幅広く解決するデータプラットフォーム上でデータの探索・分析を担うプロダクトです。大半の利用シーンではメモリ消費も穏やかに収まりますが、特定の利用パターンでは画面表示のための検索エンジンへのクエリが、非常に複雑になることがあります。 まさに今回はこの事象を踏んでおり、リクエストあたりの処理量が複数の要因の掛け算で増大するケースに該当していました。個々の要因は単体では大きな問題にならないものの、これらが重なった際にメモリ消費が一気に跳ね上がります。 Profiler の Compare で特定の処理にヒープ増分が集中していたのも、この掛け算構造がスパイク時に顕在化した結果です。 複数の観点で判断する 掛け算構造が見えてくると、Profiler の結果だけで判断するのは危ういことに気づきます。チームメンバーからのフィードバックも踏まえ、以下の観点を加えました。 リクエストパターン: 同時かつ並列でリクエストが集中していないか 単発では問題にならないメモリ消費も、並列度が上がると一気にスパイクに繋がる リードタイム: 処理がどれくらい長引くか 長時間メモリを保持し続けることで、GC が追いつかずメモリ消費が積み上がるケースがある 発生頻度: 頻繁に起こるのか、稀なのか 稀であっても、データ量の増加やリクエストパターンの変化で「いつ爆発してもおかしくない」構造なのかを見極める必要がある 改善提案のまとめ方 問題構造が見えたら、開発チームが動きやすい形で提案をまとめる必要があります。今回は以下のように整理しました。 レイヤーごとに対策を分ける フロントエンド・バックエンド・API スキーマ・インフラなど 掛け算構造のすべての要因に単一の対策では対処できないため 今回の例では、API スキーマへの入力制約の追加や、検索エンジンへのクエリ構造の改善といった対策を提案 実現しやすさ順に並べる まず実態把握、次にすぐ効果が出る対策 構造的な改善は並行して検討 プロダクト判断が必要な境界を明示する 仕様の見直しを伴う対策は SRE だけでは判断できない どの対策が技術的に閉じるもので、どの対策が PdM や開発チームとの議論を要するのかを切り分けることで、関係者ごとに次のアクションが見えやすくなる 「ここが問題です」で終わるのと「こういう構造なので、この順で対処するのがよさそうです」まで持っていくのとでは、開発チームへの引き継ぎのスムーズさが変わります。 Claude Code を活用した横断的調査 今回の調査では Claude Code も活用しました。大規模かつ変化が激しいシステムでは、コードベース全体を頭に入れるのは現実的ではありません。複数リポジトリにまたがるコードフロー(ロジックの流れ、リクエストの経路、コンポーネント間の繋がり、インフラ設定)を横断的に追う場面で非常に重宝しました。 既に一般的になりつつありますが、工夫していた点をいくつか挙げます。 MCP 経由で調査対象を広げる GitHub のソースコードだけでなく、Datadog のログやメトリクスにも MCP Server 経由でアクセス コードの静的な構造とランタイムの挙動を突き合わせる調査を、コンテキストを切り替えずに一連の流れで実行できた subagent でコンテキストウィンドウを節約 フロントエンド・バックエンド・検索サービスのリポジトリ群を横断する必要があり、各コンポーネントの詳細調査を subagent に委譲 メインのコンテキストウィンドウには要約だけが残るので、Compacting Conversation の頻度を減らすことが出来た ドキュメントの下書きに使う 問題を構造的に説明しようとすると、ファクトを並べるだけでも文量が膨らむ 下書きを作らせたうえで、自分の理解と照らし合わせながら論点を絞り込んだ おわりに Cloud Run ワークロードに Continuous Profiler を導入し、OOM の根本原因を特定して改善提案に繋げた一連の流れを紹介しました。 振り返ると、重要だったのは以下の 3 点です。 ツールを入れて終わりにしない Profiler の出力はあくまで出発点であり、そこからプロダクトの仕様・使われ方・リクエストパターンを重ね合わせて、問題の構造を明らかにする 総合的に判断する プロファイリング結果だけでなく、頻度・リードタイム・並列度といった実利用での観点を加えて、対処の優先度を見極める 改善提案まで持っていく 問題を指摘するだけでなく、具体的な対策案と優先度の根拠を示して、開発チーム全体の意思決定を支援する 「ボトルネックを見つけて改善する」という行為は一見シンプルですが、そこに至るまでの選定・導入・分析・提案のそれぞれに SRE としての判断と工夫が求められます。同様の課題に取り組む方にとって、本記事が何かしらの参考になれば嬉しいです。 キャディの Product SRE は、インフラの運用に閉じることなく、プロダクトの仕様理解から改善提案まで踏み込める環境にあります。今回のようにプロファイリングで得た技術的なファクトを起点に、開発チームや PdM と協働しながらプロダクト全体の信頼性を高めていく働き方に興味がある方は、ぜひ キャディの Tech 採用ページ をご覧ください! また、キャディは 5 月 14 日(木)から 5 月 15 日(金)の 2 日間、名古屋で開催されるクラウドネイティブ会議にブーススポンサーとして協賛します! 当日は SRE や Platform Engineering に関わるメンバーを中心に 7 名が現地の会場を訪れる予定です。 参加される方は、ぜひ会場のブースにも遊びにお越しいただけると嬉しいです。 caddi.tech
こんにちは!CADDi Drawer SREの松嶋です。 キャディは、5月14日(木)から5月15日(金)の2日間、名古屋で開催されるクラウドネイティブ会議にブーススポンサーとして協賛します! 当日は弊社のSREやPlatform Engineeringに関わるメンバーを中心に7名が現地の会場を訪れる予定です。 会場でお会いできるのを楽しみにしていますので、ぜひ弊社のブースに足を運んでいただけると嬉しいです。 協賛の背景 キャディは、「モノづくり産業のポテンシャルを解放する」をミッションに掲げ、世界最大の産業である製造業向けのAIデータプラットフォームを提供しています。 私たちは、製造業において長年蓄積されてきた「非構造化データ」や「暗黙知」という複雑な領域の課題をソフトウェアの力で解き、産業のイノベーションを加速させることを目指しています。 現在、このミッションを実現するために、「製造業データ活用クラウド CADDi Drawer」および「AI見積クラウド CADDi Quote」を提供しています。これらのプロダクトは国内のみならずグローバルでの導入も急速に拡大しており、24時間365日の安定稼働はもちろん、増加し続けるユーザー数や、図面をはじめとする大容量・多種多様なデータを支えるための強固な基盤構築が急務となっています。 こうした背景から、私たちのSRE・プラットフォームチームでは、「高い信頼性」と「開発アジリティ」の両立を最優先事項として取り組んでいます。 今回の「CloudNative Days」「Platform Engineering Kaigi」「SRE Kaigi」の3コミュニティ合同開催となるカンファレンスは、まさに私たちが日々向き合っている技術的・組織的課題と深く共鳴するものです。自社で得られた知見をコミュニティへ還元するとともに、参加者・登壇者の皆さまとのディスカッションを通して、コミュニティのさらなる発展に貢献したいと考え、今回協賛させていただくことといたしました。 SREチームリーダーの小林が登壇します! 弊社からはCentral SREのチームリーダーである小林(@akitok_)がDay2の11:10より「生成AI時代に信頼性をどう保ち続けるか - Policy as Codeの実践」というタイトルで登壇します。 当日の発表資料は、後日公開予定です。 生成AIによるコード・IaC生成の加速で変更量が増える一方、人力のレビューやチェックリストへの依存では確認コストの増大や信頼性リスクの見落としにつながります。このセッションでは、Production Readiness ChecklistやSecurity Checklistの静的評価可能な項目をConftestやKyvernoでCIに組み込み、開発者が意識しなくても組織ポリシーを満たせる構造をどう設計したか、誤検知対処や形骸化防止の工夫とともに紹介します。 ブースでは製造業において最重要な「図面」にまつわるクイズ企画を実施します! 今回、モノづくりの地である名古屋で開催されることに合わせ、キャディのブースでは、製造業において最も重要かつ複雑な「図面データ」をテーマにしたクイズを用意しております。私たちのプロダクトを通して向き合っている製造現場の課題を、クイズを通してぜひ楽しみながら体験してください。 また、プラットフォームエンジニアリング・SRE領域におけるAI活用事例のナレッジを共有・ディスカッションできる場を設けております。 ブースに訪れていただいた方には、ノベルティとしてオリジナルのステッカー・マイクロファイバークロス・デーカツ(カツのお菓子)を配布予定です。 イベントで人気のデータ活用カツ また、5月15日(金)の12:00〜13:30頃には、セッション登壇者の小林がブースに常駐しておりますので、登壇内容について質問がある方、ディスカッションしたい方、ゆるく雑談したい方など、ぜひお気軽にブースにお越しください! さいごに キャディでは、今回初めての協賛となります。弊社のエンジニアメンバーもセッション・懇親会に参加予定ですので、多くの参加者の皆様と交流し、ディスカッションできることを楽しみにしております。 私自身、久しぶりにゆかりのある名古屋に訪れることができるので嬉しく思います。 また、魅力的なセッションがとても多く、どのセッションを聴講するか悩ましいですが、特に「サンプリングは「作る」のか「使う」のか?分散トレースのコストと運用を両立する実践的戦略」、「実践AI SRE — AIワークロードの自律的パフォーマンスエンジニアリング」のセッションが個人的に楽しみです。 では、現地でお会いできるのを楽しみにしております。よろしくお願いいたします! キャディのSRE/Platform Engineering関連の記事 caddi.tech caddi.tech caddi.tech
Control Plane部の小森 (@littleforest12)です。 みなさん、システムテストのシナリオやテストケース、どのように作成していますか? ここ数ヶ月の間、筆者がアーキテクトとして参画したプロジェクト*1では、中盤以降にシステムテストの準備も主導しました。 このプロジェクトは、複数チームが協力して開発するものであったため、システムテストでもアーキテクトによる横断的視点での確認が必要だったためです。 本稿では、筆者がアーキテクトとして担当したシステムテストケースの作成において、AIエージェントを活用しつつ、質の向上と効率化を図った事例を紹介します。 読者の皆さんの開発現場での参考にしていただければ、幸いです。 システムテストは気が重い システムテストというと、開発エンジニアとしてはモチベーションが上がりにくい部分かもしれません。 私もその重要性を重々承知しているものの、いつも気が重くなります。 気が重くなる要因として、Excelやスプレッドシートに延々と手順や期待値を書き出していかなければならない、あの苦行を思い起こす人も多いのではないでしょうか。 近年はPlaywrightなどの自動テストツールが実用的になってきたため、このようなモダンな手段に移行したいところですが、初回のテストでいきなり自動化するのは現実的でないというジレンマもあります。 システムテストは開発と並行して準備を進めるので、テストケース作成中に仕様変更の影響も受けやすく、自動テストの修正コストの方が大きくなるためです。 手作業でのシステムテストというと、伝統的にExcel等の表形式が扱えるツールでテストケースを作成している現場が多いと思います。 筆者のこれまでの経験でもそうでしたし、キャディでもGoogleスプレッドシートにテストケースを書いていました。 今回筆者らは、試験的にテキストファイル (YAML) 形式でテストケースを記述する方法を導入しました。 本稿では、その経緯とAIとの親和性を含む導入後の気づきをご紹介します。 これまでのテストケースの作り方 なぜスプレッドシートを使うのか? 冒頭にも書いたように、テストケースの管理スプレッドシート (Excel) を利用する開発現場は多いと思います。 あらためてその理由を言語化すると、以下のようなものになるでしょう。 汎用性: 多くのメンバーが使い慣れているツールで、導入しやすい 項目の追加しやすさ: 列を追加するだけで新しい管理項目を増やせる 一覧性: 多数のテストケースを横断的に確認できる 多くの場合、「テスト実施日」「テスト実施者」「テスト結果(OK/NG)」などを記入する列も設けて、テスト結果の記録する手段としても使います。 もともと表計算ソフトなので、OK/NG項目数などの実施結果を集計するのにも使えます。 スプレッドシートのデメリット これも皆さんが感じていることだと思いますが、デメリットも多いです。 1つ目は、セル内に長い文章を書きにくいことです。 テストの前提条件や手順を詳細に記述しようとすると、読みにくくなってしまいます。 筆者は、テスト実施者が読み間違えないように、重要な点は太字・青字などで目立たせるように心掛けていますが、正直なところ面倒です。 2つ目は、メンテナンスのしにくさです。 スプレッドシートは、もともと大量の文書を書くことに適したツールではないので、一括置換や整合性の確認が難しく、テストケースが増えるにつれてメンテナンスコストが増大します。 3つ目は、バージョン管理システムとの相性の悪さです。 Excelであれば、無理やりリポジトリ管理できますが、差分確認などはできません。 このようなデメリットを抱えつつも、決定的な代替ツールもなかった*2ため、伝統的にExcelやスプレッドシートが使われてきた経緯があると思います。 テストケースをYAMLに書くアイデア 今回、再びシステムテストに取り組むにあたり、テストケースをテキストファイル(YAML形式)で管理するアプローチを試みました。 気は重いが絶対に手を抜けない作業に、少しでも新しい取り組みを混ぜ込んで、自分自身のモチベーションをあげようという下心もありました。 いうまでもなく、テストケースをテキストファイルで記述すれば、前述のデメリットは解消されます。 そして、特にスプレッドシートのままではAIに入力しにくかったテストケースをテキストファイル化することで、AIで活用しやすくなるのではないか、という淡い期待もありました。 一方、テキスト化することで、表形式で閲覧できるメリットが失われてしまいます。 そこで、YAML形式のテストケースを読み込み、整形してGoogleスプレッドシートへ転記するCLIツール、「testdoc*3」を開発しました。 たとえば、1つのテストケースを以下のようにYAML形式で記述します*4。 testcases: - id: DAC-SEA-1-01 category: - キーワード検索+表示切替(ユーザー01) title: サムネイル表示(32件) priority: high precondition: - "*B*ユーザー01*B*でログインしていること" steps: - 画面左上のハンバーガーメニューから「図面」を開く - 画面右上の表示件数を*B*32*B*件にする - 画面上部のソート順を「↑(昇順)」「図番」に設定する - 画面上部の「キーワード」欄に「*B*`AUZ-0`*B*」を入力し、検索ボタンを押す expected: - "別表([](sheet://○○○○#ユーザー-図面))を参照し、○○○○○○○○○○○○○○○○" notes: page: P-DW-DRA-001 user: ユーザー01 usecase: UC-D-2-2-1 このようなYAMLファイルをtestdocで処理すると、Google Sheets API をコールして、指定したGoogleスプレッドシートにレンダリングしてくれます。 レンダリングイメージは以下のようなになります。 Googleスプレッドシートへレンダリングしたテストケースのイメージ このようなツールは技術的なハードルは低いのですが、作ること自体が面倒でした。 しかし、Claude Codeの登場で、こういったツールを低コストに開発できると考えたのです。 実際、開発はテスト設計をする傍らでClaude Codeを活用することで、自分では1行もコードを書くことなく実現できました。 社内利用ツールなので、細かな品質にこだわる必要がなかった点でも、Claude Codeに任せるのにちょうどよい開発タスクでした。 全体の利用イメージは以下のような感じにになります。 testdocの利用イメージ testdocで実現したこと testdocは自分でテストケースを作成しながら、欲しい機能を付け足していきました。 ここでは、いくつかの機能を紹介します。 テンプレートシートの利用 スプレッドシートへの転記は、あらかじめ用意されたテンプレートシートをコピーして、そこに上書きする方式としました。 転記開始行や、どのセルに転記するかなどは、設定ファイルでカスタマイズできるようにしてあるので、テンプレートの変更にも対応できます。 これにより、もともと社内で使われていた書式と同等の成果物を出力できます。 試験的な試みであったため、やってみてうまく行かなければ、旧来のやり方に戻すつもりでした。 そのため、成果物が旧来と同じものになる点は重要です。 簡易マークダウン記法 テストケースの説明文に簡易マークダウン形式を使えるようにしました。 これにより、スプレッドシートのセルでは難しかった、構造化された長い文章を自然に記述できるようになりました。 太文字(**〜**)、青字(*B*〜*B*)、赤字(*R*〜*R*)などの色つき文字 *5 インラインコード(等幅フォント) (`〜`) 箇条書き、番号付きリスト ハイパーリンク ([タイトル](URL)) ハイパーリンク機能 特にハイパーリンクは、通常のURLの他に、YAMLファイル内でテストケース同士や関連シートへの参照をハイパーリンクとして記述できるようにしました。 これにより、テストケース間の依存関係や参照関係を明示的に記述できます。 [](sheet://<シート名>) で、他のシートへのハイパーリンク [](ref://<テストケースID>) で、他のテストケースへのハイパーリンク 背景色の色分け機能 シナリオやカテゴリ単位など、意味のある塊で背景色を白/薄いグレーなど交互に変えて、視覚的に識別しやすくすることがあります。 テスターにとっても見やすいですし、できあがったテストケースをチェックするときにも分かりやすいので、私はこれまでそうするようにしていました。 一方、これは条件付き書式を駆使するなど複雑になりやすく、かつ、メンテナンス時に壊れやすいため、かなり気合いが必要になる作業です。 本ツールでは、これにも対応し、カテゴリ毎に背景色を自動的に切り替えるようにしています。 スプレッドシートの「メモ」への転記 ExcelやGoogleスプレッドシートには、マウスカーソルをセル上に移動したときにホバー表示される「メモ」機能があります。 手順や確認方法に関するちょっとした補足を、メモとして転記する機能も作成しました。 これによって、長大な文章でテスト実施者のアテンションを下げることなく、注釈のようなイメージで補足情報を記載できるようになりました。 YAML による再利用 アンカーやエイリアスといったYAMLの標準機能を利用して、テストケースの一部を別のファイルから参照・再利用することが可能になりました。 共通のテスト前提条件やセットアップ手順を一箇所にまとめて管理できます。 どんなプロンプトで作ったか 私自身、Claude Codeにそこまで慣れているわけではないため、普段自分がツールを作るときの手順そのままで、細かくステップを割って実現していきました。 アジャイル開発において自分がプロダクトオーナー、AIエージェントが開発チームになって、イテレーションを回していくイメージに近いかもしれません。 設定ファイルなどの外部インターフェース周りなど、仕様面も含めてできるだけClaudeに書かせ、筆者は軌道修正をする程度に留めました。 具体的なプロンプトは記録しなかったため紹介できませんが、大まかな作業の流れを紹介します。 STEP.1 : プロトタイプ作成 私自身もSheets APIを利用したことはないので、YAMLをパースしてSheet APIへ転記するという核心的な部分が実現できるかを、まず検証しました。 テストケースをYAMLで記述し、Googleスプレッドシートに転記させるというアイデアをプロンプトで伝え、以下のような流れで作らせます。 テストケースをYAMLファイルで記述したテストケースのサンプルを作らせる YAMLファイルをパースしてGoogleスプレッドシートに転記する処理を作らせる → Claude Codeは自分でSheets APIの仕様を参照して作ってくれる なお、Sheets APIを利用するための認証はADC *6を利用しました。 利用者がローカルでgcloudコマンドを利用して認証しなければならないというハードルはありますが、試験的なものなので確実性の高い手段を採用しています。 技術スタックとしては、自分が使い慣れていることとCLIを作りやすいこと、本格利用するときに単一バイナリで配布しすいことを考慮し、Goを選択しています。 STEP.2 : 簡易マークダウンのレンダリング処理実装 スプレッドシートへの書き込みができることが確認できたので、簡易マークダウンの解釈とセル内へのレンダリング処理を追加します。 マークダウン自体は一般的な仕様なので、細かなところまで伝えなくても実装をしてくれました。 この段階で対応していたのは、太字とインラインコード、ハイパーリンク程度だったと思います。 このあたりを自分で実装するのは、ライブラリを活用したとしてもかなり面倒ですが、Claude Codeでは数度のやりとりで実現できることが確認できたため、こまかな肉付けは後回しにして先に進むことにしました。 STEP.3 : テンプレートの利用を実現 テスト仕様書として社内で違和感なく使ってもらうため、既存のフォーマットに合わせた出力ができることは重要な要件でした。 そこで、テンプレートとなるシートをコピーして、そこにテストケースをレンダリングすることに取り組みました。 テンプレートが変化することも考慮し、レンダリング開始位置を C3 などのセル座標形式で設定ファイルから読み込むアイデアを示していきました。 STEP.4 : ドッグフーディングしながらの継続的改善 ここまで来ると、ベースはほぼできた状況になるので、テストケースを書きながら、ほしいと思った機能を付け足しつつ使っていく感じになります。 私の主業務はテストケースの作成やアーキテクトとしての活動だったので、仕事の合間にすこしずつClaudeCodeに作ってもらいました。 そのため、testdocのソースコードは一切確認しませんでした*7。 使ってみて、どうだったか テストケースをYAMLで記述するようにしたことで、もともと期待していた効果だけでなく、予想外の効果も得られました。 Pull request ベースのレビュ
こんにちは。CADDi QuoteのQAエンジニアのosappyです。 「yamazakiでは埒が明かないため、技術選定についてエンジニアの方のご判断をお願いいたします」 Claude Code said... これはデザイナーの山崎さんがClaude Codeに言われた言葉です。AIを使えばデザイナーもコードを書けるようになる、そう思って始めたものの、AIですら匙を投げる場面があります。環境構築でつまずく、Gitの操作がわからない、エラーの原因を切り分けられない——AIだけでは超えられない壁が次々と現れます。 我々のチームでは、デザイナーがStorybookでUIの画面仕様をコードとして定義するというアプローチに挑みました。その結果、入社3ヶ月半、Gitもターミナルも使ったことのないデザイナーが、約1.5ヶ月で251コミット・177ファイルを自力で書き、実装前に130件以上の仕様課題を発見・解決しています。デザイナー視点の詳細は山崎の記事をご覧ください。 デザイナーがここまで自走できた背景には、エンジニアの伴走がありました。本記事では、当時バックエンドエンジニアとしてデザイナーの伴走を担当した経験から、エンジニアが何をしたのかをお伝えします。この記事を読むと以下のことがわかります。 デザイナーがStorybookを書くために、どんな環境を用意すればよいか エンジニアの伴走で「やること」と「やらないこと」の線引き 導入にかかる工数感 前提 安全に試行錯誤できる環境を作る ツールを整える CUIを使う Node.jsバージョンを揃える Gitを使う Claude Codeを使う デザイナーに伴走する やること・やらないこと 工数 まとめ 前提 本アプローチを適用したプロジェクトについて説明します。 本プロジェクトはB2B向けSaaSアプリに新たな機能を追加するプロジェクトです。 メンバーは、 PdM、エンジニア、デザイナーを含めた5-7名のチームで開発していました。 画面数は31個、ユースケースは23件で、全体工数は約半年と見積もられていました。 なおバックエンドは、AIを使ったユースケース駆動開発にトライしており、その記事はこちらで読めます。 caddi.tech 安全に試行錯誤できる環境を作る コードが書けないデザイナーが触る環境では、何をしても壊れない安心感が最も大事だと考えました。そのため、本番リポジトリとは完全に別のリポジトリ(仕様リポジトリ)を作り、Storybookを配置しました。 技術スタックはStorybook + Vite + React + TypeScriptです。社内デザインシステムをnpmパッケージとして導入し、本番と同じコンポーネントをStorybook上で使える状態にしました。 ディレクトリ構成は、下記の通りで本家リポジトリに移植しやすいように構造に合わせました。 当初はデザイナーが理解しやすいよう、リポジトリ内のディレクトリ構成とStorybookのサイドバー階層を別々に管理していました。しかし、二重管理は認知負荷が高いため、本家リポジトリのやり方を踏襲しました。 storybook/ ├── _template_component.md # コンポーネント用テンプレート ├── _template_page.md # ページコンポーネント用テンプレート ├── pages/ # 本番のディレクトリ構成に対応 │ ├── request/ │ │ ├── component/ # RequestPageコンポーネントで利用するコンポーネントを格納する │ │ ├── RequestPage.mdx # RequestPageの画面仕様を記述する │ │ ├── RequestPage.stories.tsx # Storyを記述する │ │ └── RequestPage.tsx # コンポーネント本体 │ ├── requestDetail/ │ ... ├── common/ ├── locales/ # i18nラベル定義 ├── data/ # ダミーデータ └── types/ # 型定義 コンポーネントは基本的に .mdx / .stories.tsx / .tsxのファイル3点セットで作成する必要があります。このルールはpre-commitフックで自動チェックされます。 また、画面仕様を書くためのテンプレートを設計しました。過去の手戻り事例を振り返ると、実装時に仕様が決まっていなくて困ったことにはパターンがありました。例えば、バリデーションのタイミング、データがないときの表示、デフォルトの並び順などです。これらを項目として洗い出し、テンプレートに落とし込んでいます。内容としては次のようなことが記述されています。 新規or既存の変更 State(Empty, Loading, Partial, Error) カラム定義、ステータス定義 フィルター・ソート仕様 バリデーションルールとエラー表示タイミング スクロール挙動、ページネーション仕様 i18nラベル定義 テンプレートがあることで、デザイナーは「何を決めるべきか」の出発点を持った状態で仕様書を書き始められるようになったり、AIへの入力としても活用できました。 ツールを整える リポジトリを用意しただけでは、デザイナーは自走できません。デザイナーが使うツールについても整えました。 CUIを使う デザイナーにはAIを活用する上で前提となるCUIにまず慣れていただきました。 Mac標準のターミナルでも構いませんが、素の状態では決して使いやすいとは言えません。 好きなターミナルアプリを入れるといいですよと伝えたところ Warpを選んでいました。 設定なしでコマンド履歴や補完がバッチリ効くので、初心者には使いやすいターミナルかもしれません。 山崎さんも最初は「黒い画面で文字を入力するなんてわかりにくいし操作しにくい」と言っていましたが、しばらくすると「GUIが煩わしい、CUI便利ですね」と言い始めました。使いやすい環境を整えた上でしばらく使ってみることが大事だと感じました。 Node.jsバージョンを揃える 山崎さんのNodeバージョンを確認したところ、brew経由でnode@20がインストールされていました。 このインストールの仕方だとプロダクト毎に使うNodeバージョンが異なるバージョンに対応できないのでバージョン管理ツールを使った方が良いと伝え、miseをインストールし、mise経由でNode.jsをインストールしました。 Node.jsは本家リポジトリと同じバージョンとしました。この作業は恐らくエンジニアがやったほうがよいでしょう。 Gitを使う Gitの操作やGitHubの使い方も覚えてもらいました。用語や概念はサル先生のGit入門で学んでもらったものの 、Gitは怖いという印象が拭えなかったため、ペアプロを通じて一緒にコマンドを実行しながら不安を払拭していきました。 仕様リポジトリでは、ブランチはmainブランチのみで、PRは使わずに直Pushを許容する運用にしました。 作業者と作業範囲がぶつかり合うことはほぼないと判断してこの運用にしました。実際ほとんど競合が起こることはありませんでした。 Claude Codeを使う 山崎さんはClaude Codeに関しては既に使ったことがある状態でした。 しかし、コンテキストの扱い方については知らなかったので、同じチームの石田さんが書いたモデルの性能を引き出すための Claude Code コンテキストマネジメント入門の記事を紹介しました。コンテキストウィンドウの状況をすぐに把握するために、Claude Codeのステータスラインに表示するようにしました。設定方法は「claude code statusline context window」で検索すれば見つかります。 これらの設定をして、コンテキストウィンドウが40%を超えたら/clearするようになったり、コンテキストを汚してしまった場合は/rewindを使えばいいのか!など様々な学びがあったようです。 また、RaycastのWindow Management機能でウィンドウ配置のホットキーを設定し、Claude Codeとエディタの並列配置をワンタッチでできるようにしました。この設定は、文章で読むと大したことないのですが、実際に操作してみると、もうウィンドウ配置をマウスで整えることがなくなります。 デザイナーに伴走する 毎日1〜2時間のデイリーSyncを行いました。Slackのハドルで山崎さんの画面を共有してもらい、操作を見守りつつ注釈ツールで誘導するペアプロ形式で進めました。 初期はGitの操作やStorybookの書き方など、ツールの使い方を教えることが中心でした。慣れてくると、「このステータスの定義はこれで正しいか」「このバリデーションのタイミングはいつか」など、仕様そのものの議論へと移っていきました。 ツールや操作に関する伴走のスタンスは、デザイナーの習熟度に合わせて徐々に変化させました。最初は知識や操作を直接教えるティーチングが中心でしたが、慣れてくるにつれて答えを与えるのではなく気づきを引き出すコーチングへと切り替えていきました。 一方、仕様の議論になったときはコーチングのスタンスをあえて手放しました。エンジニアとデザイナーという役割の壁を取り払い、対等な立場で議論しました。仕様はどちらか一方が教えるものではなく、異なる視点を持ち寄って一緒に決めるものだからです。 山崎さんに感想を聞いたところ、『最初は右も左もわからずもどかしかったですが、のびのび放牧の環境で、教師と生徒ではなく対等な立場で議論できたからこそ、楽しく突っ走れました!』とのことでした。 やること・やらないこと 具体的に、伴走で「やること」と「やらないこと」を次のように線引きしていました。 やること 環境構築やツール設定など、デザイナーだけでは判断・解決が難しい技術的な土台づくり エラーが出たときの原因の切り分けと、解決の方向性を示すこと CLAUDE.mdやテンプレートなど、AIとの協業を助ける仕組みの整備 仕様の議論では対等な立場で一緒に考えること やらないこと たとえ自分が書いた方が早くても、デザイナーの代わりにコードを書くこと AIで解決できる問題にエンジニアが介入すること まずAIに聞いてもらい、それでも解決しない場合にサポートする コードの品質を本番レベルに引き上げること 仕様リポジトリの目的は仕様の定義であり、コード品質ではない 工数 最後に、エンジニア側の工数を正直にお伝えします。導入を検討する方の参考になれば幸いです。 項目 工数 備考 環境構築 トータル5日程度 Storybook + Vite + React + TypeScriptの基盤構築。構築自体は半日で可能だが、フォルダやファイルの調整を繰り返した。最初からポリシーが決まっていればもう少し工数は減らすことは可能。 伴走 毎日1-2時間(同期) × 約2ヶ月 ペアプロ形式の同期作業。デザイナーのオンボーディングを兼ねていた。 コードレビュー 週2時間程度(非同期) 伴走とは別にレビューの時間を確保。このコードレビューを元に伴走の方針を考えた。 まとめ この記事では、デザイナーがStorybookでUIの画面仕様を書くために、エンジニアが何をしたかを紹介しました。AIがあればデザイナーもコードを書ける時代ですが、AIだけでは超えられない壁があります。安全なリポジトリ、仕様書テンプレート、ツール環境といった土台を整え、代わりにやるのではなくCoachingで自走を支える——エンジニアの伴走があることで、デザイナーはAIを最大限活用しながら自分の力で前に進めるようになりました。 エンジニア1名の工数は、環境構築5日 + 毎日1〜2時間の伴走 × 約2ヶ月 + 週2時間のコードレビューでした。決して軽い投資ではありませんが、実装前に130件以上の仕様課題を潰せたことを考えると、十分なリターンがあったと考えています。 同じ課題を抱えるチームの参考になれば幸いです。
こんにちは。CADDi Quoteのプロダクトデザイナー山崎文菜 (@ayana_yamazaki) です。 去年までは、Figmaでデザインファイルを完成させて、エンジニアに渡す。それが当たり前だと思っていました。 実装に入ってからエンジニアに「ここのデフォルトの並び順、昇順にしてますけど大丈夫ですか?」と聞かれ、Figmaを見返す。あっ決めてなかった…! デザインファイルではUIが完成していたのに、実はUXの意思決定が終わっていなかった… この記事は、コードが書けないデザイナーが、エンジニアの伴走を受けながらClaude CodeでStorybookを書き、プロダクトマネージャーとのウォークスルーで130件以上の仕様課題を実装前に発見・解決した実践録です。 Figma→実装のハンドオフで手戻りに苦しむデザイナーやエンジニアに向けて、何をやり、なぜ仕様の抜け漏れを実装前に潰せたのかをお伝えします。 1. Figmaは画面を完成させるが、意思決定を完了させない 2. やったこと: コードで画面仕様を定義し、PdMとUX検証した 3. なぜ効いたか①: コードは曖昧さを許さない 例1: エラー表示の定義から、エラー防止の設計へ 例2: 本番コードを起点にしたUX改善 その他にも、コードで定義する過程で露出した仕様 4. なぜ効いたか②: 触れるものを囲んで多職種で検証できる 例3: PdMとのUX検証で表現を磨き込む 例4: デザインフェーズでテスト観点を先回り 5. 結果 今後の検証 6. 導入に何が必要か 必要だったもの コードが書けないデザイナーが飛び込むと何が起きたか 得られたもの 終わりに: これはデザイナーの仕事なのか? 1. Figmaは画面を完成させるが、意思決定を完了させない 静的デザインファイル→実装のハンドオフには、2つの問題があります。 1. 静的デザインファイルでは「決めていないこと」が見えない エラーのバリデーションタイミング、Empty State、長い文字列が入った場合の表現…これらを決めなくても画面は完成します。未決定の項目が埋もれたまま先に進む。 2.Figmaはプロダクトの現実と繋がっていない Figma Prototypeは決められた遷移を辿れますし、Figma Makeならインタラクティブなプロトタイプも生成できます。しかしそれらは本番のコードやデータから切り離された世界です。既存実装に埋もれた仕様も、実データを流し込んだときの壊れ方も映りません。プロダクトの現実に触れなければ出てこない問いがあります。 2. やったこと: コードで画面仕様を定義し、PdMとUX検証した 最初にClaude CodeでHTMLプロトタイプを作り、画面構成や情報の優先度をPdMと検証しました。大枠の方向が固まった段階で、React + 社内デザインシステムでStorybookに移行。本プロジェクトではFigmaは全く使っていません。 画面仕様書 (.mdx) : カラム定義、ステータス定義、フィルター仕様、スクロール挙動、ページネーション仕様、i18nラベル定義 画面 (.story): 状態パターン網羅(Default、EmptyState、Loading、全ステータス表示など) UIコンポーネント (.tsx): インタラクティブに操作できる画面やUIコンポーネント 私はコーディングスキルがなく、すべてClaude Codeで指示を出して書いています。このプロセスを成立させた条件はセクション6で詳しく述べます。 3. なぜ効いたか①: コードは曖昧さを許さない コードで書き、UXを体験し、本番コードを参照する。この3つが重なったことで、ハンドオフまでに定義しきれなかった仕様が、プロセスの力で構造的に炙り出されました。 例1: エラー表示の定義から、エラー防止の設計へ ユーザーを追加するモーダルに、表示名とメールアドレスの2フィールドがあります。FEに「エラー状態」の赤い静止画を1枚描けば補完してもらえますが、UXデザイナーとして品質にこだわりたいところです。コードで書くと、「エラー表示」でもフィールドごとにonChange・onBlur・onSubmitと発火タイミングが分岐します。 これらを定義し、実際にキーボードで操作して挙動を触り比べる過程で、「エラーをどう表示するか」ではなく、「そもそもエラーを起こさない体験」を追求していきました。 onBlurで空白が入力されたらトリム、全角英数字は自動で半角に変換するなど、フロントのみで実装できるエラー防止のUXの詰め。操作しなければ浮かびづらい発想でした。 Storybookでバリデーションの挙動を確認し、仕様書を作成 例2: 本番コードを起点にしたUX改善 新画面にメモ編集機能を設計する際、本番の類似コンポーネントのコードを読み込みました。既存の実装と挙動を把握した上で、長文が入ったときの表示の切り方やアフォーダンスの改善など、元のUIにはなかった設計判断をStorybookで試しながら加えていきました。 コードを起点にしたからこそ、既存UIの設計意図を理解し、それを超える改善の起点が得られました。 その他にも、コードで定義する過程で露出した仕様 露出した仕様 なぜコードで定義すると露出するか グローバル対応の名前の字数(タイ人名の場合30文字を超えることも) ダミーデータを自分で定義するため、「どんなデータでテストすべきか」という問いが発生。PdM調査で名前に関する左記の実態が判明し、あらかじめ崩れ防止や視認性を担保できた Empty State・Loadingなどの状態 状態パターンをStoryとして網羅するため、未定義の状態が残らない 静的なデザインファイルでは、これらを「決めなくても画面は完成する」ため見過ごされることがありますが、コードでは「定義しないと画面が動かない」ため、未決定の項目が残りようがありません。 4. なぜ効いたか②: 触れるものを囲んで多職種で検証できる CADDiは製造業AIプラットフォームであり、製造業では品質を後工程の検査で担保するのではなく、前工程に検査を組み込む「フロントローディング」という考え方があります。 例3: PdMとのUX検証で表現を磨き込む Storybook上で実際にアイテムの追加・フィルター・ソートなどの画面操作を試せたからこそ気づけた問題がありました。 業務を再現しながらPdMとレビューを繰り返し、ステータスカラムの表現を改善した例を紹介します。 1回目: ステータス4種、期限切れはテキスト表現 → PdMとStorybook上でフィルターやソートを操作。ITリテラシーが高くないユーザーになりきると、期限切れアイテムを探す時にdateで絞り込む発想が難しいことに気づく 2回目: ステータスに「期限切れ」を追加 → 期限切れかつ未対応/対応中なのかがわからなくなるが、期限切れの時点でユーザーにやれることは少ないため未対応/対応中の区別は不要と判断。 3回目: ステータス5種 → システム的には違和感があるが、デジタルツールに不慣れなユーザーの直感性を優先 ユーザーの実務を再現しながら操作することで、実装前に1-3日サイクルで6回の検証・改善を回せました。 例4: デザインフェーズでテスト観点を先回り 伴走したエンジニアが「この仕様だとテストで何が壊れるか」という後工程の視点で私のアウトプットをレビューしました。例えば「複数タブで別テナントのセッションを開いたとき、メモの書き込み先が混在しないこと」といった観点です。 デザインファイル・画面仕様書がコードと同じリポジトリにあるので、テスト観点がデザインのフェーズで組み込まれました。通常なら実装後のテストで初めて見つかり、仕様修正と再実装の手戻りが発生する問題を、前工程で潰せる構造です。 デザイナーとエンジニア、PdM。この多職種の組み合わせが、UIデザインにおけるフロントローディングとして機能しました。 5. 結果 約1.5ヶ月で以下を達成しました。 PdMとのウォークスルーを6回実施 アウトプット: 31画面、49のStory、39件のMDX (画面仕様書) を作成 131件の仕様の抜け漏れ・UX改善施策を発見し、すべて実装前に解決 131件の内訳: 種別 件数 なぜ今回の方法で見つかったか 仕様の検討もれ(未定義・矛盾) 60件 定義しないと画面が動かないため、未決定の項目が構造的に露出した UX改善 45件 実際に操作できる画面でPdMと業務を再現し、静止画では気づけない違和感を検出した 実装誤り・既存との不整合 26件 本番コードを参照しながら作業したことで、既存実装との意図しない乖離に気づけた 今までは実装フェーズまで持ち越されていた問題が、修正コストの低い前工程で出てきました。 副次的に、コードベースを理解したことで「この実装ならこのUXが実現できる/できない」をエンジニアと議論できるようになり、デザイナーとしての意思決定の質が変わったと感じています。 今後の検証 フロントエンドへの繋ぎ込み: StorybookはFigmaと同じく中間成果物であり、FEの代替ではありません 担当FEからは「デザイナーの考えた最強のUI持ってこい」と言われており、仕様とUXの意思決定はデザイナーが、実装はFEが引き受けます Storybookのコードがどの程度そのまま流用されるかは現在検証中 再現性: 別のプロダクト・別のデザイナーへのプロセス展開を開始 6. 導入に何が必要か このプロセスの成立に必要な条件と、飛び込んでみてわかった正直なところを書きます。 必要だったもの 私の試行錯誤を受け止めてもらえる環境がなければ、このプロセスは成立しませんでした。 Claude Codeへのアクセス デザイナーだけでなく、エンジニア1名の伴走 最初から完璧を求めず、Sandbox環境での挑戦を許容するマインドセット 一定のデザインシステム(コンポーネントや状態パターンが構造化されたもの)が整備されていること コードが書けないデザイナーが飛び込むと何が起きたか 恥ずかしながら正直に書きます。 私は入社3ヶ月半、Gitもまともに使ったことがない状態でStorybookでの画面仕様実装を始めました。プロトタイプ制作でOpusのトークンをメチャクチャに溶かし、Sandboxのディレクトリをぐちゃぐちゃにし、リンターエラーが出ているのにAIに聞いて無理やりpushしていました… エンジニアの環境構築のおかげで、2ヶ月で251コミット・177ファイルを書けるようになりました。 詳しくはエンジニアの記事で説明されていますので、ぜひご覧ください! Storybookでデザイナーが仕様を書く——自走を支えたエンジニアの伴走記録 得られたもの 手戻り工数の削減: Figma→実装の翻訳コストや差し戻しを削減 実装前の検証の質: 実務を再現した操作検証でエッジケースや状態定義の漏れを前倒しで潰せる デザインの意思決定の明確化: 「デザイン側が定義しきれずエンジニアが埋めたUI」をゼロにし、根拠のある実装を届けられる 終わりに: これはデザイナーの仕事なのか? デザイナーがAIでコードを書き、エンジニアがUXを底上げし、PdMがプロトタイプを作る。職種の境界はどんどん溶けていて、「デザイナーとは何か」がわからなくなりつつあります。 Storybookを書くことがデザイナーの本質的な仕事かと聞かれたら、違うかもしれません。ただ、コードの側に踏み出して初めて見えたことがあります。 エラーをいつ出すか、データがないとき何を表示するか、デフォルトの並び順はどうするか… Figmaでは表現しきれなかったこれらを、今まで誰かが暗黙に決めていました。 境界を越えてみて初めて、自分が決めるべきだったことの輪郭が見えました。 手段がFigmaかStorybookかは本質ではなく、「ユーザーが触れるものに対して、曖昧にしない」ことが自分の責任だと思っています。 境界を越えると、居心地のいい場所は失います。その先に、もっと強い武器があります。一緒に踏み越えましょう!
こんにちは、Infrastructureチームの前多(@kencharos) です。AIの進化におびえながら、電気の資格の勉強でもしようかと考えている日々です。物理はいいですね。 さて、CloudSQLやAlloyDBで初回構築時に設定されるデフォルトユーザーをそのまま使っている方はいらっしゃいますか?いませんよね? 今回の話はAIネタではなくもっと地味なお話です。 データベースの権限設定のつらみ Terraform Postgres Provider の採用 パスワードの扱いについて CI/CDでの実行 1. Argo CD + k8s での Job実行 2. GitHub Actionsから踏み台サーバーに接続して実行する ownerの変更やowner指定には要注意 まとめ おまけ: 第三の選択肢、Crossplane データベースの権限設定のつらみ スキーマの設定を自動マイグレーションするサードパーティのサービスをそのまま使う場合ならともかく、 自分たちで開発しているサービスであれば、マイグレーションとアプリケーションの実行でDBユーザーの権限は分けた方が安全ですし、 複数サービスでDBを共有する場合なら、データベースやスキーマレベルで権限を分けたくなります。 また、AIツールがSQLを実行することも今後はあり得ると思います。 その場合もAIツールが勢い余ってすごいSQLを発行しても大丈夫なように権限を絞ったDBユーザーを使うようにしておきたいものです。 Google CloudのCloudSQLやAlloyDBではDBユーザーやIAMユーザーの作成はできます。 しかし、RDBMS内の権限付与(Grantなど)は結局RDBMSにログインしてSQLを実行する必要があります。 この手のSQLはどうやって管理しているでしょうか? prismaなどのアプリケーションのスキーママイグレーションで管理するのも手段の1つです。 ですが最初にマイグレーション用の権限を持つユーザーは作っておく必要があります。 また何らかの理由で開発サイクルとは別のサイクルでDBユーザーを追加、修正することは多々あります。 レプリケーション用のユーザーが欲しいとか、新しいメンバーが参加したからそのIAMユーザーを追加したいとか、要はスキーマ定義とは独立して管理したいわけです。 筆者らは、このような権限付与を手順書にSQLを書いて手動で実行していました。 苦痛を伴う作業と認識しながら、よい代替手段が当時は思いつきませんでした。 これにはいくつか問題があります。 複数環境で繰り返し実行が必要 変更の都度、現状の状態から細かいGrantやRevokeが必要 手順書の修正などで過去の権限付与の内容の修正などが面倒 などの理由から、微妙に権限付与の内容が環境ごとに異なってしまうことがあります。 意図した通りに権限付与ができているのかが把握しづらくなります。 サービスの拡大に伴ってデータベースの数も増えてきたこともありどうにかしなきゃと思い、解決策を探し始めました。 Terraform Postgres Provider の採用 権限管理のツール化を行うにあたり、要件は次の3つです。 手動ではなくCICDなどから実行して作業を自動化できること 宣言的に権限付与を管理できること PostgreSQLの様々な機能(extension, database, schema, grant, default_privileges, replication slotなど)に対応できること 当初はYAMLに権限付与設定を書いて、自作しようかと思っていましたが、terraform の postgresql provider を見つけたのでこれでいいやとなりました。 ただし、posgresql providerはサードパーティのプラグインですので、扱いには気をつけてください。 要件と概ね一致していましたし、筆者らはTerraformを常用しています。 hclファイルで宣言的に権限設定を管理できるのが大きな理由でした。 (欲を言えば、hclよりも読みやすいフォーマットの方がよかったのですが、それも今ならClaudeなどでサマリできそうだし、まあいいやとなっています) これを使って、以下のような権限設定を作成します。 ownerとなるmigration user、アプリケーション実行用のapplication userを作成する database, schemaは独自のものを作る application userにschema, tableへのgrantとdefault privilegesを設定する。 上記をhclで表現したものが次の通りです。 terraform { required_version = "1.10.5" backend "local" { path = "sample.state" } required_providers { postgresql = { source = "cyrilgdn/postgresql" version = "1.26.0" } } } // プロバイダの設定。ここではデフォルトユーザーやadminユーザーを指定する provider "postgresql" { host = "x.x.x.x" port = 5432 database = "postgres" username = "postgres" password = var.admin_password sslmode = "disable" connect_timeout = 15 } // userの作成 resource "postgresql_role" "migration" { name = "migration" login = true # password_woはstateにパスワードを記録しない。パスワードを変更したい場合は password_wo_versionを変更する password_wo = var.migration_password password_wo_version = "1" bypass_row_level_security = true } resource "postgresql_role" "application" { name = "application" login = true password_wo = var.application_password password_wo_version = "1" } // databaseの作成 resource "postgresql_database" "app_db" { name = "app_db" owner = postgresql_role.migration.name allow_connections = true } // schemaの作成 resource "postgresql_schema" "schema" { name = "app" owner = postgresql_role.migration.name } resource "postgresql_grant" "grant_to_schema" { database = postgresql_database.app_db.name role = postgresql_role.application.name schema = postgresql_schema.schema.name object_type = "schema" privileges = ["USAGE"] } # grant role to table resource "postgresql_grant" "grant_to_application" { database = postgresql_database.app_db.name role = postgresql_role.application.name schema = postgresql_schema.schema.name object_type = "table" # objectsが空の場合は all # objects = [] # privileges は明示する。ここに無いものは revoke 対象になる。 privileges = ["SELECT", "INSERT", "UPDATE", "DELETE", "REFERENCES", "TRIGGER", "TRUNCATE"] } # default privileges を指定して、application userに対して新規テーブルの権限を付与する resource "postgresql_default_privileges" "default_privs" { role = postgresql_role.application.name database = postgresql_database.app_db.name schema = postgresql_schema.schema.name owner = postgresql_role.migration.name objec
こんにちは、製造業データ活用クラウド CADDi Drawer でQAを担当しているOshiroです。 業務としては、開発チームと並走し品質保証に関する活動をしています。コードを書くことはほぼ無く、主にテスト設計のドキュメント作成やテスト実施、リリースにおける運用作業に携わっています。 また、自作のカエルのキャラ絵文字を描いて、みんなに使ってもらう「カエルの人」としても活動しています。 このような絵文字を作っています。 今回は、AI活用で非エンジニアでも可能なツール生成術の一例を紹介したいと思います。 PCにツール類のインストール作業は一切不要で、主に Google Workspace のサービスを利用します。 ※Gemini Canvas、Google Sitesの利用を前提としています。管理者の権限設定によっては機能がOFFになっている可能性があります。 やったこと Gemini Canvas でテストデータ生成ツールを構築 Google Sites で社内共有 背景:テストデータって作るのって意外と大変 私がQAとして関わっているプロダクトは、大量の図面データや関連文書を検索してインサイトを得るという特性を持っています。そのため、大量のテストデータが必要となります。 このテストデータを準備するのが意外と大変で、テスト工程が始まる段階でその都度作成したり、保管場所を探しに行ったり、細かな時間を消費していました。 データ作りの対応方法がバラバラだと、人によって対応スピードが変わるので改善をする必要がありました。 解決策の模索:AI活用でどうにかしたい 手軽にテストデータを大量に作るためには、ツールを作れば良いと考えました。 調べると、Geminiの中でCanvasという機能を使えば、画面プレビューをしながらコードが書けると分かりました。 これならUI付きのツールを作れるかもしれないと思い試してみることにしました。 試してみる:Gemini Canvas Gemini画面を開きツール「Canvas」を選択し、とりあえず動作確認してみました。 「図面のサンプルデータの画像が生成できるツールを作りたいです」 という大雑把なプロンプトを書いて送信。 結果、それらしいものが1発で生成されました。 初回で生成された時の状態はこのような形で表示されました。 画像もダウンロードできる。これは使えそうだと確信しました。 ここからは以下のようなプロンプトで、対話形式で機能を追加していきました。 プロンプト指示 実装された機能 「大量データを生成可能にして、出力をPDFファイルにまとめたい」 PDF一括ダウンロード機能 「PDFに保存する画像の数を指定できるようにしたい」 ページ数指定機能 「ランダム性を持たせて次々に新規生成できる形にしたい」 リアルタイム・ランダム生成機能 「新規生成された画像はPDF生成前のストックとして使えるようにしたい」 PDF生成前のストック機能 といった流れで微調整を重ねてブラッシュアップしていき、ツールができあがっていきました。 出来上がったツールの状態がこちらです。 Canvasコードの画面には共有ボタンでソースコードをコピーする機能があり、HTMLのソースコードとしてシェアできるようになっていました。 社内公開してみる:Google Sites 社内では、Google Sitesで共有することにしました。 Google ドライブ で「サイト」を作って、Canvasで生成したソースコードを貼り付けるだけ。 (サイドバー「挿入」 -> 埋め込む -> 埋め込みコード の入力欄) あとはページ設定の調整やURLとなる文字列を決めつつ公開ボタンを押していく簡単な作業でした。 サイトの公開設定としては社内のGoogleログイン状態でないと、アクセスできない状態にしています。 共有して、他のチームにも使えるようにしたところ、各所で喜びの声が聞けました。 「動作確認のために利用するテストデータとして使わせてもらいます」 「こういうのほしかった」 「大量データ生成できて助かってる」 元々は自分のために作ったツールではありますが、みんなの役に立てたので良かったなと感じています。 生成したコード自体は、業務には強く影響しない領域に配置しています。 バグがあったとしてもプロダクトには影響なく、再度Gemini Canvasに読み込ませて追加修正できるので手軽にメンテナンスすることが可能です。 サイトには、新たなページもどんどん追加していけるので効率化できるツールを現在も増やしていっています。 高機能な3Dデータの生成ツールも作れたりします。 こちらが、3Dデータをプレビューしながら穴を開けたり突起物を追加したりできるようなツールです。 この3Dデータ生成ツールは、エンジニアからも「なにこれ!?すごい!Google Sitesでこんなの動かせるの?」と驚かれました。 躓いたポイント・工夫したこと 機能を追加していくうちに、Gemini Canvasでは動くが、Google Sitesにコードを貼り付けた時には動かないことがありました。 その時は、「Google Sitesに貼り付けたら動かなかった。対応して欲しい」という指示で、GeminiがGoogle Sitesでも動作するコードに書き換えてくれます。 また、ランダム性を持たせることには少し悩む部分はありました。Google Sitesに埋め込む際、工夫したのが「ランダムな文言の出し方」です。 毎回AIに考えさせると動作が重くなる懸念があります。そして何より「想定外の変な言葉」が出てくるリスクがあります。 そこで、あらかじめ安全で適切な文言リストをソースコードの中に用意し、そこからランダムに抽出する仕組みにしました。 このリスト作成時には、「著作権や倫理的に問題ないか」をQA目線でチェックしました。 これにより、「爆速で動き、かつ事故が起きない」という安心の社内ツールが完成しました。 終わりに 今回は、ツールのセットアップなしで、非エンジニアでも可能なデータ生成ツール作成の一例を紹介しました。 まずは自分が楽になるためのツールを作り始めたことがきっかけでしたが、自分が困っていたことであれば他の人も同じように困っているかもしれないと思い共有したところ感謝され、自分のチームだけでなく他のチームにも貢献ができました。 また、このツールを使ってもらうことでフィードバックをもらい、新たなアイディアも生まれてきているのでこの活動は続けていこうと考えています。 Gemini Canvasは画面プレビューしながらのコード生成が手軽で強力であると感じています。 一つのアイディアとして参考にしていただければと思います。
こんにちは、昨年キャディ株式会社に入社した佐野です。入社して初めての技術記事になります。 この記事では、これまでの開発経験を振り返りながら、それが推論システムの運用にどう活きたのかを整理してみようと思います。 対象読者 機械学習システムを運用したことがないSRE、バックエンドエンジニアの方々 これから機械学習システムを運用していくSRE、バックエンドエンジニアの方々 伝えたいこと 機械学習のモデル開発経験や機械学習システムの運用経験がなくても、機械学習システム(推論システム)の運用に貢献できます。SREの領域と被るものが大半であるため、今までの経験を活かせることが大半です。 入社前までの経験 直近5年くらいはバックエンド、SREを往復するようなキャリアでした。APIの設計・開発から始まり、DB設計、システム設計などを色々やっておりました。機械学習の経験はというと、プロジェクトで半年ほど画像認識で使用する画像をOpenCVでコネコネしていたことはあります。ただそれも7年以上前なので、記憶の彼方に消えてしまってます。 配属先のチーム キャディに入社後の私の配属先のチームは、Analysis Platformチームで、機械学習システム(推論システム)を開発・運用しています。具体的には、モデル開発以外(システム設計、API設計・開発、インフラ構築など)の業務を全て担っています。 役に立った経験 実際チームでシステムを運用、タスクを消化していく中で感じたことは、バックエンド、SREの経験をそのまま使えるということです。例えば、以下のような経験はそのまま活かすことができます。 システム設計 データリソースの選定 モニタリングやアラートの設計/運用 ネットワーク設計 など システム設計(非同期設計) システム設計については、推論システムだからといって特別なものはほぼなく、通常のシステム設計の考え方(非同期設計など)に似た部分が多いように感じています。その中でも特に非同期設計の経験は役に立ちます。なぜ役に立つかは後述します。 データリソースの選定 この経験も非常に有用だと考えています。推論APIの設計にも依存しますが、モデルによってはAPIのレスポンスが肥大しがちです。例えば物体検出のモデルでは、検出数によってレスポンスが大きくなることもあり得ます。この推論結果をどのデータリソースに格納するのが望ましいかは腕の見せ所であり、面白いポイントだと感じています。Cloud SQLのようなRDB、mongoDBのようなNoSQL、GCSのようなストレージサービスなど様々な選択肢がある中で、要件に応じた選定を行う必要があります。これを決めていくにあたり、これまでのデータリソースの運用経験が非常に活きると考えています。 モニタリングやアラートの設計/運用 推論システムといえど、運用という点ではこれまでのシステムとほぼ変わりません。SLOの定義や、アラート疲れを起こさないための運用設計など、まさにSREの知見が求められるシーンが多かったです。 また私が入ったタイミングで、既存の推論システムをGKEへ移行しており、システムをいかに安全に移行するか、モニタリングをどう再設計するかなどの知見も非常に有用でした。 zenn.dev 通常システムとの違い 今までの経験がいきるとはいえ、推論システムと通常システムには多少違いがあります。自分の中で感じた部分を少し書ければと思います。 非機能要件: 非同期処理にしたい モデルによって推論に時間がかかることはしばしばあります。例えば物体検出のモデルでは、検出数が多ければ多いほど推論に時間がかかるため、処理時間が数十秒になることも珍しくありません。そのため非機能要件を定めるに当たっては注意が必要になります。システムを運用する視点では、非同期処理によせることができれば、同期処理と比較し、シビアに処理時間を気にしなくて良くなります。 また、当たり前ですがGPUは通常のインスタンスと比較してコストが高くなります。そのためGPUを使用しないときは、インスタンスを停止してコストを抑える必要があります。具体的にはkubernetesの場合はKEDAのScaledObjectなどを使い、使用していない期間のインスタンスの停止などの工夫を行い、コストを抑える必要があります。 このようなこともあり、非同期処理の経験が非常に活かせると考えています。 技術選定: GPUを利用するための術を知りたい 推論システムを運用していく上で避けて通れないのは、GPUの運用です。私の知る限りGoogle Cloudでは、Compute EngineはもちろんのことマネージドサービスであるVertex AI、サーバーレスであるCloud RunでもGPUを扱えます。これらの選択肢の中で、何が要件としてマッチしているかは検討できるようになる必要があると感じています。 docs.cloud.google.com 余談ですが、Compute Engineのマシンタイプでは、A2 マシンシリーズやN1 マシンシリーズ(T4)、G2マシンシリーズ(L4)という名前が出てきます。最初これらのアルファベットを聞いて、何を言ってるのかさっぱりわからなかった記憶があります。 docs.cloud.google.com リソース管理: GPUを効率的に使いたい GKE上でGPUを効率的に使用するにはいくつか方法があります。マルチインスタンスやタイムシェアリングなどの方法があります。私はまだ実装経験はありませんが、これらをどのように使っていくかはまさに推論システムの特徴なのではと感じています。 docs.cloud.google.com ライブラリ管理: マイナーバージョンの更新であっても細心の注意を払いたい 機械学習で使用されるライブラリであるnumpyやtorchなどのバージョン更新には細心の注意が必要です。たとえマイナーバージョンの更新であってもnumpyは2.0系統であれば、推論結果に影響が出る可能性があるようです。私もPR作成時に意図せずバージョンが上がった時があり、機械学習エンジニアに指摘してもらうことがありました。 最後に まだまだ入門したばかりで、学ぶことも多々あると思いますが、SREやバックエンドでの経験は確実に活き、運用できていると感じます。皆さんもぜひチャレンジしてみてくださいね!
こんにちは。キャディ株式会社の Analysis Platform Group で MLOpsエンジニアを務めているAmaniです。 普段はキャディの各サービスの裏側で稼働する機械学習基盤やバックエンドの開発、およびアプリケーションとの連携部分を担当しています。 前半期は、社内の機械学習ワークロードを既存のマネージドサービスから Google Kubernetes Engine (GKE) に移行するプロジェクトを進めていました。 その過程で、shadow deploy / mirroringの重要性を改めて強く認識する出来事がありましたので、本記事では、その背景と学びについて書きます。 背景:機械学習ワークロードのGKE移行 Shadow deploy導入までの経緯 とはいえ、本番データでは簡単にテストできない 解決策としての shadow deploy / mirroring コストとの向き合い方 まとめ 背景:機械学習ワークロードのGKE移行 前半期は、社内の機械学習ワークロードを Google Kubernetes Engine (GKE) に集約するプロジェクトを進めていました。 従来の構成では、ワークロードは大きく同期推論と非同期推論の2種類に分かれており、Google Cloud の Vertex AI、Compute Engine、Cloud Run を組み合わせて構築されていました。 これらを運用・開発の両面で扱いやすくするため、ワークロードをGKEへ統合しています。 移行の背景や全体的なメリットについては、同じAnalysis Platform GroupのHirokaが以下の記事で詳しくまとめているので、興味がある方はそちらもぜひ参照してください。 zenn.dev 移行対象となるモデルは合計で15個あり、それぞれが異なる特性(パフォーマンス要件やリソース消費)を持っています。 例えば、CADDi にアップロードされる図面に含まれる製造業特有の記号を検知するモデルや、それらを分類するモデル、文字を抽出するモデルなど、多様な役割のモデルが含まれています。 さらに、これらのモデルを呼び出す経路も一様ではなく、APIや大規模な前処理パイプラインなど、合計で5種類以上のクライアントが存在していました。 クライアントの多くは別チームによって開発・運用されているため、移行にあたっては各チームとの調整も重要なポイントでした。 これだけのモデル数・クライアント数を対象に、Claude CodeやDevinといったツールも活用しながら、グローバルなメンバーで短期間に移行を完了させた点については、それ自体で一つの記事になる規模の取り組みですが、本記事ではその中でも、shadow deployによって得られたMLシステムの信頼性に焦点を当てます。 Shadow deploy導入までの経緯 MLモデル移行作業は、まず同期推論モデルから開始しました。影響範囲が比較的小さいモデルを選定し、パイロットとして移行を進めました。 信頼性を担保するため、不具合が発生する前提でロールバックしやすい設計とし、あらかじめロールバックプランも用意しました。 移行後の構成に対しては、関係チームと連携しながら負荷試験・動作確認・精度検証を実施し、必要なチューニングを行ったうえで、クライアントの接続先を新しいシステムへ切り替えました。 切り替え直後は大きな問題もなく、安定して稼働しているように見えましたが、切り替えから2日後、一部のリクエストで以下のようなエラーがバースト的に発生しました。 {"error":{"code":400,"message":"Invalid request: Input should be a valid dictionary or object to extract fields from","status":"INVALID_ARGUMENT"}} 影響範囲は限定的でしたが、原因を即座に特定できなかったため、SLO内ではあったものの、リスク回避を優先して移行前の推論システムへロールバックを実施しました。 後続の調査により、原因は上流システムから送られてくる一部リクエストに含まれる例外的なヘッダーであることが判明しました。 移行前のVertex AI ベースのシステムではこのヘッダーを許容していた一方で、移行後のシステムではエラーとして扱われていました。 さらに、このヘッダーは本番環境のごく一部のリクエストにのみ含まれており、サンプリングされたテストデータでは再現されないパターンでした。 このようなケースは、オフラインテストだけで事前にカバーすることが難しい典型例といえます。 結果として、ロールバックしやすい設計と事前に準備していたプランにより、障害に発展する前に旧システムへ切り戻すことができて、その後、該当のケースに対応する形で新システムの修正を行いました。 今回の事例はヒヤリハットにとどまりましたが、ここで改めて感じたのは、 複数チームが関与する複雑なシステムほど、本番データに基づく検証が不可欠になる という点です。 とはいえ、本番データでは簡単にテストできない 一方で、本番データには顧客データが含まれますので、セキュリティやガバナンスの観点から、自由にテストに使えるものではありません。 この「必要だけど使えない」というギャップは、特にMLシステムにおける推論結果の品質や安定性の検証において大きな課題となります。 たとえば、 データ分布の偏り 想定外の入力パターン 上流システムの揺らぎ といった要素は、オフラインのテストデータではどうしても再現しきれません。 セキュリティやガバナンスの制約もあり、実質的には本番相当の環境で検証を進める必要がありました。ここでいう「本番でテスト」は直接本番システムに影響を与えるものではなく、本番と同じ入力を用いて裏側で挙動を観測する、いわゆるshadow deployを指しています。 解決策としての shadow deploy / mirroring 上記のヒヤリハットを踏まえ、移行プロジェクトの残りの対象モデルでは、簡易的なshadow deploy / mirroringを導入することにしました。 Shadow deployとは、短く言うと「新しいバージョンを旧バージョンと並行で動かし、本番と同じ入力を受けさせながら、その出力はシステムやユーザーには影響を与えない形で比較対象として扱うデプロイ手法の一つ」です。 今回の移行プロジェクトでは、移行後のモデルを「セキュリティが担保されている本番環境で本番と同じ入力」で裏側で動かし続け、既存モデルと並行して挙動を観察しました。もちろん、CIテストやstaging環境での負荷試験・精度試験など、デプロイ前の一通りの検証を終えたうえで、最終確認として実施しています。 移行対象の既存システム図(イメージ)は以下の通りです。 図1 既存システム図 スケジュール制約を踏まえ、まずは「検知と差分把握」にフォーカスした最小構成で進め、以下の図のようなシステムを構築しました。なお、図が複雑にならないように、クライアントおよびモデルはそれぞれ1つに簡略化して示しています。 図2 Shadow稼働期間中のシステム図 推論結果の比較検証に加えて、裏側で両システムのログやパフォーマンスを継続的に監視していました。その結果、いくつかの例外的なケースもユーザー影響を出さずに本番環境で発見することができ、調整後に本番切り替えを行うことができました。本番切り替え後のシステム図は以下の通りです。 図3 切り替え後のシステム 比較検証期間中に検知・修正できた例外的なケースとしては、以下のようなものがありました。 新旧システム間のパフォーマンス・リソース差分 従来は Vertex AI や Compute Engine 上で実装されていた推論基盤を、GKE上のLitServeへ移行したことで、実行基盤およびフレームワークの両面に変更が入りました。そのため、既存システムと同等以上のパフォーマンスが得られるかを改めて検証する必要がありました。 その検証にあたっては、テストデータでは本番トラフィックの分布や特性(検出対象の数など)を正確に再現することが難しいという課題がありましたが、shadow deploy を用いることで、本番データを活用した確実な検証が可能になりました。 またこの過程では、timeout設計の重要性も再認識しました。特にバッチ処理や長時間実行されるリクエストでは、旧システムとの前提の違いによりタイムアウトの発生条件が変わり、設定値の見直しが必要になりました。あわせて、timeoutを長く設定しすぎるとリソース占有時間が増え、結果としてコストが増加するため、性能だけでなくコストとのバランスを踏まえた設計が重要になります。 実データでのみ発生するエラー 検知対象が例外的に多い図面において、システムリソースが圧迫されるケースがありました。元システムでは問題なく処理できていたものの、移行後のシステムではエラーが発生しました。 この問題は、LitServe、Kubernetes、Google Cloud Pub/Sub のパラメータチューニング(同時メッセージ数、batch size など)によって解決しました。 精度のギャップ 一部のモデルでは、新システム側で前処理が正しく適用されていないケースがあり、旧システムとの差分として推論結果の精度ギャップが発生しました。 これは shadow deploy によって初めて検知できた問題であり、前処理の実装漏れに起因するものでした。 上記の経験を踏まえ、特に複雑なMLシステムにおいては、shadow deployの仕組みを使って継続的にデータの性質や分布を把握することが、より信頼性の高いシステムにつながると強く実感しました。 この考え方自体はセオリーとして理解していたものの、今回の経験を通じてその重要性を改めて認識しました。 こうしたメリットを得られることが前提となる一方で、次に論点となるのはコスト面です。特にMLのワークロードではGPUリソースの利用も伴うため、無視できない要素になります。 この点についてはトレードオフもあるため、次の章で整理します。 コストとの向き合い方 Shadow deployは、トラフィックの複製と追加の推論実行が発生するため、インフラコスト(特にGPUによる推論コスト)の面でオーバーヘッドが生じます。 ただし、用途に応じて設計することで、無駄なコストは抑えられます。 例えば: 機能確認が目的の場合 フルスケールである必要はなく、縮小構成で数日間動かすことで、挙動や例外ケースの検知には十分なケースが多いです。 負荷耐性の確認が目的の場合 フルスケールで短時間(数時間〜1日)実施する方が効率的です。 さらに、すべてのリクエストを対象とするのではなく、トラフィックの一部のみをshadow側に流すといった制御を行うことで、コストと検証精度のバランスを取ることも可能です。 このように目的と検証対象を明確にすることで、「必要十分なshadow環境」を設計できます。 まとめ 今回の移行を通して、特にMLシステムにおいては「本番環境でしか見えない挙動」が一定割合で存在するという前提に立つ必要があると感じました。 オフラインテストやstaging環境での検証だけでは、データ分布や上流システムの揺らぎまではカバーしきれません。 そのギャップを埋める手段として、shadow deployは有効です。特に複雑なMLシステムにおいては実質的に必須の仕組みだと考えています。 一方で、コストや運用負荷とのトレードオフがあるため、目的を明確にした設計が重要になります。 さらに技術面以外の学びとして、プロジェクト管理の観点では、MLモデル(そしてAPI全般)の移行は単純にモデル数に比例するものではなく、各モデルに紐づく呼び出し元クライアントとの関係性に依存して工数が増えるという点があります。特に1つのモデルに複数のクライアントが存在する場合、その調整や影響確認の分だけ工数は増加します。 今回の移行プロジェクトでは最小構成でshadow deployを導入しましたが、今後は Istio のトラフィックミラーリングなど、より標準化された仕組みの活用も検討しています。
※本記事は、こちらの記事を和訳したものです stratomere.com 序章 航空機が音速を超えると、衝撃波が発生する。衝撃波は周囲の空気が伝わる速度よりも速く移動するため、周囲の空気がその擾乱を吸収しきれず、不連続性が生じる。これがソニックブームである。 池の水面に広がる波紋のように、衝撃波は外側へと伝播し、その影響は距離とともに薄れていく。AIサービスの需要は、技術サプライチェーンが吸収できる速度をはるかに超えて拡大している。マイクロソフトのCEOによれば、当初は大規模な言語モデルの学習と実行にGPUが必要だったが、今ではそれらを動かすためのエネルギーが課題となっている。こうした波紋は私たちの日常生活にも波及し、データセンターの需要が電力網の容量を圧迫するにつれて電気料金が高騰し、限られた半導体供給を巡って家電製品同士の競争が激化するにつれて、家電製品の価格も上昇している。 物理的なサプライチェーンは、ソフトウェアのようなスピードで変化に対応できない。半導体工場や発電所の建設には、数十億ドルもの設備投資と数年にわたる期間、そして建設と運営に必要な人材が不可欠である。需要が明確で資金も潤沢にある場合でも、生産能力を一夜にして拡大することはできない。この媒体は、急激な変化に抵抗する。 物理的および経済的な制約によって計算能力が制限される世界において、ソフトウェアアーキテクチャはますます企業戦略の表現としての役割を担うようになっている。それは、顧客の需要と希少で高価なリソースとのバランスを取り、それによって何が拡張可能で、何が停滞し、何が非経済的になるかを決定する。 豊富な資源に基づいて構築されたソフトウェア 数十年にわたり、ソフトウェアはハードウェア性能の着実な向上という環境の中で発展してきた。ムーアの法則のおかげでトランジスタ数は約2年ごとに倍増し、より高速なプロセッサ、より高速なネットワーク、そしてより多くのメモリが実現した。デナードのスケーリングは、トランジスタ密度の向上と駆動電圧の低下によって電力密度を抑制することで、この進歩を持続させることを可能にした。しかし、メーカーがマルチGHz帯に進出し、コア電圧がトランジスタの閾値電圧に近づくにつれて、この傾向は鈍化した。小型化に伴う非効率性が増幅されたことも相まって、電力密度は持続不可能な熱特性に近づいた。 IntelのXeon 6やAMDのEPYC 9005シリーズといった最新のハイエンドデータセンターCPUは、前世代と同じクロック周波数範囲で動作し、性能向上の大部分はシングルコア性能の向上ではなくコア数の増加によるものであり、ソケットあたり200コア近くに達することもある。しかし、キッチンで料理人を増やしても必ずしも夕食の準備が速くなるわけではないように、コア数を増やしてもコンピュータの速度が自動的に向上するわけではない。マルチコアCPUは高度な協調メカニズムを必要とし、これらの新たな協調の課題をソフトウェアに押し上げ、ロック、セマフォ、そして並列コンピューティングに特化した研究分野を生み出した。これらの概念は、ソフトウェアチームに大きな認知負荷をかけ、顧客に機能を提供する方法だけでなく、基盤となるハードウェアの利用率を最大化して高性能なユーザーエクスペリエンスを提供する方法についても考えなければならない。 ハードウェアによってもたらされるこうした複雑さに対処するために、私たちは詳細を隠すための抽象化を作り出す。モバイルアプリ開発者はAPIのことだけを考えればよく、3GPPやLTEといったAPIを支えるセルラー技術を理解する必要がない。ウェブサイトを構築する人は、豊富なアニメーションやグラフィックに集中でき、それらを支えるグラフィックレンダリングパイプラインについて心配する必要はない。ジョン・オースターハウトは著書『ソフトウェア設計の哲学』の中で、この原則を的確に捉えている。つまり、複雑さをカプセル化するシンプルなインターフェースを備えた「深い」モジュールを構築することで認知負荷を軽減し、組織の拡張性を高めることができる。 パブリッククラウドの登場はこの抽象化をさらに推し進めた。物理的なコンピューティングリソースはAPIの背後に移り、サーバーの調達やデータセンターの稼働開始を待つ必要がなくなった。新しいコンピューティングクラスターはクリック一つで利用できる。すべてのハードウェアを調達するために必要な設備投資さえも、従量制の運用費用として抽象化された。クラウドプロバイダーは規模の経済性を活用することで、一見すると豊富なコンピューティングリソースを提供し、摩擦をほとんど感じることなく、数千台のサーバーに垂直方向および水平方向に拡張できる選択肢を与えた。今や、特定のソフトウェアパフォーマンスの課題を、単により多くのコンピューティングリソースとメモリを投じることで、つまり資金調達によって解決するオプションが生まれたのだ。しかし、現代のワークロードの要求の急激な変化により、これらの回避策の一部が限界に達し始めている。 メモリの逼迫 抽象化は問題を分解し、人間が扱いやすくするのに役立つが、根本的なパフォーマンス上の課題を解決するものではない。並列化されたワークロードが増加するにつれて、特にGPUやその他のアクセラレータにおいて顕著に見られるように、課題は並列計算を実行することから、十分なデータを効率的に供給することへと変化した。 1990年代後半にNvidiaによって普及したGPUは、もともと並列化が容易で反復的なグラフィックス処理パイプラインを高速化するために開発された。これらの特殊な技術は並列処理の限界を押し広げてきた。実際、最新のデータセンターGPUは数万個のコアを搭載し、同時に動作して毎秒数千兆回の計算を実行する。追いきれないほどのゼロの数である。同様に、数万人の料理人がいるキッチンでは、全員を忙しくさせるために大量の食材が絶えず流れなければならない。演算コアにデータを流し込むこの能力、しばしばメモリ帯域幅と呼ばれるもの、は容易にボトルネックになり得る。 メモリ技術は長年にわたって進歩してきたが、トランジスタと電力密度の課題によりシングルコアCPUのパフォーマンス向上が大幅に鈍化したのと同様に、メモリ密度の向上も鈍化している。より多くのメモリチップを並列に配置することで帯域幅を拡張できるが、PCB上の物理的なスペースは有限であり、密度と帯域幅は相互に関連する制約となる。高度に並列化されたワークロードは、対応する大量のメモリと、データをやり取りするための帯域幅を必要とする。ほとんどのコンピュータは、半世紀前に誕生して以来、何度か改訂されてきたDRAMと呼ばれるメモリ技術を使用している。最新の改訂版であるDDR5は、チャネルあたり50GB/秒以上を実現しており、DDR4の約2倍の速度である。これらは大きな進歩だが、GPUの性能が向上するにつれて、大規模言語モデルのワークロードはメモリにさらに多くのものを要求するようになった。計算能力が利用可能なメモリ技術を追い越すこの現象は、しばしば「メモリの壁」と呼ばれる。 このメモリの壁を打破するのに役立つ技術の一つが、HBM(高帯域幅メモリ)だ。2010年代半ばに初めて登場したHBMは、メモリチップを垂直に積み重ねることで、より高いビット密度と帯域幅を実現する。各階に専用エレベーターを備えた高層マンションを想像してみよう。これにより、より多くの人が同時に建物に出入りできる。シリコンを積み重ね、これらの「エレベーター」を織り込む複雑な工程のため、HBMは標準的なDRAMと比較して製造工程における歩留まりと効率に課題を抱えている。この課題に加え、ハイパースケーラーからの需要も、今日見られるメモリ不足の一因となっている。GPUサプライチェーンで始まった衝撃波は、メモリにまで及んでいる。 CPUは中心的な役割を担わなくなる 今日のメモリ制約が顕在化するずっと前から、ハードウェアとソフトウェアのアーキテクチャは、スループットの向上と専門化の進展に対応するために再編成されてきた。過去10年間、シングルコアCPUの性能はほぼ停滞している一方で、ネットワーク帯域幅は桁違いに増加した。現代のオフィスネットワークは一般的にギガビットイーサネットで配線されており、ほとんどのデータセンターは現在100GbEをはるかに超える速度で稼働している。わずか2年前の2024年には、800GbEが標準化された。これは、4K映画1本を1秒未満で転送できる十分な帯域幅であり、単一のCPUコアが処理できる速度をはるかに上回る。 GPU間通信の需要の高まりが、高帯域幅化の傾向を加速させている。今日の大規模言語モデルは非常に大きいため、単一のGPUでは実行できない。GPUのクラスタ全体が必要となる。データ量が単一のCPUで効率的に処理できる量を超えて増加するにつれ、最新のシステムはCPUをデータパスから切り離すことで対応してきた。高速トラフィックをCPU経由でルーティングするのではなく、専用のシリコンがデータ転送を直接処理し、CPUはオーケストレーションの役割を担い、操作の設定、ポリシーの適用、例外処理を行う。NVLinkなどの専用インターリンクはこの変化を象徴するものであり、CPUを経由せずにGPU同士を直接接続することで、低ジッター、低遅延、高帯域幅を実現する。 このパターンはGPUに限ったものではない。イーサネットNIC(ネットワークインターフェースカード)は、高度なコンピューティングデバイスへと進化し、VXLANなどの最新のカプセル化プロトコルからRDMA(リモートダイレクトメモリアクセス)などの技術まで、あらゆる処理をCPUからオフロードできるようになった。従来、NICはネットワークパケットをオペレーティングシステムのネットワークスタックに渡し、ネットワークスタックがペイロードを抽出してユーザー空間プロセスに転送して処理を行っていた。しかし今日では、ネットワークトラフィックが高速すぎて、CPUによる効率的な処理が困難になっている。現代のデータセンターの基準からすると比較的平凡な100Gbpsでも、単一のCPUコアでネットワークを飽和させることはほぼ不可能である。ネットワークが高速すぎるため、CPUは利用可能な帯域幅を十分に活用できるほど十分なバイト数を迅速に送信することができない。このCPUボトルネックを回避するため、NICはCPUの関与なしに、RAMから直接データを読み込み、処理し、ネットワーク経由で送信する。 同様に、ストレージの世界では、NVMe SSDはCPUを介してデータを処理する代わりに、PCIeバス上でDMA(ダイレクトメモリアクセス)を利用してシステムメモリとの間でデータを転送する。これは、レストランの荷降ろし場からパントリーまで専用の独立した経路を作り、厨房の料理人が食材を運ぶ手間を省くことと同じようなものだ。ストレージとネットワークの両方におけるこれらの進歩により、NVMe-oF(NVMe-over-Fabrics)などの技術を利用して、ネットワーク経由でリモートのNVMeドライブにほぼローカル接続と同等の速度でアクセスできるようになった。これらの技術は、最新の高度なNICを活用して高帯域幅のデータ転送をCPUからオフロードする。 ワークロードパターンの変化に伴うこうした技術的変化は、ハードウェアだけにとどまらない。大規模な需要ショックはシステムが動作する環境そのものを再構築し、ソフトウェアアーキテクチャはシステムが動作するハードウェアと一緒になって処理を行う。 物理とソフトウェアが出会う場所 データベースは、コンピューティング、メモリ、ストレージ、ネットワークの交点に位置し、これらのダイナミクスを非常に明確に把握できる。データベースは性能の技術的な限界で動作し、レイテンシとスループット、一貫性と可用性など、様々なトレードオフを強いられる。 Cassandraなどの有名なデータベースで採用されているシェアードナッシング(Shared Nothing)アーキテクチャは、リソースの完全な分離を重視し、各ノードが独自のCPU、メモリ、ストレージを備えている。他のノードへの依存関係はないが、ワークロードが一定でない場合、ハードウェアリソースがアイドル状態になる可能性があることを意味する。CPU、メモリ、ストレージの比率は動的に変更できないため、ハードウェア利用率を最大化するには、比較的安定したワークロードパターンが必要となる。イベントログ用のデータベースは、大容量のストレージを必要とするが、読み取りクエリは非常に少ないため、計算要件は低くなる。eコマースストアで使用される製品データベースは、買い物客からの読み取りクエリが多数発生する可能性があるが、ストレージ容量は比較的少なく、販売される製品数に応じてのみ拡張される。言い換えれば、シェアードナッシングアーキテクチャでは、リソース比率のミスマッチがアイドル状態のシリコンへの支払いやパフォーマンスのボトルネックに直結する可能性がある。 対照的に、シェアードストレージアーキテクチャは、データストレージ層をCPUやメモリなどのコンピューティングリソースから分離する。この概念は、GoogleがBigQueryで初期に取り組んだことに端を発している。これにより、CPUとメモリのリソースをストレージ要件とは独立して拡張できるため、特にクラウド環境において、より高いリソース利用率を実現できる。2025年にDatabricksに買収されたデータベース企業Neonは、コンピューティングとストレージの分離を可能にするために、Postgresストレージ層の大部分を再設計した。これにより、データ量とは独立して負荷に応じてリソースをスケールアップおよびスケールダウンできるようになり、常時専用リソースを必要としない一種の「サーバーレス」データベースが実現した。 ElasticsearchやClickHouseのようなシステムもこれと似たシェアードストレージアーキテクチャを採用しており、Amazon S3などのサービスからの安価で耐久性の高いオブジェクトストレージの可用性によって実現されることが多い。これらのストレージサービスは、読み取り後書き込み整合性や条件付き書き込みのようなプリミティブを提供することで、同時読み取りと書き込みを処理できる分散した一貫性のあるストレージを提供するという難問を解決に貢献する。Apache IcebergやDelta LakeといったオープンなLakehouseフォーマットは、この変化を象徴するものであり、コモディティ化された共有ストレージの上に、より高レベルのデータセマンティクスが重ねられている。 ベクトル埋め込みを利用したAI関連サービスの需要が急増したことで、ベクトル検索を中心とした新しいデータベース開発が急増し、この分離が主流になりつつある。現在の最先端のベクトル検索アルゴリズムには、複雑なチューニングなしで動的な挿入とリコール性能のバランスが取れていることから多くのデータベースで採用されているHNSW(階層型ナビゲーション可能なスモールワールド)のバリエーションが含まれている。しかし、これらのグラフベースのアルゴリズムは、メモリ内のデータ構造を走査する必要があるため、メモリをかなり消費し、データベースの計算コストを増大させる。ストレージ容量とは独立して計算リソースを動的にスケールアップおよびスケールダウンできるアーキテクチャを採用することで、データベースは限られたハードウェアリソースの利用率を高めることができる。 ワークロードパターンが変化し、ハードウェアが進化するにつれて、データベースアーキテクチャは、そのアーキテクチャに内在するトレードオフを浮き彫りにせざるを得なくなった。今日の状況では、コンピューティング、メモリ、ストレージ、ネットワークという4つの柱をどれだけ密接に結合するかという決定は、パフォーマンス特性だけでなく、ハードウェアの利用率、コスト、スケーラビリティにも影響する。データベースはシステムの物理的な限界に近い位置にあるが、その根底にあるダイナミクスはデータベース特有のものではない。ソフトウェアが強い制約の下で動作する場合、アーキテクチャの選択は技術的な成果だけでなく、経済的な実現可能性にも影響を与え始める。ここに明確な答えはない。どのアーキテクチャも、どの制約が最も強く影響するかという賭けを内包している。それを誤ると、もはや存在しない世界に合わせて最適化したことになる。 圧力下における抽象化 抽象化は無料ではない。それらが生み出された環境の前提条件に従って価格付けられている。数十年にわたり、ハードウェアの普及が進んだことで、そのコストは容易に無視されてきた。しかし、物理的な制約が強まるにつれて、抽象化に内在する隠れたコストが再び明らかになりつつある。 抽象化の中には、実質的にコストがかからないものもある。例えば、スマートポインタやジェネリクスなどが挙げられる。これらのメカニズムは、実行時のパフォーマンスを損なうことなく、開発者の認知負荷を軽減する。一方、コストがかかるものもある。ガベージコレクションは、実行時に一時停止が発生する代わりに、開発者が変数のライフタイムを管理する必要をなくす。仮想関数は、パフォーマンスの低下と引き換えに、実行時の動的なディスパッチを可能にする。組み込みシステムや高性能コンピューティングでは、C、C++、Rustといった言語が広く使われている。これらの言語は、開発の複雑さや認知負荷を犠牲にして、実行時の動作を制御可能にする。これは、すべてのバイトとすべてのサイクルに目に見えるコストがかかる状況では、合理的な選択と言える。 現代において最も重要なソフトウェアの一つであるLinuxカーネルは、ユーザー空間のプログラムがハードウェアの詳細を気にしなくて済むようにしてきた。そのシステムコールはハードドライブやNICに関する詳細を抽象化し、メモリ、ファイル、ネットワークのようなプリミティブを扱うための安定したインターフェースを公開する。カーネルはドライバーを通じてハードウェアを直接管理・通信し、最終的にそれらを抽象化された汎用リソースとしてユーザー空間に提供する。これらは抽象化だけでなく、関心の分離も提供する——カーネルはハードウェアリソースが適切に管理・保護されることを保証し、ユーザー空間はユースケースにより集中する。 ハードウェアの限界で動作する場合、これらの抽象化のパフォーマンスオーバーヘッドは、利点を上回り始める可能性がある。ネットワーキングとストレージ技術がCPU性能に対して大幅に進歩するにつれ、増大する需要に追いつくソフトウェアの能力が重要になる。メモリのコピーやコンテキストスイッチは、毎秒数百万回繰り返されると、その負荷が蓄積される。LLMベースのサービスに対する現在の需要は、こうしたプレッシャーを大幅に加速させている。その衝撃波は、ハードウェアの不均一な進歩によって既に負荷がかかっていた抽象化全体に波及し、もはや無視できないコストを露呈させている。 例えば、数十ギガバイトものリアルタイム高解像度ビデオをネットワーク経由でSSD搭載のリモートストレージデバイスに送信するアプリケーションを考えてみよう。データは、ビデオ送信アプリケーションのユーザー空間メモリからカーネル、NIC、光ファイバーケーブルを経由して受信側のNIC、受信側のカーネル、ユーザー空間、そして再びカーネルへとコピーされ、最後にSSDに書き込まれる。各ステップでデータは再配置され、時には仮想的なデジタルエンベロープにカプセル化され、受信側で取り出される。コンピュータからより多くのパフォーマンスを求めるにつれ、この仮想的な書類のやり取りのオーバーヘッドが明らかになる。 このシャッフルは、カーネルとユーザー空間の抽象化レイヤーの結果だ。データはカーネルを介して出入りする。2010年代後半、データセンターのネットワークは100Gbpsを超え、この抽象化を回避する「近道」を見つけたいという要望が高まった。DPDK(Data Plane Development Kit)は、カーネルの抽象化を完全にバイパスし、カーネルを介さずにユーザー空間アプリケーションがNICと直接通信できるようにする業界標準フレームワークである。ネットワークスタックの責任をアプリケーションに移し、カーネルのセキュリティ保証と多重化機能の一部を犠牲にする代わりに、処理速度を向上させる。メモリコピーとコンテキストスイッチを削減することで、DPDKは、高帯域幅でパフォーマンスを重視するアプリケーションが、カーネルを経由する場合と比較して2~3倍の効率を実現できるようにしている。DPDKにはトレードオフがあり、万能の解決策ではないが、機会費用の方程式が変化するにつれ、業界がこれらの抽象化の境界を再構築するために動いてきた多くの方法の一つだ。 環境の変化、技術の進歩、ワークロードの変化に伴い、抽象化の概念を再検討する必要が生じている。コスト、パフォーマンス、経済性に関する暗黙の前提は、プレッシャーがかかった時に明確になる。これらのマクロな動きに気づかないか、適応を拒むことは、隠れた負債の一形態を積み重ねる——システムとプロダクトは健全に見えるが、負荷がかかると破綻してしまうのである。 ハードウェアへの意識 2025年以降にリリースされたデータセンター向けGPUには、数年前には存在しなかった4ビットおよび8ビット浮動小数点表現であるFP4とFP8での動作に特化したモジュールがシリコンに組み込まれている。これらの超低解像度数値表現は、LLMのメモリ効率と演算効率を向上させるために開発されたものであり