mcpField
G
google-gemini-embeddings

google-gemini-embeddings

github.com/jackspace数据与数据库1636 次安装12 周前更新
代码仓库

关于 google-gemini-embeddings

这是一份面向开发者的 Google Gemini 文本嵌入技能指南,覆盖 gemini-embedding-001 的 SDK 与 REST 用法,并介绍批处理及语义搜索、RAG 等应用。

主要功能

  1. 01生成文本嵌入
  2. 02SDK 与 REST API 示例
  3. 03批量处理与速率限制
  4. 04任务类型配置
  5. 05RAG 与语义搜索模式
  6. 06聚类及错误处理

适用场景

  1. 01为文档和查询生成向量
  2. 02构建语义搜索流程
  3. 03将嵌入接入 RAG 与 Vectorize
  4. 04对文本集合进行聚类

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/jackspace/claudeskillz --skill google-gemini-embeddings

安装后在 Claude Code 中输入/google-gemini-embeddings确认已加载。

附带文件README.mdSKILL.json

详细介绍

Google Gemini 嵌入

Google Gemini 嵌入 API 的完整生产就绪指南

本技能全面介绍了用于生成文本嵌入的 gemini-embedding-001 模型,包括 SDK 用法、REST API 模式、批处理、与 Cloudflare Vectorize 集成的 RAG,以及语义搜索和文档聚类等高级用例。


目录

  1. 快速入门
  2. gemini-embedding-001 模型
  3. 基础嵌入
  4. 批量嵌入
  5. 任务类型
  6. RAG 模式
  7. 语义搜索
  8. 文档聚类
  9. 错误处理
  10. 最佳实践

1. 快速入门

安装

安装 Google Generative AI SDK:

npm install @google/genai@^1.27.0

对于 TypeScript 项目:

npm install -D typescript@^5.0.0
环境设置

将 Gemini API 密钥设为环境变量:

export GEMINI_API_KEY="your-api-key-here"

在此获取 API 密钥:https://aistudio.google.com/apikey

首个嵌入示例
import { GoogleGenAI } from "@google/genai";

const ai = new GoogleGenAI({ apiKey: process.env.GEMINI_API_KEY });

const response = await ai.models.embedContent({
  model: 'gemini-embedding-001',
  content: 'What is the meaning of life?',
  config: {
    taskType: 'RETRIEVAL_QUERY',
    outputDimensionality: 768
  }
});

console.log(response.embedding.values); // [0.012, -0.034, ...]
console.log(response.embedding.values.length); // 768

结果:一个 768 维嵌入向量,表示文本的语义含义。


2. gemini-embedding-001 模型

模型规格

当前模型:gemini-embedding-001(稳定,适用于生产环境)

  • 状态:稳定
  • 实验性模型:gemini-embedding-exp-03-07(已于 2025 年 10 月弃用,请勿使用)
维度

该模型使用 Matryoshka 表示学习,支持灵活设置输出维度:

维度使用场景存储性能
768大多数场景的推荐选项低快
1536准确性与效率的平衡中中
3072最高准确性(默认值)高较慢
128-3071自定义(范围内的任意值)可变可变

默认值:3072 维 推荐值:768、1536 或 3072,以获得最佳性能

上下文窗口
  • 输入限制:每段文本 2,048 个 token
  • 输入类型:仅文本(不支持图像、音频或视频)
速率限制
层级RPMTPMRPD要求
免费10030,0001,000无需结算账号
Tier 13,0001,000,000-已关联结算账号
Tier 25,0005,000,000-消费满 $250,等待 30 天
Tier 310,00010,000,000-消费满 $1,000,等待 30 天

RPM = 每分钟请求数 TPM = 每分钟 token 数 RPD = 每日请求数

输出格式
{
  embedding: {
    values: number[] // Array of floating-point numbers
  }
}

3. 基础嵌入

SDK 方式(Node.js)

单条文本嵌入:

import { GoogleGenAI } from "@google/genai";

const ai = new GoogleGenAI({ apiKey: process.env.GEMINI_API_KEY });

const response = await ai.models.embedContent({
  model: 'gemini-embedding-001',
  content: 'The quick brown fox jumps over the lazy dog',
  config: {
    taskType: 'SEMANTIC_SIMILARITY',
    outputDimensionality: 768
  }
});

