言語モデル

ウェブ機能: LanguageModel

Prompt API を使用すると、デベロッパーは Gemini Nano を使用してブラウザで直接自然言語処理タスクを実行できます。この組み込み AI アプローチにより、ユーザーのプライバシーが保護され、サーバー費用が削減され、オフライン機能が有効になります。

1. はじめに、ハードウェア要件

Prompt API は現在、Windows、macOS、Linux、Chromebook Plus 向けの Chrome バージョン 148(デスクトップ)以降で利用できます。

ハードウェアの前提条件

  • ストレージ: 22 GB の空き容量(初期プロファイルとモデル用)。
  • メモリ / CPU: 16 GB RAM、4 個以上の CPU コア。
  • GPU: 4 GB 以上の VRAM(音声入力に必要)。
  • ネットワーク: 最初のモデルのダウンロードにのみ必要です。

API を初期化する

ダウンロードをトリガーする前に、モデルが利用可能かどうかを確認します。

const availability = await LanguageModel.availability();

// Do not call create() when unavailable — the model cannot run on this device.
if (availability !== 'unavailable') {
    const session = await LanguageModel.create({
        monitor(m) {
            // Inform the user while the model downloads so the UI doesn't appear frozen.
            m.addEventListener('downloadprogress', (e) => {
                console.log(`Downloaded ${e.loaded * 100}%`);
            });
        },
    });
}

2. プロンプトの基本機能

このセクションのセッションの例では、簡潔にするために session.destroy() を省略しています。セッションが不要になったら、必ず session.destroy() を呼び出してデバイスのメモリを解放します(セクション 5 を参照)。

基本出力とストリーミング出力

短い回答には prompt() を使用します。コンテンツが長い場合は、promptStreaming() を使用して、よりレスポンシブな UI を提供します。

必須: モデル出力を innerHTML に割り当てないでください。モデル出力は信頼できず、挿入されたマークアップが含まれている可能性があります。常に textContent またはサニタイザーを使用します。

const session = await LanguageModel.create();

// prompt() accumulates the full response before resolving — use for short, one-shot output.
const result = await session.prompt('Write a haiku about coding.');
// textContent, not innerHTML — model output is untrusted and must not be parsed as markup.
outputEl.textContent = result;

// promptStreaming() yields independent chunks that must be concatenated;
// use for longer content so each chunk can be rendered progressively.
const stream = session.promptStreaming('Write a long story about a robot.');
let completeResult = '';
for await (const chunk of stream) {
    completeResult += chunk;
    outputEl.append(chunk);
}
console.log('Full story:', completeResult);

マルチモーダル入力

Prompt API は、テキスト、音声、ビジュアル入力(画像、キャンバス、動画フレーム)をサポートしています。

const session = await LanguageModel.create({
    // Declaring expected input types lets the browser optimize model loading.
    expectedInputs: [{ type: 'text' }, { type: 'image' }],
    expectedOutputs: [{ type: 'text' }],
});

const response = await session.prompt([
    {
        role: 'user',
        content: [
            { type: 'text', value: 'What is in this image?' },
            { type: 'image', value: document.querySelector('canvas') },
        ],
    },
]);

3. 高度なセッション管理

セッションにより、モデルは複数のインタラクションにわたってコンテキストを維持できます。

コンテキストと割り当て

各セッションにはトークンの上限があります。使用状況は session.contextUsage と session.contextWindow でモニタリングできます。ウィンドウがオーバーフローすると、最も古いメッセージ(システム プロンプトを除く)が削除されます。

セッションのクローン作成

クローン作成は、再初期化せずに同じ初期コンテキスト(「システム」パーソナリティなど)を共有する並列会話を開始する場合に効率的です。

const mainSession = await LanguageModel.create({
    initialPrompts: [{ role: 'system', content: 'You speak like a pirate.' }],
});

const branchA = await mainSession.clone();
const branchB = await mainSession.clone();
// Destroy the base after cloning — the clones own their own context from here.
mainSession.destroy();

過去のセッションの復元

ネイティブの「復元」機能は開発中ですが、以前の履歴を initialPrompts にフィードすることでセッションを再作成できます。

