0

无需付费与 YouTube 对话 - Francesco Saverio Zuppichini | 向量空间讲座

Demetrios Brinkmann

·

2024年3月27日

Talk with YouTube without paying a cent - Francesco Saverio Zuppichini | Vector Space Talks

“现在我确实相信 Qdrant,我不是 Qdrant 的赞助商,但我确实认为它是最好的,原因有几个。我们待会儿会看到,主要是因为我可以直接在我的电脑上运行它,所以它是完全私密的,而且我的数据由我掌控。”
– Francesco Saverio Zuppichini

Francesco Saverio Zuppichini 是苏黎世保险公司的高级全栈机器学习工程师,在大型企业和各种规模的初创公司都拥有经验。他热衷于分享知识和建设社区,并被认为是计算机视觉领域的熟练实践者。他为自己建立的社区感到自豪,因为他认识了许多了不起的人。

在 Spotify、Apple Podcast、Podcast addicts、Castbox 上收听本期节目。您也可以在 YouTube 上观看本期节目。

主要收获

对将 YouTube 内容转化为可搜索元素感到好奇?Francesco Zuppichini 详细介绍了如何以字幕作为输入编写 RAG 的过程,他利用了 YouTube DL、Hugging Face 和 Qdrant 等技术,同时探讨了框架依赖性以及选择正确软件工具的技巧。

本期节目的一些见解如下

  1. 代码背后:Francesco 揭示了如何使用 YouTube 视频创建 RAG。准备好深入了解实现这一奇妙功能的细节吧。
  2. 向量魔法:是否曾想过嵌入向量如何进行相似度搜索?Francesco 将通过他对向量数据库和寻找匹配项的令人惊叹的距离方法的精彩解释来解答你的疑问。
  3. 函数优于类:这场争论由来已久。Francesco 分享了他为何偏爱使用函数而非类来更好地组织代码,并展示了在 Ollama 上运行语言模型时这种方法的优势。
  4. 元数据魔法:了解元数据如何在 Qdrant 和 RAG 领域中扮演关键角色,而不仅仅是辅助工具。了解为什么 Francesco 将元数据视为载荷以及它在开发特定领域应用时带来的挑战。
  5. 工具选择技巧:选择合适的软件工具感觉就像穿越小行星带一样。Francesco 分享了他的标准——易于安装、完善的文档以及朋友的帮助——以确保安全着陆。

有趣的事实:Francesco 承认他用于分割字幕的代码“有点糟糕”,因为他懒惰——这证明即使是专业人士有时也会走捷径。

节目笔记

00:00 Francesco 介绍
05:36 创建用于数据检索的 YouTube RAG。
09:10 有效地展示不使用框架进行本地 Web 开发。
11:12 Qdrant:将视频文本转换为向量。
13:43 连接到向量数据库,指定配置,保持简单。
17:59 重新创建、比较向量,过滤出正确匹配项。
21:36 使用函数和共享状态简化编码。
29:32 Gemini Pro 有效地生成基于任务的输出。
32:36 好的文档体现了对产品的自豪感。
35:38 在不同的集合中组织不同类型的数据。
38:36 主动理解代码和可伸缩性的方法。
42:22 用户反馈和统计评估至关重要。
44:09 考虑用户对聊天机器人准确性和相关性的需求。

更多来自 Francesco 的引语

“所以通过 Docker,使用 Docker compose,非常简单,我只是在这里复制粘贴了 Qdrant 文档的配置。我运行它,运行后我还能得到一个非常漂亮的界面。”
– Francesco Saverio Zuppichini

“这是一种非常容易调试的方法,因为如果你在同一个地方看到来自同一文档的许多向量,也许你的分块做得不好,因为你的代码中的一个最新 bug 可能导致了太多的重叠或重复块。好了,我们的向量数据库正在运行。现在我们需要做一些设置。使用 Qdrant 非常简单。你只需要获取 Qdrant 客户端。”
– Francesco Saverio Zuppichini

“太直接了,太有用了。很多人没有意识到类型非常有用。所以赞美 Qdrant 团队,他们把所有类型都做得非常好。”
– Francesco Saverio Zuppichini

文字稿

Demetrios: 各位,欢迎来到又一期向量空间讲座。我很高兴来到这里,今天是很特别的一天,因为我有一位联合主持人。Sabrina,情况怎么样?你好吗?

Sabrina Aquino: 开始吧。非常感谢 Demetrios 邀请我来到这里。我一直想参加向量空间讲座。现在终于有机会了。所以非常感谢。

Demetrios: 你的梦想实现了,今天真是个梦想成真的好日子,因为我们今天有一位特别嘉宾。Sabrina,趁你在这里,我知道你在互联网上做了一些很棒的事情,关于如何以其他方式与 Qdrant 社区互动。在我们开始之前,你能快速介绍一下吗?

