Gemini API:使用 Qdrant 进行相似性搜索

本教程面向有编程基础的开发者,深入讲解如何结合 Gemini API 的嵌入模型与 Qdrant 向量数据库实现语义搜索。通过解析网页内容、生成嵌入向量、存储于 Qdrant 并执行相似性查询,完整演示了 RAG 系统的核心流程。教程涵盖环境配置、代码逐段解析、架构设计思想、常见错误排查及生产环境优化建议,帮助开发者快速掌握向量检索的工程实践。

技术背景

传统关键词搜索无法理解语义,而语义搜索通过向量嵌入将文本映射到高维空间,使语义相近的文本在向量空间中距离更近。Gemini API 提供强大的嵌入模型,Qdrant 作为高性能向量数据库,支持高效的相似性搜索和负载存储。该组合适用于文档检索、问答系统、推荐系统等场景,但需注意嵌入模型的选择、向量维度匹配、以及大规模数据下的性能优化。

核心原理

核心流程为:1) 使用 BeautifulSoup 解析网页,提取文本并分块;2) 调用 Gemini API 的 embed_content 函数,将文本块转换为 3072 维向量(gemini-embedding-001);3) 将向量及原始文本作为负载存入 Qdrant 集合;4) 查询时,将查询文本用相同模型(task_type=retrieval_query)转换为向量,在 Qdrant 中执行余弦相似度搜索,返回最相似的文档块。关键设计决策包括:使用 task_type 区分文档和查询嵌入,提升检索精度;Qdrant 支持负载存储,便于返回上下文;内存模式便于实验,生产需持久化。

架构分析

系统由数据摄取、嵌入生成、向量存储和查询检索四部分组成。数据摄取层使用 BeautifulSoup 解析 HTML,提取正文并分块;嵌入层通过 Gemini API 的 embed_content 生成向量,支持不同 task_type;存储层使用 Qdrant 客户端,创建集合时指定向量维度(3072)和距离度量(余弦),通过 upsert 批量写入点(向量+负载);查询层将查询文本嵌入后调用 search 接口,返回 top-k 结果。该架构解耦了各组件,便于替换嵌入模型或向量数据库。

完整实战教程

##### 版权 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:使用 Qdrant 进行相似性搜索

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

概述

Gemini API 提供了一系列生成式 AI 模型的访问权限,用于生成内容和解决问题。这些模型经过设计和训练,可以处理文本和图像作为输入。

Qdrant 是一个向量相似性搜索引擎,提供了一个易于使用的 API 来管理、存储和搜索向量,并带有额外的负载。它是一个生产就绪的服务。

在本笔记本中,您将学习如何借助 Gemini API 和 Qdrant 对网站数据进行相似性搜索。

环境设置

首先,您必须安装所需的软件包并设置必要的环境变量。

安装

安装 Google 的 Gemini API Python 客户端 SDK,即 google-genai。接下来,安装 Qdrant 的 Python 客户端 SDK,即 qdrant-client。

%pip install -q "google-genai>=2.9.0"
%pip install -q protobuf==4.25.1 qdrant-client[fastembed]

配置你的 API 密钥

要运行以下单元格,你的 API 密钥必须存储在名为 GEMINI_API_KEY 的 Colab 密钥中。如果你还没有 API 密钥,或者不确定如何创建 Colab 密钥,请参阅身份验证示例。

from google.colab import userdata
from google import genai

GEMINI_API_KEY=userdata.get('GEMINI_API_KEY')
client = genai.Client(api_key=GEMINI_API_KEY)

基本步骤

语义搜索是搜索引擎在自然搜索结果中解释关键词并将其与用户意图匹配的过程。它超越了表面的关键词匹配,利用高级算法理解单词、短语和上下文的含义,从而提供更相关、更友好的搜索体验。

语义搜索依赖于向量嵌入,它能够将用户查询与最相似的结果进行最佳匹配。

在本教程中,您将实现语义搜索的三个主要组件:

  1. 创建索引

在 Qdrant 向量存储中创建并存储数据的索引。您将使用 Gemini API 嵌入模型来创建可存储在 Qdrant 向量存储中的嵌入向量。

  1. 查询索引

