使用嵌入向量对文本进行分类:Google Colab 教程

本教程以 20 Newsgroups 数据集为例,演示如何调用 Gemini API 的 gemini-embedding-001 模型生成文本嵌入,并用 Keras 构建一个轻量分类器完成新闻组主题分类。内容涵盖 API 密钥配置、数据清洗与采样、批量嵌入生成、模型构建与训练、早停策略、损失与准确率曲线以及混淆矩阵评估。教程强调嵌入模型与任务类型必须匹配、不同模型输出互不兼容等工程约束,并给出可复现的安装、运行与排查步骤,适合希望掌握嵌入驱动分类流水线的开发者。

技术背景

传统文本分类依赖词袋、TF-IDF 等稀疏特征,难以捕捉语义相似性,且需要大量特征工程。嵌入向量将文本映射为稠密语义向量,使语义相近的文本在向量空间中距离更近,从而让简单分类器也能获得良好效果。Gemini 嵌入模型提供 CLASSIFICATION、CLUSTERING、SEMANTIC_SIMILARITY、RETRIEVAL_QUERY、RETRIEVAL_DOCUMENT 等任务类型,针对不同下游目标优化向量分布。本教程解决的核心问题是:如何以工程化方式把大模型嵌入服务接入经典机器学习流水线,并在有限算力下完成可评估、可复现的文本分类。适用场景包括新闻分类、工单路由、内容审核、意图识别等;主要限制是嵌入 API 有速率与计费约束、不同模型向量空间不兼容、长文本需截断、嵌入质量受任务类型选择影响。

核心原理

核心数据流为:原始文本 → 清洗与截断 → 按任务类型调用嵌入 API → 得到固定维度向量 → 堆叠为特征矩阵 → 训练 Keras 分类头 → 评估。嵌入模型本质是一个编码器,把离散 token 序列压缩为语义向量;CLASSIFICATION 任务类型会引导模型生成更适合线性可分分类的表示。分类头采用两层 Dense:第一层以 ReLU 做非线性变换,第二层以 softmax 输出各类别概率,损失使用 SparseCategoricalCrossentropy。关键设计决策包括:嵌入只计算一次并缓存到 DataFrame,避免每轮重复调用 API;批量大小设为 25 以匹配 API 单批上限;使用 EarlyStopping 监控 accuracy 并设 patience=3 抑制过拟合;训练前用 np.stack 将嵌入列表转为二维数组。不同嵌入模型输出维度与语义空间不同,因此必须固定 MODEL_ID,不能混用。

架构分析

系统分为四层。数据层:fetch_20newsgroups 加载训练/测试集,preprocess_newsgroup_data 用正则去除邮箱、括号姓名、From: 与 Subject: 前缀,并截断到 5000 字符,再写入 Pandas DataFrame。采样层:sample_data 按 Label 分组抽样,保留含 sci 的类别,重编码标签为 Encoded Label,保证类别平衡且规模可控。嵌入层:make_embed_text_fn 封装 client.models.embed_content,create_embeddings 按 batch_size=25 分块调用并收集向量,结果存入 Embeddings 列。模型层:build_classification_model 构建 Input→Dense(input_size, relu)→Dense(num_classes, softmax),编译后以 Adam(0.001) 训练,并用 plot_history 与混淆矩阵做可视化评估。该架构把昂贵的嵌入计算与廉价的分类训练解耦,便于替换嵌入模型或分类头。

完整实战教程

##### 版权所有 2026 Google LLC。

# @title Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

使用嵌入对文本进行分类

注意: 本笔记本需要付费层级的速率限制才能正常运行。(更多详情请参阅定价)。

概述

在本笔记本中,你将学习使用 Gemini API 生成的嵌入来训练一个模型,该模型可以根据主题对不同类型的新闻组帖子进行分类。

%pip install -U -q google-genai

获取 API 密钥

在使用 Gemini API 之前,你必须先获取一个 API 密钥。如果你还没有,可以在 Google AI Studio 中一键创建密钥。

<a class="button button-primary" href="https://aistudio.google.com/app/apikey" target="_blank" rel="noopener noreferrer">获取 API 密钥</a>

在 Colab 中,将密钥添加到左侧面板“🔑”下的密钥管理器中。将其命名为 GEMINI_API_KEY。

获取 API 密钥后,将其传递给 SDK。你可以通过两种方式完成:

* 将密钥放入 GEMINI_API_KEY 环境变量中(SDK 会自动从那里读取)。

