从应用中调用 Genkit flow

Cloud Functions for Firebase 具有 onCallGenkit 方法,可让您使用 Genkit 操作(Flow)创建可调用函数。这些函数可以使用 genkit/beta/client 或 Cloud 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/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,并在现有导入之后添加以下内容:

    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/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