Sabrina Aquino: 当然。我想宣布一件事,我们将首次举办 Discord 线上答疑时间。我们将与 Qdrant 团队成员一起回答你们所有关于 Qdrant 的问题,在那里你们可以与我们以及我们的社区互动。我们还将分享一些关于下一个 Qdrant 1.8 版本的见解。所以这非常令人兴奋,而且,我们正在。抱歉,我这里直播有点干扰。

Demetrios: 音乐干扰你了。

Sabrina Aquino: 我们还在 Twitter 上举办“向量之声”,即 X Spaces 圆桌讨论会,在那里我们邀请专家与我们的团队一起讨论某个话题。你也可以加入并提问,进行 AMA。所以这也非常令人兴奋。是的,我们到时见。我会把 Discord 的链接放在评论里,这样大家就可以加入我们的社区并成为其中一员了。

Demetrios: 我正要说这个。那么,事不宜迟,让我们请出我们的贵宾,先生。你在哪儿?

Francesco Zuppichini: 嗨。你好。你好吗?

Demetrios: 我很好。你呢?

Francesco Zuppichini: 很好。

Demetrios: 我一直在网上看到你,今天很高兴能和你聊天。我知道你为我们准备了一些东西。你有一个完整的演示,对吗?

Francesco Zuppichini: 对。

Demetrios: 但对于不认识你的人来说,你是苏黎世保险公司的一名全栈机器学习工程师。我觉得你在 LinkedIn 上也很活跃,关注你的内容很有趣。在你做完演示后,我们会在最后讨论这个。不过再次提醒大家,如果你想提问,请在聊天中向我们提问。至于今天的演示,你将和我们聊一些关于 RAG 的非常酷的东西。我就让你开始吧。在你分享屏幕的时候,我要给大家分享一个关于你的有趣事实。你会在披萨上放番茄酱,我觉得这有点亵渎神明了。

Francesco Zuppichini: 是的。那百分百是真的。我希望意大利披萨警察没有在听这次电话,不然我就真有麻烦了。

Demetrios: 我想我们刚才流失了一些观众,不过没关系。

Sabrina Aquino: 意大利观众都退出了。

Demetrios: 是的,意大利人刚退出了,不过没关系。后期制作时我们会剪掉那部分,哥们。我现在分享你的屏幕,你就开始吧。我会在后台和 Sabrina 一起待着,以防出现任何问题。给你,老兄。

Francesco Zuppichini: 太好了。你们能看到我的屏幕吧?

Demetrios: 是的,能看到。

Francesco Zuppichini: 太好了。好的,所以今天我们要谈论的是无需付费与 YouTube 对话,告别框架废话。今天的目标是展示如何编写一个 RAG,输入是一个 YouTube 视频,而不使用任何框架,比如语言类框架等等。我想向你们展示,使用一堆技术和 Qdrant,这非常简单。而且你做所有这些都不需要向任何服务付费。对吧。所以我们将在本地运行我们的向量数据库,以及语言模型。我们将在自己的机器上运行它们。

Francesco Zuppichini: 是的,这将是一场技术讲座,所以我会带领你们过一遍代码。如果你们有任何问题,想问我为什么那样做等等,随时都可以打断我。所以很快地,在我们开始之前,我只想让你们不要介绍我自己了。所以是的,高级全栈机器学习工程师。这基本上就是一堆有趣的词,意思是说我什么都做一点。开始的时候。当我工作时,我从计算机视觉工程师开始,我在普华永道工作过,然后是一些初创公司,现在我把灵魂卖给了保险公司,在保险行业工作。之前我做计算机视觉,现在因为 Chat GPT、大型语言模型,我做得更多的是这方面的事情。

Francesco Zuppichini: 但我总是参与将整个产品整合在一起。从零开始到部署和运行的东西。所以我一直对网络开发很感兴趣。我也可以做网站服务器,还有一些基础设施方面的工作。所以现在我什么都做一点。这就是为什么那里写着全栈。好的。我们开始讲一些比我自己更有趣的东西吧。

Francesco Zuppichini: 所以我们的目标是创建一个完全本地化的 YouTube RAG。如果你不知道 RAG 是什么,它基本上是一个系统,你把一些数据放进去。在这种情况下,我们将从 YouTube 视频中提取字幕,然后你基本上就可以用你的数据进行问答了。所以你可以使用语言模型,你提问,然后我们在你提供的数据中检索相关部分,希望你能得到正确的答案。所以我们来谈谈将要使用的技术。要从视频中获取字幕,我们将使用 YouTube DL,YouTube DL 是一个可以通过 Pip 获取的库。也就是 Python 的库,我想它曾经在 GitHub 上,然后因为谷歌对此有点难搞,我想它被移除了。

Francesco Zuppichini: 所以后来他们在 GitHub 上重新发布了。现在我想它又在 GitHub 上了,但你只需要通过 Pip 安装它,它非常酷。

Demetrios: 有件事,老兄,你在分享幻灯片吗?因为我只看到你的画面。我想你分享了另一个屏幕。