* 将密钥传递给 genai.Client(api_key=...)

from google import genai
from google.genai import types

# Used to securely store your API key
from google.colab import userdata

# Or use `os.getenv('GEMINI_API_KEY')` to fetch an environment variable.
GEMINI_API_KEY=userdata.get('GEMINI_API_KEY')

client = genai.Client(api_key=GEMINI_API_KEY)

关键点:接下来,你需要选择一个模型。任何嵌入模型都适用于本教程,但在实际应用中,重要的是选择一个特定的模型并坚持使用。不同模型的输出彼此不兼容。

for m in client.models.list():
  if 'embedContent' in m.supported_actions:
    print(m.name)

选择要使用的模型

MODEL_ID = "gemini-embedding-001" # @param ["gemini-embedding-2-preview", "gemini-embedding-001"] {"allow-input":true, isTemplate: true}

准备数据集

20 Newsgroups 文本数据集 包含 18,000 篇关于 20 个主题的新闻组帖子,分为训练集和测试集。训练集和测试集之间的划分基于在特定日期之前和之后发布的帖子。在本教程中,你将使用训练集和测试集的子集。你将预处理数据并将其组织到 Pandas 数据框中。

from sklearn.datasets import fetch_20newsgroups
newsgroups_train = fetch_20newsgroups(subset='train')
newsgroups_test = fetch_20newsgroups(subset='test')

# View list of class names for dataset
newsgroups_train.target_names

以下是训练集中一个数据点的示例。

idx = newsgroups_train.data[0].index('Lines')
print(newsgroups_train.data[0][idx:])

现在你将开始为本教程预处理数据。删除任何敏感信息,如姓名、电子邮件,或文本中的冗余部分,如 "From: " 和 "\nSubject: "。将信息整理到 Pandas 数据框中,使其更易读。

import re
import pandas as pd

def preprocess_newsgroup_data(newsgroup_dataset):
  # Apply functions to remove names, emails, and extraneous words from data points in newsgroups.data
  newsgroup_dataset.data = [re.sub(r'[\w\.-]+@[\w\.-]+', '', d) for d in newsgroup_dataset.data] # Remove email
  newsgroup_dataset.data = [re.sub(r"\([^()]*\)", "", d) for d in newsgroup_dataset.data] # Remove names
  newsgroup_dataset.data = [d.replace("From: ", "") for d in newsgroup_dataset.data] # Remove "From: "
  newsgroup_dataset.data = [d.replace("\nSubject: ", "") for d in newsgroup_dataset.data] # Remove "\nSubject: "

  # Cut off each text entry after 5,000 characters
  newsgroup_dataset.data = [d[0:5000] if len(d) > 5000 else d for d in newsgroup_dataset.data]

  # Put data points into dataframe
  df_processed = pd.DataFrame(newsgroup_dataset.data, columns=['Text'])
  df_processed['Label'] = newsgroup_dataset.target
  # Match label to target name index
  df_processed['Class Name'] = ''
  for idx, row in df_processed.iterrows():
    df_processed.at[idx, 'Class Name'] = newsgroup_dataset.target_names[row['Label']]

  return df_processed
# Apply preprocessing function to training and test datasets
df_train = preprocess_newsgroup_data(newsgroups_train)
df_test = preprocess_newsgroup_data(newsgroups_test)

df_train.head()

接下来,你将通过从训练数据集中抽取 100 个数据点来对部分数据进行采样,并在此教程中舍弃一些类别。选择要比较的科学类别。

def sample_data(df, num_samples, classes_to_keep):
  df = df.groupby('Label', as_index = False).apply(lambda x: x.sample(num_samples)).reset_index(drop=True)

  df = df[df['Class Name'].str.contains(classes_to_keep)]

  # Reset the encoding of the labels after sampling and dropping certain categories
  df['Class Name'] = df['Class Name'].astype('category')
  df['Encoded Label'] = df['Class Name'].cat.codes

  return df
TRAIN_NUM_SAMPLES = 100
TEST_NUM_SAMPLES = 25
CLASSES_TO_KEEP = 'sci' # Class name should contain 'sci' in it to keep science categories
df_train = sample_data(df_train, TRAIN_NUM_SAMPLES, CLASSES_TO_KEEP)
df_test = sample_data(df_test, TEST_NUM_SAMPLES, CLASSES_TO_KEEP)
df_train.value_counts('Class Name')
df_test.value_counts('Class Name')

生成嵌入