console.log(response.embedding.values);
// [0.00388, -0.00762, 0.01543, ...]
Fetch 方式(Cloudflare Workers)

适用于不支持 SDK 的 Workers/边缘环境:

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    const apiKey = env.GEMINI_API_KEY;
    const text = "What is the meaning of life?";

    const response = await fetch(
      'https://generativelanguage.googleapis.com/v1beta/models/gemini-embedding-001:embedContent',
      {
        method: 'POST',
        headers: {
          'x-goog-api-key': apiKey,
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({
          content: {
            parts: [{ text }]
          },
          taskType: 'RETRIEVAL_QUERY',
          outputDimensionality: 768
        })
      }
    );

    const data = await response.json();

    // Response format:
    // {
    //   embedding: {
    //     values: [0.012, -0.034, ...]
    //   }
    // }

    return new Response(JSON.stringify(data), {
      headers: { 'Content-Type': 'application/json' }
    });
  }
};
响应解析
interface EmbeddingResponse {
  embedding: {
    values: number[];
  };
}

const response: EmbeddingResponse = await ai.models.embedContent({
  model: 'gemini-embedding-001',
  content: 'Sample text',
  config: { taskType: 'SEMANTIC_SIMILARITY' }
});

const embedding: number[] = response.embedding.values;
const dimensions: number = embedding.length; // 3072 by default

4. 批量嵌入

在一个请求中处理多条文本(SDK)

同时为多条文本生成嵌入:

import { GoogleGenAI } from "@google/genai";

const ai = new GoogleGenAI({ apiKey: process.env.GEMINI_API_KEY });

const texts = [
  "What is the meaning of life?",
  "How does photosynthesis work?",
  "Tell me about the history of the internet."
];

const response = await ai.models.embedContent({
  model: 'gemini-embedding-001',
  contents: texts, // Array of strings
  config: {
    taskType: 'RETRIEVAL_DOCUMENT',
    outputDimensionality: 768
  }
});

// Process each embedding
response.embeddings.forEach((embedding, index) => {
  console.log(`Text ${index}: ${texts[index]}`);
  console.log(`Embedding: ${embedding.values.slice(0, 5)}...`);
  console.log(`Dimensions: ${embedding.values.length}`);
});
批量 REST API(fetch)

使用 batchEmbedContents 端点:

const response = await fetch(
  'https://generativelanguage.googleapis.com/v1beta/models/gemini-embedding-001:batchEmbedContents',
  {
    method: 'POST',
    headers: {
      'x-goog-api-key': apiKey,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      requests: texts.map(text => ({
        model: 'models/gemini-embedding-001',
        content: {
          parts: [{ text }]
        },
        taskType: 'RETRIEVAL_DOCUMENT'
      }))
    })
  }
);

const data = await response.json();
// data.embeddings: Array of {values: number[]}
为适应速率限制进行分块

处理大型数据集时,对请求分块以符合速率限制:

async function batchEmbedWithRateLimit(
  texts: string[],
  batchSize: number = 100, // Free tier: 100 RPM
  delayMs: number = 60000 // 1 minute delay between batches
): Promise<number[][]> {
  const allEmbeddings: number[][] = [];

  for (let i = 0; i < texts.length; i += batchSize) {
    const batch = texts.slice(i, i + batchSize);

    console.log(`Processing batch ${i / batchSize + 1} (${batch.length} texts)`);

    const response = await ai.models.embedContent({
      model: 'gemini-embedding-001',
      contents: batch,
      config: {
        taskType: 'RETRIEVAL_DOCUMENT',
        outputDimensionality: 768
      }
    });

    allEmbeddings.push(...response.embeddings.map(e => e.values));

    // Wait before next batch (except last batch)
    if (i + batchSize < texts.length) {
      await new Promise(resolve => setTimeout(resolve, delayMs));
    }
  }

  return allEmbeddings;
}

// Usage
const embeddings = await batchEmbedWithRateLimit(documents, 100);
性能优化

提示:

  1. 为多条文本生成嵌入时使用批量 API(单次请求,而非多次请求)
  2. 选择较低维度(768),以加快处理速度并减少存储占用
  3. 针对速率限制错误实现指数退避
  4. 缓存嵌入,避免重复调用 API