Francesco Zuppichini: 哦,天呐。

Demetrios: 我只看到你的视频。好了,来了。

Francesco Zuppichini: 整个屏幕。好的。对不起。非常感谢。

Demetrios: 来了。

Francesco Zuppichini: 太好了。好的,所以为了获取嵌入。也就是说,将文本翻译成向量,对吧,我们将使用 Hugging Face 的一个嵌入模型,这样我们就可以实际得到一些向量。然后一旦我们得到了向量,我们需要存储和搜索它们。所以我们将使用我们心爱的 Qdrant 来完成。我们还需要保存一点状态,因为我们需要知道我们处理了哪些视频,这样每次看到同一个视频时,我们就不会重新做旧的嵌入和存储。所以对于这部分,我将使用 SQLite,它基本上就是一个文件形式的 SQL 数据库。所以非常容易使用,非常轻量,而且它只在你的电脑上,所以运行语言模型是安全的。

Francesco Zuppichini: 我们将使用 Ollama。这是一种非常简单、做得非常好的方法,可以让你在电脑上运行一个语言模型。你也可以使用 OpenAI Python 库调用它,因为他们实现了与 OpenAI 相同的端点。这非常方便,非常容易使用。如果你已经有一些调用 OpenAI 的代码,你只需要改变两行代码,就可以使用 Ollama 运行不同的语言模型。所以我们要做的是,基本上,我将拿一个视频。这里是一个来自 Fireship IO 的视频。

Francesco Zuppichini: 我们将运行我们的命令行,然后问一些问题。现在,理论上,你应该仍然能看到我的整个屏幕。是的。所以很快向你们展示一下,我已经处理了这个来自 good sound YouTube 频道的视频,我的命令行已经在这里了。所以我现在就可以大概看看,比如我可以问一个问题,像德国的接触尺寸是多少?然后我们将得到回复。是的。这里我们将得到回复。现在我想带你们了解一下如何做类似的事情。

Francesco Zuppichini: 现在,目标不是创建世界上最好的 RAG。只是想展示如何从零开始构建一个实际可行的东西。如何完全在本地完成,不使用任何框架,这样你就能真正理解底层发生了什么。因为我认为很多人,他们尝试复制,只是在 Langchain 上复制粘贴东西,然后当他们需要改变某些东西时,他们就陷入困境,他们不知道东西在哪里。所以这就是为什么我只想展示一下如何从零到英雄。所以第一步是,我得到一个 YouTube 视频,现在我需要获取字幕。你实际上可以使用模型从视频中提取音频并获得文本。比如 OpenAI 的 Whisper 模型。

Francesco Zuppichini: 在这种情况下,我们利用了 YouTube 允许人们上传字幕以及 YouTube 会自动生成字幕的优势。所以这里使用 YouTube DL,我将获取我的视频 URL。我将设置一堆选项,比如所需的格式等等。然后基本上我将下载并获取字幕。它们看起来像这样。让我给你们看一个例子。类似这样的东西,对吧?我们有时间戳,并且里面有所有文本。现在下一步。

Francesco Zuppichini: 所以我们有了数据源,我们有了文本。下一步是我需要将我的文本翻译成向量。现在最简单的方法就是使用 Hugging Face 的 sentence transformers。所以我在这里安装了它。我加载了一个模型。在这种情况下,我使用的是这里的这个模型。我不知道那个模型是什么。我只是使用默认的那个我找到的模型,它似乎工作正常。

Francesco Zuppichini: 然后为了使用它,我只需要提供一个查询,然后我就会得到一个向量列表。所以我们有办法获取一个视频,获取视频中的文本,将其转换为具有语义意义的向量表示。现在我们需要存储它们。现在我确实相信 Qdrant,我没有受到 Qdrant 的赞助,但我确实认为它是最好的,原因有几个。我们待会儿会看到,主要是因为我可以直接在我的电脑上运行它,所以它是完全私密的,而且我的数据由我掌控。所以我运行它的方式是通过 Docker compose。所以通过 Docker,使用 Docker compose,这里非常简单,我只是复制粘贴了 Qdrant 文档的配置。我运行它,运行后我还能得到一个非常漂亮的界面。

Francesco Zuppichini: 我将向你们展示,因为我觉得这很酷。所以这里面我已经有一些向量了,所以我可以看看我的集合,它叫 embeddings,一个原始的名字。我们可以看到所有被嵌入的块以及元数据,在这种情况下就是视频 ID。一个超酷、超有用的调试功能是进入可视化部分,查看嵌入,也就是投影后的嵌入。你实际上可以做一堆东西。你实际上也可以在这里根据一些元数据给它们着色。比如我可以根据视频 ID 来设置不同的颜色。在这种情况下我只有一个视频。

