AI

Firebase AI Logicハイブリッド推論入門——ChromeオンデバイスAIとクラウドを切り替える

Firebase JavaScript SDK 12.14.0で一般提供になったAI LogicのWeb向けハイブリッド推論を、Next.js App RouterとFirestoreで実装する手順として解説します。

2026年6月21日
Firebase AI LogicNext.jsFirestoreChromeTypeScript
Firebase AI Logicハイブリッド推論入門——ChromeオンデバイスAIとクラウドを切り替える

はじめに

WebアプリにAI要約や入力補助を入れるとき、こんな悩みはありませんか?

  • すべてクラウドAIに投げると、通信待ちとコストが気になる
  • 個人情報に近い下書きテキストを外部APIへ送る設計にしづらい
  • オフラインや不安定な回線でも、最低限の入力支援は動かしたい
  • ただし、オンデバイスAIだけでは対応ブラウザが限られる

2026年5月28日、Firebase JavaScript SDK 12.14.0で Firebase AI LogicのWeb向けハイブリッド推論 が一般提供になりました。公式リリースノートでは、Chrome Prompt APIを使うハイブリッド推論のGA化と、オンデバイスモデルを明示的に初期化する initializeDeviceModel() の追加が案内されています。

本記事では、架空の問い合わせ管理SaaS「SupportDock」を題材に、Next.js App Router + Firestore + TypeScriptで「問い合わせ返信案を生成し、監査メタデータだけをFirestoreへ保存する」流れを実装します。

参考にした一次情報は次の通りです。

ハイブリッド推論の全体像

Firebase AI Logicのハイブリッド推論は、ブラウザ内のオンデバイスモデルが使える場合はローカルで推論し、使えない場合はクラウドホストのGeminiモデルへ切り替える仕組みです。公式ドキュメントでは、Webのオンデバイス推論はChrome Desktopでサポートされ、オンデバイス側はChrome Prompt API、クラウド側はGemini Developer APIまたはVertex AI Gemini APIを使うと説明されています。

選べる推論モードは次の4つです。

モード動き使いどころ
PREFER_ON_DEVICEオンデバイス優先、不可ならクラウド下書き返信案の標準設定
ONLY_ON_DEVICEオンデバイスのみ、不可なら例外機密度が高い入力補助
PREFER_IN_CLOUDクラウド優先、不可ならオンデバイス品質を優先する管理画面
ONLY_IN_CLOUDクラウドのみ、不可なら例外サーバー管理しやすい一括処理

ポイントは、AIの結果全文をすぐFirestoreへ保存しないことです。問い合わせ文には個人情報が混ざりやすいため、まず画面上でユーザーに確認させ、保存する場合も「どのチケットで、誰が、どのモードで生成したか」から記録します。

事前準備

公式ドキュメント上、Web向けハイブリッド推論には次の前提があります。

項目確認すること
Firebase AI LogicFirebaseプロジェクトで有効化する
API providerGemini Developer APIまたはVertex AI Gemini APIを設定する
App Check公開前に強制し、乱用を防ぐ
Web SDKfirebase/ai を使えるFirebase JavaScript SDKを導入する
ChromePrompt APIとオンデバイスモデルの準備状態を確認する

Yarnプロジェクトでは、SDKを次のように入れます。

yarn add firebase@^12.14.0

SupportDockでは、問い合わせ本文は既存の tickets コレクションに保存済みで、AI生成イベントだけを aiDraftEvents に追加する想定にします。

ハンズオン1: Firebase AI Logicのモデルを作る

まずFirebase Appを初期化します。Next.jsでは、AI生成UIをClient Componentに置くため、firebase/ai はブラウザ側のモジュールから呼びます。

// src/lib/firebase/client.ts
import { getApps, initializeApp } from "firebase/app";

const firebaseConfig = {
  apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY,
  authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN,
  projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,
  appId: process.env.NEXT_PUBLIC_FIREBASE_APP_ID,
};

export const firebaseApp =
  getApps().length === 0 ? initializeApp(firebaseConfig) : getApps()[0];

次に、AI Logic用のモデルを作ります。公式サンプルで確認できるimportは getAIgetGenerativeModelGoogleAIBackendInferenceMode です。

// src/lib/firebase/aiLogic.ts
import {
  getAI,
  getGenerativeModel,
  GoogleAIBackend,
  InferenceMode,
} from "firebase/ai";
import { firebaseApp } from "@/lib/firebase/client";

const ai = getAI(firebaseApp, {
  backend: new GoogleAIBackend(),
});

export const supportDraftModel = getGenerativeModel(ai, {
  mode: InferenceMode.PREFER_ON_DEVICE,
});

PREFER_ON_DEVICE にしておくと、オンデバイスモデルが使える場合は端末内で処理し、未準備ならクラウドホストのモデルへ自動的にフォールバックします。公式ドキュメントでは、クラウド側のデフォルトモデルは gemini-2.5-flash-lite と説明されています。

ハンズオン2: ボタン操作後に生成する

initializeDeviceModel() は、ユーザーのページ操作後、かつ generateContent() の前に呼びます。ページ読み込み時に勝手に初期化するのではなく、「返信案を作る」ボタンを押したタイミングで開始します。