5. 任务类型

taskType 参数可针对特定用例优化嵌入。为获得最佳结果,请务必指定任务类型。

可用的任务类型(共 8 种)
任务类型使用场景示例
RETRIEVAL_QUERY用户搜索查询"如何修理漏气的轮胎?"
RETRIEVAL_DOCUMENT要编入索引或供搜索的文档产品描述、文章
SEMANTIC_SIMILARITY比较文本相似度重复内容检测、聚类
CLASSIFICATION文本分类垃圾邮件检测、情感分析
CLUSTERING将相似文本分组主题建模、内容整理
CODE_RETRIEVAL_QUERY代码搜索查询"用于排序数组的函数"
QUESTION_ANSWERING寻求答案的问题FAQ 匹配
FACT_VERIFICATION根据证据验证主张事实核查系统
如何选择任务类型

RAG 系统(检索增强生成):

// When embedding user queries
const queryEmbedding = await ai.models.embedContent({
  model: 'gemini-embedding-001',
  content: userQuery,
  config: { taskType: 'RETRIEVAL_QUERY' } // ← Use RETRIEVAL_QUERY
});

// When embedding documents for indexing
const docEmbedding = await ai.models.embedContent({
  model: 'gemini-embedding-001',
  content: documentText,
  config: { taskType: 'RETRIEVAL_DOCUMENT' } // ← Use RETRIEVAL_DOCUMENT
});

语义搜索:

const embedding = await ai.models.embedContent({
  model: 'gemini-embedding-001',
  content: text,
  config: { taskType: 'SEMANTIC_SIMILARITY' }
});

文档聚类:

const embedding = await ai.models.embedContent({
  model: 'gemini-embedding-001',
  content: text,
  config: { taskType: 'CLUSTERING' }
});
对质量的影响

使用正确的任务类型可显著提升检索质量:

// ❌ BAD: No task type specified
const embedding1 = await ai.models.embedContent({
  model: 'gemini-embedding-001',
  content: userQuery
});

// ✅ GOOD: Task type specified
const embedding2 = await ai.models.embedContent({
  model: 'gemini-embedding-001',
  content: userQuery,
  config: { taskType: 'RETRIEVAL_QUERY' }
});

结果:选择正确的任务类型可将搜索相关性提升 10-30%。


6. RAG 模式

RAG(检索增强生成)将向量搜索与 LLM 生成相结合,创建能够使用自定义知识库回答问题的 AI 系统。

完整的 RAG 工作流
1. Document Ingestion
   ├── Chunk documents into smaller pieces
   ├── Generate embeddings (RETRIEVAL_DOCUMENT)
   └── Store in Vectorize

2. Query Processing
   ├── User submits query
   ├── Generate query embedding (RETRIEVAL_QUERY)
   └── Search Vectorize for similar documents

3. Response Generation
   ├── Retrieve top-k similar documents
   ├── Pass documents as context to LLM
   └── Stream response to user
文档摄取流水线
import { GoogleGenAI } from "@google/genai";

const ai = new GoogleGenAI({ apiKey: process.env.GEMINI_API_KEY });

// 1. Chunk document into smaller pieces
function chunkDocument(text: string, chunkSize: number = 500): string[] {
  const words = text.split(' ');
  const chunks: string[] = [];

  for (let i = 0; i < words.length; i += chunkSize) {
    chunks.push(words.slice(i, i + chunkSize).join(' '));
  }

  return chunks;
}

// 2. Generate embeddings for chunks
async function embedChunks(chunks: string[]): Promise<number[][]> {
  const response = await ai.models.embedContent({
    model: 'gemini-embedding-001',
    contents: chunks,
    config: {
      taskType: 'RETRIEVAL_DOCUMENT', // ← Documents for indexing
      outputDimensionality: 768 // ← Match Vectorize index dimensions
    }
  });

  return response.embeddings.map(e => e.values);
}

// 3. Store in Cloudflare Vectorize
async function storeInVectorize(
  env: Env,
  chunks: string[],
  embeddings: number[][]
) {
  const vectors = chunks.map((chunk, i) => ({
    id: `doc-${Date.now()}-${i}`,
    values: embeddings[i],
    metadata: { text: chunk }
  }));

  await env.VECTORIZE.insert(vectors);
}