Francesco Zuppichini: 等我们添加更多视频后我会展示。这太酷了,太有用了。我在工作时也会使用这个,那里我有很多文档。这是一种非常容易调试的方法,因为如果你在同一个地方看到来自同一文档的许多向量,也许你的分块做得不好,因为你的代码中的一个最新 bug 可能导致了太多的重叠或重复块。好了,我们的向量数据库正在运行。现在我们需要做一些设置。使用 Qdrant 非常简单。你只需要获取 Qdrant 客户端。

Francesco Zuppichini: 所以你与向量数据库建立了连接,你创建一个连接,指定一个名称,指定一些配置。在这种情况下,我只指定了向量大小,因为 Qdrant 需要知道向量的大小以及我想使用的距离。所以我将使用余弦距离,Qdrant 文档中有很多参数。你可以在这里做很多疯狂的事情,但保持非常简单即可。是的,另一件重要的事情是,既然我们要嵌入更多视频,当我问一个视频问题时,我需要知道哪些嵌入来自那个视频。所以我们要创建一个索引。这样基于那个索引过滤我的嵌入就会非常高效,在元数据视频上创建一个索引,因为当我在 Qdrant 中存储一个块时,我也会包含它来自哪个视频。非常简单,设置起来非常简单。

Francesco Zuppichini: 你只需要做一次。我非常懒惰,所以我假设如果这个失败了,意味着我已经创建了一个集合。所以我就跳过它,就这么办吧。好了,这基本上就是你需要做的所有预处理设置,让你的 Qdrant 准备好存储和搜索向量。存储向量。也很直接,非常直接。只需要再次获取客户端。所以数据库连接在这里我传递我的嵌入模型,也就是 sentence transformer 模型,我把我的块作为文档列表传递。

Francesco Zuppichini: 所以在我代码中的 documents 只是一个类型,它将只包含这里的这些元数据。非常简单。这里和 Langchain 类似。我只是采用了它,因为它很轻量。要存储它们,我们调用 upload records 函数。我们在这里编码它们。我的变量命名有点差,我正在替换它。所以你不应该那样做。

Francesco Zuppichini: 对此表示歉意,然后你只需要发送记录。Qdrant 另一个非常酷的功能。我真正喜欢的第二点是,他们为通过库发送的数据提供了类型。所以这个 models record 是一个 Qdrant 类型。你使用它,立刻就知道。知道你需要放入什么内容。让我给你们举个例子。对吧?所以假设我在编程,对吧,我会说 model record bank。

Francesco Zuppichini: 我立刻就知道。所以里面需要放什么,对吧?非常直接,非常有用。很多人没有意识到类型非常有用。所以赞美 Qdrant 团队,他们把所有类型都做得非常好。另一个很酷的事情是,如果你使用 FastAPI 构建 Web 服务器,如果你返回一个 Qdrant 模型类型,它实际上会自动通过 pydantic 进行序列化。所以你不需要做奇怪的事情。所有这些都由 Qdrant API 处理,由 Qdrant SDK 处理。超级酷。

Francesco Zuppichini: 现在我们有了存储和嵌入块的方法。所以这是它们在界面中的样子。我可以看到它们,可以查看它们,等等。非常好。现在缺少的部分,对吧。视频字幕。我分割了字幕。我还没有向你们展示分割代码。

Francesco Zuppichini: 代码有点糟糕,因为我非常懒惰。所以我只是按字符数进行分块,并做了一点重叠。我们有了存储和嵌入块的方法,现在我们需要一种搜索的方法。这基本上是缺少的一个步骤。现在搜索也很直接。这也是一个很好的例子,因为我可以向你们展示使用 Qdrant 创建过滤器是多么有效。那么我们需要用什么来搜索呢?当然是向量客户端、嵌入模型,因为我们有一个查询,对吧。我们需要使用相同的嵌入模型来运行查询。

Francesco Zuppichini: 我们需要创建一个嵌入向量,然后需要使用距离方法与向量数据库中的向量进行比较,在这种情况下是余弦相似度,以找到正确的匹配项,也就是在我们的向量数据库、在我们的向量搜索基础中最接近的。所以传入一个查询字符串,我传入一个视频 ID,然后我传入一个限制(limit)。也就是我想从向量数据库中获取多少匹配项。现在要再次创建过滤器,你将使用 Qdrant 框架中的 model 包。所以在这里我只是为模型创建了一个过滤器类,我说好的,这个过滤器必须匹配这个键,对吧?也就是 metadata video id 要匹配这个视频 ID。所以当我们搜索时,在进行相似度搜索之前,我们将过滤掉所有不属于那个视频的向量。太棒了。现在也非常简单。

Francesco Zuppichini: 我们只需要调用 DB.search(),对吧。我们的集合名称这里是硬编码的。抱歉,我想我忘了放正确的全局变量,它是硬编码的,我们创建一个查询,设置限制,传入查询过滤器,在每个匹配项的 payload 字段中将其作为字典返回,然后我们重新创建我们的文档字典。我有类型,对吧?所以我知道这个函数会返回什么。现在如果你要使用一个框架,对吧,这部分,基本上是一样的。如果我使用 Langchain 并想指定一个过滤器,我需要写同样多的代码。所以大多数时候你真的不需要使用框架。这里不使用框架的一个好处是,我可以控制索引。

