自托管RAG:私有AI知识库完全指南
在你自己的基础设施上运行检索增强生成——你的数据、你的嵌入、你的索引。
自托管RAG意味着在你自己控制的基础设施上运行整个检索增强生成(RAG)管道——数据摄入、嵌入、向量存储、检索和生成——而不是将你的文档和查询发送到托管API。你将获得与SaaS产品相同的“与知识库对话”功能,但你的数据永远不会离开你的服务器。本指南将讲解开发者为何要自托管RAG、2026年可行的参考栈,以及厂商定价页面上没人会告诉你的权衡取舍。内容较长,因为RAG涉及很多组件。请使用标题跳转到你需要的部分。
▶ 自己跑一遍 —— aquila-starter 是这篇指南的一键自托管版本:Ollama + Qdrant + FastAPI,
docker compose up即起。Fork 下来据为己有。
什么是RAG?
检索增强生成在查询时让大型语言模型(LLM)访问你的特定文档。模型不再仅仅依赖训练时记住的内容,而是检索出与你内容最相关的片段,并将其作为上下文粘贴到提示词中。然后LLM基于这些片段生成回答。RAG就是你如何让LLM回答关于内部Wiki、代码库、支持工单或上一季度合同的问题——无需微调,也无需模型凭空捏造从未见过的事实。如果你想深入了解检索部分的概念基础,请参阅什么是语义搜索。
为什么要自托管RAG而不是使用API?
有三个真实原因。明确哪个在驱动你,因为这会改变你的技术栈。
隐私和数据驻留
这是最有力的原因。使用托管的RAG API,你摄入的每个文档和用户提出的每个问题都会传输给第三方。对于受监管的数据(医疗、法律、金融)、客户PII或专有源代码,这通常是不可接受的——或者至少是采购和合规的麻烦。自托管将嵌入和原始文本保留在你自己的VPC或本地环境中。除非你决定发送,否则没有数据会跨越你的网络边界。
稳态量下的成本
托管的嵌入 + 托管的向量数据库启动成本低,但扩展成本高。运行开源组件的固定成本VPS具有固定的月度账单,无论查询量多大,一旦流量超过涓流,这通常是胜出的选择。我们在这篇文章中详细分析了成本:自托管RAG vs OpenAI+Pinecone:实际成本对比。
控制权和避免锁定
你选择嵌入模型、分块策略、向量索引和LLM。你可以在没有迁移项目的情况下交换任何层,固定版本以避免供应商的静默模型更新一夜之间改变你的检索质量,并且如果需要,可以完全离线运行(物理隔离)。
诚实地说:自托管意味着你现在要为数据库、GPU驱动、升级和半夜的警报负责。我们在结尾讨论了何时不应自托管。
参考栈
一个自托管RAG系统由五个组件组合而成。这里是一个稳定、经过验证且完全开源的栈:
| 层 | 角色 | 可靠的开源选项 |
|---|---|---|
| LLM运行时 | 本地生成回答 | Ollama、llama.cpp、vLLM |
| 嵌入模型 | 将文本转换为向量 | nomic-embed-text、mxbai-embed-large(通过Ollama),或bge/e5模型 |
| 向量存储 | 存储和搜索向量 | pgvector、Qdrant、Chroma、Weaviate |
| 编排 | 分块、检索、提示词组装 | LangChain 或 LlamaIndex |
| API/应用层 | 向应用暴露管道 | FastAPI(Python) |
你不需要所有这些组件都很重量级。一个完全可行的入门栈是Ollama + Chroma + LlamaIndex + FastAPI,运行在单个VPS上,无需GPU,使用小型本地嵌入模型,以及仅用于最终生成步骤的本地7-8B聊天模型或云端LLM。
管道如何逐步工作?
RAG清晰地分为索引阶段(完成一次,或文档变更时)和查询阶段(每次请求都会执行)。
1. 摄入
导入你的源文档——PDF、Markdown、HTML、Notion导出、数据库行、转录稿。LlamaIndex和LangChain中的加载器处理大多数格式。输出是纯文本加上元数据(源URL、作者、日期、章节),你可以在后续筛选时使用。
2. 分块
LLM和嵌入模型有上下文限制,并且通过嵌入小而连贯的段落而不是整个文档可以获得更好的检索效果。将文本分割成块——常见的起点是500–1000个token,重叠约10–15%,这样跨越边界的句子不会丢失。分块是RAG质量中最被低估的杠杆。尊重文档结构(在标题/段落处分块,而不是在句子中间),并将元数据附加到每个块。
3. 嵌入
将每个块通过嵌入模型运行,得到一个向量——一组浮点数,捕捉块的含义。nomic-embed-text生成768维向量,根据Nomic的基准测试,在许多任务上匹配或超过OpenAI的旧嵌入模型;mxbai-embed-large生成1024维向量,是更强的更大选项。两者都通过Ollama在本地运行。重要的规则:你必须使用完全相同的嵌入模型进行索引和查询——来自不同模型的向量不可比。
4. 存储
将向量及其元数据和源文本写入向量存储。这会构建一个索引(通常是HNSW),使最近邻搜索变得快速。
5. 检索
在查询时,使用相同的模型嵌入用户的问题,然后向向量存储请求最相似的k个块(k=4到8是合理的默认值)。如果需要,在此处添加元数据过滤器(“仅此项目的文档”、“仅过去12个月”)。为了提高精度,许多生产环境设置会添加混合搜索(结合语义相似度和关键词/BM25匹配)以及一个重排序器来重新对顶部候选者打分。
6. 生成
将检索到的块填入提示词模板,连同用户的问题和指令(“仅从上下文中回答;引用来源;如果找不到就说不知道”),然后发送给LLM。返回带有来源引用的答案,以便用户和你自己可以验证。
选择嵌入模型:本地 vs 云端
这是第一个真正的分岔点。
本地嵌入(推荐用于自托管)。 像nomic-embed-text和mxbai-embed-large这样的模型可以在CPU上运行以索引中等语料库,并且每token免费。你的文本不会离开机器。下载体积小(几百MB),对于大多数知识库用例来说已经足够好。如果隐私是你自托管的原因,请选择本地——将向量数据库保持私有,却将每个块发送给第三方进行嵌入,这很奇怪。
云端嵌入(例如OpenAI text-embedding-3-small)。 价格为每百万token $0.02(OpenAI 2026年6月列表价格;批量定价更便宜,而text-embedding-3-large约为每百万 $0.13),调用嵌入几乎是免费的,而且质量出色,无需运维。缺点:每个块和每个查询都传输给OpenAI,这违背了隐私的初衷,并且你重新引入了供应商依赖。
一个实用的中间路径:本地嵌入 + 仅在生成时使用云端LLM。 你的文档在索引期间保持私有;只有针对给定查询的一小组检索块(不是整个语料库)在回答时发送给LLM。根据检索到的文本的敏感性来做决定。
选择向量存储
没有普遍正确的答案;根据你的情况选择。
| 存储 | 最适合 | 备注 |
|---|---|---|
| pgvector | 你已经运行PostgreSQL | 一个Postgres扩展;向量+关系数据在一个地方,一个备份故事,SQL筛选器。新增运维负担最低。 |
| Chroma | 原型开发、小/中等语料库 | 轻量级,极其简单的Python API;非常适合快速入门。 |
| Qdrant | 生产RAG、较大数据集 | Rust实现,快速,原生混合搜索(稠密+稀疏),强大的筛选搜索性能,易于Docker部署。 |
| Weaviate | 你想要功能丰富的引擎 | 内置混合搜索、模块、多租户、GraphQL;功能面更大。 |
如果你已经在使用Postgres,从pgvector开始——它简化了你的技术栈,并且你可以像备份其他所有东西一样备份向量。如果你正在从零搭建并且预期会增长,Qdrant是一个安全的生产选择。使用Chroma进行原型开发,然后如果需求超出其能力再升级。(Khoj是一个开源AI助手,底层使用pgvector——这是文档问答选择的一个合理验证。)
硬件和VPS规格
你可以在没有GPU的情况下运行自托管RAG系统。问题在于你本地运行什么。
- 嵌入 + 向量存储 + 云端LLM: 一个2 vCPU / 4 GB RAM的VPS(约$20–30/月) 可以舒适地处理数万个块的语料库。索引是最耗时的步骤,且一次即可/增量完成。这是大多数团队的最佳选择。
- 完全本地,包括7-8B聊天模型在CPU上: 可行但较慢;预计多秒响应。提升至8–16 GB RAM。
- 完全本地带GPU: 一块消费级GPU(例如12–24 GB VRAM)可以真正加快本地生成速度。现在你需要专用硬件或GPU云实例,成本计算发生了变化——在投入前重新阅读成本分析。
向量存储的大小估算经验法则:一个768维float32向量约3KB原始大小;HNSW索引会增加开销,因此每个块预算几KB加上原始文本。10万个块远低于1GB——RAM(而不是磁盘)通常是内存引擎的首要限制。
一个具体的入门指南
为了让这个栈更具实感,下面是一个使用Ollama、Chroma和LlamaIndex的最小管道的示例。这是说明性的伪代码,显示流程——请查看每个库的当前文档以获取确切的API(在不同版本间会变动)。
首先,在本地拉取模型:
ollama pull nomic-embed-text # 嵌入模型
ollama pull llama3.1:8b # 本地聊天模型(可选)
然后是索引阶段——加载文档、分块、嵌入并存储:
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader
from llama_index.embeddings.ollama import OllamaEmbedding
from llama_index.vector_stores.chroma import ChromaVectorStore
import chromadb
# 1. 摄入
docs = SimpleDirectoryReader("./knowledge").load_data()
# 2. 嵌入模型(本地,通过Ollama)
embed_model = OllamaEmbedding(model_name="nomic-embed-text")
# 3+4. 分块、嵌入并存储到Chroma
client = chromadb.PersistentClient(path="./chroma_db")
vector_store = ChromaVectorStore(chroma_collection=client.create_collection("kb"))
index = VectorStoreIndex.from_documents(
docs, embed_model=embed_model, vector_store=vector_store
)
然后是查询阶段——检索相关块并生成回答:
# 5+6. 检索top-k块并生成带引用的回答
query_engine = index.as_query_engine(similarity_top_k=5)
response = query_engine.query("How do I rotate the API keys?")
print(response) # 接地气的回答
print(response.source_nodes) # 它引用的块
将该查询调用封装到FastAPI端点中,你就拥有了一个私有RAG服务。重点不在于确切的行数——而在于六个概念步骤直接映射到几个库调用。你可以将Chroma换成Qdrant或pgvector,或将本地LLM换成云端LLM,而不改变整体结构。
评估检索质量
大多数团队跳过这一步,之后为此付出代价。在调整块大小或切换模型之前,先构建一个小型评估集:
- 编写20–50个真实用户会问的代表性问题。
- 对于每个问题,记下应该检索到的文档。
- 通过你的管道运行它们,测量正确来源出现在前k个结果中的频率(召回率)以及它排名多高。
这将“演示看起来不错”变成了你可以改进的数字。当你更改块大小、切换嵌入模型或添加重排序器时,重新运行该集合并确认指标确实上升了。检索质量——而不是LLM——通常是自托管RAG的瓶颈,也是你拥有最多控制权的部分。
常见陷阱
- 分块不当。 块太大稀释相关性;太小丢失上下文。这比模型选择更容易破坏RAG系统。使用真实查询迭代块大小和重叠。
- 嵌入模型不匹配。 用一个模型索引,用另一个模型查询,静默返回垃圾数据。固定模型和版本。
- 没有评估循环。 “演示看起来不错”不是评估。在调整任何东西之前,构建一个小型问题/预期来源对集合并度量检索。
- 检索太多或太少。 块太少回答不完整;太多则超出上下文窗口并混淆模型。调整k。
- 没有来源引用。 始终返回每个答案的来源。这是可信工具与胡言乱语机器之间的区别。
- 忽略重新索引。 文档会变化。有计划更新或删除过时的向量,否则你的“知识库”会腐烂。
- 跳过混合搜索。 纯语义搜索会错过精确匹配(错误代码、SKU、名称)。添加关键词搜索可以找回它们。
何时不应自托管
自托管是一个真正的运维承诺。在以下情况下使用托管服务:
- 你处于概念验证阶段。 先在托管API上交付,验证RAG是否真的对你的用例有帮助,然后在数量和需求明确后迁移到内部。
- 你没有负责基础设施的人。 必须有人给机器打补丁、监控磁盘并处理升级。如果没有人做,托管比宕机更便宜。
- 你的用量真的很小。 每天少量查询,在托管免费/入门层上可能比VPS和你的一点时间成本更低。
- 你需要立即弹性、突发的扩展。 无服务器向量数据库和托管LLM API可以吸收突发流量,无需容量规划。
当隐私是强制要求、当你有稳定的非平凡量、或者当锁定和静默模型变化不可接受时,自托管明确胜出。
常见问题
我需要GPU来自托管RAG吗? 不需要。你可以在廉价的CPU VPS上运行嵌入和向量存储,并且要么使用小型本地LLM(较慢),要么仅针对最终生成步骤调用云端LLM。GPU主要加速本地回答生成。
我可以在不将任何数据发送给OpenAI的情况下进行RAG吗?
可以。使用本地嵌入模型(例如通过Ollama使用nomic-embed-text)、自托管向量存储(pgvector/Qdrant/Chroma)以及通过Ollama的本地LLM。整个管道在你的硬件上运行,没有数据离开你的网络。
最简单的入门栈是什么? Ollama + Chroma + LlamaIndex + FastAPI 在一个小型VPS上。这足以摄入文档、嵌入它们、检索并生成回答——然后在你了解需求后交换组件。
RAG和微调有什么不同? 微调将知识烧入模型权重,代价高昂且容易过时。RAG在查询时注入最新文档,无需重新训练,并且可以引用来源。如果你需要在你可能每天更改的良好维护的文档语料库上获得准确、可验证的回答,请使用RAG。如果你需要模型模仿一种风格、学习一种新格式或获取不常变化的大量先验知识,请进行微调。大多数严肃的生产系统两者都用:微调行为,RAG提供事实。
哪些LLM最适合RAG? 任何遵循指令并具有足够上下文窗口(8K+)的LLM都有效。性能差异源于模型在冗长的上下文中准确提取相关细节的能力。Claude、GPT-4、Llama 3 (8B/70B)、Mistral和Qwen都是经过验证的选择。对于本地RAG,7-8B模型(Llama 3 8B、Qwen 7B、Mistral 7B)是很好的性价比平衡点——它们可能不是针对所有查询的最强模型,但它们甚至可以在CPU上运行,并产生有用的答案。较大的模型(70B+)质量更高,但需要更多的GPU或更高的延迟,因此在选择之前测试你的确切查询集。
我可以在自托管RAG中使用OpenAI模型吗? 可以,但这弱化了隐私论证。一个实用的妥协方案是:本地嵌入用于索引(你的文档永远不会离开),但在生成时通过API调用OpenAI的模型,仅将检索到的块(而不是整个语料库)发送出去。如果你的数据可以承受这种有限暴露,它提供了质量与隐私之间的良好平衡。如果不是,请使用通过Ollama或vLLM的本地模型。
当文档发生变化时,我需要重新索引所有内容吗? 不必全部索引。大多数向量存储支持增量更新:添加、更新或删除单个文档的向量。如果你使用pgvector或Qdrant,你可以更新特定条目的向量,而无需重建整个集合。也就是说,如果你更改了嵌入模型或分块策略,你需要从头开始重新索引,因为旧的向量与新的比较不兼容。
Aquila 是私有、自托管AI搜索的独立指南——基于“你应该拥有你的索引,而不是租赁它”的信念。如果本文对你有帮助,请探索更多指南或订阅时事通讯,获取关于RAG、向量数据库和语义搜索的诚实、中立的文章。掌控你自己的搜索。