跳到主内容

一文搞懂本地大模型部署:Ollama + 内网知识库问答从选型到上线的避坑清单 ​

很多团队想上知识库问答,第一反应是调用云端大模型 API,方案刚写完就被合规部门拦下:客户资料、内部制度、代码仓库,一份都不能出内网。另一条路是采购商用私有化方案,报价动辄几十万,实施周期还要按月算。实际上 2025 年之后,开源模型的指令遵循能力已经足以支撑中等难度的问答场景,一台 24G 显存的工作站就能跑出可用的效果。这篇文章记录我们从选型到上线的完整过程,技术栈是 Ollama + Qwen 开源模型 + 轻量 RAG,全程数据不出内网,硬件投入就是一台单卡服务器。

选型:先算显存账,再挑运行时 ​

本地部署的第一道选择题不是「选哪个模型」,而是「选哪个运行时」。三个主流方案各有明确的适用边界:

方案优势劣势适用场景
Ollama一条命令拉模型、自动管理量化版本、内置 OpenAI 兼容接口高并发吞吐一般十人以下团队快速起步、内网单机服务
vLLMPagedAttention 带来的高吞吐与连续批处理部署调参门槛高、依赖管理复杂几十路并发的服务化场景
llama.cpp / GGUF纯 CPU 可跑、跨平台、边缘设备友好速度受限、生态工具偏底层没有显卡的机器、嵌入式环境

我们的场景是内网几十人使用、并发峰值不高,Ollama 的运维简单性价值最大,最终选了它。模型规模则由显存倒推。Q4_K_M 量化下的粗略对照如下(留 20% 余量给上下文缓存):

模型规模权重占用建议显存
7B~8B约 5GB8GB
14B约 9GB12~16GB
32B约 20GB24GB
70B约 40GB双卡 48GB 起

结论很直接:24G 显存首选 14B 或 32B 量化版,8G 消费级卡从 7B 起步。中文场景我们最终落在 Qwen 14B 的 Q4 量化版,质量与生成速度的平衡点最好。

硬件账也要算得务实。很多团队一开始就规划多卡服务器,结果采购流程走完两个月,项目还停在汇报材料阶段。我们的建议是从一台单卡 24G 的工作站起步——这个预算部门内部就能批,两周内就能让十个人真实用起来;效果验证之后,再按并发缺口横向加机器。另外,模型升级的收益往往大于硬件堆叠:同一个系列隔了两个版本,回答质量可能就拉开一档,把预算花在「跟着开源版本走」上比堆卡更划算。

实操:三步把内网问答跑起来 ​

第一步,安装与拉取模型。 内网机器不通外网的,先在一台有网机器上拉取,再用 ollama cp 导出模型目录整体迁移,或直接把 Ollama 的 models 目录打包拷贝过去:

bash
# 安装 Ollama(Linux 示例,Windows/macOS 官网下载安装包)
curl -fsSL https://ollama.com/install.sh | sh

# 拉取对话模型与 Embedding 模型
ollama pull qwen3:14b
ollama pull bge-m3

# 验证本地服务与模型清单
curl http://localhost:11434/api/tags

第二步,用 Modelfile 固化推理参数。 这是最容易被跳过、又最能决定问答质量的一步。默认参数是给通用对话准备的,知识库问答必须显式调整:

text
# Modelfile:把系统提示词与上下文长度固化进模型实例
FROM qwen3:14b
PARAMETER num_ctx 16384        # 默认仅 4096,知识库问答必须调大
PARAMETER temperature 0.2      # 问答场景要求低随机性、可复现
SYSTEM """
你是公司内部知识库助手。仅依据提供的资料回答问题,
资料中没有的信息要明确说不知道,不要编造。
"""
bash
# 创建并验证模型实例
ollama create kb-assistant -f Modelfile
ollama run kb-assistant "我们公司的年假有几天?"

第三步,接一个最小可用的 RAG 链路。 几百份文档的规模不需要重型向量数据库方案,Chroma 单文件持久化足够:

python
# pip install openai chromadb
from openai import OpenAI
import chromadb

# Ollama 提供 OpenAI 兼容接口,指向本地 11434 端口即可
client = OpenAI(base_url="http://localhost:11434/v1", api_key="ollama")
chroma = chromadb.PersistentClient(path="./kb_store")
col = chroma.get_or_create_collection("docs")

def answer(question: str) -> str:
    # 1. 向量检索:查询与入库必须使用同一个 Embedding 模型
    emb = client.embeddings.create(model="bge-m3", input=question).data[0].embedding
    hits = col.query(query_embeddings=[emb], n_results=4)["documents"][0]
    # 2. 召回片段拼装上下文,交给对话模型生成答案
    context = "\n---\n".join(hits)
    resp = client.chat.completions.create(
        model="kb-assistant",
        messages=[{"role": "user", "content": f"参考资料:\n{context}\n\n问题:{question}"}],
    )
    return resp.choices[0].message.content

print(answer("报销的审批流程是什么?"))

文档入库侧就是「按语义段落切分 → 调 bge-m3 生成向量 → 写入 Chroma」三步循环。切分粒度值得单独说一句:按固定字数硬切会把一个完整条款切成两半,检索只命中一半时模型只能靠猜。我们按 Markdown 标题与段落语义切分,每片控制在 300~500 字,并把所属章节路径作为元数据保留,召回命中时把「章节路径」一并喂给模型,答案的定位能力明显变好。上线后的实际体感:14B Q4 在 RTX 4090 上生成速度约每秒 35~50 token,八人团队同时使用没有排队感,日常问答的可用率明显超过直接裸问模型。

上线只是开始,本地模型服务同样需要「版本策略」。开源社区每个季度都有值得升级的新模型,我们约定每季度做一次评测对比:用固定的 50 条内部问题测新旧模型,赢了就切,输了就等下一版,避免为升级而升级。同时给 Ollama 的 models 目录做好备份——模型文件损坏或误删时十分钟内可恢复,这件事平时没人想起,出事时救命。

避坑总结 ​

  1. num_ctx 不调大,检索内容被静默截断:Ollama 默认上下文 4096,召回四段长文档直接溢出,表现为答非所问或只引用最后一段。务必在 Modelfile 里显式调大,同时注意上下文越长显存占用越高,14B 模型 16K 上下文比 4K 多吃 2GB 左右。
  2. 入库与查询用了不同的 Embedding 模型:两个模型的向量空间不互通,检索质量断崖式下跌。升级 Embedding 模型后必须全量重建索引,不存在增量兼容。
  3. 盲目追大参数:显存不够触发 CPU offload,生成速度掉一个数量级,体验反而不如「低一档模型 + 更好的检索」。先优化召回质量,再考虑换大模型。
  4. 量化档位只看体积:Q2/Q3 在知识密集型问答上幻觉明显增多。中文场景建议 Q4_K_M 起步,高频 FAQ 这类质量敏感内容用 Q5/Q6,模型文件大一倍换幻觉率明显下降是划算的。
  5. 11434 端口无鉴权直接暴露:Ollama 默认不校验请求方身份,绑定 0.0.0.0 之前先想清楚网络边界。内网部署也建议在前面挂一层 Nginx 做访问控制与日志,出问题时有据可查。

本地大模型的门槛已经从「能不能跑起来」变成了「会不会调参」。把显存账算清、把推理参数固化进 Modelfile、把检索链路做扎实,一台单卡工作站就能撑起一个安静、听话、数据零外传的内网问答服务。

免责声明

本工具与文章内容仅用于学习测试场景,优化建议仅供参考,请勿直接用于生产环境,由此产生的风险自行承担。