Francesco Zuppichini: 比如 Langchain,只有当你调用像 from_documents 这样的类方法时,它才会创建索引。这有点麻烦,因为有时我遇到一些 bug,我不明白为什么一个索引是在之前或之后创建的,等等。所以是的,尽量保持简单,不要总是依赖框架。太棒了。现在我有了查询视频并获取相关部分的方法。现在我们需要将这个块列表翻译成人类可以阅读的东西。在此之前,我差点忘了我们需要保存状态。现在,最后一个缺少的部分是可以存储数据的东西。

Francesco Zuppichini: 这里我有一个 setup 函数,我将创建一个 SQLite 数据库,创建一个名为 videos 的表,其中包含 ID 和标题。这样以后我就可以检查,嘿,这个视频是不是已经在我的数据库里了?是的。我就不需要处理它了。我可以直接开始对那个视频进行问答。如果不在,我就会进行分块和嵌入。这里有一些函数用来从数据库获取视频以及将视频保存到数据库。所以注意,我现在只使用函数。我这里没有使用类。

Francesco Zuppichini: 我不是面向对象编程的粉丝,因为它很容易陷入继承地狱,我们可能有十层继承。这里如果一个函数需要有状态,我们确实需要有状态,因为我们需要连接。所以我只会有一个初始化那个状态的函数。我把那个返回给我,作为调用者,我只需要调用它并传入我的状态。非常简单的技巧可以让你真正正确地划分代码。你不需要考虑我的类是否与另一个类耦合,等等。非常简单,非常有效。所以我的建议是,当你编写代码时,先从函数开始,并通过向下传递状态来共享状态。

Francesco Zuppichini: 当你意识到可以将许多具有共同行为的函数聚类在一起时,你就可以将状态放在一个类中,并将关键函数作为方法。所以尽量不要一开始就试图理解我需要使用哪些类以及如何连接它们,因为在我看来那只是浪费时间。所以先从函数开始,如果需要再尝试将它们聚类在一起。好的,最后一部分,也是最精彩的部分。语言模型。所以我们需要语言模型。为什么我们需要语言模型?因为我要提问,对吧。我将从视频中获取一堆相关的块以及语言模型。

Francesco Zuppichini: 它需要回答我这个问题。所以它需要从这些块中获取信息,然后将这些信息作为上下文来回复我。运行语言模型,在我看来最简单的方法是使用 Ollama。有很多模型可用。我在这里放了一个链接,你也可以 가져 来你自己的模型。有很多视频和教程教你如何做。你在 Linux 上安装后,立即运行这个命令。安装 Ollama 只需一行命令。

Francesco Zuppichini: 你在这里运行这个命令,它会下载 Mistral 7B 这个非常好的模型,并在你的 GPU(如果你有的话)或你的 CPU(如果你没有 GPU)上运行它。你可以在这里看到它。它大约是 6GB。所以即使使用低端 GPU,你也应该能够在你的 GPU 上运行一个 7B 模型。好的,这就是提示词,也只是为了向你们展示这有多容易,这个提示词非常懒惰。在这里从 Langchain 源代码复制粘贴:使用以下上下文来回答最后的问题。等等等等,变量用来注入上下文,问题变量用来获取问题,然后我们将得到一个答案。我们怎么称呼它?容易吗?我这里有一个名为 get_answer 的函数,它传入一堆东西,还传入 OpenAI Python 包的 OpenAI 模型客户端,传入一个问题,传入一个向量数据库客户端,我的数据库客户端,我的嵌入模型,读取我的提示词,获取我的匹配文档,调用我们刚才看过的搜索函数,创建我的上下文。

Francesco Zuppichini: 所以只需将块中的文本用换行符连接起来,然后调用 Python 的 format 函数。就这么简单。只需要调用 Python 的 format 函数,因为 format 函数会查看一个字符串,它会将匹配的变量注入到这些括号内部。传入上下文,传入问题,使用 OpenAI 模型客户端 API,然后获取回复。超级简单。在这里我返回语言模型的回复以及文档列表。所以这应该是 documents。我想我犯了一个错误。

Francesco Zuppichini: 当我复制粘贴这些内容来获取这个图片时,我们就完成了,对吧。通过将所有东西整合在一起,我们有办法从视频中获取一些答案。这看起来可能有点吓人,因为这里没有注释,但我可以向你们展示代码。我认为这样更容易,我可以高亮显示内容。我正在创建我的嵌入模型,我正在获取我的数据库,我正在获取我的向量数据库客户端,一些东西,我正在获取我的模型客户端,我正在获取我的视频 ID。所以在这里我定义了我需要的状态。你不需要注释,因为它很直接。比如这里我正在获取向量数据库,函数名很好。

