利用 AlloyDB 的最新向量搜索功能实现质量受控的 RAG!

1. 概览

在不同行业中,情境搜索是一项关键功能,是其应用的核心和中心。检索增强生成 (RAG) 凭借其由生成式 AI 提供支持的检索机制,长期以来一直是推动这项关键技术演进的主要因素。生成式模型具有大上下文窗口和出色的输出质量,正在改变 AI 领域。RAG 提供了一种系统性的方法,可将上下文注入 AI 应用和代理中,从而使它们能够基于结构化数据库或各种媒体中的信息。这些上下文数据对于清晰地呈现事实和提高输出的准确性至关重要,但这些结果的准确性如何呢?您的业务是否在很大程度上依赖于这些情境匹配和相关性的准确性?那么这个项目一定会让您心动!

向量搜索的“肮脏秘密”不仅在于构建它,还在于了解向量匹配是否真的有效。我们都有过这样的经历:茫然地盯着结果列表,心里纳闷:“这东西到底有没有在工作啊?!”接下来,我们深入了解如何实际评估向量匹配的质量。您可能会问:“那么,RAG 有哪些变化?”所有内容!多年来,检索增强生成 (RAG) 一直是一个很有前景但难以实现的目标。现在,我们终于拥有了构建 RAG 应用的工具,可满足任务关键型任务所需的性能和可靠性。

现在,我们已经对以下 3 个方面有了基础了解:

  1. 情境搜索对代理意味着什么,以及如何使用 Vector Search 实现情境搜索。
  2. 我们还深入探讨了如何在数据范围内(即在数据库本身内)实现向量搜索(如果您还不知道,所有 Google Cloud 数据库都支持这一点!)。
  3. 我们比世界其他国家/地区更进一步,告诉您如何利用 ScaNN 索引支持的 AlloyDB 向量搜索功能,以高性能和高质量实现这种轻量级向量搜索 RAG 功能。

如果您尚未完成这些基本、中级和略微高级的 RAG 实验,建议您按所列顺序依次阅读此处此处此处的内容。

专利搜索可帮助用户找到与搜索文本在情境上相关的专利,我们之前已经构建过一个版本。现在,我们将使用新的高级 RAG 功能来构建该应用,从而实现有质量控制的上下文搜索。下面我们就来深入探讨一下。

下图显示了此应用中的总体流程。~ 1c871099f1fde825.png

目标

让用户能够根据文本描述搜索专利,同时提升性能和质量,并能够使用 AlloyDB 的最新 RAG 功能评估生成的匹配项的质量。

构建内容

在本实验中,您将:

  1. 创建 AlloyDB 实例并加载 Patents Public Dataset
  2. 创建元数据索引和 ScaNN 索引
  3. 使用 ScaNN 的内嵌过滤方法在 AlloyDB 中实现高级向量搜索
  4. 实现召回率评估功能
  5. 评估查询响应

要求

  • 一个浏览器,例如 ChromeFirefox
  • 启用了结算功能的 Google Cloud 项目。

2. 准备工作

创建项目

  1. Google Cloud Console 的项目选择器页面上,选择或创建一个 Google Cloud 项目
  2. 确保您的 Cloud 项目已启用结算功能。了解如何检查项目是否已启用结算功能
  3. 您将使用 Cloud Shell,它是在 Google Cloud 中运行的命令行环境。点击 Google Cloud 控制台顶部的“激活 Cloud Shell”。

“激活 Cloud Shell”按钮图片

  1. 连接到 Cloud Shell 后,您可以使用以下命令检查自己是否已通过身份验证,以及项目是否已设置为您的项目 ID:
gcloud auth list
  1. 在 Cloud Shell 中运行以下命令,以确认 gcloud 命令了解您的项目。
gcloud config list project
  1. 如果项目未设置,请使用以下命令进行设置:
gcloud config set project <YOUR_PROJECT_ID>
  1. 启用所需的 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 集群、实例和表,以便加载专利数据集。

创建集群和实例

  1. 在 Cloud 控制台中浏览 AlloyDB 页面。在 Cloud 控制台中查找大多数页面的简单方法是使用控制台的搜索栏进行搜索。
  2. 在该页面中选择创建集群

f76ff480c8c889aa.png

  1. 您会看到如下所示的界面。使用以下值创建 集群和实例(如果您要从代码库克隆应用代码,请确保这些值匹配):
  • 集群 ID:“vector-cluster
  • 密码:“alloydb
  • PostgreSQL 15 / 最新推荐版本
  • 区域us-central1
  • 网络:“default

538dba58908162fb.png

  1. 选择默认网络后,您会看到如下所示的界面。

选择设置连接

7939bbb6802a91bf.png

  1. 然后,选择“使用自动分配的 IP 范围”,然后点击“继续”。查看信息后,选择“创建连接”。768ff5210e79676f.png
  2. 设置好网络后,您可以继续创建集群。点击创建集群以完成集群设置,如下所示:

e06623e55195e16e.png

