通过模型蒸馏优化 AI 函数费用

本文档介绍了如何在 BigQuery 中使用受管 AI 函数的优化模式。与标准的逐行 LLM 推理相比,使用优化模式处理包含数千甚至数十亿行的大规模数据集时,可显著减少大语言模型 (LLM) 的令牌消耗量并缩短查询延迟时间。此优化仅适用于 AI.IFAI.CLASSIFY 函数。

如果您想限制总词元消耗量以防止预算超支,而不是优化查询的词元效率,请参阅通过词元配额控制费用

如需更好地了解词元消耗情况,您可以在Google Cloud 控制台中查看查询使用的词元数量。如需在运行查询之前估算此用量,请使用 AI.COUNT_TOKENS 函数

以下示例展示了如何使用优化模式下的 AI.IF 函数来识别有关自然灾害的新闻报道,并使用 text-embedding-005 作为嵌入模型:

SELECT
  title,
  body,
  AI.IF(
    ('The following news story is about a natural disaster: ', body),
    embeddings => AI.EMBED(body, endpoint => 'text-embedding-005', task_type => 'CLASSIFICATION').result,
    -- Optional, 'MINIMIZE_COST' is the default when embeddings are provided.
    optimization_mode => 'MINIMIZE_COST'
   ) AS is_natural_disaster
FROM
  `bigquery-public-data.bbc_news.fulltext`;

optimization_mode => 'MINIMIZE_COST' 实参可启用优化模式。这是提供嵌入时的默认设置,因此您可以省略此实参。

在此示例中,嵌入是即时生成的。在实践中,我们建议您实现嵌入,以便重复使用。

优化模式的工作原理

对于数据集中的每一行,受管理的 AI 函数 AI.IFAI.CLASSIFY 通常会调用远程 LLM。使用优化模式时,BigQuery 会在查询执行期间自动训练轻量级精简模型。

该过程的工作原理如下:

启用优化模式时的 AI 函数工作流

  • 抽样和标记:BigQuery 会选择一小部分代表性样本数据,并调用 Gemini 来提供标签。
  • 精简模型训练:使用 LLM 标签和数据嵌入作为特征,及时训练本地精简模型。
  • 质量检查:BigQuery 会根据 LLM 的结果评估精简模型的准确率。默认情况下,如果精简模型未能达到所需的质量阈值,查询会失败,并显示一条错误消息,说明模型被舍弃的原因。如果模型质量可接受,BigQuery 仍可能会针对特定行回退到远程 LLM,以保持一致的质量,或者针对缺少有效嵌入的行回退到远程 LLM。
  • 推理:精简模型处理大部分行,从而显著减少 Gemini 调用次数。

限制

优化模式具有以下限制:

  • 最少行数:AI 函数的输入必须包含大约 3,000 行,以确保有足够的数据用于模型训练。
  • 数据类型:对于引用多个列的提示,只有字符串列支持优化。
  • 多标签分类: AI.CLASSIFYoutput_mode => 'multi' 在优化模式下不受支持。
  • 函数支持:只有 AI.IFAI.CLASSIFY 函数支持优化模式;不过,如果使用 AI.CLASSIFY 的优化模式时精简模型的质量不足,查询可能会失败。
  • 错误比率:优化模式不支持 max_error_ratio 实参。

准备工作

如需获得在 BigQuery 中运行受管 AI 函数所需的权限,请参阅为调用 Gemini Enterprise Agent Platform LLM 的生成式 AI 函数设置权限

选择嵌入模型

如需使用优化模式,您必须计算数据的嵌入内容并将其提供给 AI 函数。为了使输入列具有关联的嵌入,所有行的嵌入维度必须保持一致,并且必须由同一嵌入模型生成。

为了获得最佳的成本效益和可伸缩性,我们建议您使用嵌入模型(例如 text-embedding-005 或 Gemini 嵌入模型)来计算数据的嵌入,以完成英语或多语言任务。对于多模态数据(文本和图片),我们建议使用多模态嵌入模型,例如 Gemini Embedding 2 (gemini-embedding-2)

生成嵌入

您可以使用由 BigQuery 管理的自主生成功能来计算数据的嵌入,也可以手动创建嵌入列。以下部分介绍了如何将这两种方法与 AI.CLASSIFYAI.IF 函数搭配使用。

自主生成嵌入

如果您使用自主嵌入生成,则在调用 AI.IFAI.CLASSIFY 时,BigQuery 会自动使用嵌入。这是推荐的方法,但每个表只能有一个嵌入列。

以下示例创建了一个包含自主生成的嵌入列的表,使用 text-embedding-005 作为嵌入模型,然后使用 AI.CLASSIFY 函数对数据进行分类:

-- Create a table with an autonomously generated embedding column
CREATE TABLE my_dataset.bbc_news (
  title STRING,
  body STRING,
  body_embedding STRUCT<result ARRAY<FLOAT64>, status STRING>
    GENERATED ALWAYS AS (
      AI.EMBED(
        body,
        connection_id => '<my_connection_id>',
        task_type => 'CLASSIFICATION',
        endpoint => 'text-embedding-005')
    ) STORED
    OPTIONS(asynchronous = TRUE)
);

-- Insert data into the table
INSERT INTO my_dataset.bbc_news (title, body)
SELECT title, body FROM `bigquery-public-data.bbc_news.fulltext`;

-- Run the optimized query.
-- Wait for the background job to finish generating embeddings before running.
SELECT
  title,
  body,
  AI.CLASSIFY(
    body,
    categories => ['tech', 'sport', 'business', 'other']
  ) AS category
FROM
  my_dataset.bbc_news;

手动指定列