// src/components/support/ReplySuggestionButton.tsx
"use client";

import { useState, useTransition } from "react";
import { supportDraftModel } from "@/lib/firebase/aiLogic";
import { saveAiDraftEvent } from "@/app/support/actions";

type Props = {
  ticketId: string;
  message: string;
  operatorId: string;
};

export function ReplySuggestionButton({ ticketId, message, operatorId }: Props) {
  const [suggestion, setSuggestion] = useState("");
  const [progress, setProgress] = useState<number | null>(null);
  const [isPending, startTransition] = useTransition();

  const handleClick = () => {
    startTransition(async () => {
      await supportDraftModel.initializeDeviceModel((value) => {
        setProgress(Math.round(value * 100));
      });

      const prompt = [
        "あなたは問い合わせ管理SaaSのサポート担当です。",
        "次の問い合わせに対して、丁寧で短い返信案を日本語で作成してください。",
        "個人情報を推測で補完せず、不明点は確認事項として書いてください。",
        "",
        message.slice(0, 2000),
      ].join("\n");

      const result = await supportDraftModel.generateContent(prompt);
      const text = result.response.text();
      setSuggestion(text);

      await saveAiDraftEvent({
        ticketId,
        operatorId,
        inputLength: message.length,
        outputLength: text.length,
        mode: "prefer_on_device",
      });
    });
  };

  return (
    <section className="space-y-3">
      <button
        type="button"
        onClick={handleClick}
        disabled={isPending}
        className="rounded bg-black px-4 py-2 text-white disabled:opacity-50"
      >
        {isPending ? "生成中..." : "返信案を作る"}
      </button>

      {progress !== null && (
        <p className="text-sm text-gray-600">モデル準備: {progress}%</p>
      )}

      {suggestion && (
        <textarea
          value={suggestion}
          onChange={(event) => setSuggestion(event.target.value)}
          className="min-h-40 w-full rounded border p-3"
        />
      )}
    </section>
  );
}

公式ドキュメントでは、モデルのダウンロードが終わっていない状態で PREFER_ON_DEVICE のリクエストを送ると、ダウンロード完了を待たずにクラウドホストのモデルへフォールバックすると説明されています。初回体験を止めたくない業務アプリでは、この挙動を前提にできます。

ハンズオン3: Firestoreに監査メタデータを残す

生成結果はユーザーが編集する前提にし、Firestoreへは監査メタデータを保存します。サーバー側はFirebase Admin SDKで書き込み、クライアントから監査コレクションへ自由に書ける状態にしません。

// src/app/support/actions.ts
"use server";

import { FieldValue } from "firebase-admin/firestore";
import { adminDb } from "@/lib/firebase/admin";

type SaveAiDraftEventInput = {
  ticketId: string;
  operatorId: string;
  inputLength: number;
  outputLength: number;
  mode: "prefer_on_device" | "only_on_device" | "prefer_in_cloud" | "only_in_cloud";
};

export async function saveAiDraftEvent(input: SaveAiDraftEventInput) {
  if (!input.ticketId || !input.operatorId) {
    throw new Error("ticketId and operatorId are required");
  }

  await adminDb.collection("aiDraftEvents").add({
    ticketId: input.ticketId,
    operatorId: input.operatorId,
    inputLength: input.inputLength,
    outputLength: input.outputLength,
    mode: input.mode,
    createdAt: FieldValue.serverTimestamp(),
  });
}

保存方針は次のように分けます。

コレクション保存する内容保存しない内容
tickets問い合わせ本文、担当者、ステータスAIの一時生成途中の全文
aiDraftEventsticketId、operatorId、文字数、推論モード、時刻prompt全文
auditLogs送信・承認などの確定操作未確認のAI提案

GitHub Actionsで確認する

オンデバイス推論そのものはブラウザ条件に左右されます。CIではまず、Firebase SDKの型、Next.jsのbundle境界、Firestore用Server Actionのimportを落とさないことを確認します。

name: Web CI

on:
  pull_request:
    branches: [main]

permissions:
  contents: read

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: "22"
          cache: "yarn"

      - run: yarn install --frozen-lockfile
      - run: yarn build

レビューでは、firebase/ai をServer Componentへ混ぜていないか、prompt全文をログやFirestoreへ残していないか、App Checkを公開前に強制する計画があるかを確認します。

まとめ

Firebase AI Logicのハイブリッド推論は、WebアプリのAI機能を「クラウドだけ」から一歩進める選択肢です。

  • Firebase JavaScript SDK 12.14.0でWeb向けハイブリッド推論が一般提供になった
  • InferenceMode.PREFER_ON_DEVICE でオンデバイス優先の設計にできる
  • initializeDeviceModel() はユーザー操作後、generateContent() の前に呼ぶ
  • 未準備時のクラウドフォールバックを前提にUIを設計する
  • Firestoreにはprompt全文ではなく、まず監査メタデータを保存する

Next.js + Firestoreの業務アプリでは、AI機能の価値だけでなく、どこで推論し、何を保存し、誰が確認するかが重要です。問い合わせ返信案や下書き整形のような小さな機能から、オンデバイス優先の体験を検証するのが現実的です。