为了账号安全,请及时绑定邮箱和手机立即绑定

100% 免费的向量搜索,使用 OpenLlama、Postgres、Node.js 和 Next.js

所以你想尝试向量搜索,但不想支付 OpenAI 的费用,也不想使用 Huggingface,并且不想支付向量数据库公司的费用。我来帮助你。让我们在你自己的机器上免费启动向量搜索。

文章缩略图图像

我们在做什么?

让我们稍微回退一步,谈谈我们正在做什么以及为什么要这样做。基于AI嵌入的向量搜索是一种基于概念创建搜索的方法。例如,搜索“宠物”可能会同时返回狗和猫的结果。这非常有价值,因为它意味着您的客户可以获得更好的搜索结果。

为了实现这一点,我们首先将要搜索的文本发送给AI,让它创建一个“嵌入”。嵌入是一个长的浮点数值数组,通常包含大约300到1500个数字。

猫、狗和宠物的嵌入值会比较相似。所以如果你比较猫和狗,它们会很接近,而狗和披萨则不会接近。

向量数据库允许你存储这些向量及其相关联的数据(可能是原始的数据文本)。一旦数据被存储,你就可以用一个新的向量查询数据库以获取任何附近的匹配结果。例如,如果我们把“猫”和“狗”及其嵌入向量存储在数据库中,然后我们再输入文本“宠物”,创建该文本的嵌入向量,再用这个向量查询数据库,我们很可能会得到“猫”和“狗”作为返回结果。

为什么是Postgres和OpenLlama?

Postgres 是一个出色的数据库,你可以轻松地在本地安装和运行它。并且通过 pgvector 扩展,你可以在 Postgres 中创建可以在 SQL 查询中使用的向量字段。

在你的机器上安装 Postgres 有多种方式。在我的 Mac 上,我使用 Postgres.app 来安装 Postgres。

OpenLlama 是一种非常简单的方式,可以在本地安装和运行 AI 模型。我使用 Homebrew 安装了 OpenLlama,命令为 brew install ollama

对于我们的简单测试应用程序,我们将加载来自1986年恐怖电影《异形》的所有台词。

设置环境

