Firebase Cloud Functions の Genkit

Firebase Genkit には、Firebase Cloud Functions へのフローのデプロイに役立つプラグインが含まれています。このページでは、デフォルトのサンプルフローを Firebase にデプロイするプロセスを一例として説明します。

フローを Cloud Functions の関数としてデプロイする

  1. 必要なツールをインストールします。

    1. Node.js バージョン 20 以降を使用していることを確認します(node --version を実行して確認します)。

    2. Firebase CLI をインストールします。

  2. Firebase コンソールを使用して新しい Firebase プロジェクトを作成するか、既存のプロジェクトを選択します。

    Cloud Functions のデプロイに必要な Blaze プランにプロジェクトをアップグレードします。

  3. Firebase CLI でログインします。

    firebase login
    firebase login --reauth # alternative, if necessary
    firebase login --no-localhost # if running in a remote shell
    
  4. 新しいプロジェクト ディレクトリを作成します。

    export PROJECT_ROOT=~/tmp/genkit-firebase-project1
    mkdir -p $PROJECT_ROOT
    
  5. フォルダ内の Genkit を使用して Firebase プロジェクトを初期化します。

    cd $PROJECT_ROOT
    firebase init genkit
    
    • 先ほど作成したプロジェクトを選択します。
    • 使用するモデル プロバイダを選択します。

    残りのプロンプトについては、デフォルト値を受け入れます。genkit ツールは、独自の AI フローの開発を開始できるように、いくつかのサンプル ソースファイルを作成します。このチュートリアルでは、サンプルフローのみをデプロイします。

  6. Cloud Functions の関数で API 認証情報を利用できるようにします。選択したモデル プロバイダに応じて、次のいずれかを行います。

    Gemini(Google AI)

    1. Google AI がお住まいの地域で利用可能であることを確認します。

    2. Google AI Studio を使用して Gemini API の API キーを生成します。

    3. GOOGLE_GENAI_API_KEY 環境変数を自分の鍵に設定します。

      export GOOGLE_GENAI_API_KEY=<your API key>
      
    4. src/index.ts を編集して、既存のインポートの後に以下を追加します。

    import {defineSecret} from "firebase-functions/params";
    defineSecret("GOOGLE_GENAI_API_KEY");
    

    この関数をデプロイすると、API キーが Cloud Secret Manager に保存され、Cloud Functions 環境から使用できるようになります。

    Gemini(Vertex AI)

    1. Cloud コンソールで、Firebase プロジェクトに対して Vertex AI API を有効にします

    2. [IAM] ページで、デフォルトのコンピューティング サービス アカウントVertex AI ユーザーのロールが付与されていることを確認します。

    3. 省略可: 次のステップのように、フローをローカルで実行する場合は、追加の環境変数を設定し、gcloud ツールを使用してアプリケーションのデフォルト認証情報を設定します。

      export GCLOUD_PROJECT=<your project ID>
      export GCLOUD_LOCATION=us-central1
      gcloud auth application-default login
      

    このチュートリアル用に設定する必要があるシークレットは、モデル プロバイダ用だけですが、通常は、フローで使用するサービスごとに同様のことを行う必要があります。

  7. ウェブアプリからフローにアクセスする場合は(次のセクションで行います)、httpsOptions パラメータで CORS ポリシーを設定します。

    export const menuSuggestionFlow = onFlow(
      {
        name: "menuSuggestionFlow",
        // ...
        httpsOptions: {cors: true}, // Add this line.
      },
      async (subject) => {
        // ...
      }
    );
    

    本番環境アプリでは、より厳格なポリシーが必要になる可能性がありますが、このチュートリアルではこの方法を使用します。

  8. 省略可: デベロッパー UI でフローを試します。

    1. UI を起動します。

      cd $PROJECT_ROOT/functions
      genkit start
      
    2. デベロッパー UI(http://localhost:4000/)で次のフローを実行します。

      1. [menuSuggestionFlow] をクリックします。

      2. [Input JSON] タブで、モデルの被写体を指定します。

        "AI app developers"
        
      3. [Auth JSON] タブで、シミュレートされた認証オブジェクトを入力します。

        {
          "uid": 0,
          "email_verified": true
        }
        
      4. [実行] をクリックします。

  9. ここまでの作業ですべてが正常に動作していれば、フローをデプロイできます。

    cd $PROJECT_ROOT
    firebase deploy --only functions
    

これで、フローが Cloud Functions の関数としてデプロイされました。ただし、フローの認可ポリシーにより、curl などを使用して、デプロイされたエンドポイントにアクセスできません。フローに安全にアクセスする方法については、次のセクションをご覧ください。

デプロイされたフローを試す

デプロイするすべてのフローで認可ポリシーを設定することが重要です。これがないと、コストがかかる可能性のある生成 AI のフローを誰でも呼び出せるようになります。

デフォルトのサンプルフローには、次のような認可ポリシーがあります。

firebaseAuth((user) => {
  if (!user.email_verified) {
    throw new Error('Verified email required to run flow');
  }
});

このポリシーでは、firebaseAuth() ヘルパーを使用して、確認済みのメールアドレスを持つアプリの登録ユーザーのみにアクセスを許可します。クライアント側では、ポリシーを満たす Firebase ID トークンに Authorization: Bearer ヘッダーを設定する必要があります。Cloud Functions クライアント SDK には、これを自動化する呼び出し可能関数メソッドが用意されています。

Flow エンドポイントを試すには、次の最小限のウェブアプリをデプロイします。

  1. Firebase コンソールの [プロジェクトの設定] セクションで、新しいウェブアプリを追加し、Hosting も設定するオプションを選択します。

  2. Firebase コンソールの [Authentication] セクションで、この例で使用する Google プロバイダを有効にします。

  3. プロジェクト ディレクトリで、サンプルアプリをデプロイする Firebase Hosting を設定します。

    cd $PROJECT_ROOT
    firebase init hosting
    

    すべてのプロンプトでデフォルト値を受け入れます。

  4. public/index.html を次のように置き換えます。

    <!doctype html>
    <html>
      <head>
        <title>Genkit demo</title>
      </head>
      <body>
        <div id="signin" hidden>
          <button id="signinBtn">Sign in with Google</button>
        </div>
        <div id="callGenkit" hidden>
          Subject: <input type="text" id="subject" />
          <button id="suggestMenuItem">Suggest a menu theme</button>
          <p id="menuItem"></p>
        </div>
        <script type="module">
          import { initializeApp } from 'https://www.gstatic.com/firebasejs/10.10.0/firebase-app.js';
          import {
            getAuth,
            onAuthStateChanged,
            GoogleAuthProvider,
            signInWithPopup,
          } from 'https://www.gstatic.com/firebasejs/10.10.0/firebase-auth.js';
          import {
            getFunctions,
            httpsCallable,
          } from 'https://www.gstatic.com/firebasejs/10.10.0/firebase-functions.js';
    
          const firebaseConfig = await fetch('/__/firebase/init.json');
          initializeApp(await firebaseConfig.json());
    
          async function generateMenuItem() {
            const menuSuggestionFlow = httpsCallable(
              getFunctions(),
              'menuSuggestionFlow'
            );
            const subject = document.querySelector('#subject').value;
            const response = await menuSuggestionFlow(subject);
            document.querySelector('#menuItem').innerText = response.data;
          }
    
          function signIn() {
            signInWithPopup(getAuth(), new GoogleAuthProvider());
          }
    
          document
            .querySelector('#signinBtn')
            .addEventListener('click', signIn);
          document
            .querySelector('#suggestMenuItem')
            .addEventListener('click', generateMenuItem);
    
          const signinEl = document.querySelector('#signin');
          const genkitEl = document.querySelector('#callGenkit');
    
          onAuthStateChanged(getAuth(), (user) => {
            if (!user) {
              signinEl.hidden = false;
              genkitEl.hidden = true;
            } else {
              signinEl.hidden = true;
              genkitEl.hidden = false;
            }
          });
        </script>
      </body>
    </html>
    
  5. ウェブアプリと Cloud Functions の関数をデプロイします。

    cd $PROJECT_ROOT
    firebase deploy
    

deploy コマンドで出力された URL にアクセスして、ウェブアプリを開きます。このアプリでは、Google アカウントでログインする必要があります。その後、エンドポイント リクエストを開始できます。

Firebase Local Emulator Suite を使用した開発

Firebase には、Genkit で使用できるローカル開発用のエミュレータ スイートが用意されています。

Firebase Emulator Suite で Genkit を使用するには、次のように Firebase エミュレータを起動します。

GENKIT_ENV=dev firebase emulators:start --inspect-functions

これにより、エミュレータでコードが実行され、開発モードで Genkit フレームワークが実行されます。これにより、Genkit リフレクション API が起動して公開されます(Dev UI は提供されません)。

次に、--attach オプションを指定して Genkit Dev UI を起動し、Firebase Emulator 内で実行されているコードに接続します。

genkit start --attach http://localhost:3100 --port 4001

Dev UI で Firestore のトレースを表示するには、[検証] タブに移動して [開発/本番] スイッチを切り替えます。[prod] に切り替えると、トレースが Firestore から読み込まれます。