Francesco Zuppichini: 然后如果我没有向量数据库,抱歉。如果我的数据库中没有视频 ID,我就会获取一些视频信息。我会下载字幕,分割字幕。我将进行嵌入。最后,我将把它保存到向量数据库。最后,我将获取我的视频回来,打印一些东西,然后开始一个 while 循环,你可以在其中获取答案。所以这就是完整的流程。非常简单,都是函数。

Francesco Zuppichini: 这里函数也很简单,可以用来划分事物。这里我有一个名为 RAG 的文件,这里我只做所有关于 RAG 的事情。对。所有东西都类似地在这里。我有一个名为 database 的文件,在这里我做所有需要与数据库相关的事情,等等。还有一个名为 YouTube 的文件。所以尽量根据它们的功能而不是它们的类型来划分事物。

Francesco Zuppichini: 我认为这样更容易编码。是的。所以实际上我可以向你们展示一个演示,我们在其中从头开始嵌入一个视频。所以让我在这里停止这个进程。我们来找一个 Sam 的有趣的 YouTube 视频。我们可以用 Gemma。我们可以用 Gemma。我想我还没有嵌入过它。

Francesco Zuppichini: 对不起。我的广告拦截器在这里做一些奇怪的事情。好的,让我把这个放这里。

Demetrios: 这是我们需要向演示之神祈祷的时刻,希望它能工作。

Francesco Zuppichini: 哦,是的。我非常抱歉。我非常抱歉。我想它已经被处理过了。所以让我试试这个。我不知道这个(视频)。我还注意到我看到一个非常奇怪的事情,这是我昨天还没看到的。所以这会很有趣。

Francesco Zuppichini: 我想我的可怜的 Linux 电脑快要放弃运行语言模型了。好的。正在下载(日志/嵌入过程输出),正在进行嵌入,现在我们有了。在我忘记之前,因为我想你们在这方面花了一些时间。所以我们去可视化页面,我们实际进行颜色分类,我们按元数据、视频 ID 分类。视频 ID。运行它。元数据,元数据,视频元数据。哦,天哪。

Francesco Zuppichini: 数据视频 ID。为什么看不到另一个?我不知道。这就是现场演示的魅力。

Demetrios: 这就是我们知道它是真实的。

Francesco Zuppichini: 是的,我的意思是,这个正在工作,对吧?这被称为 Gemini Pro。那个视频。是的,我不太清楚。我不太清楚。之前是工作的。我可以确定。所以我可能做错了什么,可能是之后出了问题。我们再试试。

Francesco Zuppichini: 看看。我肯定是哪里做错了,所以不用担心。但我们已经准备好提问了,所以也许我可以直接问,比如,Gemini Pro 是什么?所以让我们看看,运行在 GPU 上速度还挺快的,不需要太多时间。在这里我们可以看到我们使用了 6GB,1GB 用于嵌入模型。所以这里语言模型占用了 4GB、5GB,它说 Gemini Pro 是一个可以根据给定任务生成输出的工具。等等等等。是的,看来它工作了。

Francesco Zuppichini: 你们看。谢谢。当然。我不知道是否还有关于它的问题。

Demetrios: 有很多问题。聊天中有一个简单的问题我们可以马上回答,那就是我们可以在哪里获取这些代码?

Francesco Zuppichini: 是的,在我的 GitHub 上。我可以在聊天中分享链接给你们吗?可以吗?那应该是 YouTube 的项目。我把它放在这里可以吗?

Demetrios: 是的,当然可以。我们会把它放在所有地方,以便我们都能获取。好了。我的下一个问题,同时也有人在提问,现在聊天中你有一些粉丝,所以。

Francesco Zuppichini: 顺便说一句,大家好。

Demetrios: 从我的角度来说,我想知道你在构建技术栈时是否有特定的设计决策标准?比如你选择了 Mistral,选择了 Ollama,选择了 Qdrant。听起来你在 Qdrant 上做了一些测试,并且很欣赏它的能力。对于 Ollama 和 Mistral,情况也类似吗?

Francesco Zuppichini: 所以我的测试标准是安装那个工具需要多长时间。如果花太长时间而且因为文档不好很难安装,那么这就是一个危险信号,对吧?因为如果安装困难而且安装文档很差,那是人们首先会阅读的东西。所以以后使用这个工具可能就不会很顺畅。安装 Ollama 只花了二分钟,只花了二分钟,太不可思议了。只要安装,运行,就完成了。Qdrant 也是一样,Hugging Face 库也是一样。所以对我来说,通常一旦我看到某个东西容易安装,那通常意味着它很好。而且如果安装文档很好。