请务必将实例 ID(可在配置集群 / 实例时找到)更改为

vector-instance。如果您无法更改,请务必在所有后续引用中使用您的实例 ID

请注意,创建集群大约需要 10 分钟。成功后,您应该会看到一个屏幕,其中显示了您刚刚创建的集群的概览。

4. 数据注入

现在,我们来添加一个包含商店相关数据的表格。前往 AlloyDB,选择主集群,然后选择 AlloyDB Studio:

847e35f1bf8a8bd8.png

您可能需要等待实例完成创建。完成后,使用您在创建集群时创建的凭据登录 AlloyDB。使用以下数据向 PostgreSQL 进行身份验证:

  • 用户名:“postgres
  • 数据库:“postgres
  • 密码:“alloydb

成功通过身份验证进入 AlloyDB Studio 后,您可以在编辑器中输入 SQL 命令。您可以使用最后一个窗口右侧的加号添加多个编辑器窗口。

91a86d9469d499c4.png

您将在编辑器窗口中输入 AlloyDB 命令,并根据需要使用“运行”“格式”和“清除”选项。

启用扩展程序

在构建此应用时,我们将使用扩展程序 pgvectorgoogle_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 文件中,我们将运行此文件来加载专利数据。

  1. 在 Google Cloud 控制台中,打开 AlloyDB 页面。
  2. 选择新创建的集群,然后点击相应实例。
  3. 在 AlloyDB 导航菜单中,点击 AlloyDB Studio。使用凭据登录。
  4. 点击右侧的新标签页图标,打开新标签页。
  5. 将上述 insert_scripts.sql 脚本中的 insert 查询语句复制到编辑器中。您可以复制 10-50 条 insert 语句,以便快速演示此使用情形。
  6. 点击运行。查询结果会显示在结果表中。

注意:您可能会注意到,插入脚本中包含大量数据。这是因为我们在插入脚本中加入了嵌入。如果您在 GitHub 中加载文件时遇到问题,请点击“查看原始”。这样做是为了避免您在使用 Google Cloud 试用版结算账号时,在后续步骤中生成过多的嵌入内容(最多 20-25 个),从而省去麻烦。

5. 为专利数据创建嵌入

首先,我们运行以下示例查询来测试嵌入函数:

SELECT embedding('text-embedding-005', 'AlloyDB is a managed, cloud-hosted SQL database service.');

这应该会返回查询中示例文本的嵌入向量(看起来像一个浮点数数组)。如下所示:

25a1d7ef0e49e91e.png

更新 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;

在此查询中,

  1. 用户搜索的文本为:“情感分析”。
  2. 我们正在使用模型 text-embedding-005 在 embedding() 方法中将其转换为嵌入。
  3. “<=>”表示使用余弦相似度距离方法。
  4. 我们将嵌入方法的结果转换为向量类型,以使其与存储在数据库中的向量兼容。
  5. LIMIT 10 表示我们选择的是与搜索文本最接近的 10 个匹配项。

AlloyDB 将向量搜索 RAG 提升到了新的高度:

我们推出了许多新功能。其中两个以开发者为中心:

  1. 内嵌过滤
  2. 召回率评估器

内嵌过滤

以前,作为开发者,您必须执行 Vector Search 查询,并处理过滤和召回率问题。AlloyDB 查询优化器会选择如何执行带有过滤条件的查询。内嵌过滤是一种新的查询优化技术,可让 AlloyDB 查询优化器同时评估元数据过滤条件和向量搜索,并利用向量索引和元数据列上的索引。这提高了召回率性能,使开发者能够充分利用 AlloyDB 的开箱即用功能。

内嵌过滤最适合中等选择性的情况。当 AlloyDB 搜索向量索引时,只会计算符合元数据过滤条件(查询中通常在 WHERE 子句中处理的功能性过滤条件)的向量的距离。这可大幅提升这些查询的性能,从而弥补后过滤或预过滤的优势。

  1. 安装或更新 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 索引,因为该索引不适用于行数较少的情况。在这种情况下,请跳过以下步骤。

  1. 如需创建 ScaNN 索引,请安装 alloydb_scann 扩展程序。
CREATE EXTENSION IF NOT EXISTS alloydb_scann;
  1. 首先,在使用索引且启用内嵌过滤条件的情况下运行向量搜索查询:
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;

结果应如下所示:

6989de0fc3f0f753.png

  1. 对其运行 Explain Analyze:(不使用索引和内嵌过滤)

908dcf87c7f00ed4.png

执行时间为 2.4 毫秒

  1. 让我们在 num_claims 字段上创建一个常规索引,以便按该字段进行过滤:
CREATE INDEX idx_patents_data_num_claims ON patents_data (num_claims);
  1. 让我们为专利搜索应用创建 ScaNN 索引。在 AlloyDB Studio 中运行以下命令:
CREATE INDEX patent_index ON patents_data 
USING scann (abstract_embeddings cosine)
WITH (num_leaves=32);

