Skip to main content

Supabase (Postgres)

Supabase是一个开源的Firebase替代品。Supabase是建立在PostgreSQL之上的,它提供了强大的SQL查询功能,并且可以与已有的工具和框架简单地进行交互。

PostgreSQL也被称为Postgres,是一个强调可扩展性和SQL兼容性的免费开源关系数据库管理系统(RDBMS)。

这个笔记本展示了如何将Supabasepgvector作为您的VectorStore使用。

要运行这个笔记本,请确保:

  • pgvector扩展已启用
  • 您已安装supabase-py
  • 您在数据库中创建了一个match_documents函数
  • 您在public模式下有一个类似下面的documents表。

下面的函数确定余弦相似度,但您可以根据需要进行调整。

       -- 启用pgvector扩展以处理嵌入向量
create extension vector;

-- 创建一个表来存储您的文档
create table documents (
id uuid primary key,
content text, -- 对应Document.pageContent
metadata jsonb, -- 对应Document.metadata
embedding vector(1536) -- 1536适用于OpenAI嵌入,如果需要可以更改
);

CREATE FUNCTION match_documents(query_embedding vector(1536), match_count int)
RETURNS TABLE(
id uuid,
content text,
metadata jsonb,
-- 我们返回匹配的向量以实现最大边际相关搜索
embedding vector(1536),
similarity float)
LANGUAGE plpgsql
AS $$
# variable_conflict use_column
BEGIN
RETURN query
SELECT
id,
content,
metadata,
embedding,
1 -(documents.embedding <=> query_embedding) AS similarity
FROM
documents
ORDER BY
documents.embedding <=> query_embedding
LIMIT match_count;
END;
$$;
# 使用pip安装
pip install supabase

# 使用conda安装
# !conda install -c conda-forge supabase

我们想要使用OpenAIEmbeddings,所以我们需要获取OpenAI API密钥。

import os
import getpass

os.environ["OPENAI_API_KEY"] = getpass.getpass("OpenAI API密钥:")
os.environ["SUPABASE_URL"] = getpass.getpass("Supabase URL:")
os.environ["SUPABASE_SERVICE_KEY"] = getpass.getpass("Supabase Service Key:")
# 如果您将Supabase和OpenAI API密钥存储在.env文件中,可以使用dotenv加载它们
from dotenv import load_dotenv

load_dotenv()
import os
from supabase.client import Client, create_client

supabase_url = os.environ.get("SUPABASE_URL")
supabase_key = os.environ.get("SUPABASE_SERVICE_KEY")
supabase: Client = create_client(supabase_url, supabase_key)
from langchain.embeddings.openai import OpenAIEmbeddings
from langchain.text_splitter import CharacterTextSplitter
from langchain.vectorstores import SupabaseVectorStore
from langchain.document_loaders import TextLoader
from langchain.document_loaders import TextLoader

loader = TextLoader("../../../state_of_the_union.txt")
documents = loader.load()
text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=0)
docs = text_splitter.split_documents(documents)

embeddings = OpenAIEmbeddings()
# 这里使用默认的`documents`表。您可以通过向`from_documents`方法传递`table_name`参数来修改它。
vector_store = SupabaseVectorStore.from_documents(docs, embeddings, client=supabase)
query = "What did the president say about Ketanji Brown Jackson"
matched_docs = vector_store.similarity_search(query)
print(matched_docs[0].page_content)
    今晚。我呼吁参议院:通过自由投票法案。通过约翰·刘易斯投票权法案。而且,趁机通过披露法案,这样美国人就可以知道谁在资助我们的选举。

今晚,我想向一个致力于为这个国家服务的人表示敬意:司法部长斯蒂芬·布雷耶——一位陆军退伍军人、宪法学者和即将退休的美国最高法院法官。布雷耶法官,感谢您的服务。

总统拥有的最重要的宪法责任之一是提名人选担任美国最高法院法官。

我在4天前做到了这一点,当时我提名了巡回上诉法院法官凯坦吉·布朗·杰克逊。她是我们国家最顶尖的法律智慧之一,将继续布雷耶法官的卓越传统。

带有分数的相似度搜索

返回的距离分数是余弦距离。因此,较低的分数表示更好的匹配。