Francesco Zuppichini: 这意味着人们考虑过这个问题,并且他们很在意编写好的文档,因为他们希望人们使用他们的工具。很多时候,对于企业工具,比如云企业服务,文档都很糟糕,因为他们知道你会付费,因为你是企业。而且有些经理在五年前就已经决定使用那个云服务商了,而不是其他的。所以我想,如果你看到推荐,那就意味着背后的人、公司、初创企业、企业希望你使用他们的软件,因为他们知道并且为之感到自豪。比如他们知道它是好的。所以通常这是我的方法。然后当然我会看很多 YouTube 视频,所以我看到人们谈论不同的技术栈等等。如果我信任的某个 Youtuber 说他试过某个东西,看起来工作得很好,我就会记下来。

Francesco Zuppichini: 这样以后我就知道,嘿,对于这些事情,我认为我可以使用 ABC,而且这个已经被某人测试过了。我就去使用它。另一件重要的事情是联系你的朋友网络,问他们,嘿哥们,我需要做这个。你们知道有没有什么你们已经尝试过并且有经验的好的技术栈?

Demetrios: 是的。关于企业软件工具,我看到一个很搞笑的东西。意思是说客户(customer)和用户(user)不是一回事。客户是付钱的人,用户是受罪的人。

Francesco Zuppichini: 对于企业软件来说,这确实是真的,我得告诉你。所以那是真的。

Demetrios: 是的,我们都经历过。所以聊天中还有另一个问题,问是否会基于你的独特视频 ID 为每个嵌入的视频创建一个集合?

Francesco Zuppichini: 不。你想做的是,我的意思是当然你可以那样做,但在我看来,集合应该或多或少地封装你正在做的项目。所以在这种情况下我只是称之为 embeddings。也许我应该称之为 videos。所以它们都会在同一个集合中,它们只会拥有不同的元数据。我想如果你认为我错了需要纠正我,从你们 Qdrant 的代码来看,在同一个集合中搜索东西,可能在某种程度上更有效。想象一下,如果你有 1000 个视频,你需要创建 1000 个集合。然后我认为从集合概念上来说,集合应该包含来自同一来源、具有相同语义价值的数据。

Francesco Zuppichini: 所以在我的案例中,我包含了所有视频。如果我有不同的数据,也许来自 PDF 文件。如果我不想让它们在同一个部分并进行搜索,我可能会创建另一个集合,对吧。将所有视频放在同一个集合中的一个很酷的事情是,如果我想的话,我可以同时向所有视频提问,或者我可以改变我的过滤器,向两三个视频提问。具体来说,如果你为每个视频创建一个集合,你就可以这样做,对吧?比如在工作时,我嵌入 PDF 并使用 Qdrant,有时你需要同时与两三个 PDF 文件交互,或者只与一个,或者也许是那个文件夹里的所有 PDF。所以我只需要改变过滤器,对吧?只有当它们都在同一个集合中时,这才能做到。

Sabrina Aquino: 是的,这是对集合的一个很棒的解释。我真的很喜欢你将所有东西放在本地并以结构化的方式组织它们的方法,这样你就可以真正理解你在做什么。我知道你提到有时框架不是必需的。我想知道,从你的角度来看,你认为什么时候框架是必需的,这是否与扩展性有关?你怎么看?

Francesco Zuppichini: 这是一个很好的问题。理论上,框架应该给你的是好的接口,对吧?所以一个好的接口意味着如果我遵循那个接口,我知道我总是可以用相同的方式调用实现那个接口的东西。比如在 Langchain 中,如果我调用一个向量数据库,我可以直接替换向量数据库,然后用相同的方式调用它。如果接口很好,框架就很有用。如果你知道你将来会改变一些东西。在我的案例中,我从一开始就知道我将使用 Qdrant,我将使用 Ollama,我将使用 SQLite。那我为什么要费力去阅读框架文档呢?我安装库,然后你需要安装框架里一堆你甚至不知道为什么需要的包。可能还会有包冲突,等等等等。

Francesco Zuppichini: 如果你已经知道了。那么你想做的就是直接编写代码,就这么办吧?就像在这种情况下,我知道我不会改变向量数据库。如果你认为你可能会改变一些东西,即使是一个简单的方法,那也足够公平,改变东西很简单。比如我会说,如果你知道你想改变你的向量数据库提供商,那么你要么定义你自己的接口,要么使用一个已经定义好接口的框架。但要小心,因为过度依赖框架会... 首先,基本上你不知道 Langchain 底层发生了什么,因为它是如此... (复杂),但是赞美他们。他们是第一个这样做的人。他们非常聪明,等等等等。

Francesco Zuppichini: 但他们的代码里有继承地狱。为了理解如何做某些事情,我不得不去看源代码,对吧。并试图搞清楚。那么哪个类是从那个继承的?然后一级一级往上追溯,以便理解那个类应该有什么行为。如果我传入这个参数,有时定义一个接口非常直接,也许你只是想在一个类中定义几个函数。你调用它,你只需要定义输入和输出,如果你想扩展,你只需要实现一个遵循那个接口的新类。是的,至少这是我的看法。我尝试先完成一些事情,然后如果我需要扩展,至少我已经有一个能工作的东西,我可以对其进行扩展,而不是一开始就试图做到完美。

