AI 与向量

向量列


Supabase 提供了多种在 Postgres 中存储和查询向量的方法。本指南中的 SQL 适用于所有编程语言的客户端。如果您是 Python 用户,在阅读完"学习"部分后,请查看您的 Python 客户端选项

Supabase 中的向量功能通过 pgvector 实现,这是一个用于在 Postgres 中存储和查询向量的扩展。它可用于存储 嵌入向量

使用方法

启用扩展

  1. 进入控制面板中的数据库页面
  2. 点击侧边栏中的扩展
  3. 搜索"vector"并启用该扩展

创建存储向量的表

启用 vector 扩展后,您将获得名为 vector 的新数据类型。向量大小(括号内数字)表示该向量存储的维度数量。

1
2
3
4
5
6
create table documents ( id serial primary key, title text not null, body text not null, embedding vector(384));

在上述 SQL 代码片段中,我们创建了一个 documents 表,其中包含名为 embedding 的列(注意这只是普通的 Postgres 列 - 您可以任意命名)。我们将 embedding 列设置为具有 384 维的 vector 数据类型。请根据您的嵌入模型产生的维度数修改此值。例如,如果您使用开源的 gte-small 模型生成嵌入向量,则应将该数字设为 384,因为该模型会产生 384 维向量。

存储向量/嵌入

在这个示例中,我们将使用 Transformers.js 生成一个向量,然后通过 Supabase JavaScript 客户端将其存储到数据库中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import { pipeline } from '@xenova/transformers'const generateEmbedding = await pipeline('feature-extraction', 'Supabase/gte-small')const title = 'First post!'const body = 'Hello world!'// 使用 Transformers.js 生成向量const output = await generateEmbedding(body, { pooling: 'mean', normalize: true,})// 提取嵌入输出const embedding = Array.from(output.data)// 将向量存储到 Postgresconst { data, error } = await supabase.from('documents').insert({ title, body, embedding,})

本示例使用了 JavaScript 版的 Supabase 客户端,但您可以修改它以适配任何支持的编程语言库

查询向量/嵌入

相似性搜索是向量最常见的用例。pgvector 支持3种新的距离计算运算符:

运算符描述
<->欧几里得距离
<#>负内积
<=>余弦距离

选择合适的运算符取决于您的需求。如果向量已归一化,点积通常是速度最快的选择。有关嵌入工作原理及其相互关系的更多信息,请参阅什么是嵌入?

supabase-js 这样的 Supabase 客户端库通过 PostgREST 连接到您的 Postgres 实例。PostgREST 目前不支持 pgvector 的相似性运算符,因此我们需要将查询封装在 Postgres 函数中,并通过 rpc() 方法调用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
create or replace function match_documents ( query_embedding vector(384), match_threshold float, match_count int)returns table ( id bigint, title text, body text, similarity float)language sql stableas $$ select documents.id, documents.title, documents.body, 1 - (documents.embedding <=> query_embedding) as similarity from documents where 1 - (documents.embedding <=> query_embedding) > match_threshold order by (documents.embedding <=> query_embedding) asc limit match_count;$$;

此函数接收 query_embedding 参数,并将其与 documents 表中的所有其他嵌入进行比较。每次比较都会返回一个相似度分数。如果相似度大于 match_threshold 参数,则返回该记录。返回的行数由 match_count 参数限制。

您可以根据应用需求自由修改此方法。match_threshold 确保只返回与 query_embedding 具有最低相似度的文档。没有这个阈值,可能会返回主观上不匹配的文档。这个值因应用而异——您需要进行自己的测试来确定适合您应用的阈值。

如果对向量列建立了索引,请确保 order by 直接按距离函数排序(而不是按计算的 similarity 列排序,否则可能导致索引被忽略和性能下降)。

要从客户端库执行此函数,使用 rpc() 调用您的 Postgres 函数:

1
2
3
4
5
const { data: documents } = await supabaseClient.rpc('match_documents', { query_embedding: embedding, // 传入要比较的嵌入向量 match_threshold: 0.78, // 为您的数据选择合适的阈值 match_count: 10, // 选择匹配数量})

在这个例子中,embedding 是您希望与预生成嵌入文档表进行比较的另一个嵌入向量。例如,如果您正在构建搜索引擎,每次用户提交查询时,您会先为搜索查询本身生成嵌入,然后将其传入上述 rpc() 函数进行匹配。

向量和嵌入的用途远不止搜索。了解更多关于嵌入的信息,请参阅什么是嵌入?

索引

当您的向量表开始增长时,您可能会希望添加索引以加速查询。请参阅向量索引了解向量索引的工作原理及创建方法。