详细讲解如何搭建本地检索增强生成系统,让想自建AI应用的程序员降低云服务依赖,提升隐私和成本控制。
当我们推出 Skald 时,我们希望它不仅能自我托管,而且用户能够在不向第三方发送任何数据的情况下运行它。
随着 LLMs 的不断改进,注重隐私的组织不应该被迫在无法访问前沿模型和放弃(或法律要求的)数据隐私承诺之间做出选择。
所以这是我们为了支持这个用例所做的工作,以及一些对比专有 API 和自托管开源技术性能的基准测试。
一个基本的 RAG 通常具有以下核心组件:
向量嵌入模型
大多数时候它还会有这些组件:
文档解析(用于 PDFs、PowerPoints 等)
这意味着当你想要构建一个完全本地的 RAG 设置时,你需要用本地选项替换你使用的任何 SaaS 提供商的每个组件。
下面是一个表格,其中包含一些示例,说明在可以使用第三方云服务的场景和不能的场景中我们可能使用的内容:
请注意,在本地运行某些内容并不意味着它需要是开源的,因为人们可以为自托管的专有软件付费。但在 Skald,我们的目标是使用完全开源的技术,这正是我在这里要讨论的。
上面的表格远未涵盖两列中的所有可用选项,但基本上它为你提供了应该研究哪些内容的指示,以便选择适合你的工具。
与所有事情一样,什么对你有效在很大程度上取决于你的用例。如果你一直在调用 API,你需要准备好运行比你习惯的更多服务。
对于我们的本地栈,我们现在选择了最容易的设置来让它工作(它确实有效!见下面的介绍),但我们将对所有其他选项运行基准测试,以确定最好的设置。
这是我们现在拥有的:
向量数据库:Postgres + pgvector。我们已经使用 Postgres,不想将另一个服务捆绑到我们的栈中,但这是有争议的,我们将运行基准测试以便做出更明智的决定。不过请注意,pgvector 对于数百万个文档的许多用例都能很好地工作。
向量嵌入:用户可以在 Skald 中配置这个,我们使用 Sentence Transformers(all-MiniLM-L6-v2)作为默认值(在速度和检索方面表现稳定,仅英文)。我还使用 bge-m3(更大的多语言模型)运行了 Skald,并在本文后面分享结果。
LLM:我们甚至没有在 Skald 中捆绑默认值,由用户来运行和管理。我在 EC2 上使用 GPT-OSS 20B 测试了我们的设置(结果如下所示)。
重排器:用户也可以在 Skald 中配置,默认是 Sentence Transformers cross encoder(稳定,仅英文)。我还使用过提供多语言支持的 bge-reranker-v2-m3 和 mmarco-mMiniLMv2-L12-H384-v1。
文档解析:这个没什么问题。我们使用 Docling。它很棒。我们通过 docling-serve 运行它。
所以这里的主要目标首先是让某些东西工作,然后确保它与我们的平台配合良好,可以轻松部署。从这里开始,我们将运行广泛的基准测试,并与我们的客户合作,提供一个既能良好运行又不是部署和管理噩梦的坚实设置。
从这个角度来看,这是一个巨大的成功。
使用整个栈部署 Skald 的生产实例只需 8 分钟,其中包括向量数据库(嗯,Postgres)、重排和嵌入服务以及 Docling。
我唯一需要单独运行的是 LLM,我通过 llama.cpp 做的。
整理好这一切后,我从 PostHog 网站导入了所有内容 [1],在 Skald 内设置了一个小的问题和预期答案数据集 [2],然后使用我们的实验功能在该数据集上运行 RAG。
我明确地保持 topK 值非常高(向量搜索为 100,重排后为 50),因为我主要是在测试准确性,想看看当问题需要聚合 15+ 文档的上下文时的性能。
这是在 Skald UI 中为实验配置的参数。
所以不再延迟,这是我使用 Skald 内部实验平台进行的基准测试的结果。
这是我们的默认云设置。我们分别使用来自 Voyage AI 的 voyage-3-large 和 rerank-2.5 作为我们的嵌入和重排模型,并默认使用 Claude Sonnet 3.7 进行响应(用户可以配置模型)。
它表现出色通过了。
我们的 LLM-as-a-Judge 对响应的平均评分为 9.45,我基本上同意这个评估。所有答案都是正确的,其中一个缺少了一些额外的上下文。
完成对照实验后,我继续进行一个设置,其中我保留了 Voyage 作为嵌入和重排提供商,然后使用在 g5.2xlarge EC2 实例上的 llama.cpp 服务器上运行的 GPT-OSS 20B 作为 LLM。
这里的目标是看看开源 LLM 模型本身与通过 API 访问的前沿模型相比表现如何。
我们还不支持在完全本地部署上使用 LLM-as-a-Judge,所以这里唯一的评分是我的。我对答案的平均评分为 9.18,它们都是正确的,其中两个只是缺少了一些信息或突出了上下文中不太相关的信息。
最后,是真相大白的时刻:运行完全本地设置。
为此我进行了两次测试:
最受欢迎的开源模型是用于嵌入的 all-MiniLM-L6-v2 和作为 reranker 的 ms-marco-MiniLM-L6-v2,所以我在第一个基准测试中使用了这些。
这里的平均评分为 7.10。还不错,但绝对不是很好。不过,当我们深入了解结果时,我们可以更好地理解这个设置失败的方式。
基本上,它正确回答了所有点查询,这些是答案在文档混乱中的某个地方,但可以从一个特定位置找到的问题。
非英文查询:嵌入模型和 reranker 是基于英文的,所以我用葡萄牙语提的问题显然没有得到答案
一个背景很少的模糊问题("what's ch")
聚合来自多个文档/块的信息,例如它只找到了 PostHog 的 7 轮融资中的 5 轮,以及只是提供会话重放的 PostHog 竞争对手的一个子集(如源数据中所提及的)
在我看来,这是个好消息。这意味着如果你的用例只是在英文中进行点查询,默认选项将大有帮助,应该能给你很好的性能。另一个很好的事情是这些模型也很快。
现在,如果你需要更好地处理歧义,或处理其他语言的问题,那么这个设置就不适合你了。
我进行的下一个测试使用 bge-m3 作为嵌入模型,mmarco-mMiniLMv2-L12-H384-v1 作为 reranker。据说嵌入模型比前面测试中使用的模型好得多,而且也是多语言的。另一方面,reranker 使用之前测试中的相同交叉编码器作为基础模型,但也增加了多语言支持。更标准的选择应该是更受欢迎的 bge-reranker-v2-m3 模型,但我发现它慢得多。不过,我打算调整我的设置并再次测试。
无论如何,来看结果!我对它的平均评分为 8.63,这非常好。没有完全失败,它很好地处理了葡萄牙语问题。
它犯的错误是:
这个新设置在聚合信息方面也做得不太好,遗漏了 PostHog 的 2 轮融资,以及一些其会话重放竞争对手
它也正确回答了一个问题,但之后添加了不正确的额外上下文
总的来说,它表现得相当好。我们再次看到的主要问题是当响应所需的上下文分散在多个文档中时。有各种技术可以帮助解决这个问题,我们很快就会试验一些!云版本上不需要这些,因为更好的模型可以让你避免为最小的性能提升增加复杂性,但由于我们专注于为本地部署构建真正坚实的设置,我们会越来越多地研究这个问题。
我希望这篇文章至少为你提供了对构建本地 RAG 的一些洞察和背景,以及它确实有效、可以服务于很多用例的事实,并且随着 a) 模型的改进 b) 我们在整个领域获得更多开源模型,这个设置往往会越来越好,这两点似乎都是我们的发展趋势。
对于我们在 Skald,我们打算进一步完善这个设置,以便更好地服务更多用例,并打算很快发布更多关于开源空间中模型的合理基准测试,从 LLMs 到 rerankers。
如果你是一家需要在隔离网络基础设施中运行 AI 工具的公司,让我们聊天——随时可以给我发邮件到 yakko [at] useskald [dot] com。
最后,如果你想参与其中,随时可以在我们的 GitHub 仓库(MIT 许可)上与我们聊天,或在 Slack 上找我们。
[1] 我在这里使用 PostHog 网站,因为网站内容是 MIT 许可的(是的,疯狂),并且在 GitHub 上可作为 markdown 获得,在那里工作过,我对很多答案了如指掌,使其成为一个我很熟悉的约 2000 个文档的很好的数据集。
[2] 我用于实验的问题和答案数据集如下: