はじめに:ブラウザAIの隠れたボトルネック、重複キャッシュ
最近、Webブラウザ上で直接AIモデルを実行する「オンデバイスAI」のトレンドが注目されています。Transformers.js、WebLLM、wllamaといったライブラリを使えば、別途サーバーを用意することなく、ユーザーのブラウザで自然言語処理や音声認識などのタスクを実行できます。
しかし、ここには大きな問題が一つあります。同じモデルファイルを複数のWebサイトがそれぞれダウンロードして保存するという点です。例えば Xenova/whisper-tiny.en モデル(約177MB)をサイトAでダウンロードしても、サイトBで同じモデルを使う場合は最初から再ダウンロードが必要です。これはブラウザの「Cache Isolation(キャッシュ分離)」ポリシーによるもので、セキュリティとプライバシーのためにオリジン(origin)ごとにキャッシュを分離しているため、同一URLのリソースでも異なるサイトではキャッシュヒットが発生しません。
実際にChrome DevToolsのStorageパネルを開いてみると、同じWasmランタイムファイル(ort-wasm-simd-threaded.asyncify.wasm、約4.7MB)もサイトごとに個別に保存されている様子が確認できます。これはユーザーのディスク容量の無駄遣いであるだけでなく、ネットワークトラフィックとローディング時間にも悪影響を及ぼします。
この記事では、この問題を解決するために提案された Cross-Origin Storage API の概念と、Transformers.jsでの実験的な適用方法について詳しく解説します。

Cross-Origin Storage API:ハッシュベースの共有キャッシュ
Cross-Origin Storage(COS)APIは、navigator.crossOriginStorage という新しいインターフェースを通じて、オリジン間(Cross-Origin)でのファイル保存と共有を可能にします。ここで重要なのは、ファイルの識別子としてURLではなく**暗号学的ハッシュ(SHA-256)**を使用する点です。
基本動作フロー
// 1. ハッシュ値の準備(SHA-256)
const hash = {
algorithm: 'SHA-256',
value: '8f434346648f6b96df89dda901c5176b10a6d83961dd3c1ac88b59b2dc327aa4',
};
try {
// 2. COSからファイルを検索
const handle = await navigator.crossOriginStorage.requestFileHandle(hash);
// キャッシュヒット!すぐにBlobとして読み込んで使用
const fileBlob = await handle.getFile();
console.log('COSキャッシュ使用成功!', fileBlob.size, 'bytes');
} catch {
// 3. キャッシュミス -> ネットワークからダウンロード後、COSに保存
const fileBlob = await fetch('https://cdn.example.com/model.onnx')
.then(r => r.blob());
const handle = await navigator.crossOriginStorage.requestFileHandle(
hash,
{ create: true, origins: '*' } // すべてのオリジンからアクセス可能
);
const writableStream = await handle.createWritable();
await writableStream.write(fileBlob);
await writableStream.close();
console.log('COSに保存完了!次回訪問者はこのファイルを再利用します。');
}
アクセス制御:originsオプション
COSはすべてのファイルを無条件に共有しないよう、origins オプションを提供しています。
origins 値 | 動作 | 使用例 |
|---|---|---|
'*' | グローバル共有。すべてのオリジンからハッシュで検索可能 | 公開AIモデル重み、共通Wasmランタイム |
['https://app1.example.com', 'https://app2.example.com'] | 特定のオリジンのみアクセス可能 | 社内専用モデル、プロプライエタリライブラリ |
| 省略(デフォルト) | same-site内でのみ共有 | 組織内サブドメイン間の共有リソース |
重要なルール:一度 '*'(グローバル)で保存されたファイルは、後で origins を狭めることはできません。逆に、特定のオリジンのみ許可したファイルは、後により広い範囲にアップグレード可能です。これは悪意のあるサイトが公開ファイルを隠蔽するのを防ぐためです。
整合性保証
COSはファイル保存時にハッシュを検証します。書き込み操作中にデータが宣言されたハッシュと一致しない場合、エラーが発生します。したがって、COSから読み取ったファイルは常に期待通りのバイト列であることが保証されます。これは、CDNからダウンロードしたモデル重みを別途検証する必要がなくなることを意味します。
プライバシーに関する考慮事項
オリジン間共有キャッシュは、「このファイルがキャッシュされているかどうか」を通じてユーザーの閲覧履歴を推測できるサイドチャネル攻撃の可能性があります。COSはこの問題を2つの方法で緩和します:
originsフィールド:機密性の高いリソースは'*'で保存しないよう開発者に推奨- 可用性ゲーティング(Availability Gating):グローバルファイルであっても、十分な数のオリジンからアクセスされていない場合、存在確認を返さない(ファイルがない場合と同じエラーを返す)
したがって、COSの検索失敗は「ファイルがない」という確定的事実ではなく、「今は教えられない」という意味の場合もあります。アプリは常に失敗時にネットワークフォールバックを実装する必要があります。