注: localStorage は暗号化されておらず、永続的です。保存された会話履歴にはユーザーの PII が含まれる可能性があるため、チャット履歴を保存する前にプライバシーへの影響を考慮してください。

// || '[]' ensures JSON.parse never receives null when the key doesn't exist yet.
const history = JSON.parse(localStorage.getItem('chat_history') || '[]');
const session = await LanguageModel.create({
    initialPrompts: history, // Array of {role, content} objects
});

4. JSON スキーマを使用した構造化出力

モデルが「おしゃべり」(例: 「はい、JSON は次のとおりです」)を追加しないようにするには、responseConstraint フィールドを介して JSON スキーマを使用します。これにより、出力が有効な JSON になり、すぐに解析できるようになります。

例: 感情分類

// Pass the schema as a plain object — do not JSON.stringify() it first.
const schema = {
    type: 'object',
    properties: {
        rating: { type: 'number', minimum: 1, maximum: 5 },
        is_positive: { type: 'boolean' },
    },
    required: ['rating', 'is_positive'],
};

const result = await session.prompt(
    "Rate the following feedback: 'The food was great!'",
    { responseConstraint: schema },
);

const data = JSON.parse(result);
console.log(data.rating); // 5

制約と接頭辞

prefix: true を使用してアシスタントのレスポンスを事前に入力することで、モデルをさらにガイドできます。

const character = await session.prompt([
    { role: 'user', content: 'Create a character sheet' },
    { role: 'assistant', content: '```json\n', prefix: true },
]);

5. ベスト プラクティスと安全性

  • リソースのクリーンアップ: 会話が終了したら、必ず session.destroy() を呼び出してメモリを解放します。
  • 出力の安全性: モデル出力は信頼できません。悪意のあるモデル出力による XSS インジェクションを防ぐため、結果は常に innerHTML ではなく textContent に書き込みます。
  • 制限付きの HTML を許可する必要がある場合は、ネイティブの Sanitizer API や DOMPurify などのサニタイザーを使用します。
  • タスクの中止: AbortController を使用して、ユーザーが長時間実行される生成を停止できるようにします。signal を LanguageModel.create() ではなく prompt() または promptStreaming() に渡します。
  • セキュリティ: 権限ポリシーを使用して iframe でのアクセスを制御します(<iframe src="..." allow="language-model"></iframe>)。
  • 設計: People + AI ガイドブックを確認して、責任ある AI の実装を確実にします。

構造化された出力と堅牢なセッション管理を組み合わせることで、デベロッパーは完全にユーザーのデバイス上で実行される、複雑でステートフルな AI アプリケーションを構築できます。

推奨事項と非推奨事項

推奨事項と禁止事項の完全なリストについては、https://developer.chrome.com/docs/ai/built-in-ai-dos-donts.md.txt をご覧ください。要点は次のとおりです。

適切なタイミングでモデルを準備する

対象: すべての API(Summarizer、Translator、Writer など)。

推奨: ユーザーが AI 機能を使用する意図を明確に示した時点で、セッションを初期化します。たとえば、ユーザーが関連する AI ツール画面に移動したとき、AI ワークスペースにカーソルを合わせたとき、機能の周囲の UI を操作したときなどです。セッションを事前にウォームアップすると、ユーザーがタスクを設定している間にモデルがバックグラウンドでメモリに読み込まれるため、コールド スタートのレイテンシを回避できます。たとえば、機能が反復的な使用を想定して設計されている場合は、現在の結果のレンダリングを開始するとすぐに、次に可能性の高い AI タスクを開始して、一歩先を行くようにします。

避けるべきこと: 必要な場合を除き、ユーザーが [生成] をクリックするまでセッションの初期化を待たないでください。モデルをまずメモリに読み込み、実行パイプラインを準備する必要があるため、コールド スタートの遅延が発生します。

作成時に初期プロンプトを設定する

適用対象: Prompt API。

推奨: セッションの初期化時にシステム指示を指定して、最初のプロンプトの速度を向上させます。

推奨されない方法: 空のセッションから開始し、最初の prompt() 呼び出しの一部としてシステム指示を送信する。これにより、モデルは最後の瞬間にこれらの指示を処理する必要があるため、レイテンシが増加します。

繰り返し行うタスクのセッションを複製する