// Complete pipeline
async function ingestDocument(env: Env, documentText: string) {
  const chunks = chunkDocument(documentText, 500);
  const embeddings = await embedChunks(chunks);
  await storeInVectorize(env, chunks, embeddings);

  console.log(`Ingested ${chunks.length} chunks`);
}
查询流程(检索 + 生成)
async function ragQuery(env: Env, userQuery: string): Promise<string> {
  // 1. Embed user query
  const queryResponse = await ai.models.embedContent({
    model: 'gemini-embedding-001',
    content: userQuery,
    config: {
      taskType: 'RETRIEVAL_QUERY', // ← Query, not document
      outputDimensionality: 768
    }
  });

  const queryEmbedding = queryResponse.embedding.values;

  // 2. Search Vectorize for similar documents
  const results = await env.VECTORIZE.query(queryEmbedding, {
    topK: 5,
    returnMetadata: true
  });

  // 3. Extract context from top results
  const context = results.matches
    .map(match => match.metadata.text)
    .join('\n\n');

  // 4. Generate response with context
  const response = await ai.models.generateContent({
    model: 'gemini-2.5-flash',
    contents: `Context:\n${context}\n\nQuestion: ${userQuery}\n\nAnswer based on the context above:`
  });

  return response.text;
}
与 Cloudflare Vectorize 集成

创建 Vectorize 索引(Gemini 使用 768 个维度):

npx wrangler vectorize create gemini-embeddings --dimensions 768 --metric cosine

在 wrangler.jsonc 中绑定:

{
  "name": "my-rag-app",
  "main": "src/index.ts",
  "compatibility_date": "2025-10-25",
  "vectorize": {
    "bindings": [
      {
        "binding": "VECTORIZE",
        "index_name": "gemini-embeddings"
      }
    ]
  }
}

完整的 RAG Worker:

完整实现请参见 templates/rag-with-vectorize.ts。


7. 语义搜索

语义搜索根据含义查找内容,而不仅仅是匹配关键词。

余弦相似度

余弦相似度用于衡量两个嵌入的相似程度(范围:-1 到 1,其中 1 = 完全相同):

function cosineSimilarity(a: number[], b: number[]): number {
  if (a.length !== b.length) {
    throw new Error('Vectors must have same length');
  }

  let dotProduct = 0;
  let magnitudeA = 0;
  let magnitudeB = 0;

  for (let i = 0; i < a.length; i++) {
    dotProduct += a[i] * b[i];
    magnitudeA += a[i] * a[i];
    magnitudeB += b[i] * b[i];
  }

  if (magnitudeA === 0 || magnitudeB === 0) {
    return 0;
  }

  return dotProduct / (Math.sqrt(magnitudeA) * Math.sqrt(magnitudeB));
}
向量归一化

将向量归一化为单位长度,以加快相似度计算:

function normalizeVector(vector: number[]): number[] {
  const magnitude = Math.sqrt(vector.reduce((sum, val) => sum + val * val, 0));

  if (magnitude === 0) {
    return vector;
  }

  return vector.map(val => val / magnitude);
}

// Normalized vectors allow dot product instead of cosine similarity
function dotProduct(a: number[], b: number[]): number {
  return a.reduce((sum, val, i) => sum + val * b[i], 0);
}
Top-K 搜索

查找与查询最相似的文档:

interface Document {
  id: string;
  text: string;
  embedding: number[];
}

function topKSimilar(
  queryEmbedding: number[],
  documents: Document[],
  k: number = 5
): Array<{ document: Document; similarity: number }> {
  // Calculate similarity for each document
  const similarities = documents.map(doc => ({
    document: doc,
    similarity: cosineSimilarity(queryEmbedding, doc.embedding)
  }));

  // Sort by similarity (descending) and return top K
  return similarities
    .sort((a, b) => b.similarity - a.similarity)
    .slice(0, k);
}

// Usage
const results = topKSimilar(queryEmbedding, documents, 5);

results.forEach(result => {
  console.log(`Similarity: ${result.similarity.toFixed(4)}`);
  console.log(`Text: ${result.document.text}\n`);
});
完整的语义搜索示例

