PostgreSQL与AI大模型:使用开源工具和 pgvector 创建 AI 专家

原文:

https://www.percona.com/blog/create-an-ai-expert-with-open-source-tools-and-pgvector/

前言

2023 年是人工智能 (AI) 的一年。许多公司都在考虑如何通过人工智能改善用户体验,最常见的第一步是使用公司数据(内部文档、票务系统等)更快、(或)自动回答客户问题。

在这篇博文中,我们将解释基本概念,以及如何利用公司的数据构建自己的人工智能专家。为了深入了解事情是如何运作的,我们将刻意避免使用非开源工具。这也将允许任何人免费试用它,同时将代码转换为任何付费 API,例如 OpenAI。


目标

我们将执行以下步骤:

1. 预配基础结构

2. 捕获公司数据并使用 pgvector 将其存储在 PostgreSQL 中

3. 提出问题并生成回复

l 提示将由两部分组成:

1) 用户问题

2) 背景 – 我们的数据

l LLM 将使用提示生成对用户问题的响应


为了便于阅读,我们将在博客文章中展示代码概念,而完整的示例可以在 GitHub 存储库中找到:blog-data/percona-ai-pgvector。我将提供相应行的链接。

链接:https://github.com/spron-in/blog-data/tree/master/percona-ai-pgvector


词汇表和术语

本节介绍本博客文章中使用的一些术语,这些术语对读者来说可能是新的。


向量嵌入(Vector embeddings)

它是数据的数字表示,捕捉其含义和关系。从本质上讲,它是一个数字列表。您可以将任何数据编码为向量嵌入(文本、图片、视频、语音),并执行语义搜索以查找匹配项和相似之处。嵌入通常存储在向量数据库中,如 pgvector。一旦你有了文本的向量嵌入,你就可以使用数学运算(如余弦距离)轻松计算它们的相似程度。您可以预处理公司文档并生成嵌入,然后使用用户的输入搜索这些文档。 