Transformers.jsでのCOS適用方法
Transformers.jsライブラリは、すでにCOS実験サポートをPR #1549で導入しています。使い方は非常に簡単です。
1. opt-inフラグの設定
import { env, pipeline } from "https://cdn.jsdelivr.net/npm/@huggingface/transformers@4.2.0";
// 👇 Cross-Origin Storageキャッシュバックエンドを有効化(実験的)
env.experimental_useCrossOriginStorage = true;
const asr = await pipeline(
'automatic-speech-recognition',
'Xenova/whisper-tiny.en',
{ device: 'webgpu' }
);
const result = await asr('jfk.wav');
console.log(result);
experimental_ プレフィックスは意図的なものです。まだ標準化されていないAPIであり、メジャーバージョンアップデートなしに変更される可能性があることを示しています。
2. 動作方式
フラグが設定されると、Transformers.jsはXet追跡モデルファイル(大容量ONNX重みファイル)のSHA-256ハッシュを自動計算し、navigator.crossOriginStorage のキーとして使用します。
- COSにファイルがすでに存在する場合:ネットワーク要求なしで即座にロード
- COSにファイルがない場合:通常ダウンロード後、COSに保存(他のオリジンの次回訪問者が再利用)
3. モデルレジストリとの連携
Transformers.jsの ModelRegistry.is_pipeline_cached() APIはCOSと直接統合されており、ユーザーのキャッシュにどのモデルがあるかを確認した上で最適なモデルを選択する戦略を実装できます。
// ユーザーのCOSにwhisper-tiny, medium, large-v3のどれがキャッシュされているか確認
const cachedModel = await ModelRegistry.is_pipeline_cached([
'Xenova/whisper-tiny.en',
'Xenova/whisper-medium.en',
'Xenova/whisper-large-v3'
]);
// キャッシュされている最も大きなモデルを選択(より正確な結果)
if (cachedModel) {
const pipeline = await createPipeline(cachedModel);
// ...
}
4. 実際の効果
2つの異なるオリジン(例:https://googlechrome.github.io と https://rawcdn.rawgit.net)でCOSを有効化したTransformers.jsアプリを実行すると、最初のサイトでダウンロードした177MBのWhisperモデルが2つ目のサイトではミリ秒単位でロードされます。Wasmランタイム(4.7MB)も同様に共有されます。
5. 注意点と制限
- ブラウザネイティブ未サポート:現在COS APIはいずれのブラウザにもネイティブ実装されていません。実験するにはChrome拡張機能 Cross-Origin Storage Extension をインストールする必要があります。
- フォールバック安全性:拡張機能がインストールされていない環境では、
env.experimental_useCrossOriginStorage = true設定は無視され、既存のCache APIにフォールバックします。そのため、プロダクションに適用しても副作用はありません。 - プライバシーリスク:グローバル共有ファイルがごく少数のサイトでのみ使用される場合、ユーザー識別に悪用される可能性があります。Chromeチームはこれに対する具体的な緩和策を引き続き研究中です。

日本国内の開発エコシステムにおける適用コンテキスト
日本国内のWebサービス環境でCOS APIが特に有用となるシナリオは以下の通りです。
- AI搭載ドキュメントエディタ:メルカリ、LINE、SmartHRなどが提供するAI文書要約、校正、画像生成機能。ユーザーが複数のサービスを利用する際、同じAIモデルを重複ダウンロードする非効率を削減できます。
- 大規模SaaSプラットフォーム:一つの企業が複数のサブドメイン(例:
service1.company.com、service2.company.com)で同一のAIモデルを使用する場合、COSのデフォルトsame-site共有ポリシーで簡単に最適化可能です。 - 国内CDNとの連携:日本では
cdn.jsdelivr.netやunpkgなどのグローバルCDNに依存するよりも、国内CDN(さくらインターネット、IDCフロンティアなど)とCOSを組み合わせてトラフィックコストを削減することも検討できます。
この技術の限界または注意点
- 標準化の遅延可能性:COSはまだ初期提案段階です。W3C標準化プロセスでAPIデザインが大幅に変更されたり、採用されない可能性もあります。
- 拡張機能依存:現在の実験は拡張機能を通じてのみ可能であり、一般ユーザーに拡張機能のインストールを要求するのは現実的に難しいです。
- セキュリティ監査の必要性:オリジン間共有キャッシュは新たな攻撃面を生み出す可能性があります。特にハッシュ衝突やタイミング攻撃に対する綿密な検討が必要です。
次のステップ学習方向
- 実際に実験する:Cross-Origin Storage Extension をインストールし、公式デモページでCOSの動作を確認してみてください。
- Transformers.jsへのコントリビュート:PR #1549のコードを分析し、自身のプロジェクトにCOSバックエンドを統合する方法を研究してみてください。
- 関連標準ドキュメントを読む:Explainerドキュメント と WICGの議論 をフォローして最新の議論を追いかけましょう。
- 類似技術との比較:Cache API、Origin Private File System(OPFS)、Service WorkerキャッシュとCOSの違いを理解すると、より豊かなアーキテクチャ決定が可能になります。