使用查询字符串查询索引,以返回查询的前 n 个邻居。

在实现应用程序时,您将在接下来的部分中了解更多关于这些阶段的内容。

导入所需的库

from bs4 import BeautifulSoup
from qdrant_client import models, QdrantClient
from urllib.request import urlopen

1. 创建索引

在此阶段,您将执行以下步骤:

  1. 使用Python的BeautifulSoup库读取并解析网站数据。
  1. 创建网站数据的嵌入。
  1. 将嵌入存储在Qdrant的向量数据库中。

Qdrant是一个向量相似度搜索引擎。除了提供方便的API来存储、搜索和管理点(即向量)之外,它还提供了添加额外负载的选项。负载本质上是额外的数据片段,您可以使用它们来优化搜索并获取相关信息,然后与用户分享。

读取并解析网站数据

要将网站数据作为文本读取,你将使用 Python 中的 BeautifulSoup 库。

url = "https://blog.google/outreach-initiatives/sustainability/"\
      "report-ai-sustainability-google-cop28/"
html = urlopen(url).read()
soup = BeautifulSoup(html, features="html.parser")

# Remove all script and style elements
for script in soup(["script", "style"]):
    script.extract()    # Self-destruct

# Get the text
text_content = soup.get_text()

如果你只想选择网站数据中的特定部分来为提示添加上下文,可以使用正则表达式、文本切片或文本分割。

在本例中,你将使用 Python 的 split() 函数来提取所需部分的文本。

# The text content between the substrings "Later this month at COP28" to
# "POSTED IN:" is relevant for this tutorial. You can use Python's `split()`
# to select the required content.
text_content_1 = text_content.split("Later this month at COP28",1)[1]
final_text = text_content_1.split("POSTED IN:",1)[0]

texts = final_text.split(".")

documents = []

# Convert text into a chunk of 3 sentences.
for i in range(0, len(texts), 3):
  documents.append({"content": " ".join(texts[i:i+3])})

初始化嵌入模型

为了从网站数据创建嵌入,你将使用 gemini-embedding-001 模型,该模型支持从文本创建嵌入。

要使用嵌入模型,你必须使用 google-genai 包中的 embed_content 函数。要了解更多关于嵌入模型的信息,请阅读模型文档。

传递给嵌入函数的参数之一是 task_type。指定 task_type 参数可确保模型为预期任务和输入生成适当的嵌入。它是一个字符串,可以取以下值之一:

| task_type | 描述 |

|---|---|

| RETRIEVAL_QUERY | 指定给定文本是搜索或检索设置中的查询。 |

| RETRIEVAL_DOCUMENT | 指定给定文本是搜索或检索设置中的文档。 |

| SEMANTIC_SIMILARITY | 指定给定文本将用于语义文本相似度(STS)。 |

| CLASSIFICATION | 指定嵌入将用于分类。 |

| CLUSTERING | 指定嵌入将用于聚类。 |

from google.genai import types

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


# Function to convert text to embeddings
def make_embed_text_fn(text, model=MODEL_ID,
                       task_type="retrieval_document"):
    embedding = client.models.embed_content(
        model=model,
        contents=text,
        config=types.EmbedContentConfig(
          task_type=task_type,
        )
    )
    return embedding.embeddings[0].values

使用 Qdrant 存储数据

接下来,你将把网站数据的嵌入向量存储在 Qdrant 的向量存储中。

首先,你需要通过创建 QdrantClient 的实例来初始化一个 Qdrant 客户端。在本教程中,你将把嵌入向量存储在内存中。要创建内存中的 Qdrant 客户端,请在 QdrantClient 类初始化器的 location 参数中指定 :memory:。你可以在 存储参考指南 中阅读更多关于 Qdrant 中不同类型存储的信息。

初始化客户端后,你需要使用 QdrantClient 的 recreate_collection 函数创建一个 Qdrant 集合。你可以在 recreate_collection 函数内指定向量配置。传入一个 VectorParams 实例,其中 size 设置为 768 以匹配嵌入模型,distance 设置为余弦距离。

注意:由于你将在实验过程中多次运行脚本,因此 recreate_collection 适用于本教程。recreate_collection 将首先尝试移除具有相同名称的现有集合。