在本节中,你将了解如何使用 Gemini API 的嵌入模型为数据框中的不同文本生成嵌入。

Gemini 嵌入模型支持多种任务类型,每种类型都针对特定目标而设计。以下是可用类型及其应用场景的总体概述:

任务类型 | 描述

from tqdm.auto import tqdm
from google.genai import types

tqdm.pandas()

import numpy as np
import math

def make_embed_text_fn(model):

    def embed_fn(texts: list[str]) -> list[list[float]]:
        # Set the task_type to CLASSIFICATION and embed the batch of texts
        result = client.models.embed_content(model=model,
                                            contents=[texts],
                                            config=types.EmbedContentConfig(
                                                task_type="CLASSIFICATION")).embeddings
        return np.array([embedding.values for embedding in result])

    return embed_fn


def create_embeddings(df):
    embed_fn = make_embed_text_fn(MODEL_ID)

    batch_size = 25  # at most 25 requests can be in one batch
    all_embeddings = []

    # Loop over the texts in chunks of batch_size
    for i in tqdm(range(0, len(df), batch_size)):
        batch = df["Text"].iloc[i : i + batch_size].tolist()
        embeddings = embed_fn(batch)
        all_embeddings.extend(embeddings)

    df["Embeddings"] = all_embeddings
    return df
import numpy as np
from tqdm.auto import tqdm
tqdm.pandas()


def make_embed_text_fn(model):

  def embed_fn(text: str) -> list[float]:
    # Set the task_type to CLASSIFICATION.
    result = client.models.embed_content(model=model,
                                            contents=text,
                                            config=types.EmbedContentConfig(
                                                task_type="CLASSIFICATION"))
    return np.array(result.embeddings[0].values)

  return embed_fn

def create_embeddings(df):
  df['Embeddings'] = df['Text'].progress_apply(make_embed_text_fn(MODEL_ID))
  return df

准备训练数据集:

df_train = create_embeddings(df_train)
df_train
df_test = create_embeddings(df_test)
df_test

构建一个简单的分类模型

在这里,你将定义一个简单的模型,它包含一个隐藏层和一个单一类别概率输出。预测结果将对应于一段文本属于特定新闻类别的概率。当你构建模型时,Keras 会自动打乱数据点。

import keras
from keras import layers

def build_classification_model(input_size: int, num_classes: int) -> keras.Model:
  inputs = x = keras.Input(shape=(input_size,))
  x = layers.Dense(input_size, activation='relu')(x)
  x = layers.Dense(num_classes, activation='softmax')(x)
  return keras.Model(inputs=inputs, outputs=x)
# Derive the embedding size from the first training element.
embedding_size = len(df_train['Embeddings'].iloc[0])

# Give your model a different name, as you have already used the variable name 'model'
classifier = build_classification_model(embedding_size, len(df_train['Class Name'].unique()))
classifier.summary()

classifier.compile(loss = keras.losses.SparseCategoricalCrossentropy(from_logits=False),
                   optimizer = keras.optimizers.Adam(learning_rate=0.001),
                   metrics=['accuracy'])
embedding_size

训练模型对新闻组进行分类

最后,你可以训练一个简单的模型。使用较少的轮数以避免过拟合。第一轮比其余轮次耗时更长,因为嵌入只需要计算一次。

NUM_EPOCHS = 25
BATCH_SIZE = 32

# Split the x and y components of the train and validation subsets.
y_train = df_train['Encoded Label']
x_train = np.stack(df_train['Embeddings'])
y_val = df_test['Encoded Label']
x_val = np.stack(df_test['Embeddings'])

# Train the model for the desired number of epochs.
callback = keras.callbacks.EarlyStopping(monitor='accuracy', patience=3)

history = classifier.fit(x=x_train,
                         y=y_train,
                         validation_data=(x_val, y_val),
                         callbacks=[callback],
                         batch_size=BATCH_SIZE,
                         epochs=NUM_EPOCHS,)

评估模型性能

使用 Keras 的 <a href="https://www.tensorflow.org/api_docs/python/tf/keras/Model#evaluate"><code>Model.evaluate</code></a> 获取测试数据集上的损失和准确率。

classifier.evaluate(x=x_val, y=y_val, return_dict=True)

评估模型性能的一种方法是将分类器性能可视化。使用 plot_history 查看损失和准确率随 epoch 的变化趋势。

import matplotlib.pyplot as plt