適用対象: Prompt API。

Prompt API の場合、各セッションは会話のコンテキストを追跡し、以前のすべてのやり取りを考慮します。クローンは、初期プロンプトやクローン作成時点までのすべてのインタラクション履歴など、親セッションからすべてを継承するため、必要なもののみを継承するように使用方法を構成します。

行うこと:

  • ベース セッションを作成する: 関連性のないタスクを効率的に処理するには、システム指示のみを含み、以前の会話コンテキストを含まないベース セッションを作成します。
  • ベースラインのクローンを作成する: 新しいタスクのベース セッションで clone() を使用して、システム指示の再解析のオーバーヘッドを削減します。これにより、並列会話を作成したり、タスクをベースラインにリセットしたりできます。

避けるべきこと:

  • 関連性のないタスクに同じセッションを再利用しないでください。また、不要なやり取りの履歴がすでに含まれているセッションのクローンを作成しないでください。どちらのパターンでも、無関係な以前のコンテキストが現在のタスクに干渉する可能性があります。
  • 同じシステム指示で create() を繰り返し呼び出さないでください。代わりに、クローニング パターンを使用してパフォーマンスを最適化します。

未使用のセッションを破棄する

対象: すべての API。

推奨: 不要になったセッションで destroy() を明示的に呼び出し、機能が使用されなくなったときにメモリを解放します。クローン作成パターンを使用する場合は、ベース セッションを保持し、不要になったクローンを破棄します。

推奨されない方法: 複数の大規模なセッションをアクティブなままにする。各セッションはメモリを消費するため、不要なリソース使用量が発生し、問題になる可能性があります。セッションはガベージ コレクタによって自然にクリーンアップされますが、destroy() を呼び出すと、より迅速にメモリを解放できます。

ストリーミング レスポンスを安全かつ効率的にレンダリングする

対象: ストリーミングをサポートするすべての API(Prompt、Summarizer、Writer、Rewriter、Translator)。

推奨事項: すべての LLM 出力を信頼できないコンテンツとして扱います。悪意のあるコードが更新に分割されている可能性があるため、チャンクだけでなく、結合された出力全体をサニタイズします。レンダリングする前に、サポートされている場合は Sanitizer API を使用します。パフォーマンスの低下を回避するには、streaming-markdown などのストリーミング Markdown パーサーを使用します。

推奨されない方法: チャンクの更新ごとに innerHTML を直接設定する。この方法は、特に構文のハイライト表示などの複雑な形式設定では処理が遅く、インジェクションに対して脆弱です。

速度を重視して入力を最適化する

対象: すべての API。

推奨事項: モデルには、厳密に必要なもののみを渡します。目の前のタスクに関係のないものはすべて取り除きます。大規模なデータセットの場合は、簡単な概要と関連するアイテムの小さな選択を提供します。

推奨されない方法: 未処理のテキスト、不要なメタデータ、HTML タグ、フィルタされていない大きなリストを API に送信する。レイテンシは入力サイズとともに大幅に増加するため、多くのデバイスで AI 機能が破損しているように見えることがあります。

予測可能な結果を得るために構造化出力を使用する

適用対象: Prompt API。

推奨: モデルが特定の形式でデータを返す必要がある場合は、responseConstraint フィールドを指定して JSON スキーマを提供し、構造化出力を使用します。これにより、出力が予測可能になり、複雑な後処理や手動での解析が不要になります。

禁止事項: 自然言語の指示(「JSON のみを出力する」など)のみに依存する。モデルに、パーサーを破損する会話のフィラーが含まれている可能性があります。

生成を長さの制約から切り離す

適用対象: Prompt API。構造化出力スキーマをサポートする唯一の API であるため。

推奨: モデルにレスポンスを自然に生成させ、クライアントサイドのロジックを使用して、UI に合わせてテキストを切り詰めます。

推奨されない方法: 構造化出力スキーマを使用して、maxLength: 125 などの厳格な文字数制限を適用する。モデルのレスポンスが設定した上限よりも長い場合、モデルは外国語や絵文字などの高密度トークンに切り替えて意味を圧縮し、意味のない出力になる可能性があります。

ユーザーに情報を知らせる

対象: すべての API。