完整实现(包含 Gemini API)请参见 templates/semantic-search.ts。


8. 文档聚类

聚类会自动将相似文档分组。

K-Means 聚类
interface Cluster {
  centroid: number[];
  documents: number[][];
}

function kMeansClustering(
  embeddings: number[][],
  k: number = 3,
  maxIterations: number = 100
): Cluster[] {
  // 1. Initialize centroids randomly
  const centroids: number[][] = [];
  for (let i = 0; i < k; i++) {
    centroids.push(embeddings[Math.floor(Math.random() * embeddings.length)]);
  }

  // 2. Iterate until convergence
  for (let iter = 0; iter < maxIterations; iter++) {
    // Assign each embedding to nearest centroid
    const clusters: number[][][] = Array(k).fill(null).map(() => []);

    embeddings.forEach(embedding => {
      let minDistance = Infinity;
      let closestCluster = 0;

      centroids.forEach((centroid, i) => {
        const distance = 1 - cosineSimilarity(embedding, centroid);
        if (distance < minDistance) {
          minDistance = distance;
          closestCluster = i;
        }
      });

      clusters[closestCluster].push(embedding);
    });

    // Update centroids
    let changed = false;
    clusters.forEach((cluster, i) => {
      if (cluster.length > 0) {
        const newCentroid = cluster[0].map((_, dim) =>
          cluster.reduce((sum, emb) => sum + emb[dim], 0) / cluster.length
        );

        if (cosineSimilarity(centroids[i], newCentroid) < 0.9999) {
          changed = true;
        }

        centroids[i] = newCentroid;
      }
    });

    if (!changed) break;
  }

  // Build final clusters
  const finalClusters: Cluster[] = centroids.map((centroid, i) => ({
    centroid,
    documents: embeddings.filter(emb =>
      cosineSimilarity(emb, centroid) === Math.max(
        ...centroids.map(c => cosineSimilarity(emb, c))
      )
    )
  }));

  return finalClusters;
}

完整实现和示例请参见 templates/clustering.ts。

使用场景
  1. 内容整理:自动将相似的文章、产品或文档分组
  2. 重复内容检测:查找近似重复的内容
  3. 主题建模:发现大量文本语料中的主题
  4. 客户反馈分析:将相似的客户投诉或功能请求分组

9. 错误处理

常见错误

1. 缺少或无效的 API 密钥

// ❌ Error: API key not set
const ai = new GoogleGenAI({});

// ✅ Correct
const ai = new GoogleGenAI({ apiKey: process.env.GEMINI_API_KEY });

if (!process.env.GEMINI_API_KEY) {
  throw new Error('GEMINI_API_KEY environment variable not set');
}

2. 维度不匹配

// ❌ Error: Embedding has 3072 dims, Vectorize expects 768
const embedding = await ai.models.embedContent({
  model: 'gemini-embedding-001',
  content: text
  // No outputDimensionality specified → defaults to 3072
});

await env.VECTORIZE.insert([{
  id: '1',
  values: embedding.embedding.values // 3072 dims, but index is 768!
}]);

// ✅ Correct: Match dimensions
const embedding = await ai.models.embedContent({
  model: 'gemini-embedding-001',
  content: text,
  config: { outputDimensionality: 768 } // ← Match index dimensions
});

3. 速率限制

// ❌ Error: 429 Too Many Requests
for (let i = 0; i < 1000; i++) {
  await ai.models.embedContent({ /* ... */ }); // Exceeds 100 RPM on free tier
}

// ✅ Correct: Implement rate limiting
async function embedWithRetry(text: string, maxRetries = 3) {
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    try {
      return await ai.models.embedContent({
        model: 'gemini-embedding-001',
        content: text,
        config: { taskType: 'SEMANTIC_SIMILARITY' }
      });
    } catch (error: any) {
      if (error.status === 429 && attempt < maxRetries - 1) {
        const delay = Math.pow(2, attempt) * 1000; // Exponential backoff
        await new Promise(resolve => setTimeout(resolve, delay));
        continue;
      }
      throw error;
    }
  }
}

所有 8 种已记录错误及其详细解决方案,请参见 references/top-errors.md。


10. 最佳实践

务必做到

