关于此 Codelab
1. 概览
在各个行业中,内容相关搜索都是构成应用核心的关键功能。检索增强生成(RAG)已成为推动这项关键技术演变的重要驱动力,其检索机制由生成式 AI 赋能。生成式模型具有较大的上下文窗口和出色的输出质量,正在颠覆 AI 技术。RAG 提供了一种系统的方法,可将上下文注入 AI 应用和代理,将其置于结构化数据库或各种媒体中的信息之上。这些背景数据对于阐明真相和确保输出结果的准确性至关重要,但这些结果的准确性如何?您的业务是否在很大程度上取决于这些内容相关匹配的准确性和相关性?那么,这个项目一定会让您爱不释手!
向量搜索的秘密不仅仅在于构建它,还在于了解向量匹配是否确实有效。我们都曾有过这样的经历:呆呆地盯着一长串结果,心想“这玩意儿到底有用吗?”我们来深入了解如何实际评估矢量匹配的质量。您可能会问:“RAG 有什么变化?”万事万物!多年来,检索增强生成 (RAG) 一直被视为一个前景广阔但难以实现的目标。现在,我们终于有了构建 RAG 应用所需的工具,这些应用具有执行任务关键型任务所需的性能和可靠性。
现在,我们已经对以下 3 点有了基本的了解:
- 情境搜索对您的客服人员意味着什么,以及如何使用 Vector Search 实现情境搜索。
- 我们还深入探讨了如何在数据范围内(即数据库本身)实现向量搜索(如果您还不知道,所有 Google Cloud 数据库都支持向量搜索)。
- 我们比其他人更进一步,向您介绍了如何利用由 ScaNN 索引提供支持的 AlloyDB Vector Search 功能,实现高性能、高质量的轻量级 Vector Search RAG 功能。
如果您尚未完成基本、中级和稍高级别的 RAG 实验,建议您按照此处、此处和此处的顺序阅读这 3 篇文章。
专利搜索可帮助用户查找与其搜索文本在上下文上相关的专利,我们之前就已构建过此类版本。现在,我们将使用先进的新版 RAG 功能构建该应用,以便为该应用实现质量受控的上下文搜索。我们开始吧!
下图显示了此应用中发生的整体流程。~
目标
允许用户根据文本说明搜索专利,同时提升性能和质量,还能使用 AlloyDB 的最新 RAG 功能评估生成的匹配项的质量。
构建内容
在本实验中,您将执行以下操作:
- 创建 AlloyDB 实例并加载专利公共数据集
- 创建元数据索引和 ScaNN 索引
- 使用 ScaNN 的内嵌过滤方法在 AlloyDB 中实现高级向量搜索
- 实现 Recall 评估功能
- 评估查询响应
要求
2. 准备工作
创建项目
- 在 Google Cloud Console 的项目选择器页面上,选择或创建一个 Google Cloud 项目。
- 确保您的 Cloud 项目已启用结算功能。了解如何检查项目是否已启用结算功能。
- 您将使用 Cloud Shell,它是在 Google Cloud 中运行的命令行环境。点击 Google Cloud 控制台顶部的“激活 Cloud Shell”。
- 连接到 Cloud Shell 后,您可以使用以下命令检查自己是否已通过身份验证,以及项目是否已设置为您的项目 ID:
gcloud auth list
- 在 Cloud Shell 中运行以下命令,以确认 gcloud 命令了解您的项目。
gcloud config list project
- 如果项目未设置,请使用以下命令进行设置:
gcloud config set project <YOUR_PROJECT_ID>
- 启用所需的 API。 您可以在 Cloud Shell 终端中使用 gcloud 命令:
gcloud services enable alloydb.googleapis.com compute.googleapis.com cloudresourcemanager.googleapis.com servicenetworking.googleapis.com run.googleapis.com cloudbuild.googleapis.com cloudfunctions.googleapis.com aiplatform.googleapis.com
您可以通过控制台搜索各个产品或使用此链接,以替代 gcloud 命令。
如需了解 gcloud 命令和用法,请参阅文档。
3. 数据库设置
在本实验中,我们将使用 AlloyDB 作为专利数据的数据库。它使用集群来存储所有资源,例如数据库和日志。每个集群都有一个主实例,可提供对数据的访问点。表将存储实际数据。
我们来创建一个 AlloyDB 集群、实例和表,以便加载专利数据集。
创建集群和实例
- 在 Cloud 控制台中,前往 AlloyDB 页面。在 Cloud 控制台中查找大多数页面时,最简单的方法是使用控制台的搜索栏进行搜索。
- 从该页面中选择创建集群:
- 您将看到如下所示的界面。使用以下值创建集群和实例(如果您要从代码库克隆应用代码,请确保这些值一致):
- 集群 ID:“
vector-cluster
” - 密码:“
alloydb
” - PostgreSQL 15 / 推荐使用最新版本
- 区域:"
us-central1
" - 网络:“
default
”
- 选择默认网络后,您会看到如下所示的界面。
选择设置连接。
- 然后,选择使用自动分配的 IP 范围并点击“继续”。查看信息后,选择“创建关联”。
- 设置好网络后,您可以继续创建集群。点击创建集群以完成集群设置,如下所示:
请务必将实例 ID(您可以在配置集群 / 实例时找到)更改为
vector-instance
。如果您无法更改它,请记得在接下来的所有引用中使用实例 ID。
请注意,创建集群大约需要 10 分钟。成功完成后,您应该会看到一个屏幕,其中显示了您刚刚创建的集群的概览。
4. 数据注入
现在,我们需要添加一个包含商店数据的表格。前往 AlloyDB,选择主集群,然后选择 AlloyDB Studio:
您可能需要等待实例创建完成。完成后,使用您在创建集群时创建的凭据登录 AlloyDB。使用以下数据对 PostgreSQL 进行身份验证:
- 用户名:“
postgres
” - 数据库:“
postgres
” - 密码:“
alloydb
”
成功通过身份验证登录 AlloyDB Studio 后,您可以在编辑器中输入 SQL 命令。您可以使用最后一个窗口右侧的加号添加多个编辑器窗口。
您将在编辑器窗口中输入 AlloyDB 命令,并根据需要使用“Run”“Format”和“Clear”选项。
启用扩展程序
如需构建此应用,我们将使用扩展程序 pgvector
和 google_ml_integration
。借助 pgvector 扩展程序,您可以存储和搜索向量嵌入。google_ml_integration 扩展程序提供了用于访问 Vertex AI 预测端点以在 SQL 中获取预测结果的函数。通过运行以下 DDL 启用这些扩展程序:
CREATE EXTENSION IF NOT EXISTS google_ml_integration CASCADE;
CREATE EXTENSION IF NOT EXISTS vector;
如果您想检查数据库上已启用的扩展程序,请运行以下 SQL 命令:
select extname, extversion from pg_extension;
创建表
您可以在 AlloyDB Studio 中使用以下 DDL 语句创建表:
CREATE TABLE patents_data ( id VARCHAR(25), type VARCHAR(25), number VARCHAR(20), country VARCHAR(2), date VARCHAR(20), abstract VARCHAR(300000), title VARCHAR(100000), kind VARCHAR(5), num_claims BIGINT, filename VARCHAR(100), withdrawn BIGINT, abstract_embeddings vector(768)) ;
abstract_embeddings 列将允许存储文本的向量值。
授予权限
运行以下语句以授予对“embedding”函数的执行权限:
GRANT EXECUTE ON FUNCTION embedding TO postgres;
向 AlloyDB 服务账号授予 Vertex AI User 角色
在 Google Cloud IAM 控制台中,向 AlloyDB 服务账号(格式为:service-<<PROJECT_NUMBER>>@gcp-sa-alloydb.iam.gserviceaccount.com)授予“Vertex AI 用户”角色的访问权限。PROJECT_NUMBER 将包含您的项目编号。
或者,您也可以从 Cloud Shell 终端运行以下命令:
PROJECT_ID=$(gcloud config get-value project)
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:service-$(gcloud projects describe $PROJECT_ID --format="value(projectNumber)")@gcp-sa-alloydb.iam.gserviceaccount.com" \
--role="roles/aiplatform.user"
将专利数据加载到数据库中
我们将使用 BigQuery 上的 Google 专利公共数据集作为数据集。我们将使用 AlloyDB Studio 运行查询。数据会导入到此 insert_scripts.sql
文件中,我们将运行此文件以加载专利数据。
- 在 Google Cloud 控制台中,打开 AlloyDB 页面。
- 选择新创建的集群,然后点击实例。
- 在 AlloyDB 导航菜单中,点击 AlloyDB Studio。使用凭据登录。
- 点击右侧的新标签页图标,打开新标签页。
- 将上述
insert_scripts.sql
脚本中的insert
查询语句复制到编辑器中。您可以复制 10-50 个插入语句,以便快速演示此用例。 - 点击运行。查询结果会显示在结果表中。
注意:您可能会注意到,插入脚本中包含大量数据。这是因为我们在插入脚本中添加了嵌入。如果您在 GitHub 中加载文件时遇到问题,请点击“查看原始”。这样做是为了避免您在使用 Google Cloud 的试用版抵用金结算账号时,在后续步骤中生成多个嵌入(例如最多 20-25 个)而遇到麻烦。
5. 为专利数据创建嵌入
首先,我们通过运行以下示例查询来测试嵌入函数:
SELECT embedding('text-embedding-005', 'AlloyDB is a managed, cloud-hosted SQL database service.');
这应该会返回查询中示例文本的嵌入向量,该向量看起来像一个浮点数数组。如下所示:
更新 abstract_embeddings 向量字段
仅当您未在插入脚本中插入 abstract_embeddings 数据时,才应运行以下 DML 以使用相应的嵌入更新表中的专利摘要:
UPDATE patents_data set abstract_embeddings = embedding( 'text-embedding-005', abstract);
如果您使用的是 Google Cloud 试用型抵用金结算账号,则可能无法生成多个嵌入(例如最多 20-25 个)。因此,我已在插入脚本中添加嵌入,如果您已完成“将专利数据加载到数据库”步骤,则应在加载的表中看到该嵌入。
6. 使用 AlloyDB 的新功能执行高级 RAG
现在,表格、数据和嵌入都已准备就绪,接下来我们将对用户搜索文本执行实时向量搜索。您可以通过运行以下查询来进行测试:
SELECT id || ' - ' || title as title FROM patents_data ORDER BY abstract_embeddings <=> embedding('text-embedding-005', 'Sentiment Analysis')::vector LIMIT 10;
在此查询中,
- 用户搜索的文字是:“Sentiment Analysis”。
- 我们将在 embedding() 方法中使用模型 text-embedding-005 将其转换为嵌入。
- “<=>”表示使用 COSINE SIMILARITY 距离方法。
- 我们将嵌入方法的结果转换为向量类型,以使其与存储在数据库中的向量兼容。
- LIMIT 10 表示我们要选择与搜索文本最相符的 10 个结果。
AlloyDB 将向量搜索 RAG 提升到了一个新的水平:
我们介绍了许多内容。其中两个侧重于开发者的功能是:
- 内嵌过滤
- 召回率评估器
内嵌过滤
以前,作为开发者,您必须执行向量搜索查询,并处理过滤和召回。AlloyDB 查询优化器会选择如何执行带有过滤条件的查询。内嵌过滤是一种新的查询优化技术,可让 AlloyDB 查询优化器同时评估元数据过滤条件和向量搜索,同时利用元数据列的向量索引和索引。这提高了召回率,让开发者能够充分利用 AlloyDB 的开箱即用功能。
内嵌过滤最适合选择性中等的情况。在搜索向量索引时,AlloyDB 只会计算与元数据过滤条件(查询中的函数过滤条件,通常在 WHERE 子句中处理)匹配的向量的距离。这极大地提高了这些查询的性能,并补充了后置过滤器或前置过滤器的优势。
- 安装或更新 pgvector 扩展程序
CREATE EXTENSION IF NOT EXISTS vector WITH VERSION '0.8.0.google-3';
如果 pgvector 扩展程序已安装,请将向量扩展程序升级到 0.8.0.google-3 或更高版本,以获取召回率评估器功能。
ALTER EXTENSION vector UPDATE TO '0.8.0.google-3';
只有当您的矢量扩展程序版本为 <0.8.0.google-3> 时,才需要执行此步骤。
重要提示:如果行数少于 100 行,则无需创建 ScaNN 索引,因为它不适用于行数较少的情况。在这种情况下,请跳过以下步骤。
- 如需创建 ScaNN 索引,请安装 alloydb_scann 扩展程序。
CREATE EXTENSION IF NOT EXISTS alloydb_scann;
- 首先,不启用索引和不启用内嵌过滤器的情况下运行向量搜索查询:
SELECT id || ' - ' || title as title FROM patents_data
WHERE num_claims >= 15
ORDER BY abstract_embeddings <=> embedding('text-embedding-005', 'Sentiment Analysis')::vector LIMIT 10;
结果应类似如下所示:
- 对其运行“解释分析”功能:(不使用索引也不使用内嵌过滤)
执行时间为 2.4 毫秒
- 我们在 num_claims 字段上创建一个常规索引,以便按该字段进行过滤:
CREATE INDEX idx_patents_data_num_claims ON patents_data (num_claims);
- 我们来为专利搜索应用创建 ScaNN 索引。从 AlloyDB Studio 运行以下代码:
CREATE INDEX patent_index ON patents_data
USING scann (abstract_embeddings cosine)
WITH (num_leaves=32);
重要提示 :(num_leaves=32)
适用于包含 1,000 多行的整个数据集。如果行数少于 100 行,则无需创建索引,因为索引不适用于行数较少的情况。
- 在 ScaNN 索引上设置内嵌过滤功能:
SET scann.enable_inline_filtering = on
- 现在,我们来运行包含过滤条件和 Vector Search 的相同查询:
SELECT id || ' - ' || title as title FROM patents_data
WHERE num_claims >= 15
ORDER BY abstract_embeddings <=> embedding('text-embedding-005', 'Sentiment Analysis')::vector LIMIT 10;
如您所见,相同的向量搜索的执行时间显著缩短。这得益于向 Vector Search 注入了内嵌过滤的 ScaNN 索引!
接下来,我们来评估启用 ScaNN 的此向量搜索的召回率。
召回率评估器
在相似搜索中,召回率是指通过搜索检索到的相关实例的百分比,即真正正例的数量。这是衡量搜索质量时最常用的指标。召回率损失的一个原因来自近似最近邻搜索(即 aNN)与 k(精确)最近邻搜索(即 kNN)之间的差异。AlloyDB 的 ScaNN 等向量索引会实现 aNN 算法,让您能够加快对大型数据集的向量搜索速度,但需要以略微降低召回率为代价。现在,AlloyDB 让您能够直接在数据库中衡量单个查询的这种权衡,并确保其长期稳定。您可以根据这些信息更新查询和索引参数,以取得更好的结果和性能。
搜索结果召回背后的逻辑是什么?
在向量搜索的上下文中,召回率是指索引返回的、真正最近邻向量的百分比。例如,如果对 20 个最近邻进行的最近邻查询返回 19 个接地最近邻,则召回率为 19/20x100 = 95%。召回率是一种用于搜索质量的指标,定义为返回结果中与查询向量客观上最接近的结果所占的百分比。
您可以使用 evaluate_query_recall 函数获得采用给定配置时,对向量索引进行的向量查询的召回率。借助此函数,您可以对参数进行调优以实现所需的向量查询召回率结果。
重要提示:
如果您在执行以下步骤时遇到 HNSW 索引的权限被拒错误,请暂时跳过整个召回率评估部分。此时,这可能与访问权限限制有关,因为此 Codelab 文档编写时该库刚刚发布。
- 在 ScaNN 索引和 HNSW 索引上设置“启用索引扫描”标志:
SET scann.enable_indexscan = on
SET hnsw.enable_index_scan = on
- 在 AlloyDB Studio 中运行以下查询:
SELECT
*
FROM
evaluate_query_recall($$
SELECT
id || ' - ' || title AS title,
abstract
FROM
patents_data
where num_claims >= 15
ORDER BY
abstract_embeddings <=> embedding('text-embedding-005',
'sentiment analysis')::vector
LIMIT 25 $$,
'{"scann.num_leaves_to_search":1, "scann.pre_reordering_num_neighbors":10}',
ARRAY['scann']);
evaluate_query_recall 函数会将查询作为参数并返回其召回率。我将用于检查性能的查询用作函数输入查询。我已将 SCaNN 添加为索引方法。如需了解更多参数选项,请参阅文档。
我们一直在使用的这个向量搜索查询的召回率为:
我发现 Recall 为 70%。现在,我可以使用这些信息更改索引参数、方法和查询参数,并提高此向量搜索的召回率!
7. 使用修改后的查询和索引参数进行测试
现在,我们根据收到的 Recall 修改查询参数,以测试查询。
- 我已将结果集中的行数修改为 7(之前为 25),发现 Recall 有所提高,即 86%。
这意味着,我可以实时调整用户看到的匹配项数量,以便根据用户的搜索情境来提高匹配项的相关性。
- 我们再来修改一下索引参数,看看能否成功:
在本测试中,我将使用“L2 距离”,而不是“余弦”相似度距离函数。我还会将查询限制更改为 10,以便展示即使搜索结果集数量增加,搜索结果质量是否有所提升。
[之前] 使用余弦相似度距离函数的查询:
SELECT
*
FROM
evaluate_query_recall($$
SELECT
id || ' - ' || title AS title,
abstract
FROM
patents_data
where num_claims >= 15
ORDER BY
abstract_embeddings <=> embedding('text-embedding-005',
'sentiment analysis')::vector
LIMIT 10 $$,
'{"scann.num_leaves_to_search":1, "scann.pre_reordering_num_neighbors":10}',
ARRAY['scann']);
重要提示:您可能会问:“我们如何知道此查询使用的是余弦相似度?”您可以使用“<=>”表示余弦距离,从而识别距离函数。
指向向量搜索距离函数的文档链接。
上述查询的结果如下所示:
如您所见,在不更改索引逻辑的情况下,RECALL 为 70%。还记得我们在“内嵌过滤”部分的第 6 步中创建的 ScaNN 索引“patent_index
”吗?在运行上述查询时,该索引仍然有效。
现在,我们使用不同的距离函数查询创建一个索引:L2 距离:<->
drop index patent_index;
CREATE INDEX patent_index_L2 ON patents_data
USING scann (abstract_embeddings L2)
WITH (num_leaves=32);
删除索引语句只是为了确保表中没有不必要的索引。
现在,我可以执行以下查询,以评估更改向量搜索功能的距离函数后召回率。
[AFTER] 使用余弦相似度距离函数的查询:
SELECT
*
FROM
evaluate_query_recall($$
SELECT
id || ' - ' || title AS title,
abstract
FROM
patents_data
where num_claims >= 15
ORDER BY
abstract_embeddings <-> embedding('text-embedding-005',
'sentiment analysis')::vector
LIMIT 10 $$,
'{"scann.num_leaves_to_search":1, "scann.pre_reordering_num_neighbors":10}',
ARRAY['scann']);
上述查询的结果如下所示:
召回率竟然提高到了 90%!
您还可以在索引中更改其他参数,例如 num_leaves 等,具体取决于所需的召回率值和应用使用的数据集。
8. 清理
为避免系统因本博文中使用的资源向您的 Google Cloud 账号收取费用,请按照以下步骤操作:
- 在 Google Cloud 控制台中,前往资源管理器页面。
- 在项目列表中,选择要删除的项目,然后点击删除。
- 在对话框中输入项目 ID,然后点击关停以删除项目。
- 或者,您也可以点击“DELETE CLUSTER”(删除集群)按钮,删除我们为此项目刚刚创建的 AlloyDB 集群(如果您在配置时未为集群选择 us-central1,请更改此超链接中的相应位置)。
9. 恭喜
恭喜!您已成功使用 AlloyDB 的高级矢量搜索功能构建了情境专利搜索查询,以实现高性能并使其真正以意义为导向。我已整合了一个质量受控的多工具代理应用,该应用使用 ADK 和我们在此处讨论的所有 AlloyDB 内容,打造了高性能、高质量的专利矢量搜索和分析器代理,您可以点击以下链接查看:https://youtu.be/Y9fvVY0yZTY
如果您想了解如何构建该代理,请参阅此 codelab。