ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

DeepSeek本地化部署实操:用Ollama搭建RAG本地知识库

DeepSeek本地化部署实操:用Ollama搭建RAG本地知识库 简介一份以深度求索大模型本地化部署与检索增强生成技术为主题的实操型PDF文档面向开发者、技术运维及人工智能应用爱好者旨在解决通用大模型在特定领域落地难、知识更新慢等问题。资源整体为一个PDF文件大小约4.91MB内容系统阐述了深度求索开源推理模型的特性、多种本地部署途径以及推荐与最低硬件配置要求并对微调和检索增强生成两种领域化方案进行了细致比较。文档围绕基于检索增强生成搭建本地知识库的案例逐步演示了创建知识库、导入语料、新建助手并关联大模型等关键环节同时给出产品手册库回答客户咨询等典型场景可让读者直接获得可复用的操作思路与配置参考。目前该资源已有三百四十四人学习适合作为入门指南和案头手册。1. DeepSeek本地化部署案例实操为什么RAG本地知识库值得搭很多团队第一次做DeepSeek本地化部署先把精力全花在模型上跑通之后才发现真正决定问答质量的不是大模型而是资料切分和检索。这篇案例实操围绕一个目标展开用Ollama把DeepSeek跑起来再用RAG检索增强把PDF、Word、Markdown变成可检索的本地知识库全程在一台普通办公电脑上完成。适合手里有大量内部资料、又不想把数据交给公有云的工程师和知识管理岗。你不需要懂GPU训练只需要会命令行和Python照着下面的步骤就能跑通最小闭环。2. 用Ollama和vLLM部署DeepSeek模型选型、量化位宽与API服务2.1 先定部署形态单机API服务还是高并发推理引擎在本地知识库的RAG链路里DeepSeek这类大模型只负责最后一步“根据上下文生成回答”并不直接存储资料。所以本地化部署的第一步不是急着下载模型而是先确定要用什么形态把模型跑起来。常见做法有两个一是用Ollama做单机API服务二是用vLLM做高并发推理引擎。前者几乎零依赖CPU也能跑适合个人或小团队在办公电脑上搭RAG本地知识库后者需要NVIDIA显卡和CUDA环境适合十几个人同时问问题的生产环境。选型时还要看模型的量化位宽。DeepSeek R1在Ollama社区里有不同的量化版本我一般会用Q4_K_M这种4bit量化版。同样是7B模型量化后体积只有4GB多16G内存的笔记本能跑14B量化版大约9GB最好准备32G内存32B版本则建议有24G显存或48G内存再去碰。很多用户在这里有个误区总以为模型参数越大RAG知识库回答越准。实际在知识库问答场景里7B蒸馏版已经能做好“依据文档回答”更大的模型只是让推理更细并不会修复检索不到资料的问题。部署形态直接决定后续如何与RAG框架对接。Ollama启动后会监听11434端口提供一个OpenAI兼容接口vLLM启动后也监听8000端口。我建议统一按OpenAI SDK的方式调用这样昨天用Ollama明天换vLLM业务代码完全不用改。另外要提前决定embedding模型也放在同一个Ollama实例里还是单独部署。最常见的做法是放在同一个实例用模型名区分省一个服务进程。硬件上M系列MacBook的16G内存跑7B量化版也很流畅唯一要注意的是散热。如果是Windows办公机先看内存是不是16G以上低于16G还是老老实实去调用远程API不要硬撑本地部署。内存不够时Ollama会把模型部分卸载到磁盘问答延迟会从几秒变成几十秒这种体验基本没法用。2.2 从拉模型到跑通第一个对话Ollama最小命令安装好Ollama之后命令行里依次执行下面三条就能把DeepSeek跑起来。如果只想快速验证可以跳过ollama serve直接ollama run会自动拉起常驻进程。# 拉取 DeepSeek R1 的 7B 量化版本默认是 Q4 量化 ollama pull deepseek-r1:7b # 单独启动常驻服务让RAG程序通过HTTP调用 ollama serve # 换一个终端交互式验证 ollama run deepseek-r1:7b第一次ollama pull会把模型权重下载到本地网速慢的时候需要等一会儿。下载完成后ollama run会进入对话界面先问一句“用一句话介绍本地知识库”确认模型能正常输出。确认之后再用curl验证HTTP接口是否可用因为RAG程序不会跑在ollama run的交互界面里而是通过接口发消息。curl http://localhost:11434/v1/chat/completions \ -H Content-Type: application/json \ -d { model: deepseek-r1:7b, messages: [{role: user, content: 用一句话介绍本地知识库}] }注意这里用的是/v1/chat/completions不是Ollama原生接口/api/chat。OpenAI兼容接口的好处是后面Python代码里可以直接用openai库把base_url指向http://localhost:11434/v1。接口返回的字段也兼容包含choices[0].message.content解析成本很低。有几个环境变量会影响RAG体验。OLLAMA_NUM_PARALLEL控制同一模型同时处理的请求数本地知识库问答一般是单用户设置成1或2就够了设太高会导致CPU或内存被打满。OLLAMA_KEEP_ALIVE控制模型在内存中的驻留时间默认只有5分钟RAG场景下每次提问都要重新加载模型就会很慢我一般会设成30m让模型一直驻留这样第一次加载之后的请求都快得多。启动命令可以写成OLLAMA_KEEP_ALIVE30m OLLAMA_NUM_PARALLEL2 ollama serve。2.3 换到vLLM部署DeepSeek三个必调参数如果后面想把知识库开放给团队用Ollama的并发能力很快就到瓶颈。这时候可以换vLLM。vLLM对显卡和依赖环境有要求这里给一个最小启动命令假设你已经装好了CUDA和Python环境模型会自动拉取DeepSeek R1蒸馏版权重。python -m vllm.entrypoints.openai.api_server \ --model deepseek-ai/DeepSeek-R1-Distill-Qwen-7B \ --served-model-name deepseek-r1 \ --max-model-len 8192 \ --gpu-memory-utilization 0.8 \ --enforce-eager部署DeepSeek时有三个参数我每次都会重点检查。第一个是--max-model-len它决定模型最多能接收多长的上下文。RAG场景会把切分后的多个片段拼进prompt如果超过这个长度请求会直接报错。如果是7B模型我一般设8192再长的资料就要靠减少top_k来解决。第二个是--gpu-memory-utilization不要设成0.95因为同一张显卡上还要跑embedding模型做向量化得给4到8GB显存留余地设0.8比较稳。第三个是--served-model-name给模型起一个客户端友好的名字后面多个知识库服务切换时不用改代码。--enforce-eager不是必须的但我在小规模部署时都会加上它关闭CUDA graph优化能减少显存碎片代价是推理速度掉一些。本地知识库对首token延迟没那么敏感宁可稳定一点。vLLM跑通后客户端只要把base_url换成http://localhost:8000/v1model写成deepseek-r1和Ollama的调用方式完全一致。还有一个常被忽略的点vLLM启动时会扫描权重目录如果磁盘剩余空间不足加载到一半会崩溃。启动前先看df -h。Ollama则没有这么严格模型是增量下载的磁盘不够时会提示。二者相比入门阶段还是推荐Ollama它的上手速度和资源占用更适合先跑通流程。如果机器没有NVIDIA显卡就不要硬上vLLM。DeepSeek本地化部署最大的门槛不是模型授权而是手里有什么硬件。我的习惯是先用Ollama跑一周记录一次问答需要多久、并发最多几个人只有连续三天的监控显示单服务撑不住才去申请GPU机器换vLLM。这个决策顺序能帮团队少走很多弯路。3. 本地知识库的RAG核心组件嵌入模型、向量库、文档切分与检索瓶颈3.1 先画链路从PDF到答案之间发生了什么很多人把RAG简单理解成“把文档丢进模型”实际上RAG检索增强的完整链路至少有七步文档解析、文本清洗、切分、向量化、入库、检索、拼装上下文后交给DeepSeek生成。为什么不能把整篇PDF直接塞给大模型因为DeepSeek的上下文窗口有限而且回答长文档问题时模型容易漏掉碎片信息。RAG的做法是先把文档切分成几百字的块每一块用embedding模型转成向量存进向量数据库提问时把用户的问题也转成向量在库里做相似度检索找出最相关的几个块再和问题拼成一段带上下文的prompt。这样模型只面对“精选过”的证据而不是整篇文档。这一套流程说的简单真正做的时候瓶颈通常出现在三个地方切分边界、召回排序和元数据过滤。RAG框架有很多LangChain、LlamaIndex、LangChain4j的Easy RAG都能少写胶水代码但框架不能替你决定“一段该切多长”“标题要不要保留”。我在实际项目中见过不少案例换了大模型之后效果没提升最后发现是检索出的前几名全是同一个章节的重复内容。有些团队会拿RAG知识库和Wiki对比。Wiki依赖人来维护目录和页面结构资料一旦超过一千篇就很难保证每个人都在正确位置更新RAG知识库允许粗糙的目录结构靠切分和检索兜底。但代价是召回存在不确定性不能保证百分之百准确。所以RAG适合问答不适合当作唯一的事实来源重要结论还需要保留来源链接。3.2 embedding模型选型中文场景别随便用通用英文模型embedding模型决定“相似”的语义标准这一步选择失误后面的DeepSeek再强也救不回来。很多零基础教程默认用云端的Embedding模型但那是公有云接口本地化部署场景不能这么干。本地知识库必须跑本地embedding模型。中文场景我一般选两个BAAI/bge-m3和BAAI/bge-large-zh-v1.5。bge-m3是多语言模型同时支持中英文混合的文档输出向量维度1024bge-large-zh是中文专注模型在纯中文语料上召回更稳。如果你用Ollama也可以直接拉取bge-m3标签这样embedding模型和DeepSeek共用同一个服务少装一套Python依赖。from sentence_transformers import SentenceTransformer # 首次运行会下载权重建议放在有足够磁盘的目录 model SentenceTransformer(BAAI/bge-m3) emb model.encode(DeepSeek本地化部署怎么开始) print(emb.shape) # (1024,)这段代码是向量化最小验证。SentenceTransformer不只是加载模型还会自动读取模型配置里的池化方式。第一次执行时如果网络不稳定会卡在下载建议提前下好权重并设置本地缓存目录。embedding模型的推理不需要GPUCPU也能跑但入库时几千个文档要等很久我的经验是先用小批量跑通流程再全量灌入。embedding模型的选型有一个边界不要追求向量维度越大越好。维度高确实语义表达更细但向量库的内存占用和检索耗时都会上涨而且本地知识库数据量通常在几万块以内1024维已经足够。如果机器只有8G内存我会降级用bge-small-zh维度512牺牲一些召回精度换启动速度。有一点要注意已经写入向量库的向量维度不能和新的embedding模型混用否则查询时会报维度不匹配一旦中途换模型整个向量库都要重建。3.3 向量库选型与文档切分参数Chroma、FAISS、Qdrant怎么选向量数据库的选择不用太纠结。本地RAG知识库第一版我推荐Chroma。它是嵌入式向量库不需要单独起服务pip install chromadb之后直接以目录形式持久化支持metadata过滤。FAISS更轻但索引需要手动管理没有内置的增量和过滤能力Qdrant和Milvus功能强但需要额外部署服务对普通本地化项目来说过重。如果没有多租户和千万级数据的需求别急着上重型组件。向量库部署成本元数据过滤适合场景Chroma低嵌入进程支持本地知识库、原型验证FAISS低但自管索引需自己实现实验、纯相似度检索Qdrant中需Docker或服务支持需要过滤、多集合Milvus高组件多支持大规模生产这里要说一下切分参数。LangChain的RecursiveCharacterTextSplitter是常用起点但它首先按“\n\n、\n、空格”等分隔符切分然后再按chunk_size限制长度。中文文档尤其要用字符数而不是token数来估算因为中文一个字约1到2个token用token计算容易切出半个句子。我一般设chunk_size400chunk_overlap80。400字能装下一个完整自然段80字的重叠保证段落边界信息不丢失。如果要检索长结构化手册我会改用MarkdownHeaderTextSplitter按文档的标题层级切分而不是固定长度。切分参数的影响比大多数人想的大。chunk_size太小检索到的块缺少上下文chunk_size太大多个主题混在一个块里相似度检索会把无关内容一起召回。chunk_overlap也不是越大越好它会把相邻块变成重复内容占用有限的上下文窗口。我的调参顺序是先用一个小样本库分别试400/600/800三组人工看召回结果选“一段之内主题唯一”的那组而不是盲目抄教程。4. 案例实操搭建一个DeepSeek本地知识库的完整流程4.1 初始化项目与依赖现在把前面的理论落到一个可复制的工程里。这个案例基于Python 3.10用LangChain做文档处理和切分用Chroma做向量库用Ollama跑DeepSeek R1。整个流程既是传统意义上的“零基础可复制教程”也可以作为后续接入更多RAG框架的基础。先建目录。mkdir -p deepseek-rag/docs src cd deepseek-ragdocs目录放原始PDF和Wordsrc目录放Python脚本。然后准备依赖文件。cat requirements.txt EOF langchain langchain-community langchain-huggingface chromadb sentence-transformers pypdf openai fastapi uvicorn EOF pip install -r requirements.txt依赖里的openai并不是要去访问公有云而是它的SDK兼容Ollama和vLLM提供的本地接口。pypdf用于解析PDFfastapi和uvicorn用于最后给同事提供HTTP接口。如果你的资料主要是扫描件还需要加pytesseract做OCR这个我放到踩坑部分重点讲。4.2 文档加载、切分与入库写一个src/build_store.py把docs目录下所有PDF切分并写入Chroma。代码里的persist_directory参数很关键Chroma会把向量数据写到本地目录下次启动不用重新入库。from pathlib import Path from langchain_community.document_loaders import PyPDFLoader from langchain_text_splitters import RecursiveCharacterTextSplitter from langchain_huggingface import HuggingFaceEmbeddings from langchain_community.vectorstores import Chroma docs_dir Path(docs) persist_dir data/chroma # 本地embedding模型bge-m3对中文效果好 embedding HuggingFaceEmbeddings( model_nameBAAI/bge-m3, encode_kwargs{normalize_embeddings: True}, ) text_splitter RecursiveCharacterTextSplitter( chunk_size400, chunk_overlap80, separators[\n\n, \n, 。, , , , ], ) all_chunks [] for pdf_file in docs_dir.glob(*.pdf): loader PyPDFLoader(str(pdf_file)) pages loader.load() # 把文件名作为元数据后面检索时可以用来过滤 for page in pages: page.metadata[source] pdf_file.stem chunks text_splitter.split_documents(pages) all_chunks.extend(chunks) vectorstore Chroma.from_documents( documentsall_chunks, embeddingembedding, persist_directorypersist_dir, ) print(f入库完成共 {len(all_chunks)} 个片段)这段代码有几个值得说的参数。separators里把中文句号、感叹号、问号都放进去了这是因为RecursiveCharacterTextSplitter默认分隔符按英语习惯中文文本在句号处不容易被切开。normalize_embeddingsTrue会做向量归一化搭配Chroma的cosine距离查询更稳定。source元数据可以让你知道每个答案来自哪份文件这是RAG知识库最后回溯证据的关键。首次运行会比较慢几百页的PDF可能要走十几分钟中间不要关终端。跑完后检查data/chroma目录多出来的SQLite和index文件。4.3 实现检索问答主流程库是空的接下来写src/qa.py它负责两步先用同样的embedding模型把用户问题转成向量到Chroma里检索最相关的4个片段再把这些片段作为上下文拼接成一个系统提示词调用本地DeepSeek接口生成答案。from openai import OpenAI from langchain_huggingface import HuggingFaceEmbeddings from langchain_community.vectorstores import Chroma # 注意base_url是Ollama的OpenAI兼容端口 client OpenAI( base_urlhttp://localhost:11434/v1, api_keyollama, # 本地服务不校验key随便填 ) embedding HuggingFaceEmbeddings( model_nameBAAI/bge-m3, encode_kwargs{normalize_embeddings: True}, ) vectorstore Chroma( persist_directorydata/chroma, embedding_functionembedding, ) def ask(question: str, top_k: int 4): # 检索找出最相关的top_k个片段 docs vectorstore.similarity_search_with_relevance_scores( question, ktop_k ) context \n\n.join( f来源({d.metadata.get(source)}): {d.page_content} for d, _score in docs ) response client.chat.completions.create( modeldeepseek-r1:7b, temperature0.2, messages[ { role: system, content: 请只根据context中的资料回答不要编造。 资料不足以回答时直接说不知道。\ncontext\n context, }, {role: user, content: question}, ], ) return response.choices[0].message.content if __name__ __main__: print(ask(DeepSeek本地化部署需要什么硬件))这段代码的similarity_search_with_relevance_scores会返回相似度分数方便后面做阈值过滤。temperature0.2很重要本地知识库问答要的是稳定引用不是开放性创作温度高了容易凭空编造。系统提示词里我强制要求“资料不足以回答时直接说不知道”这是对抗幻觉的第一道防线。如果检索结果不好可以先打印docs里的分数和page_content不要直接怀疑模型。4.4 包一个/ask接口并接入企业微信机器人命令行跑通之后同事不会都来用Python脚本。我用FastAPI包了一层HTTP接口代码很短from fastapi import FastAPI from pydantic import BaseModel from qa import ask app FastAPI() class AskRequest(BaseModel): question: str app.post(/ask) def ask_api(req: AskRequest): return {answer: ask(req.question)}启动命令是uvicorn api:app --host 0.0.0.0 --port 8000然后在同一内网里任何程序都能用POST http://你的IP:8000/ask调用这个本地知识库。如果想接入企业微信常见做法是在企业微信后台建一个自建应用或群机器人把回调消息转发到这个/ask接口再把返回文本发回群里。这样RAG知识库就变成团队里随时能用的小助手本质上就是一个最小可用的RAG智能体。接入企业微信时要注意消息格式。企业微信机器人回传的JSON里content字段带上人的标记会包含一串ID直接转发给大模型会影响回答。我一般先只保留content.text过滤掉...和URL再进入ask函数。这一步看似无关紧要但能明显减少模型把消息ID当正文的问题。到这里一个能用的DeepSeek本地化部署案例实操就完整了剩下的就是看翻车点。5. 踩坑记录从部署到检索的5个常见问题与排查方法5.1 现象模型回答不引用知识库答得像通用聊天模型明明已经能对话但问它资料里的细节它给出一段四平八稳的通用回答和文档毫无关系。这个现象最容易误导人让你以为模型能力不够其实问题出在提示词。原因是你的系统提示词太软了。如果只是说“请参考以下资料”DeepSeek会把资料当成背景补充而不是唯一事实来源。尤其是RAG场景里模型见过太多对话默认会走“通用知识优先”的路径。解决方法是把约束写死只能使用context中的信息禁止使用内部知识资料不足时直接说不知道。同时把temperature降到0到0.2top_p也可以设到0.1。在LangChain或OpenAI调用里这两个参数都能直接传。另外排查时要先看检索结果不要一上来就调模型。打印similarity_search_with_relevance_scores返回的前4个片段如果这些片段本身就和问题无关那模型再强也回答不到点上。这时候问题在切分和embedding不在DeepSeek。5.2 现象中文乱码、扫描版PDF导出后全是空把PDF喂进去以后检索到的文本全是乱码或空白。这个坑在中文知识库里几乎人人都会遇到。原因是PDF有两种一种自带文本层pypdf能直接抽出来另一种是扫描图片看起来是一页纸其实里面没有一个文字。还有人遇到过部分页面乱码那是PDF内置字体编码不规范抽取时映射错了Unicode。解决扫描件只有一个可靠办法OCR。常见做法是把PDF按页转成图片再用pytesseract识别中文。这里要额外装tesseract-ocr和中文语言包否则识别出来全是英文或问号。如果是少量页面乱码可以尝试用pdfplumber的extract_text或者page.extract_words()做二次提取它能保留部分字体映射信息。乱码严重的页面直接扔掉不要让脏文本进入向量库否则检索时会把噪声也召回。有人问过“RAG知识库能存储图片嘛”严格说图片本身不能直接检索语义。正确做法是把图片里的文字OCR后存入向量库原图作为附件保留在metadata里回答时带着图片路径返回。这样既保留了证据又不会让embedding模型处理二进制图片。5.3 现象Ollama第一次请求超时测完一次就挂代码写好后第一次请求可能要等几十秒然后超时第二次请求快了隔一会儿再问又卡住。这个现象的原因有两个模型第一次要从磁盘加载进内存Ollama默认的keep_alive只有5分钟超过时间就卸载如果同时设了多个模型常驻内存不够还会互相挤占。解决方法是把环境变量设成长驻OLLAMA_KEEP_ALIVE30m OLLAMA_NUM_PARALLEL2 ollama serve。用ollama ps可以看到当前模型是否常驻以及正在跑多少并发。如果设了长驻还是慢那就是内存不够换小模型或加内存条。另外不要把Ollama的默认并发调太高本地知识库通常是单人提问NUM_PARALLEL设成2已经够用超过4时7B模型会让内存爆掉。5.4 现象检索top_k结果全是同一段内容答不出细节问一个具体问题返回的4个片段看起来都在说同一件事只是换了几句话导致最终答案来回重复。原因是切分时chunk_overlap太大或者文档原本就有大量重复描述。更隐蔽的情况是连续几个片段都落在同一个章节里语义高度相似Chroma默认按相似度排序不会帮你做“多样性”。解决方法是先用metadata过滤掉来源比如限定只搜某一个章节或文件然后再做相似度检索。第二个办法是改用MMR检索LangChain里可以用vectorstore.max_marginal_relevance_search(question, k4, fetch_k20)它会先取20个候选再筛掉和已选片段高度重复的结果。第三个办法是调小chunk_size从400降到250让每个片段包含更少的主题。我在做技术手册时通常会把“只保留前k个相似片段”改成“先按标题分组每组取一个”这样答案覆盖面明显更广。5.5 现象回答到一半截断接口报错对话进行到一半输出突然停住或者HTTP状态码变成400/413。这个现象常见于文档片段拼得太多prompt长度超过模型上下文。Ollama里很多模型的默认num_ctx只有2048而RAG把4个片段加历史记录拼进去轻松超过这个值。解决方法是显式设置上下文长度。用ollama run交互时输入/set parameter num_ctx 8192它会写入当前会话如果通过API调用可以在请求参数里传num_ctx或max_tokens。vLLM部署时则直接改启动命令里的--max-model-len但要注意设置过大的上下文会显著增加推理耗时和显存占用。我的一般做法是检索片段总字数控制在2000字以内多轮对话只保留最近两轮历史生成回复的max_tokens设512。这样既不会截断也不会因为上下文太长让首token延迟变得不可接受。6. 进阶技巧用重排序和多路召回提升问答质量以及如何验证基础版本跑通后如果想要更好的效果我建议先做两件事加一个重排序模型以及做关键词和向量的多路召回。重排序是在Chroma返回约20个候选之后用一个轻量的交叉编码器重新打分只取前3个进prompt。本地可以用BAAI/bge-reranker-base代码很短把“问题候选片段”拼在一起让模型输出一个相关度分数分数高的排在前面。重排模型虽然也要跑推理但只作用于候选片段速度快效果立竿见影。很多“检索出来相关但答案不对”的问题都是因为相似度排序选错了片段重排能修正这一层。多路召回的做法是向量检索负责语义相似BM25关键词检索负责精确命中把两路结果合并后再去重。LangChain里的EnsembleRetriever可以配这个权重一般设向量0.7、关键词0.3。对本地知识库来说这种组合能覆盖那些“文档里没有与问题完全相同的表述但包含关键术语”的情况。验证方法也很重要。我会准备20个真实问题分成四类直接能从单段找到答案的、需要跨章节拼装的、文档里根本没有答案的、需要拒绝回答的。跑完一遍后看两个指标第一是否检索到了正确片段第二DeepSeek是否依据片段完成回答。如果第一项失败回去调切分和embedding如果第一项成功但第二项失败回去调提示词和温度。没有这个测试集后面每次改参数都是玄学。最后说一个我的教训别在第一天就追求大模型和大向量库。先用7B量化版加Chroma跑通再用重排序把不理想的问题一个个掰过来最后才考虑换更大模型或迁移到Qdrant。这套顺序能让你在真实投入前看到RAG知识库的边界而不是把工程复杂度当成护城河。希望帮到你。本文还有配套的精品资源点击获取
返回列表