本地大模型RAG实战:用Ollama+Chroma搭一个私有知识库
简单说:本地搭RAG核心就三步——Ollama起模型、Chroma存切片向量、LangChain串问答链。最大的坑不是模型小,是切片太大和Top-K太少,把这两点调好,7B模型也能答准。
本地RAG实战这事我上周帮公司内部折腾了一整周,目标是让员工直接问"年假怎么算""差旅报销标准",AI 翻公司几十份制度文档答出来。没跑GPT,全程本地Ollama+Chroma。这篇就把完整SOP和踩的坑都写下来。本地RAG实战的关键其实不在模型多大,在切片和检索那两步。
RAG是什么,为什么本地搭
RAG就是检索增强生成,先从你的文档里检索相关片段,再喂给大模型让它基于片段回答。省得你把全部知识塞进模型,又省钱又准。
为啥要本地搭,不直接调API?一是公司文档涉密,制度、合同、客户资料不能传出去;二是API长期算下来贵,我们一个月问答量大概3000次,调GPT-4o要200多美元,本地模型电费几乎为零。
说实话本地搭还有个隐性好处,你能完全控制切片和检索逻辑,调试起来比黑盒API直观多了。本地部署大模型的具体玩法,开源大模型本地部署那篇讲过Ollama和LM Studio对比,可以连着看。
需要什么硬件
跑7B模型至少16G内存加一张8G显存的显卡,跑14B建议24G显存起步。没显卡也能跑,但CPU推理慢得想砸键盘。
我用的配置是RTX 4060 Ti 16G + 32G内存,跑Qwen2.5-7B-Instruct量化版绰绰有余,单次问答大概3秒出结果。同事的MacBook M2 16G也能跑,速度差不多,苹果芯优化做得不错。
没显卡的纯CPU机器我也试过,i5-12400跑7B量化版,单次问答要15到20秒,能用但体验差一截。所以预算够一定要上显卡。
根据Ollama官方2025年社区报告,7B量级模型在消费级显卡上的部署量占比超过60%(数据见 Ollama官网),说明7B就是目前本地RAG的主流选择,不用贪大。
Ollama和Chroma怎么配
Ollama负责跑大模型,Chroma负责存向量,两者用LangChain串起来。三件套分工明确,互不干扰。
第一步装Ollama,去官网下载安装包,Windows版一路下一步装完。然后命令行拉模型:ollama pull qwen2.5:7b-instruct-q4_K_M,这个量化版大概4.7G,下载十几分钟。
第二步装Chroma和依赖。Python环境里跑pip install chromadb langchain langchain-chroma langchain-ollama。Chroma是个轻量向量库,数据存本地SQLite,单机够用,不用搭服务。Chroma的详细文档在 Chroma官网。
第三步装embedding模型。检索要靠向量,得有个把文字转向量的模型。我用的是bge-m3,中英双语效果好,ollama pull bge-m3就行。
切片是最大的坑
chunk_size设800、overlap设150,是我反复试下来对中文公司文档最稳的参数。默认的1000太大,检索时一个切片塞太多内容,模型答非所问。
切片这块我吃过亏。最开始我图省事用RecursiveCharacterTextSplitter默认参数chunk_size=1000,overlap=200,结果问"年假计算公式",检索回来的切片里一半是差旅报销内容,模型直接串了。
后来调成chunk_size=600,overlap=120,准确率上来了,但长表格被切断了,问"加班补偿标准"答不全。折中800+150,对制度类文档命中率最高。表格类内容得单独用MarkdownTextSplitter按行切,别用通用切法。
具体代码长这样:
splitter = RecursiveCharacterTextSplitter(chunk_size=800, chunk_overlap=150, separators=["\n\n", "\n", "。", "!", "?"])
separators里加中文标点很重要,不然英文句号切中文文档切不动。
向量化和入库
用Ollama的bge-m3做embedding,存进Chroma,整个过程二十行代码搞定。比想象中简单。
核心代码:
embeddings = OllamaEmbeddings(model="bge-m3")
vectorstore = Chroma.from_documents(docs, embeddings, persist_directory="./chroma_db")
30份制度文档切完大概420个切片,入库用时1分钟左右,本地SQLite文件12M。检索时调vectorstore.similarity_search(query, k=4),k=4是经验值,太小漏召回,太大塞噪声。
检索不准怎么办
先扩k到6,再叠一个BM25混合检索,准确率能从65%提到88%左右。纯向量检索对专有名词和编号天生不敏感。
我做的对比:纯向量检索问"差旅报销编号TR-2024-007对应的政策",命中率0,因为编号是字符串,向量距离算不准。加了BM25关键词检索做混合,命中了。
混合检索用LangChain的EnsembleRetriever,向量权重0.5、BM25权重0.5。代码:
bm25 = BM25Retriever.from_documents(docs)
ensemble = EnsembleRetriever(retrievers=[vector_retriever, bm25], weights=[0.5, 0.5])
还有个调优点是重排序。检索回来8条,用bge-reranker-base重排取前4条喂模型,准确率再涨5%。重排虽然多一步,但模型小的话这一步性价比极高。
问答链怎么串
用LangChain的RetrievalQA链,把检索结果和用户问题一起塞prompt喂给Ollama。模板要写死"仅基于以下上下文回答,不知道就说不知道"。
prompt模板:
你是公司制度问答助手。仅基于以下上下文回答问题,如果上下文里没有相关信息,就说"我没有找到相关内容",不要编造。
上下文:{context}
问题:{question}
这一句"不要编造"特别关键。不加这句模型爱幻觉,编出根本不存在的报销比例。加上之后幻觉率明显下降,我们测试50个问题,编造次数从12次降到1次。
想知道怎么把这种检索能力包装成更复杂的Agent,从零搭建AI Agent那篇有进阶玩法。如果嫌自己搭麻烦,也可以先看Kimi K3开源发布这种现成方案对比下。
性能和成本实测
整套链路单次问答平均3.2秒,显存占用6.8G,CPU占用15%左右。对比API又快又省。
我跑了200个真实员工问题做评测。准确率88.5%,平均回答长度180字,其中3秒内返回的占72%,5秒内的占95%。最慢的是问到表格数据要重排,最长9秒。
对比同期调GPT-4o-mini的方案,准确率91%,速度更快(1.5秒),但一个月API费210美元。本地方案一次性硬件投入之外零成本,半年回本。对中小公司这个账算得过来。
能做什么场景
公司文档问答、个人知识库、客服知识库、技术文档检索,这四类是RAG最成熟的应用。别想太复杂,先把文档问答做扎实。
我们公司除了制度问答,还做了个产品手册问答,销售出去见客户前能快速查参数。效果出乎意料地好,销售反馈比翻PDF快十倍。
如果想往深做,RAG还能接代码库做代码问答,接数据库做自然语言查SQL。但这些复杂度高一截,新手先把文档问答这条线跑顺再说。
觉得模型不够聪明想做微调的,LoRA QLoRA微调教程那篇讲过怎么低成本微调,但老实说RAG场景下微调收益远不如调切片和检索。
常见问题
本地RAG需要显卡吗?
不是必须,但强烈建议有。CPU能跑7B量化版,速度15秒左右一次,能用但慢。有8G显存显卡能压到3秒,体验差一个量级。预算紧就先CPU跑通逻辑,再上显卡。
Chroma和FAISS选哪个?
新手选Chroma。Chroma自带持久化,数据存SQLite重启不丢,API简单。FAISS更快但纯内存,要自己管存储。文档量10万切片以下Chroma完全够用,超过再考虑Milvus这种分布式方案。
模型用多大合适?
公司文档问答用7B够。Qwen2.5-7B-Instruct中文表现很顶,显存6到8G能跑。14B准确率会高一点但显存翻倍,性价比不如把检索调好。72B那种本地基本跑不动,别折腾。
embedding模型必须用bge-m3吗?
不一定,但中文场景bge-m3是我测下来最好的。试过nomic-embed-text,英文场景强但中文拉胯。m3e-base也行,但要通过HuggingFace加载不如Ollama省事。预算够直接bge-m3,别浪费时间试。
检索回来很多无关内容怎么办?
三招:缩小chunk_size到500、加reranker重排、prompt里强调"仅基于上下文"。三个一起上,无关内容基本能压下去。还不行就检查你的文档本身质量,垃圾进垃圾出。
觉得有用的话分享给朋友吧。