Francesco Zuppichini: 另外,因为我讨厌阅读文档,所以我通常会尽量避免这样做。

Sabrina Aquino: 是的,我完全喜欢这个。关键在于你的最终项目是什么?你真的需要构建什么?并理解你背后正在构建的东西?我觉得这非常棒。我们还有一个问题,说他还没用过 Qdrant。元数据也是嵌入的一部分吗?也就是说,是附加在块前面还是怎样?所以他基本上是问,元数据是否也嵌入在答案中。请回答。

Francesco Zuppichini: 我记得你们有一篇关于一种搜索方式的好文章,你们可能也嵌入了标题。是的,我记得你们有一篇好文章,展示了块中包含来自章节的标题,对吧?你先进行搜索,找到正确的标题,然后再在里面搜索。也就是来自那个段落,我认为是来自那个章节的所有块,如果我没记错的话。不过这真的取决于用例。如果你的文档信息量很大,有很多段落,非常长,并且你需要非常精确地获取内容,那么你需要利用文档的结构,对吧?

Sabrina Aquino: 是的,完全正确。元数据在 Qdrant 中作为载荷(payload)存储。所以基本上它就像附加在你的数据上的 JSON 类型信息,它是*没有*被嵌入的。我们也有相关的文档。我也会在评论中回答。我认为我还有一个问题想问你,Franz,是关于评估的,你如何对你创建的这个 RAG 进行一些评估。

Francesco Zuppichini: 好的,这是一个有趣的问题,因为每个人都在谈论指标和评估。大多数时候你实际上没有这些,对吧?所以你有基准测试,对吧。每个人都可以使用基准测试来评估他们的管道。但是当你拥有特定领域的文档时,比如在工作时,我正在对保险文档进行 RAG。我如何从中创建一个数据集来评估我的 RAG?这会非常耗时。所以我们正在尝试做的是,我们找一些了解这些文档的人,选择一些段落,尝试提问,然后他们提供回复,基本上从他们那里获取真实答案(ground truth)。很多时候,回复需要由文档的不同部分组成。所以,是的,这非常困难。

Francesco Zuppichini: 这非常困难。所以我的建议是,尝试使用现有基准测试,或者然后你凭经验去尝试。如果你正在构建一个用户将要使用的 RAG,总是包含一种收集反馈和收集统计数据的方式。所以在符合你的隐私规定的前提下,收集对话记录。因为在我看来,与其等待太长时间,不如先把东西投入生产,因为你需要运行所有指标等等。一旦人们开始使用它,你就能看到它是否足够好。对于语言模型本身,这是一个不同的任务,因为你需要确保它们不会误导用户。这里很难真正获取真实答案的来源。评估它们非常困难。

Francesco Zuppichini: 所以我知道人们也会尝试这样做,比如,他们获取一些段落或一些块,他们让 GPT-4 根据这些段落生成一个问题和答案,然后他们用这个作为自动标注数据的方法来创建一个数据集,以评估你的 RAG。我想这也可以有效,百分百有效,是的。

Demetrios: 而且取决于你的用例,你可能需要更严格或不那么严格的评估,比如在这种情况下,你做的这个,可能就不需要那么严格。

Francesco Zuppichini: 你看,实际上,我想是加拿大航空,对吧?

Demetrios: 是的。

Francesco Zuppichini: 如果你的东西是面向付费用户的,那就要三思而后行。在我看来,我这里的这个东西是给内部用户使用的,而且我们和他们有沟通。所以如果我的聊天机器人说错了什么,他们会告诉我。最坏的情况就是他们需要手动去查找答案。但只要你的聊天机器人需要做一些涉及付费用户或医疗方面的事情。你需要明白,对于某些用例,你需要应用严格的规则,而对于其他用例,你可以更宽松一些,可以说,这取决于你的聊天机器人会造成多大的伤害。

Demetrios: 是的,我想现在问题就这些了。感谢你来到这里和我们聊天。我也感谢所有收听的朋友。还没有关注 Fran 的,去关注他吧,至少为了那些欢笑和笑声,也非常感谢你,Sabrina,加入我们。很高兴你来到这里。我期待着做更多这样的节目。

Sabrina Aquino: Demetrios,我的荣幸,非常高兴。Fran,我今天的讲座中学到了很多。

Francesco Zuppichini: 非常感谢。非常感谢。也请大家去 LinkedIn 上关注 Qdrant。他们发布很多很酷的内容,并且阅读 Qdrant 的博客。他们的博客非常好。非常好。

Demetrios: 就是这样。我相信团队会很高兴听到这些。所以如果你在使用我们好用的 Qdrant 做任何很酷的事情,请联系我们,这样我们就可以在向量空间讲座中展示你。下次再见,不要迷失在向量空间中。我们稍后再见。各位,祝好。

免费开始使用 Qdrant

开始使用