Modern Web Guidance 日本語解説

技術深掘り・ワークフロー

技術深掘り:CLIと意味検索はどう動くか

元の資料:Local vector search for coding agents: From 507 MB to a 7-line loop(How the Modern Web Guidance CLI and semantic search work)
2026年11月12日(Chrome for Developers ブログ、Paul Irish)

このページには実際に動く作例があります。

200件超のガイドから、目の前の課題に合う1件を、トークンを無駄にせず、オフラインで、ミリ秒で見つける。その検索の仕組みを3世代の作り替えから解説した技術記事です。

土台の考え方:段階的な開示と、エージェント側のRAG

ガイド全部は1.7MBのMarkdownです。これを AGENTS.md に貼るのは現実的ではありません。そこで検索CLIを持つ構成になっています。

  1. 平常時、エージェントが見ているのはスキルの説明文だけです(約205トークン)。
  2. フロントエンドの課題で、エージェントがCLIで検索します。modern-web-guidance search "animate height auto" のような形で、関連する10件(約530トークン)が返ります。
  3. 選んだガイドを modern-web-guidance retrieve animate-to-intrinsic-sizes で丸ごと取り込みます(約800トークン)。互換性、フォールバック、書き方の要点が入ります。

MCPサーバではなくCLIにした理由も書かれています。MCPはトークンの無駄か、動的な道具発見による起動の不確かさがあること。Web検索は古い回答や参照文書が混ざり、ネットワーク越しで数秒かかり、オフラインでは動きません。ローカルのCLIはCPUでミリ秒で動きます。

3世代の作り替え

指標第1世代第2世代第3世代(現在)
中身LanceDB+ネイティブONNXTensorFlow.js+MiniLM-L6-v2静的なInt8埋め込み×Gemini埋め込み+BM25
パッケージの大きさ507MB(展開後)23.4MB7.1MB
検索の初回(コールド)の遅さ約35ms(ただしビルドできれば)770ms185ms
検索語の埋め込み(温まった後)約34ms約227ms30µs(0.03ms)
最大メモリ400MB超346MB145MB
実地の検索の的中率(Hit@K)未測定80.6%→調整後94.7%95.4%(クラウドのGemini埋め込みAPIでは96.9%)

第1世代:507MB

LanceDB、Apache Arrow、Transformers.jsとネイティブのONNXランタイムの構成です。開発者の機械では動きましたが、スキルを入れるときにアーキテクチャ依存のバイナリのダウンロードやC++のコンパイルが走り、クラウドのサンドボックスでは失敗しがちでした。展開後は507MBありました。

第2世代:23MB

ネイティブを捨て、純JavaScriptのCPUエンジンに替えました。TensorFlow.jsの400超のモジュールからMiniLMが使う26のカーネルだけを残して6MB→830KBにし、ベクトルの置き場はLanceDBから、ビルド時に圧縮したベクトルとメモリ上の内積走査(1ms未満)に替えました。埋め込み器は遅延読み込みにして、retrieve と list は10ms未満で終わります。依存なしで23MBになり、約75万回の検索が実行されました。

第2世代が実地で壊れたところ

スキルが入っているのに古いコードを書いた実行を調べると、検索の穴が2つ見つかりました。

実例では、削除確認のプロンプトに対してエージェントが正しく検索したのに結果が空で、結局 window.confirm() を書きました。本来は <dialog closedby="any"> のガイドがある課題です。

直し方:実地のデータで測り、ハイブリッド検索にする

元のベンチマークはガイド自身から作った850件の合成クエリで、ガイドの言い回しに寄りすぎていて、この失敗を捉えられませんでした。新しい評価は、実際のCLIの利用記録から取った約4,000件の検索(記録されるのはエージェントの2〜5語の検索引数だけで、利用者のプロンプトやコードは記録されません。DISABLE_TELEMETRY=1 で止められます)と、毎夜のエージェント評価から取った1,029件で作られています。

この2つで、実地クエリでの的中率は80.6%から94.7%に上がりました。

第3世代:事前に焼いた埋め込みと、7行のループ

それでも残った問題は重さです。実際の検索の86.7%は2〜5語(中央値3語)しかないのに、そのたびにTensorFlow.jsを起動し、22.6MBのニューラルネットを読み、初回770msと最大346MBのメモリを使っていました。

発想の転換は、ガイド側と検索側で同じモデルを使う必要はない、という点です。ガイドは約200件で、版を切った後は変わりません。そこでガイド側のベクトルは、公開時にクラウドで gemini-embedding-001 を使って事前に作り、256次元のInt8ベクトルとして同梱します(圧縮で335KB)。検索側は、知っている単語ごとのベクトルの表を引き、重み付きで足すだけです。実行時の処理は、記事の題のとおり7行のループに収まります。

// 各単語の重みとInt8のスケールは scales[i] に畳み込み済み
for (const [i, f] of enc) {
  const wt = scales[i] * f;
  const offset = i * 256;
  for (let k = 0; k < 256; k++) {
    out[k] += wt * table[offset + k];
  }
}

単語の表は、29,165語の語彙(fetchpriority、light-dismiss、popover、scrollytelling のような現代のWeb用語が1語として入っています)を同じ埋め込みで作り、33,000件の実在のWeb検索で調整したものです。「light」+「dismiss」が照明ではなく <dialog closedby="any"> のほうを指すように、組み合わせの着地点まで調整されています。表全体は圧縮で5.3MBです。

ガイド側にも同じ単語表を使う方法は試されましたが、数百語の平均を取ると全ガイドが「普通の英語」の近くの狭い範囲に潰れてしまい、関係ない検索が高スコアになる失敗が起きました。短い検索側だけ静的な表、ガイド側は本格的なモデル、という非対称な組み合わせが、クラウド級の精度とオフライン30µsの両立になっています。

作例:検索の感触

実際のCLIは意味検索とキーワード検索の併用です。下はキーワード一致だけで再現した簡易版で、雰囲気をつかむためのものです。例えば「dialog」「フォーム 検証」「パスキー」と入れてみてください。

本物はターミナルで試せます。

npx modern-web-guidance@latest search "confirm destructive action"
# → dialog ガイドが先頭に返ります(第2世代では空でした)
記事の締めは「コードは安くなった。測ることが仕事だ」という趣旨です。候補の実装をエージェントは数分で書けます。しきい値0.38が実地の検索の9%を静かに壊していたような失敗に気づけるかどうかが本体で、チームは検索の実装よりも、約5,000件の実クエリと自動採点を人の評価に合わせる測定の仕組みのほうに時間をかけた、と書かれています。

原文を読む:Local vector search for coding agents: From 507 MB to a 7-line loop(How the Modern Web Guidance CLI and semantic search work)

短縮URL(投稿の記載):https://goo.gle/4zJWa2F / 解決先:https://developer.chrome.com/blog/mwg-technical-deep-dive

← コード生成の先:Modern Web Guidanceで学び続ける技術深掘り:リファクタ(モダナイズ)の仕組み →