如果您有现有的嵌入列,请在 AI.IFAI.CLASSIFYembeddings 实参中指定该列。您可以使用 AI.EMBED 函数 生成此内容。

以下示例演示了如何创建包含嵌入列的表,使用 text-embedding-005 作为嵌入模型,然后在 AI.CLASSIFY 查询中使用该列:

-- Create a table with an embedding column
CREATE TABLE my_dataset.bbc_news AS
SELECT
  title,
  body,
  AI.EMBED(
    body,
    endpoint => 'text-embedding-005',
    task_type => 'CLASSIFICATION'
  ).result AS body_embedding
FROM
  `bigquery-public-data.bbc_news.fulltext`;

-- Run the optimized query
SELECT
  title,
  body,
  AI.CLASSIFY(
    body,
    categories => ['tech', 'sport', 'business', 'other'],
    embeddings => body_embedding,
  ) AS category
FROM
  my_dataset.bbc_news;

如果您的提示引用了多个列,请在 embeddings 实参中提供列名称及其对应的嵌入的列表。例如:embeddings => [('body', body_embedding), ('title', title_embedding)]

监控查询优化

如需验证查询执行期间优化了多少行,您可以在 Google Cloud 控制台中或通过 API 查看执行统计信息:

控制台

如需查看优化了多少行,以及查看有关优化状态的系统消息,请执行以下操作:

  1. 在 Google Cloud 控制台中,前往 BigQuery 页面。

    转到 BigQuery

  2. 在导航菜单中,点击作业探索器

  3. 点击作业 ID 以查看作业详情窗格。

  4. 点击作业信息标签页,然后在生成式 AI 函数优化字段中查看指标和状态。

    “作业信息”标签页中的“生成式 AI 函数优化”字段

API

检查作业元数据的 GenAIFunctionStats 对象中的 FunctionGenAiCostOptimizationStats。此对象包含通过优化后的工作流推断出的行数,以及提供优化状态相关数据洞见的系统生成的消息。

问题排查

以下各节将解释如何诊断和解决使用优化模式时遇到的常见问题。

数据量太小

问题:用于模型训练的数据不足。您可能会看到以下错误消息:Fail to apply cost optimization because the data size is too small.

解决方案:将输入数据的大小增加到大约 3,000 行,并验证是否已为所有行正确生成有效的嵌入。

某些类别的样本数量很少或没有样本

问题:在抽样阶段,某些类别的样本数量不足,导致无法进行模型训练。您可能会看到以下错误消息:Fail to apply cost optimization because some classes have few or no samples.

解决方案

  • AI.CLASSIFY 函数调用中移除罕见或空的类别。
  • 将稀有类别归入更广泛的类别,以增加样本规模。您可以使用 OTHER 类别来对更具体类别未涵盖的商品进行分组。不过,如果您的类别列表已完整,请勿添加 OTHER,因为此术语含义模糊,可能会造成混淆。

嵌入的维度不一致

问题:各行之间的嵌入维度不一致。您可能会看到以下错误消息:Fail to apply cost optimization because the embeddings have inconsistent dimensions.

解决方案:验证嵌入是否由同一模型生成,并且具有相同的嵌入向量长度。您可以使用类似于以下内容的 SQL 查询来检查列中的嵌入是否具有相同的长度:

SELECT ARRAY_LENGTH(body_embedding.result), COUNT(*)
FROM `PROJECT_ID.DATASET.TABLE_NAME`
GROUP BY 1;

提示过于复杂

问题: 提炼后的模型无法达到较高的准确率阈值。您可能会看到以下错误消息:Fail to apply cost optimization because the prompt complexity is too high.

解决方案

  • 使用构成分区的一组类别。确保类别之间的重叠程度尽可能小,并且涵盖所有可能的输入。

    • 避免出现重叠类别,即输入可能同时属于多个类别。例如,避免使用 ['terrible', 'bad', 'okay', 'good', 'excellent'] 等类别。
    • 避免出现没有适用的类别的缺口。例如,类别列表 ['bad', 'average'] 不涵盖表达赞扬的评价。
    • 提供类别描述,以指导 LLM 解决类别之间的歧义。例如:

      AI.CLASSIFY(
        review,
        categories => [
          ('terrible', 'Review where customer was not happy and the message indicates they will never try this product again'),
          ('bad', 'Review where customer was not happy but suggested improvements to the product'),
          ('okay', 'Review where customer was neutral about the product. Short reviews qualify for this category'),
          ('good', 'Review where customers were happy using this product but had minor critiques'),
          ('excellent', 'Review where customers were very happy using this product and will recommend others to try it too')],
        embeddings => review_embeddings)
      
  • 尝试使用更高级的嵌入模型,例如 text-embedding-005gemini-embedding-2

  • 如需获得更多调试帮助,请发送电子邮件至 bqml-feedback@google.com

LLM 处理的行数超出预期

问题:查询执行统计信息显示,远程 LLM 处理了异常多的行,而不是由精炼模型处理。这可能是由以下原因造成的:

  • 精简模型已成功训练,但部分行的嵌入内容缺失。这些行由远程 LLM 处理。
  • 蒸馏模型无法应用于每一行,因此不得不回退到远程 LLM 以保持质量的一致性。

解决方案:验证嵌入是否已正确生成,并且对数据中的所有行都有效。如果问题仍然存在,请发送电子邮件至 bqml-feedback@google.com 以进行调试。

未检测到自主嵌入列

问题:BigQuery 无法检测到自主嵌入列。如果脚本使用临时表,并且对原始表的引用丢失,则可能会发生这种情况。

解决方案:使用 embeddings 参数显式传递一个自主嵌入列(例如 embeddings => content_embedding.result),以触发费用优化。

后续步骤