✅ 指定任务类型

// Task type optimizes embeddings for your use case
const embedding = await ai.models.embedContent({
  model: 'gemini-embedding-001',
  content: text,
  config: { taskType: 'RETRIEVAL_QUERY' } // ← Always specify
});

✅ 确保维度与 Vectorize 匹配

// Ensure embeddings match your Vectorize index dimensions
const embedding = await ai.models.embedContent({
  model: 'gemini-embedding-001',
  content: text,
  config: { outputDimensionality: 768 } // ← Match index
});

✅ 实现速率限制

// Use exponential backoff for 429 errors
async function embedWithBackoff(text: string) {
  // Implementation from Error Handling section
}

✅ 缓存嵌入

// Cache embeddings to avoid redundant API calls
const cache = new Map<string, number[]>();

async function getCachedEmbedding(text: string): Promise<number[]> {
  if (cache.has(text)) {
    return cache.get(text)!;
  }

  const response = await ai.models.embedContent({
    model: 'gemini-embedding-001',
    content: text,
    config: { taskType: 'SEMANTIC_SIMILARITY' }
  });

  const embedding = response.embedding.values;
  cache.set(text, embedding);
  return embedding;
}

✅ 对多个文本使用 Batch API

// Single batch request vs multiple individual requests
const embeddings = await ai.models.embedContent({
  model: 'gemini-embedding-001',
  contents: texts, // Array of texts
  config: { taskType: 'RETRIEVAL_DOCUMENT' }
});
绝不要

❌ 不要省略任务类型

// Reduces quality by 10-30%
const embedding = await ai.models.embedContent({
  model: 'gemini-embedding-001',
  content: text
  // Missing taskType!
});

❌ 不要混用不同维度

// Can't compare embeddings with different dimensions
const emb1 = await ai.models.embedContent({
  model: 'gemini-embedding-001',
  content: text1,
  config: { outputDimensionality: 768 }
});

const emb2 = await ai.models.embedContent({
  model: 'gemini-embedding-001',
  content: text2,
  config: { outputDimensionality: 1536 } // Different dimensions!
});

// ❌ Can't calculate similarity between different dimensions
const similarity = cosineSimilarity(emb1.embedding.values, emb2.embedding.values);

❌ 不要在 RAG 中使用错误的任务类型

// Reduces search quality
const queryEmbedding = await ai.models.embedContent({
  model: 'gemini-embedding-001',
  content: query,
  config: { taskType: 'RETRIEVAL_DOCUMENT' } // Wrong! Should be RETRIEVAL_QUERY
});

使用捆绑资源

模板(templates/)
  • package.json - 包配置,包含已验证的版本
  • basic-embeddings.ts - 使用 SDK 对单个文本生成嵌入
  • embeddings-fetch.ts - 面向 Cloudflare Workers 的 fetch 实现
  • batch-embeddings.ts - 带速率限制的批处理
  • rag-with-vectorize.ts - 使用 Vectorize 的完整 RAG 实现
  • semantic-search.ts - 余弦相似度和 Top-K 搜索
  • clustering.ts - K-means 聚类实现
参考资料(references/)
  • model-comparison.md - 比较 Gemini、OpenAI 和 Workers AI 的嵌入
  • vectorize-integration.md - Cloudflare Vectorize 的设置与模式
  • rag-patterns.md - 完整的 RAG 实现策略
  • dimension-guide.md - 选择合适的维度(768、1536 还是 3072)
  • top-errors.md - 8 个常见错误及详细解决方案
脚本(scripts/)
  • check-versions.sh - 检查 @google/genai 软件包版本是否为最新

官方文档


相关技能

  • google-gemini-api - 用于文本/图像生成的 Gemini API 主技能
  • cloudflare-vectorize - 用于存储嵌入的向量数据库
  • cloudflare-workers-ai - Workers AI 嵌入(BGE 模型)

成功指标

节省令牌:与手动实现相比,约节省 60% 预防错误:记录了 8 个错误及其解决方案 经过生产环境测试:✅ 已在 RAG 应用中验证 软件包版本:@google/[email protected] 最后更新:2025-10-25


许可证

MIT 许可证 - 可免费用于个人和商业项目。


有问题或遇到故障?

评论

支持 Markdown