从应用中调用 Genkit flow

Cloud Functions for Firebase 具有 onCallGenkit 方法,可让您使用 Genkit 操作(Flow)创建可调用函数。这些函数可以使用 genkit/beta/clientCloud Functions 客户端 SDK 进行调用,后者会自动添加身份验证信息。

准备工作

  • 您应该熟悉 Genkit 的 flow 概念以及如何编写 flow。本页面中的说明假定您已定义要部署的一些 flow。
  • 如果您之前使用过 Cloud Functions for Firebase,那么这会有所帮助,但不是必需的。

设置 Firebase 项目

  1. 使用 Firebase 控制台创建新的 Firebase 项目,或选择现有项目。

  2. 将项目升级到 Blaze 方案,这是 Cloud Functions 正式版部署所必需的。

  3. 安装 Firebase CLI

  4. 使用 Firebase CLI 登录:

    firebase login
    firebase login --reauth # alternative, if necessary
    firebase login --no-localhost # if running in a remote shell
  5. 创建新的项目目录:

    export PROJECT_ROOT=~/tmp/genkit-firebase-project1
    mkdir -p $PROJECT_ROOT
  6. 在目录中初始化 Firebase 项目:

    cd $PROJECT_ROOT
    firebase init functions

本页面的其余部分假定您已选择使用 JavaScript 编写函数。

将 flow 封装在 onCallGenkit

使用 Cloud Functions 设置 Firebase 项目后,您可以在项目的 functions 目录中复制或编写 flow 定义。以下示例 flow 演示了这一过程:

const ai = genkit({
  plugins: [googleAI()],
  model: gemini15Flash,
});

const jokeTeller = ai.defineFlow({
  name: "jokeTeller",
  inputSchema: z.string().nullable(),
  outputSchema: z.string(),
  streamSchema: z.string(),
}, async (jokeType = "knock-knock", {sendChunk}) => {
  const prompt = `Tell me a ${jokeType} joke.`;

  // Call the `generateStream()` method to
  // receive the `stream` async iterable.
  const {stream, response: aiResponse} = ai.generateStream(prompt);

  // Send new words of the generative AI response
  // to the client as they are generated.
  for await (const chunk of stream) {
    sendChunk(chunk.text);
  }

  // Return the full generative AI response
  // to clients that may not support streaming.
  return (await aiResponse).text;
},
);

如需部署此类 flow,请使用 firebase-functions/https 中的 onCallGenkit 对其进行封装。此辅助方法具有可调用函数的所有功能,并且自动支持流式传输和 JSON 响应。

const {onCallGenkit} = require("firebase-functions/v2/https");
exports.tellJoke = onCallGenkit({
  // Bind the Gemini API key secret parameter to the function.
  secrets: [apiKey],
},
// Pass in the genkit flow.
jokeTeller,
);

向已部署的 Flow 提供 API 凭据

部署后,您的 flow 需要一种方法来对其所依赖的任何远程服务进行身份验证。大多数 flow 至少需要凭据才能访问其使用的模型 API 服务。

对于此示例,请根据您选择的模型提供方,执行以下操作之一:

Gemini (Google AI)

  1. 确保您所在的区域提供 Google AI

  2. 使用 Google AI Studio 为 Gemini API 生成 API 密钥

  3. 将 API 密钥存储在 Cloud Secret Manager 中:

    firebase functions:secrets:set GOOGLE_GENAI_API_KEY

    此步骤非常重要,可防止您的 API 密钥意外泄露,从而授予对潜在按计量方式收费的服务的访问权限。

    如需详细了解如何管理密钥,请参阅存储和访问敏感的配置信息

  4. 修改 src/index.js,并在现有 import 之后添加以下内容:

    const {defineSecret} = require("firebase-functions/params");
    // Store the Gemini API key in Cloud Secret Manager.
    const apiKey = defineSecret("GOOGLE_GENAI_API_KEY");
    

    然后,在可调用函数定义中,声明该函数需要访问此密钥值:

    // Bind the Gemini API key secret parameter to the function.
    secrets: [apiKey],
    

现在,当您部署此函数时,您的 API 密钥将存储在 Cloud Secret Manager 中,并可从 Cloud Functions 环境中获取。

Gemini (Vertex AI)

  1. 在 Cloud 控制台中,为您的 Firebase 项目启用 Vertex AI API

  2. IAM 页面上,确保为默认计算服务账号授予 Vertex AI User 角色。

在本教程中,您只需要为模型提供方设置 Secret,但一般来说,您必须为 flow 使用的每项服务执行类似的操作。

(可选)添加 App Check 强制执行

Firebase App Check 使用原生证明来验证您的 API 是否仅由您的应用调用。onCallGenkit 支持以声明方式进行 App Check 强制执行。

export const generatePoem = onCallGenkit({
  enforceAppCheck: true,
  // Optional. Makes App Check tokens only usable once. This adds extra security
  // at the expense of slowing down your app to generate a token for every API
  // call
  consumeAppCheckToken: true,
}, generatePoemFlow);

配置 CORS(跨域资源共享)

您可以使用 cors 选项控制哪些来源可以访问您的函数。

默认情况下,Callable 函数会将 CORS 配置为允许来自所有来源的请求。若要允许部分(而非全部)跨域请求,请传递应允许的特定网域或正则表达式的列表。例如:

export const tellJoke = onCallGenkit({
  cors: 'mydomain.com',
}, jokeTeller);

完整示例

完成上述所有更改后,您的可部署 flow 将如下所示:

const {onCallGenkit} = require("firebase-functions/v2/https");
const {defineSecret} = require("firebase-functions/params");

// Dependencies for Genkit.
const {gemini15Flash, googleAI} = require("@genkit-ai/googleai");
const {genkit, z} = require("genkit");

// Store the Gemini API key in Cloud Secret Manager.
const apiKey = defineSecret("GOOGLE_GENAI_API_KEY");

const ai = genkit({
  plugins: [googleAI()],
  model: gemini15Flash,
});

const jokeTeller = ai.defineFlow({
  name: "jokeTeller",
  inputSchema: z.string().nullable(),
  outputSchema: z.string(),
  streamSchema: z.string(),
}, async (jokeType = "knock-knock", {sendChunk}) => {
  const prompt = `Tell me a ${jokeType} joke.`;

  // Call the `generateStream()` method to
  // receive the `stream` async iterable.
  const {stream, response: aiResponse} = ai.generateStream(prompt);

  // Send new words of the generative AI response
  // to the client as they are generated.
  for await (const chunk of stream) {
    sendChunk(chunk.text);
  }

  // Return the full generative AI response
  // to clients that may not support streaming.
  return (await aiResponse).text;
},
);

exports.tellJoke = onCallGenkit({
  // Bind the Gemini API key secret parameter to the function.
  secrets: [apiKey],
},
// Pass in the genkit flow.
jokeTeller,
);

将 flow 部署到 Firebase

使用 onCallGenkit 定义 flow 后,您可以像部署其他函数一样部署这些 flow:

cd $PROJECT_ROOT
firebase deploy --only functions