有许多模型可供选择,详情请见这里。对于这个应用,我选择了 [snowflake-arctic-embed](https://ollama.com/library/snowflake-arctic-embed),因为它非常适合快速生成嵌入。安装时我使用了命令 ollama pull snowflake-arctic-embed

设置的最后一步是创建一个本地Postgres数据库。你可以给它起任何你喜欢的名字,我选择将它命名为lines,因为我们正在搜索电影中的台词。

有了数据库后,我们可以使用 psql 命令来运行一些命令。第一个命令是向数据库中添加 vector 扩展。这将启用 vector 字段类型。为此,我使用了 create extension 命令:

    CREATE EXTENSION vector;

现在我们需要创建一个表来存储行文本以及向量,以下是创建表以及在 position 值上创建索引的命令,position 是行在脚本中的位置。

    CREATE TABLE lines (  
      id bigserial PRIMARY KEY,  
      position INT,  
      text TEXT,  
      embedding VECTOR(1024)  
    );  
    CREATE UNIQUE INDEX position_idx ON lines (position);

需要注意的是向量的大小。不同的模型会产生不同大小的向量。在我们的雪flake模型中,嵌入大小为1,024个数字,所以我们设置向量大小为这个数值。

你希望在存储和查询时使用相同的嵌入式AI。如果你使用不同的模型,那么数字将无法对齐。

创建向量索引

正如你可以想象的,比较两个包含1,024个浮点数值的数组可能会很耗时。而比较大量的数组则会非常耗时。因此,这些新的向量数据库提出了不同的索引模型来提高效率。Postgres的向量支持有不同类型的索引,我们将使用Hierarchical Navigable Small Worlds(HNSW)类型来创建三个不同的索引:

    创建索引 ON lines 使用 hnsw (embedding vector_ip_ops);  
    创建索引 ON lines 使用 hnsw (embedding vector_cosine_ops);  
    创建索引 ON lines 使用 hnsw (embedding vector_l1_ops);

为什么是三种?因为比较两个向量有多种方式。常用的是余弦相似度,适合做概念上的比较。还有欧几里得距离和点积比较。Postgres 支持所有这些方法(以及其他方法)。

无论你使用哪种方法,都确保启用了索引,以便能够进行高速查询。

加载数据库

模型下载完成后,以及Postgres设置好之后,我们现在可以开始用我们的电影台词及其嵌入向量来填充数据库了。我已经在Github上发布了整个项目,该项目还包括一个NextJS App Router UI。脚本位于load-embeddings目录。原始数据来自这个脚本页面

在你可以加载数据之前,你需要将 .env.example 文件复制为 .env,然后将值更改为与你的 Postgres 连接详情匹配。

要将嵌入加载到Postgres中,请使用Node 20或更高版本运行node loader.mjs

脚本的关键部分是嵌入生成:

    import ollama from "ollama";  
    ...  
      const response = await ollama.embeddings({  
        model: "snowflake-arctic-embed",  
        prompt: text,  
      });

在哪里我们使用 ollama 库逐行调用 snowflake 嵌入模型。

我们然后使用 INSERT 语句将该行插入数据库中:

      await sql`INSERT INTO lines  
        (position, text, embedding)  
      VALUES  
        (${position}, ${text}, ${`[${response.embedding.join(",")}]`})  
      `;

这里唯一棘手的地方是如何格式化嵌入,方法是将所有数字连接成一个字符串,并用括号包裹起来。

将所有数据加载到数据库中后,现在是时候进行查询了。

制作我们的第一个查询

为了确保这能正常工作,有一个 [test-query.mjs](https://github.com/jherr/aliens-vector-search/blob/main/load-embeddings/test-query.mjs) 文件位于 [load-embeddings](https://github.com/jherr/aliens-vector-search/blob/main/load-embeddings/test-query.mjs) 目录中。为了进行向量查询,我们首先运行模型将查询转换为向量,如下所示:

    const response = await ollama.embeddings({  
      model: "snowflake-arctic-embed",  
      prompt: "食物",  
    });

在这种情况下,提示词是 food,我们使用与加载脚本中相同的过程将其转换为嵌入。

我们然后使用 SQL SELECT 语句查询带有该向量的数据库:

    const query = await sql`SELECT  
      位置, 文本  
    FROM  
      线条  
    ORDER BY  
      嵌入向量 <#> ${`[${response.embedding.join(",")}]`}   
    LIMIT 10`;

我们使用 ORDER BY 按数据库中记录与给定嵌入的相似度对记录进行排序,然后使用 LIMIT 获取最相似的前 10 条记录。

<#> 语法在 ORDER BY 中很重要,因为它定义了使用哪种比较算法。根据文档,我们的选项有:

    <-> - L2 距离  
    <#> - (负) 内积  
    <=> - 余弦距离  
    <+> - L1 距离 (在 0.7.0 版本中添加)

你可以自己决定哪种比较方法能为你的应用提供最佳输出,但请确保根据所选的比较方法正确地为表建立索引。

在我的机器上,这个测试查询返回了其他一些内容:

    317 看来她也不喜欢玉米面包。

哪一句是电影中提到的一种食物(玉米面包)的经典台词。

一个用户界面的搭建

通过稍微多一点的努力,我在上面添加了一个 NextJS App Router 接口,你可以在项目根目录下通过运行 pnpm dev 来体验它,前提是数据库已经加载并且 .env 文件已经正确设置。

这个 NextJS 应用使用完全相同的 SELECT 操作从数据库查询行。

结论

显然你不会用一个搜索《异形》剧本的应用程序来投入生产。但从我这里展示的内容来看,你可以搜索文本内容、产品描述、评论,几乎任何类型的文本。

享受吧!

一个简单的解释 🚀

感谢你成为In Plain English社区的一员!在你离开之前:

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消