matched_docs = vector_store.similarity_search_with_relevance_scores(query)
matched_docs[0]
    (Document(page_content='今晚。我呼吁参议院:通过自由投票法案。通过约翰·刘易斯投票权法案。而且,趁机通过披露法案,这样美国人就可以知道谁在资助我们的选举。\n\n今晚,我想向一个致力于为这个国家服务的人表示敬意:司法部长斯蒂芬·布雷耶——一位陆军退伍军人、宪法学者和即将退休的美国最高法院法官。布雷耶法官,感谢您的服务。\n\n总统拥有的最重要的宪法责任之一是提名人选担任美国最高法院法官。\n\n我在4天前做到了这一点,当时我提名了巡回上诉法院法官凯坦吉·布朗·杰克逊。她是我们国家最顶尖的法律智慧之一,将继续布雷耶法官的卓越传统。', metadata={'source': '../../../state_of_the_union.txt'}),
0.802509746274066)

Retriever选项

本节介绍了如何将SupabaseVectorStore作为检索器使用的不同选项。

最大边际相关搜索

除了在检索器对象中使用相似度搜索之外,您还可以使用mmr

retriever = vector_store.as_retriever(search_type="mmr")
matched_docs = retriever.get_relevant_documents(query)
for i, d in enumerate(matched_docs):
print(f"\n## Document {i}\n")
print(d.page_content)
    
## Document 0

今晚。我呼吁参议院:通过自由投票法案。通过约翰·刘易斯投票权法案。而且,趁机通过披露法案,这样美国人就可以知道谁在资助我们的选举。

今晚,我想向一个致力于为这个国家服务的人表示敬意:司法部长斯蒂芬·布雷耶——一位陆军退伍军人、宪法学者和即将退休的美国最高法院法官。布雷耶法官,感谢您的服务。

总统拥有的最重要的宪法责任之一是提名人选担任美国最高法院法官。

我在4天前做到了这一点,当时我提名了巡回上诉法院法官凯坦吉·布朗·杰克逊。她是我们国家最顶尖的法律智慧之一,将继续布雷耶法官的卓越传统。

## Document 1

其中一位驻扎在基地上,呼吸着“燃烧坑”中燃烧的战争废物——医疗和危险材料、喷气燃料等。

当他们回家时,许多世界上最健壮、训练有素的战士再也不一样了。

头痛。麻木。头晕。

一种癌症会让他们躺在用国旗包裹的棺材里。

我知道。

其中一位士兵是我的儿子贝奥中校。

我们不确定燃烧坑是否是他的脑癌的原因,或者是否是我们的许多军队的疾病的原因。

但我致力于尽一切可能弄清楚。

致力于像俄亥俄州的丹妮尔·罗宾逊这样的军事家庭。

他是军士长希思·罗宾逊的遗孀。

他生来就是一个士兵。国民警卫队。科索沃和伊拉克的战地医生。

驻扎在巴格达附近,距离足球场大小的燃烧坑只有几码。

他的遗孀丹妮尔今晚和我们在一起。他们喜欢去俄亥俄州立大学看橄榄球比赛。他喜欢和女儿一起玩乐高积木。

## Document 2

我正在采取有力措施,确保我们的制裁对俄罗斯经济产生影响。我们将利用我们掌握的一切工具来保护美国的企业和消费者。

今晚,我可以宣布,美国已与其他30个国家合作,从全球储备中释放了6000万桶石油。

美国将领导这一努力,从我们自己的战略石油储备中释放3000万桶。如果有必要,我们愿意做更多,与我们的盟友团结一致。

这些措施将有助于减轻国内的汽油价格。我知道目前发生的事情可能看起来令人担忧。

但我想让您知道,我们会没事的。

当这个时代的历史被书写时,普京对乌克兰的战争将使俄罗斯变得更加弱小,世界其他地区变得更加强大。

虽然这不应该需要发生如此可怕的事情才能让世界各地的人们看清楚现在的局势,但现在每个人都看得很清楚。

## Document 3

我们无法改变我们的分歧。但我们可以改变我们前进的方式——在COVID-19和其他我们必须共同面对的问题上。

不久前,我在纽约市警察局访问了威尔伯特·莫拉警官和他的搭档杰森·里维拉警官的葬礼后的几天。

他们在接到一个911电话时,一个男人用一把偷来的枪射杀了他们。

莫拉警官27岁。

里维拉警官22岁。

他们都是多米尼加裔美国人,他们在同一条街道上长大,后来选择作为警察官员巡逻。

我与他们的家人交谈,并告诉他们,我们对他们的牺牲永远感激,并将继续履行他们恢复每个社区应有的信任和安全的使命。

我在这些问题上已经工作了很长时间。

我知道什么是有效的:投资于犯罪预防和社区警察官员,他们会走街串巷,了解社区,恢复信任和安全。