大语言模型 (LLM:Large Language Model

LLM 是 AI 的动力。它是深度学习算法的集合,可以执行各种任务——理解文本、生成响应、转换数据等。OpenAI 的 GPT3 和 GPT4 就是 LLM 的例子


标识(Tokens

在大型语言模型 (LLM) 的上下文中,术语“标识”是指模型读取或生成的文本块标识通常不是一个词;它可以是一个较小的单位,如一个字符或单词的一部分,也可以是一个较大的单位,如整个短语。这取决于型号。

 

输入和输出正在经历标记化的过程——将文本分成更小的单元。例如,OpenAI 使用“字节对编码 (BPE)”。短语“Hello, World!”有 13 个字符,但只有 4 个标记

1. “你好”

2. ","

3. 《世界》

4. "!"

 

此外,这些标记被赋予数字标识符,正如您可能已经猜到的那样,这些标识符被放置在向量中。因此,该短语将如下所示:

[15496, 11, 995, 0]

此向量用于创建嵌入或作为提示


Hugging Face 中心

Hugging Face 是一家开源公司,致力于为机器学习和 AI 构建解决方案和工具。他们有一个中心,公开了数千个 LLM、数据集和演示应用程序。我们将使用 Hugging Face 提供的模型和库


提供基础设施

pgvector

pgvector 是一个 PostgreSQL 扩展,允许存储向量嵌入。您可以使用 Percona Distribution for PostgreSQL 安装它。我将使用 Percona Operator for PostgreSQL 及其最新的实验性自定义扩展功能将其安装在 Kubernetes 上。此功能允许您构建扩展,将其存储在 S3 存储桶中,并指示操作员使用它,而无需重新构建容器映像。

 

您可以在存储库的 k8s-operator 文件夹中找到相关清单和预构建的扩展。

# upload pgvector to your S3 bucket
# install the Operator
kubectl apply -f bundle.yaml --server-side
 
# apply secrets for S3 bucket
kubectl apply -f s3-secret.yaml
 
# apply init.yaml - this enables the extensions and creates schema
kubectl apply -f init.yaml
 
# deploy the database cluster
kubectl apply -f cr.yaml

 

在我的自定义资源清单 (cr.yaml) 中,我为我们的实验创建了用户和数据库,并指示操作员从存储桶加载扩展:


YAML

...
 users:
   - name: vector
    databases:
     - vector-db
...
extensions:
   image: percona/percona-postgresql-operator:2.3.0
   imagePullPolicy: Always
   storage:
    type: s3
    bucket: MY_TEST_BUCKET
    region: us-west-2
    secret:
     name: ext-secret
   custom:
   - name: pgvector
    version: 0.5.1

 

准备数据库

数据库启动并运行后,让我们创建表:

create table perconavec (
   id bigserial primary key,
   content text,
   url text,
   embedding vector(1024)
  );
 

向量是 pgvector 引入的新数据类型。我们创建一个具有向量类型和 1024 个向量维度的嵌入列。不同的型号有不同的尺寸。例如,OpenAI文本嵌入 ada-002有 1535 个维度。我们将使用具有 1024 个嵌入维度的UAE-Large-V1模型目前在海量文本嵌入基准 (MTEB) 排行榜中处于领先地位。您应该从一开始就仔细选择模型,因为以后更改模型需要为数据重新创建向量嵌入。

 

pgvector 引入了三个可用于计算相似度的新运算符

l <-> – 欧几里得距离

l <#> – 负内积

l <=> – 余弦距离

 

余弦距离,计算向量之间的角度,是大多数AI产品的常用选择。例如,您可以执行以下操作:

select
 1 - (perconavec.embedding <=> query_embedding),
 perconavec.url
from perconavec
order by perconavec.embedding <=> query_embedding
limit 3;

 

此查询将输出按相似度排序的前三个 URL,是最接近用户搜索的 URL。为简单起见,我们创建了函数 match_documents,为我们带来了魔力。你可以在python/01-pg-provision.py中找到它。相关链接:

https://github.com/spron-in/blog-data/blob/master/percona-ai-pgvector/python/01-pg-provision.py#L26


GPU 和 python

GPU 擅长多重处理,这对于创建矢量嵌入至关重要。您可以在没有 GPU 的情况下解析文档和创建嵌入,但可能需要 10 倍以上的时间。公有云为深度学习提供了各种基于 GPU 的机器和操作系统映像。对于 Linux 机器,您需要安装 Nvidia 驱动程序和 CUDA。

 

Python 在机器学习任务中广受欢迎。它有很多库和工具,可以通过 pip 访问。

在安装脚本中,您可以找到用于 Ubuntu 的各种命令,这些命令将安装必要的 GPU 驱动程序和 Python 库。我们将在下面详细讨论这些库。


从公司数据生成嵌入

负载嵌入模型

为了生成嵌入,我们将使用来自 Hugging Face 的库文件sentence_transformers。

Python

from sentence_transformers import SentenceTransformer
model = SentenceTransformer('WhereIsAI/UAE-Large-V1')
 
def create_embedding(content):
   embeddings = model.encode([content], device='cuda', show_progress_bar=True)
   return(embeddings)

 

正如承诺的那样,我们正在使用 UAE-Large-V1 模型。首次运行脚本时,它将自动从 Hugging Face 中心获取。

device='cuda' 指示代码使用 GPU。您可以切换到 CPU,但会导致性能欠佳。

抓取公司文件

这完全取决于您拥有的数据。在我们的示例中,我们抓取了 Percona 文档和博客文章,它们都是公开的。我们使用Python包BeautifulSoup来简化 HTML 和 XML 解析。您可能还希望添加逻辑以在将文档转换为嵌入之前消除文档中的噪音,例如可重复菜单、各种数据横幅等。

 

Python

from bs4 import BeautifulSoup
 
# from blog post - remove noisy divs
def extract_text_from_blog(url):
   html = requests.get(url).text
   soup = BeautifulSoup(html, features="html.parser")
 
  # remove noisy content
   for div in soup.find_all("div", {"id": "jp-relatedposts"}):
     div.decompose()
   for div in soup.find_all("div", {"class": "share-wrap"}):
     div.decompose()
   for div in soup.find_all("div", {"class": "comments-sec"}):
     div.decompose()
 
   text = soup.find("div", {"class": "blog-content-inner"}).get_text()
   lines = (line.strip() for line in text.splitlines())
   return 'n'.join(line for line in lines if line)


数据块

你可以把一篇大文章转换为向量嵌入,但这可能会损害你的语义搜索。建议将文本分成更小的块——段落、句子,有时甚至是单词。关于如何拆分数据的决定应该由你最终用来生成答案的模型和数据本身来驱动。


例如,我们的文档存储在 markdown 中。在我们的代码中,我们使用 langchain 的库 MarkdownTextSplitter 从这些文件中生成块。请参阅 02-put.py。相关链接:

https://github.com/spron-in/blog-data/blob/master/percona-ai-pgvector/python/02-put.py#L111-L114


将数据加载到 pgvector 中

一旦我们创建了嵌入,就该将它们放入 pgvector 中了。我们使用 psycopg2 连接到 PostgreSQL 和pgvector库来处理向量本身:

 

Python

import psycopg2
from pgvector.psycopg2 import register_vector
 
conn = psycopg2.connect(CONN_STRING)
cur = conn.cursor()
register_vector(conn)
 
cur.execute('INSERT INTO perconavec (content, url, embedding) VALUES (%s,%s,%s)', (sentence, page['source'], embeddings[0],))

 将它们粘合在一起

 从概念上讲,我们的代码如下所示:

 Python

# Load the model
model = SentenceTransformer('WhereIsAI/UAE-Large-V1')
 
# parse the web
for page in pages:
 
  # remove noisy data and/or extract the text
  text = extract_text_from_page(page)
 
  # split the data into chunks
  chunks = split_text_into_chunks(text)
 
  # generate embeddings and store in the database
  for chunk in chunks:
 
   # create embedding vectors from chunks
   embeddings = create_embedding(chunk) 
 
   # store in the databse
   cur.execute('INSERT INTO perconavec (content, url, embedding) VALUES (%s,%s,%s)', (chunk, page['source'], embeddings[0],))

 

您可以在 python/02-put.py 中找到我们用来解析数据并将其放入 pgvector 中的代码。


搜索和回答

快速搜索载体

一旦向量嵌入进入数据库,我们就可以使用之前创建的 match_documents 函数进行语义搜索。


我们的python/03-quick-search.py执行以下操作:

1. 接受输入字符串(用户问题)

2. 将其转换为向量嵌入

3. 调用函数match_documents

4. 返回输入字符串的前五个语义相关的 URL。它还可以返回内容,因为它也在数据库中。

 

$ python3 03-quick-search.py 'How to configure MySQL replication?'
...
0.8186284570586514 https://www.percona.com/blog/mysql-myisam-active-active-clustering-looking-for-trouble/
0.7665825272179729 https://www.percona.com/blog/innodb-undelete-and-sphinx-support/
0.7567072114946343 https://www.percona.com/blog/mysql-to-use-or-not-to-use/
0.7539063903781531 https://www.percona.com/blog/filtered-mysql-replication/
0.7192081516498201 https://www.percona.com/blog/filtered-mysql-replication/


用上下文回答问题

现在我们有了上下文(我们公司的数据),这一切都归结为发送适当的提示——用户问题 + 上下文。

 

我们将在 t5 模型中使用(参见 04-context-search.py)高级 HuggingFace 管道抽象包装器。它是适用于各种用例的基本预训练模型——问答、文本生成等。

04-context-search.py链接地址:

https://www.percona.com/blog/create-an-ai-expert-with-open-source-tools-and-pgvector/

 

根据管道和模型的不同,提示看起来会有所不同。但对于 text2text 管道,它将如下所示:

Python

    prompt = f"""
   question: {query}
   context: {context}
   """
   qa = pipeline('text2text-generation', do_sample=True, model=model_name, tokenizer=model_name, top_k=3)

 

其中 query – 是用户提出的问题和context – 是我们通过语义搜索从数据库中获取的数据。

$ python3 04-context-search.py "What is Everest?"
...
[{'generated_text': 'Percona Everest is an open source private database-as-a-service'}]


需要考虑的事项

模型训练

在我们的示例中,我们不执行任何模型训练,并假设它可以从我们提供的上下文中提供答案。它适用于演示目的,但对于实际用例来说不是最佳的。建议先在数据上训练模型。这是另一篇博客文章的主题。


重用脚本

GitHub 存储库中的脚本作为示例给出。语言模型和在数据库中构建数据的方式严格取决于用例。不要盲目重用脚本。


使用公共 API

我们特意使用开源工具。但是,您可以轻松地使用公共 API 来嵌入生成和问答。例如,对于嵌入生成,您可以使用 OpenAI API:

Python

def create_embedding(content):
 
# embeddings = model.encode([content], device='cuda', show_progress_bar=True)
  response = openai.Embedding.create(model= "text-embedding-ada-002",input=[content])
 embeddings = response["data"]
 return(embeddings)


总结

将嵌入存储在 pgvector 中是一个不错的选择,因为您的团队不需要学习新技术或更改现有的 PostgreSQL 库。使用开源工具,您可以轻松创建自己的 AI 或聊天机器人,这些机器人使用专有公司数据进行训练。这将提升用户体验并实现各种业务流程的自动化。试用带有 pgvector 的自定义扩展功能的 Percona Operator for PostgreSQL。有了它,您将在几秒钟内启动并运行您的数据库。


本文分享自微信公众号 - 开源软件联盟PostgreSQL分会(kaiyuanlianmeng)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

展开阅读全文
加载中
点击引领话题📣 发布并加入讨论🔥
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部