# Initialize Qdrant client.
qdrant = QdrantClient(":memory:")

# Create a collection named "GeminiCollection".
qdrant.create_collection(
    collection_name="GeminiCollection",
    vectors_config=models.VectorParams(
        size=3072,  # Vector size of `gemini-embedding-001`
        distance=models.Distance.COSINE,
    ),
)

现在,你将把从网站数据中解析出的 documents 插入到之前创建的 Qdrant 集合中,并使用 QdrantClient 的 upsert 函数对它们进行索引。

upsert 函数接受要存储和索引的数据,这些数据以 PointsStruct 数组的形式提供。

点是 Qdrant 操作中的主要实体。一个点由向量和可选的有效载荷组成。你可以在一个集合中的点之间执行相似性搜索。有关点的更多信息,请参阅 Qdrant 的点文档。

你将通过枚举之前从网站数据中准备好的文档来创建一个点数组。

# Qdrant uses batch loading of points to optimize performance.
# You can create a batch in two ways - record-oriented and column-oriented.
# Here you are using the record-oriented approach.

qdrant.upsert(
    collection_name="GeminiCollection",
    points=[
        # Use PointStruct function to intialize the point.
        models.PointStruct(
            # Use `make_embed_text_fn` to convert text to embeddings.
            # Pass the same data as payload for a refined search.
            id=idx, vector=make_embed_text_fn(doc["content"]), payload = doc
        )
        for idx, doc in enumerate(documents)
    ]
)

2. 查询索引

现在,你将使用与网站文档中包含的数据相关的问题,查询之前创建的 Qdrant 索引。

要查询索引,你必须指定集合名称和查询向量。查询向量应首先使用你为网站数据创建嵌入向量时所用的 Gemini API 嵌入模型转换为嵌入向量。使用你之前定义的 make_embed_text_fn 函数从查询中创建嵌入向量。由于你正在嵌入用于搜索 retrieval_document 嵌入的查询字符串,因此 task_type 必须设置为 retrieval_query。

hits = qdrant.search(
    collection_name="GeminiCollection",
    query_vector=make_embed_text_fn("How can AI address climate challenges?",
                                    task_type="retrieval_query"),
    limit=3,
)
for hit in hits:
    print("score:", hit.score, "- content:", hit.payload.get("content").replace("\n", ""))

结论

就这样。你已经成功借助 Gemini API 嵌入模型,使用 Qdrant 执行了相似性搜索。

常见问题

常见错误:1) API 密钥未设置或无效,导致认证失败;2) 向量维度不匹配,如使用 gemini-embedding-001 但集合 size 设为 768,应设为 3072;3) 未正确设置 task_type,导致检索效果差;4) 内存模式数据丢失,重启后需重新索引;5) 网络请求超时,可增加重试机制。排查方法:检查 API 密钥、确认模型 ID 和维度、打印嵌入向量长度、使用 Qdrant 的调试接口。生产优化:使用持久化存储(如 Docker 部署 Qdrant)、批量嵌入、异步处理、索引优化(HNSW 参数调优)、缓存嵌入结果。

企业应用扩展

可扩展方向:1) 集成更多数据源(PDF、数据库)并实现增量索引;2) 使用 Qdrant 的过滤功能,结合元数据(如日期、类别)进行混合检索;3) 结合大语言模型生成答案,构建完整的 RAG 问答系统;4) 使用 gemini-embedding-2-preview 等新模型,对比效果;5) 部署为微服务,提供 REST API;6) 引入评估指标(如 Recall@K)优化分块策略和嵌入模型选择。

总结

本教程面向有编程基础的开发者,深入讲解如何结合 Gemini API 的嵌入模型与 Qdrant 向量数据库实现语义搜索。通过解析网页内容、生成嵌入向量、存储于 Qdrant 并执行相似性查询,完整演示了 RAG 系统的核心流程。教程涵盖环境配置、代码逐段解析、架构设计思想、常见错误排查及生产环境优化建议,帮助开发者快速掌握向量检索的工程实践。

内容来源与验证

继续系统学习

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

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

加入会员
查看全部RAG 与知识库教程