def plot_history(history):
  """
    Plotting training and validation learning curves.

    Args:
      history: model history with all the metric measures
  """
  fig, (ax1, ax2) = plt.subplots(1,2)
  fig.set_size_inches(20, 8)

  # Plot loss
  ax1.set_title('Loss')
  ax1.plot(history.history['loss'], label = 'train')
  ax1.plot(history.history['val_loss'], label = 'test')
  ax1.set_ylabel('Loss')

  ax1.set_xlabel('Epoch')
  ax1.legend(['Train', 'Validation'])

  # Plot accuracy
  ax2.set_title('Accuracy')
  ax2.plot(history.history['accuracy'],  label = 'train')
  ax2.plot(history.history['val_accuracy'], label = 'test')
  ax2.set_ylabel('Accuracy')
  ax2.set_xlabel('Epoch')
  ax2.legend(['Train', 'Validation'])

  plt.show()

plot_history(history)

Notebook output

查看模型性能的另一种方式,除了仅测量损失和准确率之外,是使用混淆矩阵。混淆矩阵允许你在准确率之外评估分类模型的性能。你可以看到被错误分类的点被归类为什么。为了为这个多类分类问题构建混淆矩阵,获取测试集中的实际值和预测值。

首先使用 Model.predict() 为验证集中的每个示例生成预测类别。

y_hat = classifier.predict(x=x_val)
y_hat = np.argmax(y_hat, axis=1)
labels_dict = dict(zip(df_test['Class Name'], df_test['Encoded Label']))
labels_dict
import sklearn.metrics as skmetrics

cm = skmetrics.confusion_matrix(y_val, y_hat)
disp = skmetrics.ConfusionMatrixDisplay(confusion_matrix=cm,
                              display_labels=labels_dict.keys())
disp.plot(xticks_rotation='vertical')
plt.title('Confusion matrix for newsgroup test dataset');
plt.grid(False)

Notebook output

后续步骤

你现在已经创建了自己的文本分类!要了解如何使用 Gemini API 中的其他服务,请参阅快速入门指南。

常见问题

常见错误一:未设置 GEMINI_API_KEY,导致客户端初始化失败;应通过 Colab userdata 或环境变量注入,避免硬编码。错误二:混用不同嵌入模型,向量维度或语义空间不一致,训练结果异常;必须固定 MODEL_ID。错误三:任务类型选错,例如分类任务误用 RETRIEVAL_QUERY,会降低分类效果;应使用 CLASSIFICATION。错误四:批量超过 25 触发 API 限制;需按 batch_size 分块。错误五:文本过长导致截断或超限;预处理已限制 5000 字符。错误六:过拟合,训练准确率上升但验证下降;可减少 epoch、增大 patience 或加正则。错误七:标签编码未重置,采样后类别编号错乱;sample_data 中已用 cat.codes 重编码。排查时先打印 client.models.list() 确认模型支持 embedContent,再检查嵌入维度与标签分布,最后查看损失曲线与混淆矩阵定位问题类别。

企业应用扩展

生产环境可从以下方向优化:一是嵌入缓存与持久化,将向量写入向量库或 Parquet,避免重复计费;二是并发与重试,使用指数退避处理 429/5xx,并控制 QPS;三是批量调优,在 API 上限内增大批量以提升吞吐;四是模型选择,对比 gemini-embedding-001 与 gemini-embedding-2-preview 的维度与效果,但需整体切换;五是分类头升级,可尝试 Dropout、L2 正则、类别权重或改用逻辑回归/线性 SVM 作为基线;六是评估体系,除准确率外加入 macro-F1、混淆矩阵与错误样本分析;七是流水线化,把预处理、嵌入、训练、评估封装为可配置脚本,支持增量更新与版本管理;八是安全与合规,清洗 PII、控制日志中的原文输出,并遵守 API 定价与配额策略。

总结

本教程以 20 Newsgroups 数据集为例,演示如何调用 Gemini API 的 gemini-embedding-001 模型生成文本嵌入,并用 Keras 构建一个轻量分类器完成新闻组主题分类。内容涵盖 API 密钥配置、数据清洗与采样、批量嵌入生成、模型构建与训练、早停策略、损失与准确率曲线以及混淆矩阵评估。教程强调嵌入模型与任务类型必须匹配、不同模型输出互不兼容等工程约束,并给出可复现的安装、运行与排查步骤,适合希望掌握嵌入驱动分类流水线的开发者。

内容来源与验证

继续系统学习

站内还有更多完整实战教程

加入会员,解锁全部教程、完整代码与持续更新内容。

加入会员
查看全部API 与工程实践教程