
简介面向需要搭建本地知识库智能体的AI应用开发者这份代码包提供了一套以Ollama为核心的大模型部署方案涵盖与BGE-M3嵌入模型、Vllm、Dify以及本地DeepSeek大模型的对接集成。内容覆盖Ollama安装配置、模型目录调整、模型选择与下载、端口修改、功能测试及Dify嵌入的完整链路并针对集成中常见报错给出了可落地的排错思路便于规避环境冲突与版本兼容问题。压缩包约8KB共4个文件以Markdown说明文档为主体配合HTML页面和InsCode配置既方便离线阅读部署步骤也支持在云端环境快速还原配置。虽然体积精简但方案覆盖较完整还附带AI大模型学习路径梳理能帮助读者从模型部署、嵌入接入到智能体编排形成系统认知。目前已有193人学习使用对于正在摸索Ollama生态与Dify集成的开发者来说是一份值得直接复用或排查问题的参考。1. 方案整体设计与思路拆解1.1 这套组合到底要解决什么问题最近本地大模型的热度一直不减我在实际项目里被问得最多的一个需求就是能不能把私有知识库和本地大模型串起来实现一个真正能回答自己文档问题的问答系统。单纯跑一个Qwen或者Llama模型只能靠训练时见过的知识回答遇到你公司内部的产品文档、技术手册、个人笔记它就哑火了。这个问题的标准解法是RAG检索增强生成而RAG的落地绕不开两个核心组件一是负责读资料的嵌入模型Embedding Model二是负责开口说话的大语言模型LLM。我最终选择的方案就是Ollama加BGE-M3Ollama负责本地部署和调用大模型BGE-M3负责把文本转成向量两套系统通过Python代码对接组合成一条完整的RAG流水线。1.2 为什么选Ollama和BGE-M3这对组合先说Ollama。它最大的价值在于把大模型的部署门槛降到了极低——你不需要手动配置Python环境、CUDA、PyTorch一条命令就能把模型下载下来一条命令就能启动服务。在Ollama之前的时代本地跑一个7B模型需要花半天配环境现在十分钟搞定。而且Ollama提供了兼容OpenAI格式的HTTP API对接代码写起来非常省事。再说BGE-M3。这是智源研究院发布的多功能嵌入模型名字里的M3指的是Multi-Linguality多语言、Multi-Granularity多粒度、Multi-Functionality多功能。我最看重它的三点第一支持1024维的密集向量语义匹配精度比很多老款嵌入模型高出一个档次第二最大输入长度是8192个token处理长文档时不用频繁切片第三它同时支持稠密检索、稀疏检索和多向量检索三种方式做混合检索有天然优势。这里要特别说明一个容易踩坑的点Ollama官方模型库里其实没有直接提供BGE-M3直接用ollama pull bge-m3是拉不下来的。实际做法是BGE-M3运行在Python侧的FlagEmbedding或sentence-transformers框架中Ollama负责LLM推理两者通过本地HTTP请求完成数据交换。市面上有些教程含糊其辞让读者以为BGE-M3被Ollama原生支持我实际验证下来并非如此这次会把这个过程写得清清楚楚。1.3 这套方案适合谁如果你手头有本地知识库问答、企业文档检索、自动化总结工具这类需求并且希望整个流程跑在本地、数据不出内网那这套方案非常合适。假设你刚好有一台带独立显卡的机器哪怕是消费级的NVIDIA显卡8G显存就能起步配置好之后就能免费获得一套完全自主可控的RAG问答系统。2. 环境准备先把Ollama和Python环境跑通2.1 Ollama安装与国内加速Ollama的安装本身不复杂官网下载对应系统的安装包即可。但国内用户经常被下载速度折磨——客户端几百MB加上后续要拉取几个GB的模型文件官方源的速度实在感人。好在这个问题有相对成熟的解法。Linux系统下安装Ollama官方脚本默认指向GitHub的安装源国内网络环境下经常超时。我实测有效的做法是配置国内镜像源# 使用国内镜像加速安装Ollama curl -fsSL https://mirrors.tuna.tsinghua.edu.cn/ollama/install.sh | sh如果你的网络环境还是不稳定可以直接去镜像站手动下载对应的安装包# 以清华大学开源软件镜像站为例 wget https://mirrors.tuna.tsinghua.edu.cn/ollama/linux/amd64/ollama chmod x ollama mv ollama /usr/local/bin/Windows用户相对简单直接下载安装包双击安装即可。安装完成后确认服务是否正常运行ollama --version ollama serveollama serve会启动本地服务端默认监听127.0.0.1:11434这个端口后续对接代码要用来发请求。2.2 拉取并启动本地大模型Ollama装好后下一步就是拉取大模型。考虑到多数人的显卡显存情况我推荐从Qwen2.5的7B版本起步ollama pull qwen2.5:7b下载过程中如果速度太慢可以在环境变量里配置国内模型镜像# Linux/macOS export OLLAMA_MODELS/tmp/ollama-models # 指定模型存放目录 # 配置镜像地址部分版本有效实测可以加速模型拉取 export OLLAMA_BASE_URLhttps://hf-mirror.com注意OLLAMA_BASE_URL这个变量在不同版本中的行为不完全一致如果设置后反而拉取失败建议取消设置回到默认源。下载慢的问题更稳妥的解法是找一台网络通畅的机器拉取模型然后通过U盘或内网传输到目标机器模型文件默认存放在~/.ollama/models目录下。模型拉取完成后验证一下是否正常ollama run qwen2.5:7b 请简单介绍一下你自己如果模型能在终端正常回复说明LLM部分已经就绪。2.3 Python环境与依赖安装BGE-M3跑在Python侧需要准备一个干净的Python环境。我习惯用conda创建独立环境避免污染系统Pythonconda create -n rag python3.10 -y conda activate rag然后安装必要的依赖库。这里要特别注意PyTorch的安装方式——如果你有NVIDIA显卡一定要装CUDA版本的PyTorch否则模型会默认跑在CPU上速度慢到你怀疑人生# 先安装PyTorchCUDA版以官方实际命令为准 pip install torch --index-url https://download.pytorch.org/whl/cu121 # 再安装其他依赖 pip install FlagEmbedding sentence-transformers ollama numpy安装完成后可以用一行Python代码验证CUDA是否可用import torch print(torch.cuda.is_available()) # 输出 True 说明GPU可用3. BGE-M3模型本地部署要点3.1 模型权重下载与缓存目录配置BGE-M3的权重大约2.2GB从HuggingFace下载在国内同样会被卡脖子。这里我用的方案是先从ModelScope魔搭社区下载再指定本地路径加载from modelscope import snapshot_download # 从ModelScope下载BGE-M3模型权重 model_dir snapshot_download(BAAI/bge-m3, cache_dir./models) print(f模型已下载到: {model_dir})如果你不方便用ModelScope也可以从HuggingFace下载后手动解压本质上一样——反正代码加载时用的是本地路径来源并不重要。下载完成后目录里应该有config.json、pytorch_model.bin或safetensors格式的权重文件、tokenizer.json等文件。3.2 加载模型并生成向量BGE-M3的加载我推荐用sentence-transformers库接口友好文档也齐全from sentence_transformers import SentenceTransformer # 加载本地模型指定本地路径 model SentenceTransformer(./models/BAAI/bge-m3, devicecuda) # 生成向量 sentences [数据库连接超时请检查网络配置, 今天天气很好] embeddings model.encode(sentences, batch_size8, max_length8192) print(embeddings.shape)这里有一个很重要的细节默认情况下sentence-transformers加载模型后输入句子的embedding是一个1024维的向量。但是BGE系列模型官方建议在编码查询query时加上指令前缀。对于中文BGE-M3推荐的查询指令是为这个句子生成表示以用于检索相关文章加上前缀后检索效果会有肉眼可见的提升queries [数据库连接超时怎么办] q_embeddings model.encode([为这个句子生成表示以用于检索相关文章 q for q in queries])编码文档document时不需要加前缀这一点搞反了会影响精度。3.3 模型参数理解BGE-M3最核心的亮点是三种检索方式的统一。用sentence-transformers只能用到它的稠密向量能力如果你需要混合检索要改用FlagEmbedding库from FlagEmbedding import BGEM3FlagModel model BGEM3FlagModel(./models/BAAI/bge-m3, use_fp16True) # 混合编码同时得到稠密、稀疏和多向量三种表示 output model.encode( sentences, return_denseTrue, return_sparseTrue, return_colbert_vecsTrue ) dense_vecs output[dense_vecs] sparse_weights output[lexical_weights] colbert_vecs output[colbert_vecs]稀疏检索SPLADE风格擅长精确关键词匹配稠密检索擅长语义匹配多向量检索ColBERT风格在处理长文档和细粒度相关性上有优势。BGE-M3把它们统一到一个模型里检索阶段可以根据场景自由切换或融合。只做简单问答的话用稠密向量就够了如果文档结构复杂、需要精确匹配专有名词混合检索明显更稳。4. 对接代码实现4.1 整体流程设计现在进入核心部分把Ollama和BGE-M3对接起来。完整流程分四步用BGE-M3把知识库文档切片后向量化存入内存列表生产环境可换成向量数据库收到用户问题时用BGE-M3把问题编码成查询向量计算查询向量与文档向量的余弦相似度选取TopK最相关的文档片段把文档片段作为上下文拼接进Prompt发给Ollama的本地大模型生成回答这段流程里Ollama和BGE-M3各司其职它们唯一的沟通桥梁就是Python代码。4.2 核心代码逐段拆解先放一份可以直接跑的完整代码然后我再逐段解释关键逻辑。这里以本地知识库问答为例import numpy as np import ollama from sentence_transformers import SentenceTransformer # 加载BGE-M3模型 embed_model SentenceTransformer(./models/BAAI/bge-m3, devicecuda) # 准备知识库文档实际场景从文件读取 documents [ Ollama是一个本地大模型运行工具支持一键部署多种开源模型。, BGE-M3是智源研究院发布的嵌入模型支持多语言和多功能的文本向量化。, RAG检索增强生成技术通过检索外部知识来增强大模型的回答能力。, Ollama的API接口兼容OpenAI格式可以通过HTTP请求调用。 ] # 第一步文档向量化 doc_embeddings embed_model.encode(documents, batch_size8, max_length8192) def search_topk(query, k2): # 第二步编码查询注意加指令前缀 query_embedding embed_model.encode( [为这个句子生成表示以用于检索相关文章 query] )[0] # 第三步计算余弦相似度取TopK scores [ np.dot(query_embedding, doc_vec) / (np.linalg.norm(query_embedding) * np.linalg.norm(doc_vec)) for doc_vec in doc_embeddings ] top_indices np.argsort(scores)[::-1][:k] return [documents[i] for i in top_indices], [scores[i] for i in top_indices] def ask_ollama(question, context): # 第四步构造Prompt交给Ollama prompt f请基于以下资料回答问题如果资料中没有相关信息请明确说明。 资料 {context} 问题{question} 回答 response ollama.chat( modelqwen2.5:7b, messages[{role: user, content: prompt}] ) return response[message][content] # 测试 query BGE-M3是谁发布的 context, scores search_topk(query) print(f检索到相关文档相似度分数: {scores}) answer ask_ollama(query, \n.join(context)) print(f回答{answer})逐段说明几个关键点文档向量化部分batch_size8是编码的批大小如果显存不够可以降到1或2。max_length8192是BGE-M3支持的最大输入长度超过这个长度会被截断实际使用时需要在切片阶段控制好文本长度建议单段不要超过6000字。检索部分这里用的是余弦相似度计算方式就是两个向量点积除以模长。BGE-M3的embedding本身没有做归一化所以必须显式做这一步。如果你觉得循环算相似度太慢可以改用矩阵运算一次算完# 矩阵化计算速度更快 query_embedding query_embedding.reshape(1, -1) scores (query_embedding doc_embeddings.T).flatten()Ollama调用部分ollama.chat是官方Python库提供的接口底层走的就是本地127.0.0.1:11434的HTTP服务。model参数要和你ollama pull时指定的名字完全一致否则会报错找不到模型。4.3 通过HTTP API对接的备选方案如果你不想装ollama这个Python库也可以直接用requests调用Ollama的HTTP接口原理是一样的import requests import json response requests.post( http://127.0.0.1:11434/api/chat, json{ model: qwen2.5:7b, messages: [{role: user, content: prompt}], stream: False } ) answer response.json()[message][content]两种方式我都在实际项目里用过。个人体感是ollama库更省心但requests方案少一个依赖还能让你清楚看到API请求的结构。如果你要做到流式输出一个字一个字往外蹦的效果requests方案里把stream设为True然后逐行解析响应即可。5. 常见问题与排查技巧实录5.1 模型下载太慢卡在几十KB/s这个问题出现频率最高。Ollama拉取模型走的是官方仓库国内网络下大模型文件经常让人崩溃。我建议按优先级做三件事第一步检查是否能用镜像加速。部分版本的Ollama支持通过环境变量OLLAMA_HOST、OLLAMA_ORIGINS调整服务行为但模型下载地址是内置的直接改环境变量不一定生效。第二步换个网络环境用热点或非高峰时段再试。第三步最稳妥——在方便下载的机器上把模型目录整个打包拷过去。模型文件默认在~/.ollama/models拷贝到目标机器的相同位置ollama list就能直接看到模型不会校验原始下载记录。5.2 Ollama启动失败代码2Windows下双击Ollama桌面端时偶尔会看到启动失败、退出代码2的错误。这个问题的根源通常是端口冲突——11434端口被其他程序占用了。排查办法# 查看端口占用情况 netstat -ano | findstr 11434如果端口确实被占用可以换端口启动# Windows PowerShell $env:OLLAMA_HOST127.0.0.1:11435 ollama serve启动后记得代码里的请求地址也要同步改为11435。5.3 Ollama调用输出乱码在Windows终端里调用中文模型偶尔会看到一大堆乱码或???。这个多半不是模型问题而是终端编码问题。确保你的终端代码页是UTF-8# 在CMD中执行 chcp 65001另外Python脚本里建议在开头加上import sys import io sys.stdout io.TextIOWrapper(sys.stdout.buffer, encodingutf-8)这样print出来的中文不会因为编码不一致而变成乱码。5.4 BGE-M3加载时显存不足BGE-M3的参数量虽然只有不到6亿但默认用fp32加载时显存占用仍然可观。我实测8G显存的机器上编码长文档时偶尔会爆显存。解决办法是开启半精度# sentence-transformers方式 model SentenceTransformer(./models/BAAI/bge-m3, devicecuda, model_kwargs{torch_dtype: float16}) # FlagEmbedding方式 model BGEM3FlagModel(./models/BAAI/bge-m3, use_fp16True)5.5 如何确认Ollama用了GPU而不是CPU模型跑起来很慢第一步先确认推理是否真的在用GPU。Windows下打开任务管理器看GPU占用Linux下用nvidia-smi查看nvidia-smi -l 1看到ollama或python进程占用显存就对了。如果模型跑在CPU上检查两件事NVIDIA驱动是否正常安装、Ollama版本是否支持你的显卡。当年用AMD Ryzen AI 9 HX 370这类新平台的CPU时Ollama对核显的利用很有限需要在BIOS里手动分配显存否则效果很失望。5.6 检索效果不佳怎么办如果你按上面流程跑通后发现回答质量一般问题八成出在检索环节。我有几个调优经验一是检查切片长度BGE-M3最长8192个token但知识库文档最好控制在300到500字一片切得太长会让最核心的信息被稀释掉。二是调整TopK参数普通问答取2到3篇就够了取太多个会把不相关内容塞进上下文干扰LLM判断。三是尝试混合检索用FlagEmbedding同时拿稠密向量和稀疏权重各自检索后做结果融合能兼顾语义匹配和关键词精确匹配。6. 从能跑到好用一套组合拳让RAG真正落地代码跑通只是第一步从能跑到好用中间还有不少优化空间。我整理了几个实测有效的小技巧上下文长度要控制好。Ollama启动时建议设置更大的上下文窗口否则Prompt过长会直接被截断# 启动时指定上下文窗口大小 OLLAMA_CONTEXT_LENGTH8192 ollama serve或者使用Ollama的Modelfile对模型做定制FROM qwen2.5:7b # 设置更大的上下文窗口 PARAMETER num_ctx 8192 # 关闭温度随机性问答场景更稳定 PARAMETER temperature 0.3然后创建并运行定制后的模型ollama create qwen2.5-rag -f Modelfile如果你处理的是PDF、Word这类格式的文档记得在做向量化之前先做文本抽取和清洗把页眉页脚、目录、无关符号全部去掉。这一道工序对最终检索质量的影响往往比换更好的模型还明显。向量持久化方面当知识库文档量到了一定规模比如几千篇以上内存列表就不够用了。可以考虑引入纯本地的向量数据库如Chroma或LanceDB代码改动量并不大无非是把原来的内存数组换成数据库的collection操作。最后分享一个我踩过几次坑之后的习惯对接代码写完一定要用最简单的语句做一次端到端自测——用一句话介绍你自己这种级别确认Ollama正常响应你好确认BGE-M3编码不报错。把问题拆开定位永远比在完整RAG链路上排查要快得多。这套组合拳打下来本地知识库问答系统就已经完全跑起来了。本文还有配套的精品资源点击获取