重要提示: (num_leaves=32) 适用于包含 1000 行以上的完整数据集。如果您的行数少于 100,则无需创建索引,因为索引不适用于行数较少的情况。

  1. 设置在 ScaNN 索引上启用的内嵌过滤:
SET scann.enable_inline_filtering = on
  1. 现在,我们来运行同一查询,但其中包含过滤条件和 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;

aa54cba2b2ada2cb.png

如您所见,对于相同的向量搜索,执行时间显著缩短。Vector Search 中融入了内嵌过滤功能的 ScaNN 索引实现了这一点!

接下来,我们来评估启用 ScaNN 的向量搜索的召回率。

召回率评估器

相似度搜索中的召回率是指从搜索中检索到的相关实例的百分比,即真正例数。这是衡量搜索质量最常用的指标。召回率损失的一个来源是近似最近邻搜索 (aNN) 与 k(精确)近邻搜索 (kNN) 之间的差异。AlloyDB 的 ScaNN 等向量索引实现了 aNN 算法,让您能够加快对大型数据集的向量搜索速度,但召回率会略有下降。现在,AlloyDB 可让您直接在数据库中衡量这种权衡,以确保其随时间推移保持稳定。您可以根据这些信息更新查询和索引参数,以获得更好的结果和性能。

搜索结果召回背后的逻辑是什么?

在向量搜索的上下文中,召回率是指索引返回的、真正最近邻向量的百分比。例如,如果对 20 个最近邻进行的最近邻查询返回 19 个标准答案最近邻,则召回率为 19/20x100 = 95%。召回率是一种用于搜索质量的指标,定义为返回结果中与查询向量客观上最接近的结果所占的百分比。

您可以使用 evaluate_query_recall 函数获得采用给定配置时,对向量索引进行的向量查询的召回率。借助此函数,您可以对参数进行调优以实现所需的向量查询召回率结果。

重要提示

如果您在以下步骤中遇到 HNSW 索引的“权限遭拒”错误,请暂时跳过整个召回评估部分。这可能与当前阶段的访问权限限制有关,因为此功能是在编写此 Codelab 文档时刚刚发布。

  1. 在 ScaNN 索引和 HNSW 索引上设置“启用索引扫描”标志:
SET scann.enable_indexscan = on
SET hnsw.enable_index_scan = on
  1. 在 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 作为索引方法。如需了解更多参数选项,请参阅文档

我们一直在使用的 Vector Search 查询的召回率:

c98f38fbe6a0b6c5.png

我看到召回率为 70%。现在,我可以利用这些信息来更改索引参数、方法和查询参数,从而提高向量搜索的召回率!

7. 使用修改后的查询和索引参数进行测试

现在,我们来测试查询,方法是根据收到的召回信息修改查询参数。

  1. 我已将结果集中的行数修改为 7(之前为 25),并且发现召回率有所提高,即 86%。

c12f7b92b8481ceb.png

这意味着,我可以根据用户的搜索情境实时调整用户看到的匹配项数量,以提高匹配项的相关性。

  1. 我们来修改一下指数参数,再试一次:

在此测试中,我将使用 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']);

非常重要的注意事项:您可能会问:“我们怎么知道此查询使用的是余弦相似度?”您可以通过使用“<=>”来表示余弦距离,从而识别距离函数。

Vector Search 距离函数的文档链接

上述查询的结果如下:

c62ef8922d6bf0b2.png

如您所见,在不更改任何索引逻辑的情况下,召回率为 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);

drop index 语句只是为了确保表上没有不必要的索引。

现在,我可以执行以下查询,以评估更改向量搜索功能的距离函数后的召回率。

[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']);

上述查询的结果如下:

6c163dd08cf4d693.png

召回价值的提升幅度高达 90%!

您还可以根据所需的召回率值和应用所用的数据集,更改索引中的其他参数,例如 num_leaves 等。

8. 清理

为避免系统因本博文中使用的资源向您的 Google Cloud 账号收取费用,请按照以下步骤操作:

  1. 在 Google Cloud 控制台中,前往资源管理器页面。
  2. 在项目列表中,选择要删除的项目,然后点击删除
  3. 在对话框中输入项目 ID,然后点击关停以删除项目。
  4. 或者,您也可以点击“DELETE CLUSTER”按钮,删除我们刚刚为此项目创建的 AlloyDB 集群(如果您在配置时未选择 us-central1 作为集群的位置,请更改此超链接中的位置)。

9. 恭喜

恭喜!您已成功使用 AlloyDB 的高级矢量搜索功能构建了情境化专利搜索查询,以实现高性能并真正实现语义驱动。我已组建一个受质量控制的多工具智能体应用,该应用使用 ADK 和我们在此讨论的所有 AlloyDB 内容来创建高性能的优质专利向量搜索和分析代理,您可以在此处查看:https://youtu.be/Y9fvVY0yZTY

如果您想学习如何构建该代理,请参阅此 Codelab

立即开始