在企业数据合规与成本控制的双重压力下,xinference + dify + ollama 构建本地知识库已成为中型企业技术选型中的主流方案。这套组合的核心价值在于:ollama 提供轻量级模型推理底座,xinferece 负责模型生命周期管理与高并发推理调度,dify 则承担 RAG 流程编排与知识库管理。三者结合,可完全脱离公有云 API,实现数据不出内网。
本文将直接切入业务场景,给出可运行的代码、API 调用细节以及扩容策略,不涉及任何概念性废话。
一、业务场景架构:本地知识库的三层解耦
在实际业务中,我们通常将系统拆分为以下三层,避免单一组件成为瓶颈:
- 接入层(Dify):负责用户对话、知识库上传/分段、检索策略编排(如混合检索 + Rerank)。Dify 在此处作为编排器,不承载模型推理。
- 推理调度层(Xinference):负责加载并管理多个模型(如 embedding、rerank、chat)。它提供了兼容 OpenAI 的 API 接口,支持流式输出、多模型并发、以及模型热加载。
- 模型仓库层(Ollama):作为底层模型运行时,负责执行实际的神经网络推理。Xinference 通过
OLLAMA_BASE_URL对接 Ollama,将请求转发至本地 GPU/CPU。
为什么不用 Ollama 直接对接 Dify?
Dify 对 Ollama 的原生支持仅限 chat 模型,且无法管理 embedding/rerank 模型的生命周期。而 Xinference 作为一个模型网关,可以统一管理三种模型,并提供统一的鉴权、统计与并发控制。同时,Xinference 支持将模型加载到内存中复用,避免 Ollama 反复加载模型导致的延迟抖动。
二、环境搭建与模型部署(硬核操作)
1. 启动 Ollama 服务
# 以 GPU 模式启动,监听内网端口
ollama serve --host 0.0.0.0 --port 11434
# 拉取所需模型(以 qwen2.5:7b 和 bge-m3 为例)
ollama pull qwen2.5:7b
ollama pull bge-m3
2. 启动 Xinference 并注册 Ollama 模型
# 启动 Xinference 服务
xinference-local --host 0.0.0.0 --port 9997
# 通过 CLI 注册模型(关键:指定 model_type 与 model_format)
xinference register --model-type embedding --model-name bge-m3 --model-format gguf --model-path /models/bge-m3.gguf
# 启动 embedding 模型
xinference launch --model-name bge-m3 --model-type embedding --model-format gguf --replica 2
注意:若使用 Ollama 作为后端,Xinference 需要配置环境变量 XINFERENCE_USE_OLLAMA=true,并设置 XINFERENCE_OLLAMA_URL=http://localhost:11434。此时 Xinference 会将 embedding 请求转发至 Ollama 的 /api/embed 端点。
3. 配置 Dify 连接 Xinference
在 Dify 的“设置-模型供应商”中,选择 OpenAI-API-compatible 类型,填入:
API Base URL: http://xinference-host:9997/v1
API Key: 任意值(Xinference 默认不校验,可配置)
模型类型: Text Embedding / Rerank / LLM
在知识库配置中,选择 bge-m3 作为 Embedding 模型,选择 rerank 模型(如 bge-reranker-v2-m3)作为 Rerank 模型。
三、API 调用实战:从 Dify 到 Xinference 的完整链路
以下代码演示如何绕过 Dify UI,直接通过 API 创建知识库、上传文档、发起检索增强生成。
1. 创建知识库并上传文档(Python)
import requests
import json
DIFY_URL = "http://dify-host:5001/v1"
DIFY_API_KEY = "app-xxxxxx" # 从 Dify 控制台获取
headers = {
"Authorization": f"Bearer {DIFY_API_KEY}",
"Content-Type": "application/json"
}
# 1.1 创建空知识库
payload = {
"name": "内部技术手册",
"description": "包含运维与开发规范",
"indexing_technique": "high_quality", # 高质量模式,使用 embedding + rerank
"permission": "only_me",
"provider": "vendor",
"embedding_model": "bge-m3",
"embedding_model_provider": "xinference"
}
resp = requests.post(f"{DIFY_URL}/datasets", headers=headers, json=payload)
dataset_id = resp.json()["id"]
print(f"知识库 ID: {dataset_id}")
# 1.2 上传文件(支持 pdf/docx/txt)
file_path = "./deployment_guide.pdf"
with open(file_path, "rb") as f:
files = {"file": (file_path, f, "application/pdf")}
data = {"data": json.dumps({"indexing_technique": "high_quality", "process_rule": {"mode": "automatic"}})}
resp = requests.post(
f"{DIFY_URL}/datasets/{dataset_id}/document/create_by_file",
headers={"Authorization": f"Bearer {DIFY_API_KEY}"},
files=files,
data=data
)
print(f"文档上传状态: {resp.json()}")
2. 发起 RAG 对话(Curl 示例,展示流式输出)
curl -X POST "http://dify-host:5001/v1/chat-messages" \
-H "Authorization: Bearer app-xxxxxx" \
-H "Content-Type: application/json" \
-d '{
"inputs": {},
"query": "请总结本地部署的 GPU 显存要求",
"response_mode": "streaming",
"conversation_id": "",
"user": "internal-engineer",
"files": [],
"model": "qwen2.5:7b",
"model_provider": "xinference"
}'
响应为 SSE 流,其中 event: message 携带最终回答,event: agent_message 携带中间思考过程。
3. 直接调用 Xinference 的 embedding API(用于自建检索)
import requests
XINFERENCE_URL = "http://xinference-host:9997/v1/embeddings"
payload = {
"model": "bge-m3",
"input": ["如何配置 GPU 显存", "显存不足的排查方法"]
}
resp = requests.post(XINFERENCE_URL, json=payload)
vectors = resp.json()["data"]
print(f"向量维度: {len(vectors[0]['embedding'])}") # 1024 维
四、高并发扩容建议:从单体到集群
当业务量增长至每秒 50+ 次检索或 20+ 次对话时,需进行以下改造:
1. 模型副本横向扩展
在 Xinference 中,使用 --replica 参数启动多个模型副本。例如:
xinference launch --model-name bge-m3 --model-type embedding --replica 4
xinference launch --model-name qwen2.5:7b --model-type llm --replica 2 --max-workers 8
Xinference 内部采用轮询 + 最少连接数策略进行负载均衡。注意:LLM 副本数不宜超过 GPU 显存容量的 50%,否则会引发 OOM。
2. 引入 Redis 缓存与异步任务队列
对于高频重复查询(如“重置密码步骤”),在 Dify 前端接入 Redis 缓存层。建议使用 dify-cache 插件或自建中间层:
import redis
import hashlib
r = redis.Redis(host='redis-host', port=6379, decode_responses=True)
def get_cached_answer(query: str):
key = hashlib.md5(query.encode()).hexdigest()
return r.get(f"rag_cache:{key}")
def set_cached_answer(query: str, answer: str):
key = hashlib.md5(query.encode()).hexdigest()
r.setex(f"rag_cache:{key}", 3600, answer)
3. 数据库层拆分
Dify 默认使用 PostgreSQL + pgvector。当知识库文档超过 10 万条时,建议:
- 将向量索引从 HNSW 切换为 IVFFlat,降低内存占用。
- 将 Dify 的日志表与业务表分离至不同磁盘。
- 使用读写分离:主库处理写入,从库处理向量检索。
4. 推理网关前置 Nginx
在 Xinference 前增加 Nginx 做超时控制与限流:
upstream xinference_backend {
server 192.168.1.10:9997;
server 192.168.1.11:9997;
keepalive 32;
}
server {
listen 9998;
location / {
proxy_pass http://xinference_backend;
proxy_read_timeout 300s;
proxy_send_timeout 300s;
limit_req zone=api_limit burst=20 nodelay;
}
}
5. 监控与告警
使用 Prometheus 采集 Xinference 的 /metrics 端点,重点监控:
xinference_model_queue_size:队列积压数 > 100 时告警。xinference_gpu_memory_used_bytes:超过 90% 时自动扩容。dify_rag_retrieval_latency:P99 超过 2 秒时触发降级。
五、总结
xinference + dify + ollama 构建本地知识库 是一条经过验证的可行路径。本方案的优势在于:
- 模型管理统一化:embedding、rerank、chat 三类模型由 Xinference 统一暴露 OpenAI 兼容 API,业务代码无需感知底层切换。
- 资源利用率高:Ollama 负责纯推理,Xinference 负责调度,Dify 负责业务编排,各层可独立扩缩容。
- 数据安全可控:全程内网部署,适合金融、政务、医疗等强合规场景。
最后给出三条落地建议:
- 模型选型:embedding 优先选择 bge-m3(中文效果优于 m3e),rerank 必须搭配使用,否则检索准确率下降 30% 以上。
- 显存规划:7B 模型量化后约需 6GB 显存,建议单卡 24GB 可承载 3 个副本。
- 版本锁定:Dify 0.6.x 与 Xinference 0.9.x 存在已知兼容性问题,建议锁定
dify:0.10.2+xinference:0.12.0+ollama:0.3.6组合。
按上述方案,一个 50 人研发团队的知识库系统,在 2 张 4090 显卡上即可支撑日均 5000 次检索请求,且 P95 延迟低于 1.5 秒。若需进一步压测,可参考 locust 脚本对 Dify API 进行负载测试,逐步调整副本数直至满足业务指标。