推奨: タスクの複雑さと予想される所要時間に応じて、アニメーション、視覚的な手がかり、進行状況インジケーターを使用して、ユーザーに情報を提供します。最適なアプローチは、ユースケースと API 出力の想定される長さによって異なります。以下に例を紹介します。

  • 長いコンテンツのストリーミング: 要約やチャットの場合、ストリーミングではデフォルトでトークンごとにタイプライター効果が作成されます。これにより、自然な操作感で、すぐにフィードバックを得ることができます。
  • 短いタスク(または長い非同期タスク)の非ストリーミング: 代替テキストなどの短い出力の場合、非ストリーミングを使用すると、より洗練された UI を作成できます。また、現在の AI タスクがレンダリングされている間に、次の AI タスクを推測的に準備する時間も確保できます。この手法は、より長い非同期タスクやバックグラウンド タスクでも有効です。ユーザーがジャーニーを続行する際に出力でブロックされていない場合、出力が生成されたときにすぐに出力を生成する必要はありません。UI でプロセスが進行中であることを示します。
  • 更新の視覚的な遷移: テキストを翻訳または書き換える場合は、ワードモーフィングなどのアニメーションを使用します。

避けるべきこと: 視覚的な手がかりなしで UI を更新する。

時間と作業に関するユーザーのメンタルモデルに合わせる

対象: すべての API。

推奨: レスポンスがほぼ瞬時に返される場合は、1 ~ 2 秒の人工的な遅延を検討します。逆説的ですが、ユーザーは、タスクの難易度に見合った生成プロセスを認識すると、結果をより信頼できると感じる可能性があります。アニメーションを使用して、AI 処理が発生したことを示します。

避けるべきこと: UI を即座に置き換えてユーザーを驚かせる。

ユーザーが AI による編集をすばやく操作して元に戻せるようにする

対象: すべての API。

推奨事項: UI にステッパーやナビゲーション履歴を搭載して、ユーザーがさまざまな結果を安心して探索できるようにし、AI による編集をすばやく元に戻せるようにします。これにより、異なるバージョンをすぐに利用できます。

避けるべきこと: ユーザーの以前の下書きや、ユーザーが気に入った可能性のある AI の結果を上書きし、バージョンを戻したり、元に戻したり、比較したりする方法がない。

ユーザーによる制御とオーバーライドを可能にする

対象: すべての API。

推奨事項: 生成されたすべてのコンテンツの最終編集者をユーザーにします。ユーザーが最終的な出力を完全に管理できるように、直感的なオーバーライドを提供します。API が不正確な結果を生成する可能性があります。

禁止事項: AI 生成の結果を唯一のオプションとして強制する。

繰り返すタスクの結果をキャッシュに保存する

対象: すべての API。

推奨: 繰り返される入力やクエリに対して、ローカル結果キャッシュ(sessionStorage や IndexedDB など)を実装します。空白文字を削除して小文字に変換することで入力を正規化し、キャッシュ ヒットを増やします。画像などの重い入力の場合は、キャッシュキーとして使用するハッシュを生成します。キャッシュに保守的な有効期間(TTL)を設定します(または、バックグラウンドで更新しながらキャッシュに保存された結果を提供します)。結果が不十分な場合は、ユーザーが新しい推論をトリガーできるようにします。

推奨されない方法: ユーザーが検索結果を前後に移動する場合など、変動が望ましくない繰り返しの検索クエリや同一のデータ入力に対して、同じ推論を再実行する。これにより、応答性が最適化され、ローカル コンピューティングを効率的に使用できます。

6. 代替戦略

使用する前に、LanguageModel オブジェクトがグローバル スコープで使用可能かどうかを確認します。

if ('LanguageModel' in self) {
  // The Prompt API is supported.
} else {
  // Execute fallback strategy
}

Prompt API がサポートされていない場合や、可用性チェックで「利用不可」が返された場合は、適切にフォールバックする必要があります。

  • リモート API フォールバック: 検出リクエストをサーバー エンドポイントまたはクラウド API(Vertex AI Gemini API など)にリダイレクトします。
  • ローカル API へのフォールバック: 検出リクエストをローカル エンドポイントにリダイレクトします(Transformers.js を使用するなど)。