xinference + dify + ollama 构建本地知识库:从零到高并发落地的完整指南

在企业数据合规与成本控制的双重压力下,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 负责业务编排,各层可独立扩缩容。
  • 数据安全可控:全程内网部署,适合金融、政务、医疗等强合规场景。

最后给出三条落地建议:

  1. 模型选型:embedding 优先选择 bge-m3(中文效果优于 m3e),rerank 必须搭配使用,否则检索准确率下降 30% 以上。
  2. 显存规划:7B 模型量化后约需 6GB 显存,建议单卡 24GB 可承载 3 个副本。
  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 进行负载测试,逐步调整副本数直至满足业务指标。

发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注

滚动至顶部