与 YouTube 无需付费即可交流 - Francesco Saverio Zuppichini | 向量空间讲座
Demetrios Brinkmann
·2024年3月27日

“现在我确实相信 Qdrant,我没有得到 Qdrant 的赞助,但我确实相信它是最好的,原因有几个。我们将看到它们,主要是因为我可以在我的电脑上运行它,所以它是完全私有的,而且我负责我的数据。”
– Francesco Saverio Zuppichini
Francesco Saverio Zuppichini 是苏黎世保险公司的高级全栈机器学习工程师,在大型企业和各种规模的初创公司都有经验。他热衷于分享知识,建立社区,并以计算机视觉领域的熟练实践者而闻名。他为他建立的社区感到自豪,因为他认识了许多了不起的人。
在 Spotify、Apple Podcast、Podcast addicts、Castbox 上收听此集。您也可以在 YouTube 上观看此集。
主要收获
好奇如何将 YouTube 内容转换为可搜索元素?Francesco Zuppichini 讲述了如何通过使用字幕作为输入、利用 YouTube DL、Hugging Face 和 Qdrant 等技术来编写 RAG,同时讨论了框架依赖以及选择合适软件工具的精妙艺术。
以下是本集的一些见解
- 代码背后:Francesco 揭示了如何使用 YouTube 视频创建 RAG。准备好深入研究实现这一魔法的细节吧。
- 向量魔法:有没有想过嵌入向量是如何进行相似性搜索的?Francesco 用他精彩的向量数据库解释和寻求匹配的令人费解的距离方法为您解答。
- 函数优于类:这个争论和宇宙一样古老。Francesco 分享了他为什么喜欢使用函数而不是类来更好地组织代码,并演示了在 Ollama 上运行语言模型时这种方法的有效性。
- 元数据魔法:了解元数据不仅仅是辅助工具,它在 Qdrant 和 RAG 领域中扮演着关键角色。了解 Francesco 为什么将元数据视为有效负载以及它在开发领域特定应用程序中带来的挑战。
- 工具选择技巧:决定正确的软件工具可能感觉像是在小行星带中航行。Francesco 分享了他的标准——易于安装、健全的文档以及朋友的一些帮助——以确保安全着陆。
趣闻:Francesco 承认他用于字幕分块的代码“有点糟糕”,因为他懒惰——这证明即使是专业人士有时也会走捷径。
节目笔记
00:00 Francesco 介绍
05:36 为数据检索创建 YouTube 机架。
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
“这是一种非常简单的调试方法,因为如果你在同一个地方看到来自同一个文档的大量向量,那么你的分块可能做得不好,因为你的代码中最近的错误可能有一些太多的重叠,导致分块重复。好的,我们的向量数据库正在运行。现在我们需要做一些设置。使用 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 上举办 Vector Voices,即 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 也很简单。你无需支付任何服务费用即可完成所有这些。是的。所以我们将在本地运行我们的 PEDro DB,以及语言模型。我们将在我们的机器上运行。
Francesco Zuppichini:是的,这将是一个技术性的演讲,所以我将引导您完成代码。如果您有任何问题,如果您想问我为什么这样做等等,请随时打断我。所以,在我们开始之前,我只想很快地介绍一下我自己。所以是的,高级全栈机器工程师。这只是一堆有趣的词,基本上是说我做一点点所有的事情。一开始,当我工作时,我是一名计算机视觉工程师,我在普华永道工作,然后是一堆初创公司,现在我将我的灵魂卖给了保险公司,在保险公司工作。以前我做计算机视觉,现在由于 Chat GPT、超语言模型,我做得更多了。
Francesco Zuppichini:但我总是参与将完整产品整合在一起。所以从零到部署和运行的东西。所以我一直对 Web 开发感兴趣。我也可以做网站服务器,甚至一点点基础设施。所以现在我只是做一点点所有的事情。这就是为什么那里有全栈。是的。好的,让我们开始一些比我自己更有趣的事情。
Francesco Zuppichini:所以我们的目标是创建一个完整的本地 YouTube 机架。如果你不想要机架,它基本上是一个系统,你获取一些数据。在这种情况下,我们将从 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:现在,目标不是创建世界上最好的机架。它只是为了展示如何从零到实际工作的东西。如何以完全本地的方式实现,而不使用任何框架,这样你就可以真正理解幕后发生的事情。因为我认为很多人,他们试图复制,只是复制和粘贴 Langchain 上的东西,然后他们最终陷入需要更改某些东西,但他们不知道东西在哪里。这就是为什么我只想展示从零到英雄的旅程。所以第一步是,我得到一个 YouTube 视频,现在我需要获取字幕。所以你实际上可以使用模型从视频中获取音频并获取文本。例如,来自 OpenAI 的 Whisper 模型。
Francesco Zuppichini:在这种情况下,我们利用了 YouTube 允许人们上传字幕,YouTube 会自动生成字幕。所以这里使用 YouTube dial,我将获取我的视频 URL。我将设置一堆选项,比如我想要的格式等等。然后基本上我将下载并获取字幕。它们看起来像这样。让我给你看一个例子。类似这样的东西,对吧?我们有时间戳,我们有所有文本。现在下一步。
Francesco Zuppichini:所以我们有了数据源,我们有了文本键。下一步是,我需要将我的文本转换为向量。现在最简单的方法就是使用 sentence transformers 进行回溯。所以这里我已经安装了它。我加载了一个模型。在这种情况下,我正在使用这个模型。我不知道这个模型是什么。我只是默认了一个模型,它似乎运行良好。
Francesco Zuppichini:然后为了使用它,我只是提供一个查询,然后我得到一个向量列表。所以我们有一种方法可以获取视频,从视频中获取文本,将其转换为具有语义有意义表示的向量。现在我们需要存储它们。现在我确实相信 Qdrant,我没有得到 Qdrant 的赞助,但我确实相信它是最好的,原因有几个。我们将主要看到它们,因为我可以在我的电脑上运行它,所以它是完全私有的,我负责我的数据。所以我运行它的方式是通过 Docker compose。所以通过 Docker,使用 Docker compose,这里非常简单,我只是复制并粘贴了 Qdrant 文档的配置。我运行它,当我运行它时,我还会得到一个非常漂亮的界面。
Francesco Zuppichini:我将向您展示,因为我觉得它非常酷。所以这里我已经有一些向量了,所以我可以在我的集合中查看,它叫做 embeddings,一个原始的名字。我们可以看到所有嵌入的块,以及元数据,在这种情况下只是视频 ID。一个超级酷的东西,对调试非常有用,是进入可视化部分并查看嵌入,投影的嵌入。您实际上可以做很多事情。您实际上也可以去这里并按一些元数据给它们着色。比如我可以根据视频 ID 设置不同的颜色。在这种情况下,我只有一个视频。
Francesco Zuppichini:一旦我们添加更多视频,我就会展示它。这太酷了,太有用了。我也会在工作中用到它,我有大量文档。这是一种非常简单的调试方法,因为如果你在同一个地方看到来自同一个文档的大量向量,那么你的分块可能做得不好,因为你的代码中最近的错误可能有一些太多的重叠,导致分块重复。好的,我们的向量数据库正在运行。现在我们需要做一些设置。使用 Qdrant 非常简单。你只需要获取 Qdrant 客户端。
Francesco Zuppichini:所以你与 vectordb 建立连接,你创建一个连接,你指定一个名称,你指定一些配置,在这种情况下,我只指定了向量大小,因为 Qdrant 需要知道向量会有多大以及我想使用的距离。所以我要使用 Qdrant 文档中的余弦距离,其中有很多参数。你可以在这里做很多疯狂的事情,但要保持非常简单。是的,另一个重要的事情是,由于我们要嵌入更多视频,当我向视频提问时,我需要知道哪些嵌入来自该视频。所以我们将创建一个索引。所以根据该索引过滤我的嵌入非常高效,该索引是关于元数据视频的,因为当我将一个块存储到 Qdrant 中时,我也会包含它来自哪个视频。非常简单,设置起来非常简单。
Francesco Zuppichini:你只需要做一次。我非常懒惰,所以我只是假设如果这会失败,那是因为我已经创建了一个集合。所以我只是把它传下去,然后就算了。好的,这基本上是你需要做的所有预处理设置,以便你的 Qdrant 准备好存储和搜索向量。存储向量。也很简单,非常简单。只需要再次客户端。所以连接到数据库,这里我传入我的嵌入,所以 sentence transformer 模型,我将我的块作为文档列表传入。
Francesco Zuppichini:所以我的代码中的文档只是一个只包含这个元数据的类型。非常简单。它类似于这里的 Lang chain。我只是附加了一个标签,因为它很轻。为了存储它们,我们调用 upload records 函数。我们在这里对它们进行编码。这里我有一些不好的变量名,我正在替换它们。所以你不应该这样做。
Francesco Zuppichini:为此道歉,你只需发送记录。Qdrant 的另一个非常酷的地方是。所以第二件我真正喜欢的事情是,它们对你通过库发送的东西有类型。所以这个模型记录是一个 Qdrant 类型。所以你使用它,你立即知道。所以你需要放入什么。让我给你一个例子。对吧?所以假设我在编程,对吧,我会说模型记录库。
Francesco Zuppichini:我立刻知道要放入什么,对吧?如此直观,如此有用。很多人没有意识到类型非常有用。所以感谢 Qdrant 团队使所有类型都非常出色。另一个很酷的地方是,如果你使用 fast API 构建 Web 服务器,如果你返回 Qdrant 模型类型,它实际上会自动通过 pydantic 序列化。所以你不需要做奇怪的事情。所有这些都由 Qdrant API、产品 SDK 处理。超级酷。
Francesco Zuppichini:现在我们有一种方法来存储我们的块并嵌入它们。所以它们在界面中看起来是这样的。我可以看到它们,我可以访问它们,等等。非常好。现在缺少的部分,对。所以视频字幕。我已经分块了字幕。我还没有向你展示分块代码。
Francesco Zuppichini:它有点糟糕,因为我太懒了。所以我只是按字符数和一点点重叠进行分块。我们有一种方法来存储和嵌入我们的块,现在我们需要一种方法来搜索。这基本上是缺少的一个步骤。现在搜索也很简单。这也是一个很好的例子,因为我可以向你展示使用 Qdrant 创建过滤器是多么有效。所以我们需要再次使用向量客户端、嵌入进行搜索,因为我们有一个查询,对吧。我们需要使用相同的嵌入模型运行查询。
Francesco Zuppichini:我们需要重新创建嵌入向量,然后我们需要使用距离方法,在这种情况下是余弦相似度,与向量数据库中的向量进行比较,以便获得正确的匹配,对吧,在我们的向量数据库,在我们的向量搜索空间中最近的。所以传入一个查询字符串,我传入一个视频 ID,我传入一个标签。所以我想从元数据库中获取多少命中。现在要再次创建过滤器,您将使用 Qdrant 框架中的模型包。所以我在这里只是为模型创建一个过滤器类,我说,好的,这个过滤器必须匹配这个键,对吧?所以元数据视频 ID 和这个视频 ID。所以当我们搜索时,在我们进行相似度搜索之前,我们将过滤掉所有不属于该视频的向量。太棒了。现在也超级简单。
Francesco Zuppichini:我们只需调用 DB 搜索,传入。我们的集合名称在这里是硬编码的。对此表示歉意,我想我忘了放正确的全局变量。我们硬编码的,我们创建一个查询,设置限制,传入查询过滤器,我们以字典的形式在每个命中的 payload 字段中获取它,我们重新创建一个文档字典。我有类型,对吧?所以我知道这个函数会返回什么。现在,如果你要使用一个框架,这部分基本上是相同的。如果我要使用 Langchain,我想指定一个过滤器,我将不得不编写相同数量的代码。所以大多数时候你真的不需要使用框架。这里不使用框架的一个好处是,我可以控制索引。
Francesco Zuppichini:例如,Lang chain 只会在你调用一个类方法(比如 from document)时创建索引。这有点麻烦,因为有时我会遇到一些错误,我不明白为什么一个索引是在之前或之后创建的,等等。所以是的,尽量保持简单,不要总是编写框架。太棒了。现在我有一种方法可以提出查询,以从该视频中获取相关部分。现在我们需要将这个块列表转换为我们可以作为人类阅读的东西。在我们这样做之前,我几乎忘记了我们需要保持状态。现在,最后缺少的部分之一是我可以存储数据的地方。
Francesco Zuppichini:这里我只是有一个设置函数,我将创建一个 SQL lite 数据库,创建一个名为 videos 的表,其中包含一个 id 和一个标题。这样以后我就可以检查,嘿,这个视频是否已经在我的数据库中?是的。我不需要处理它。我可以立即开始对该视频进行问答。如果没有,我将进行分块和嵌入。这里有一些函数可以从数据库获取视频,保存视频,以及将视频保存到数据库。所以现在我只使用函数。我在这里不使用类。
Francesco Zuppichini:我不喜欢面向对象编程,因为很容易陷入继承地狱,其中我们有十层继承。这里,如果一个函数需要有状态,我们确实需要有状态,因为我们需要一个连接。所以我只会有一个初始化该状态的函数。它会返回给我,而作为调用者的我只会调用它并传递我的状态。非常简单的技巧可以让你正确地划分代码。你不需要考虑我的类是否与另一个类耦合,等等。非常简单,非常有效。所以我建议你在编码时,从函数开始,并共享状态,只需传递状态。
Francesco Zuppichini:当你意识到你可以将许多功能与共同行为一起聚类时,你可以继续将状态放入一个类中,并将关键功能作为方法。所以,尽量不要先尝试理解我需要使用哪个类,以及如何连接它们,因为在我看来,那只是浪费时间。所以,只需从功能开始,然后如果需要,再尝试将它们聚类。好的,最后一部分,也是最精彩的部分。语言模型。所以我们需要语言模型。为什么我们需要语言模型?因为我将提出一个问题。我将从视频中获取一堆相关片段,而语言模型。
Francesco Zuppichini:它需要回答我。所以它需要从块中获取信息,并使用该信息作为上下文回复给我。为了运行语言模型,在我看来最简单的方法是使用 Ollama。有很多可用的模型。我在这里放了一个链接,你也可以带上你自己的模型。有很多视频和教程教你如何做到这一点。你安装完 Linux 上的 Ollama 后运行这个命令。它只需要一行代码来安装 Ollama。
Francesco Zuppichini:您运行此处的命令,它将下载 Mistral 7B,一个非常好的模型,并在您的 GPU(如果有)或 CPU(如果没有 GPU)上运行它。在 GPU 上运行。在这里您可以看到它,它大约 6GB。所以即使是低端 GPU,您也应该能够在您的 GPU 上运行一个七分钟的模型。好的,这是提示,也只是为了向您展示这有多么简单,这个提示只是非常懒惰地复制粘贴了 Langchain 源代码中的提示:使用以下上下文片段来回答最后的问题。等等等等,用于注入上下文的变量,用于获取问题的变量,然后我们将得到一个答案。我们如何称呼它?容易吗?我这里有一个名为 getanswer 的函数,传入了一堆东西,还传入了 OpenAI Python 包模型客户端中的 OpenAI,传入了一个问题,传入了一个 vdb,我的数据库客户端,我的嵌入,读取我的提示,获取我的匹配文档,调用我们刚刚看到的搜索函数,创建我的上下文。
Francesco Zuppichini:所以只是将文本连接到新行上的块中,调用 Python 中的 format 函数。就这么简单。只需调用 Python 中的 format 函数,因为 format 函数会查找字符串,然后它会注入与这些括号内的变量匹配的变量。传入上下文,传入问题,使用 OpenAI 模型客户端 API,然后获取回复。超级简单。这里我返回语言模型的回复以及文档列表。所以这应该是文档。我想我犯了一个错误。
Francesco Zuppichini:当我复制粘贴这个以获取此图像时,我们完成了。我们有一种方法可以通过将所有内容组合在一起来从视频中获取一些答案。这可能看起来很吓人,因为这里没有注释,但我可以向您展示 Tson 代码。我认为这样更容易,我可以突出显示内容。我正在创建我的嵌入,我正在获取我的数据库,我正在获取我的向量数据库登录,一些内容,我正在获取我的模型客户端,我正在获取我的 vid。所以在这里我正在定义我需要的状态。你不需要注释,因为我直接明白了。比如这里我正在获取向量数据库,很好的函数名。
Francesco Zuppichini:然后,如果我的数据库中没有向量数据库,抱歉。如果我的数据库中没有视频 ID,我将获取一些视频信息。我将下载字幕,分割字幕。我将进行嵌入。最后我将把它保存到数据库中。最后我将取回我的视频,打印一些东西,然后启动一个 while 循环,在其中你可以得到一个答案。所以这是完整的管道。非常简单,所有都是函数。
Francesco Zuppichini:这里也是,fit 函数将事物划分得很简单。我这里有一个名为 RAG 的文件,这里我只做所有 RAG 的事情。对。都在这里,类似。我有一个名为 crude 的文件。这里我正在做所有我需要用我的数据库做的事情,等等。还有一个名为 YouTube 的文件。所以,尝试根据它们做什么而不是它们是什么来划分事物。
Francesco Zuppichini:我觉得这样编码更容易。是的。所以我实际上可以向您展示一个演示,我们可以在其中从头开始嵌入一个视频。所以让我把这个坏家伙杀了。让我们从 Sam 那里获取一个有趣的 YouTube 视频。我们可以选择 Gemma。我们可以选择 Gemma。我想我还没有嵌入它。
Francesco Zuppichini:对不起。我的 Eddie block 在这里做着奇怪的事情。好的,让我把这个放在这里。
Demetrios:这是我们所有人都需要向演示之神祈祷它能成功的时刻。
Francesco Zuppichini:哦,是的。对不起。对不起。我想它已经被处理了。所以让我。我不知道这个。我还注意到我看到了这个非常奇怪的东西,我昨天没有看到。所以这会很有趣。
Francesco Zuppichini:我想我可怜的 Linux 电脑快要放弃运行语言模型了。好的。下载陶瓷日志,嵌入,现在我们有了。在我忘记之前,因为我想你们花了一些时间做这个。所以我们去可视化页面,然后我们实际上按元数据,视频 ID 进行颜色分类。视频 ID。让我们运行它。元数据,元数据,视频元数据。哦,天哪。
Francesco Zuppichini:数据视频 ID。为什么我看不到另一个?我不知道。这就是现场直播的魅力。
Demetrios:这就是我们知道它是真的方式。
Francesco Zuppichini:是的,我的意思是,这个正在工作,对吧?这个叫做 Chevroni 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 做了一些测试,并且很欣赏它的能力。Qdrant 与 Ollama 和 Mistral 类似吗?
Francesco Zuppichini:所以我的测试是安装那个工具需要多长时间。如果安装时间太长,并且因为文档糟糕而难以安装,那是一个危险信号,对吗?因为如果安装困难且安装文档糟糕,那是人们会阅读的第一件事。所以将来使用它可能不会太好。使用 Olama,我花了不到两分钟,令人难以置信。只是安装,运行,就完成了。Qdrant 也是一样,黑客阶段库也是一样。所以对我来说,通常如果我看到某个东西容易安装,那通常意味着它很好。如果安装文档很好。
Francesco Zuppichini:这意味着人们已经考虑过它,并且他们关心编写好的文档,因为他们希望人们使用他们的工具。很多时候,对于企业工具,比如云企业服务,文档很糟糕,因为他们知道你会付费,因为你是一个企业。而且一些经理在五年前决定使用 TatCloud 供应商,而不是另一个。所以我想,如果你看到推荐,那意味着背后的人、公司、初创企业、企业希望你使用他们的软件,因为他们知道并且为之自豪。就像他们知道那是好的。所以通常这就是我的做法。然后当然,我看很多 YouTube 视频,所以我会看到人们谈论不同的文本,等等。如果一些我信任的 youtuber 说我尝试了这个,它似乎运行良好,我就会记下来。
Francesco Zuppichini:所以将来我就知道,嘿,对于这些事情,我想我使用了 ABC,而且这已经有人测试过了。我不知道我会使用它。另一个重要的事情是联系你的朋友网络,说嘿,伙计们,我需要做这个。你们知道有没有什么你们已经尝试过并有经验的好库存?
Demetrios:是的。关于企业软件工具,我看到了一件非常搞笑的事情。大概是说客户和用户不是一回事。客户是付费的人,用户是受苦的人。
Francesco Zuppichini:对于企业软件来说确实如此,我必须告诉你。所以这是真的。
Demetrios:是的,我们都经历过。所以聊天中还有另一个问题,关于是否会为每个嵌入式视频创建一个集合,基于您独特的视频 ID?
Francesco Zuppichini:不。你想要做的是,我的意思是你可以这样做,当然,但集合应该在我的脑海中更多或或少地封装你正在做的项目。所以在这种情况下,我只是称之为嵌入。也许我应该称之为视频。所以它们将只是在同一个集合中,它们只是会有不同的元数据。我想你如果我错了,你需要纠正我,从你的角度来看,从 Qdrant 代码的角度来看,在同一个集合中搜索东西,可能在某种程度上更有效。想象一下,如果你有 1000 个视频,你需要创建 1000 个集合。然后我想,集合的目的是为了拥有来自同一来源、具有语义价值的数据。
Francesco Zuppichini:所以在我的案例中,我拥有所有的视频。如果我拥有不同的数据,也许来自 PDF。我可能会创建另一个集合,对吧,如果我不想让它们在同一个部分并搜索它们。并且将所有视频放在同一个集合中的一个很酷的事情是,如果我想,我可以同时向所有视频提问,或者我可以更改我的过滤器并向两三个视频具体提问。如果你每个视频有一个集合,你就可以做到这一点,对吧?例如,在工作中,我正在嵌入 PDF 并使用定性,有时你需要同时与两个 PDF、三个 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 中。所以基本上它就像一种 JSON 类型的信息,附加到您的数据上,但未被嵌入。我们也有相关文档。我也会在评论中回答,我想我还有另一个问题要问你,弗朗兹,关于您创建的这个 RAG 的评估方式。
Francesco Zuppichini:好的,这是一个有趣的问题,因为每个人都在谈论指标和评估。大多数时候你并没有这些,对吧?所以你有基准,对。每个人都可以使用基准来评估他们的管道。但是当你拥有领域特定文档时,例如在工作中,我正在对保险文档进行 RAG。我如何从中创建数据集来评估我的 RAG?这将非常耗时。所以我们正在尝试做的是,我们找来一群了解这些文档的人,抓取一些段落,尝试提出问题,然后那里有答案,基本上是从他们那里获得一个事实真相。很多时候,答案需要由文档的不同部分组成。所以,是的,这非常困难。
Francesco Zuppichini:这很难。所以我会建议尝试使用没有基准的方法,然后你凭经验尝试。如果你正在构建一个用户会使用的 RAG,请务必包含一种收集反馈和统计数据的方法。所以收集对话,如果你的隐私规则允许的话。因为在我看来,总是最好尽快将产品投入生产,而不是等待太长时间,因为你需要运行所有指标等等。一旦人们开始使用它,你就会看到它是否足够好,也许对于语言模型本身来说,这是一个不同的任务,因为你需要确保他们不会对用户说出不当言论。我这里没有真实答案的来源。评估它们非常困难。
Francesco Zuppichini:所以我知道人们也尝试这样做,他们获取一些段落或块,他们要求 GPD four 根据段落生成问题和答案,他们将其用作自动标记的方式来创建数据集以评估你的 RAG。这可能也有效,我想百分之百有效。
Demetrios:而且根据你的用例,你可能需要更严格的评估,或者更少,就像你正在做的事情,可能不需要那么严格。
Francesco Zuppichini:你实际上可以看到,我想是加拿大航空,对吧?
Demetrios:是的。
Francesco Zuppichini:如果你面对付费用户,那么在做之前要三思。在我的情况下,我有一些内部用户使用的东西,我们会与他们沟通。所以如果我的聊天机器人说错了什么,他们会告诉我。最糟糕的情况是他们需要手动查找答案。但一旦你的聊天机器人需要做一些涉及到付费用户或医疗方面的事情,你就需要明白,对于某些用例,你需要应用某些规则,对于其他用例,你可以更放松,我会说,这取决于你的聊天机器人将产生的危害。
Demetrios:是的,我想这就是我们目前所有的问题了。感谢你来这里和我们聊天。我也感谢所有收听的人。所有没有关注 Fran 的人,去关注他,至少为了欢笑和开心,也非常感谢 Sabrina 加入我们。很高兴能邀请你来这里。我期待着做更多这样的事情。
Sabrina Aquino:荣幸之至,Demetrios,非常荣幸。Fran,我今天从您的课程中学到了很多。
Francesco Zuppichini:非常感谢。非常感谢。也请关注 Qdrant 在 LinkedIn 上的动态。他们发布了很多很酷的东西,并阅读 Qdrant 博客。它们非常棒。非常棒。
Demetrios:就是这样。团队一定会很高兴听到这个消息。所以如果你正在用 Qdrant 做任何很酷的事情,请联系我们,这样我们就可以在向量空间讲座中介绍你。下次再见,不要迷失在向量空间中。我们稍后再见。祝大家一切顺利。