全流程实操:Dify+Ollama+Xinference 搭建法律咨询大模型平台(含环境部署/ 数据清洗 / 知识库构建 / 工作流设计)
文章目录
前言
本文从零开始完成了基于Dify的法律咨询大模型平台搭建的全流程。流程中先解决环境部署问题,因单台服务器系统盘存储空间有限,采用两台服务器分别部署不同服务,一台部署Dify与Ollama实现大模型调用和平台交互,另一台部署Xinference以提供Dify混合检索所需的rerank模型,针对两台服务器间网络不通的问题,通过内网穿透实现相互访问。
在部署过程中,完成Docker安装与配置,随后通过Ollama拉取Qwen3相关模型并配置GPU环境变量保障运行。同时,在另一台服务器完成Xinference的安装,创建并启动rerank模型,进而完成其与Dify的对接配置。
接着搭建高级检索知识库,先安装MinerU工具,将《中华人民共和国民营经济促进法》的PDF非结构化文档转换为Markdown格式,随后编写Python脚本对转换后的文档做数据清洗,如为章节和条款添加标识、优化段落格式等,之后基于清洗后的文档创建向量知识库,并完成分段清洗验证以及靶场命中率、模糊访问命中两类测试以保障知识库检索效果。
最后在Dify上创建多轮工作流项目,设置了细致的问题分类规则,能精准区分法律相关与无关问题,同时配置了关键内容提炼与规范回答的提示词,明确要求回答需100%基于知识库并标注条款出处,还附加免责声明,最终通过法律相关问题测试,实现了法律条文精准查询与规范回复的功能。

使用的云平台:
muliao
autodl
项目相关软件包和文件已上传
平台私有化部署
docker安装
git clone 速度太慢 可以开启AudoDL学术资源加速:
source /etc/network_turbo
取消代理:
unset http_proxy && unset https_proxy

export http_proxy=http://10.132.19.35:7890
export https_proxy=http://10.132.19.35:7890
命令行:
sudo apt-get update
#这个步骤可以不做
sudo apt-get install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
#如果网络不好,这个文件用手动的方式下载,然后把文件改名叫docker.asc即可
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
#将Docker的APT仓库添加到Ubuntu系统的APT源列表中,
#以便后续可以通过APT包管理器安装Docker相关的软件包
# Add the repository to Apt sources:
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
# 安装Docker 建议开启学术资源加载
sudo apt-get install docker-ce docker-ce-cli containerd.io
# 启动Docker服务
sudo systemctl start docker
sudo systemctl status docker

遇到的问题:

问题原因是:Ubuntu 系统的自动更新进程 unattended-upgr 占用了 dpkg 包管理器的锁文件,导致当前安装命令无法获取锁资源。等待自动更新完成即可。
unattended-upgr 是系统后台自动更新服务,通常会在几分钟内完成(具体耗时看网络和更新内容多少)。可执行以下命令,确认自动更新进程是否还在运行:
# 查看 unattended-upgr 进程状态(输出有结果说明正在运行)
ps aux | grep unattended-upgr
若输出为空,说明自动更新已结束。

看到running状态说明docker已经正常启动
配置daemon.json文件
vim /etc/docker/daemon.json
{
"exec-opts": ["native.cgroupdriver=systemd"],
"registry-mirrors":[
"https://hub.fast360.xyz",
"https://hub.rat.dev",
"https://hub.littlediary.cn",
"https://docker.kejilion.pro",
"https://dockerpull.cn",
"https://docker-0.unsee.tech",
"https://docker.tbedu.top",
"https://docker.1panelproxy.com",
"https://docker.melikeme.cn",
"https://cr.laoyou.ip-ddns.com",
"https://hub.firefly.store",
"https://docker.hlmirror.com",
"https://docker.m.daocloud.io",
"https://docker.1panel.live",
"https://image.cloudlayer.icu",
"https://docker.1ms.run"
],
"insecure-registries": ["http://easzlab.io.local:5000"],
"max-concurrent-downloads": 10,
"log-driver": "json-file",
"log-level": "warn",
"log-opts": {
"max-size": "10m",
"max-file": "3"
},
"data-root": "/var/lib/docker"
}
systemctl daemon-reload
systemctl restart docker
模型下载
# 使⽤conda创建虚拟环境
conda create -n hybrid-retrieval python=3.11 -y
# 进入虚拟环境
conda activate hybrid-retrieval
-y 是 conda 的一个可选参数,作用是自动确认所有交互式提示,无需手动输入 y(yes)确认操作。
方案一: 魔塔社区下载模型
魔塔社区地址:https://modelscope.cn/models
# 下载工具
pip install modelscope -i https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple
#下载模型
mkdir /data/models -pv
modelscope download --model Qwen/Qwen3-0.6B --local_dir /data/models/qwen3-0.6B

方案二:HuggingFace下载模型
官⽹地址(需要科学上⽹才能访问):https://huggingface.co/
# 安装下载工具
pip install huggingface_hub -i https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple
# 配置国内源
export HF_ENDPOINT="https://hf-mirror.com"
# 下载模型
huggingface-cli download --resume-download --local-dir-use-symlinks False
Qwen/Qwen2.5-VL-7B-Instruct --local-dir /data/models/qwen2-vl-7b/
方案三: 直接使用ollama拉取里面已经做好的模型(本文使用此方法)
ollama 启动模型
下载地址:https://github.com/ollama/ollama/releases/download/v0.6.8/ollama-linux-amd64.tgz
tar -zxvf ollama-linux-amd64.tgz -C /usr/
useradd -r -s /bin/false -m -d /usr/share/ollama ollama
配置ollama启动程序:
cat > /etc/systemd/system/ollama.service << EOF
[Unit]
Description=Ollama Service
After=network-online.target
[Service]
ExecStart=/usr/bin/ollama serve
Environment="OLLAMA_HOST=0.0.0.0:8891"
User=ollama
Group=ollama
Restart=always
RestartSec=3
[Install]
WantedBy=default.target
EOF
为了能在本地让Dify接入Ollama,所以我们需要修改Ollama的端口号 8891(因为是租的服务器的缘故)
配置GPU环境变量:在文件的最末尾加上
vim /root/.bashrc
export OLLAMA_GPU_OVERHEAD=524288000 # 保留 500MB 显存
export OLLAMA_SCHED_SPREAD=0 # 均匀分配负载到所有 GPU
export OLLAMA_FLASH_ATTENTION=1 # 启用 Flash Attention
export OLLAMA_KV_CACHE_TYPE=f16 # 使用半精度浮点数
export OLLAMA_MAX_LOADED_MODELS=1 # 每个 GPU 最多加载 1 个模型
# 加载环境变量
source /root/.bashrc
#启动服务程序
ollama serve
#拉取并运行模型
OLLAMA_HOST=127.0.0.1:8891 ollama pull qwen3:8b

vllm启动模型:(仅展示vllm启动流程,不用操作此步骤,存储空间会不够)
# 拉取镜像
docker pull vllm/vllm-openai
# 启动镜像
docker run --entrypoint /bin/bash --network host --name node --shm-size 24g --gpus all
-e VLLM_HOST_IP=192.168.2.133 -e NCCL_SOCKET_IFNAME=eno1 -v
"/data/models:/data/models" "vllm/vllm-openai:latest" -c "ray start --block --head --
port=8888 --node-ip-address=192.168.2.133"
# 进入容器
docker exec -it node bash
# 运行模型
vllm serve /data/models/qwen3-14b/ --served_model_name qwen3-14b --max_model_len 20480
--max_num_seqs 8
dify 部署
# 下载
git clone https://github.com/langgenius/dify.git
# 进入到环境目录
cd dify/docker
# 将环境变量模板生效
cp .env.example .env
.env.example 是项目提供的环境变量模板文件,包含了运行项目所需的各类配置项(如数据库地址、API 密钥等),但通常是示例值或占位符。
cp .env.example .env
将环境变量模板文件复制为实际生效的环境变量文件。
修改Dify端口号
vim .env


启动 dify
# docker-compose启动dify
docker-compose up -d
遇到的问题:

docker-compose下载地址:docker-compose
(此安装包已上传到csdn)
chmod +x docker-compose
mv docker-compose /usr/local/bin/
设置管理员用户 ---- 登录


修改密码 :
docker exec -it docker-api-1 flask reset-password
遇到的错误:

这个报错是权限被拒绝错误,核心原因是程序尝试写入文件(private.pem)时,没有对应的文件系统权限。
# 回到 Dify 的 docker 目录(关键!所有操作需在该目录执行)
cd ~/dify/docker
# 查看 docker-compose.ymal 中的挂载配置(找 volumes 字段)
grep -E 'volumes|volume' docker-compose.yaml

从 docker-compose.yaml 的挂载配置来看,Dify 所有数据都存储在宿主机的 ./volumes/ 目录下(包含数据库、缓存、存储等所有子目录)。之前的权限报错,本质是 宿主机的 ./volumes/ 目录或其下子目录不存在 / 权限不足,导致容器内程序无法创建 private.pem 等文件。
# 确保当前在 ~/dify/docker 目录(关键!)
cd ~/dify/docker
# 1. 创建 volumes 父目录(若不存在)
mkdir -p ./volumes
# 2. 给 volumes 目录及所有子目录开放最大权限(确保容器能读写)
chmod -R 777 ./volumes
# 3. 验证目录权限(输出 drwxrwxrwx 即为成功)
ls -ld ./volumes
在线模型配置及召回率测试



离线安装插件:
访问:https://marketplace.dify.ai/


ollama 模型配置
# 启动模型
systemctl start ollama
模型导入:


使用的是公网地址:

模型调用:


如果显存不⾜运⾏qwen3-14b模型,可以先停掉ollama,如下命令:
systemctl stop ollama
普通知识库创建
上传文件:



召回率测试
召回率很低,也没有命中评分,接下来实现⾼级命中配置内容。

embedding 模型
随着大家的深入使用,发现ollama部署大模型虽然方便,但是Dify知识库混合检索,需要有rerank模型,这一点上,ollama是不支持rerank模型的,因此,部署一个Xinference平台来部署rerank模型的呼声越来越强烈。
因为第一个服务器系统盘满了,这里第二台服务器在autodl平台租用:
修改 pip 缓存目录(解决磁盘空间不足问题) 和 配置 pip 使用清华 PyPI 镜像源(加速包下载)
Xinference安装步骤:
# 使⽤conda创建虚拟环境
conda create -n xinference python=3.11 -y
# 进入虚拟环境
conda activate xinference
# 修改pip缓存
echo 'export PIP_CACHE_DIR=/data/pip/cache' >> ~/.bashrc
source ~/.bashrc
# 验证缓存文件夹改变
pip cache dir
# 配置清华源
python -m pip install --upgrade pip
pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple
# 使用清华源进行升级
python -m pip install -i https://pypi.tuna.tsinghua.edu.cn/simple --upgrade pip
# 安装所有依赖
# 直接执行
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple "xinference[all]"
# 启动服务
# 前台
xinference-local --host 0.0.0.0 --port 8893
# 后台
#nohup xinference-local --host 0.0.0.0 --port 8890 & > output.log
可能遇到的问题:

# 从清华源安装 xoscar 0.7.13(预编译 wheel 包,直接安装无需编译)
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple xoscar==0.7.13
可能遇到的问题:

systemctl daemon-reload
systemctl restart ollama.service
# 再次验证端口监听(必须有输出)
ss -tulpn | grep 8891
# 现在执行带端口的拉取,必然成功
OLLAMA_HOST=127.0.0.1:8891 ollama pull qwen3:8b


创建rerank模型 并启动:

配置embedding 与 rerank模型到 dify

配置embedding:
dify所在环境与 Xinference 服务的网络不通(Xinference 运行在服务器,dify在其他服务器运行,未开放端口);基于此问题使用内网穿透的方法实现访问。

配置rerank:
高级检索知识库
安装转换工具:
MinerU 是 OpenDataLab(开放数据实验室)开发的开源数据处理工具集,核心定位是 高效解析、转换、处理非结构化文档(尤其是 PDF),常被用于大模型训练的数据预处理、文档内容提取等场景。
文档解析与转换支持 PDF、Word 等格式的文档解析,能将非结构化内容(如排版复杂的 PDF)转换为结构化格式(Markdown、JSON、文本等),同时保留章节、条款等层级关系。

git clone https://github.com/opendatalab/MinerU.git
cd MinerU
uv pip install -e .[core]
将pdf转为md
mv 中华人民共和国民营经济促进法.pdf china.pdf
mineru -p china.pdf -o ./output-china
# 主要文件
ls output-china/china/auto/china.md
数据清洗:
# 切换到转换目录下
cd output-china/china/auto
# 程序编写
vim prompt.py
#!/opt/miniconda3/envs/mineru/bin/python
import re
def process_file(input_file_path, output_file_path):
try:
with open(input_file_path, 'r', encoding='utf-8') as file:
content = file.read()
# 为章节添加 @
chapter_pattern = r'(第[一二三四五六七八九十百千]+章\s+[^\n]*)'
content = re.sub(chapter_pattern, lambda m: m.group(1).strip() + ' @', content)
# 为条款添加 @,确保条款内容完整(修复换行截断问题)
article_pattern = r'(第[一二三四五六七八九十百千]+条\s+.*?)(?=(第[一二三四五六七八九十百千]+条|第[一二三四五六七八九十百千]+章|$))'
content = re.sub(article_pattern, lambda m: m.group(1).strip() + ' @', content, flags=re.S)
# 修复段落格式:在句号和分号后添加换行
content = re.sub(r'([。;])\s*', r'\1\n', content)
# 去除多余的空行
content = re.sub(r'\n{3,}', '\n\n', content)
with open(output_file_path, 'w', encoding='utf-8') as file:
file.write(content)
print(f"处理完成,结果已保存到 {output_file_path}")
except FileNotFoundError:
print(f"错误:未找到文件 {input_file_path}")
except Exception as e:
print(f"发生未知错误: {e}")
if __name__ == "__main__":
# 注意:文件路径要和你的实际文件位置对应!
input_file = './china.md' # 你的输入MD文件路径(当前目录下)
output_file = './china-out.md' # 输出文件路径
process_file(input_file, output_file)
执行python程序:
python prompt.py
向量知识库创建:



分段与清洗 验证查看:

靶场命中率测试:

模糊访问命中测试:

创建多轮工作流项目

工作流初始化:

问题分类流:



分类提示词:
分类1:
用于法律相关的任何问题查询的分支,如用户提问第几章、第几条,还有任何关于法律隐晦的表述,我做了什么事情,某某事情该如何处理等等,都视为法律。
分类2:
1. 法律内容直接提及••
包含法律名称
引用具体条款
涉及法律概念
••2. 法律行为描述••
提及权利义务关系
描述法律程序
涉及法律主体
••3. 法律实务需求••
法律条文查询
法律解释需求
法律文书需求
••4. 法律关联特征••
包含法律术语
涉及司法程序
包含法律文件
••5. 特殊标识情形••
明确标注法律章节
引用条文编号
涉及法律修订
••执行规则••
••全字段匹配••:只要出现上述任一特征即触发法律分类
••优先级排序••:
直接引用法律条文(章节/条款) > 法律概念 > 法律行为描述
••动态兼容••:
新增法律条文自动纳入分类(无需调整规则)
法律概念库持续扩展(如新增"数据安全法"相关术语)
分类3:
与任何法律不相关的问题,比如生活常识与经验类、科学技术与知识类、社会文化与情感类等等任何不与法律相关的问题。
分类4:
与法律完全不相关的内容

相关问题:



不相关问题:

我是一名法律助手,请问法律相关的问题。
比如:因合同纠纷提起的诉讼该如何处理。离婚案件,涉及商业秘密的案件,当事人是否可以申请不公开审理等等。

提取关键内容:



## 任务
请精准提炼用户所提出的法律条文相关问题中的核心要点,转化为用于高效检索法律条文知识库的关键内容。
确保关键内容能够准确反映问题主旨,以便从知识库中获取相关且有用的信息。
## 输出
以多个关键字或关键句的形式输出提炼结果,各关键字或关键句之间用空格分隔,仅呈现关键内容,不得包含
任何多余文本,严禁直接对用户输入的问题进行回答。尤其注意针对法律条文类问题进行准确提炼。
## 知识库引用
在回答用户问题时,请优先参考已上传的知识库内容。
请确保所有引用的内容都来自知识库,不要编造。


根据关键内容回答问题:







系统提示词:
【角色定位】
您作为法律咨询AI助手,必须严格扮演专业法律顾问角色,以知识库为唯一依据提供法律服务。
【核心指令】
回答规范:
所有回答必须100%基于知识库原文内容
禁止任何超出知识库范围的推测、解释或补充
对知识库未涵盖的问题必须明确声明"根据现有知识库无法回答"
特别要求:
时间信息必须逐字引用知识库表述(包括但不限于时效、期限、天数等)
法律条款必须完整标注知识库中的出处条目
专业术语必须保持与知识库完全一致
回答结构:
1.明确声明"根据知识库第几章第几条"
2.直接引用相关条文内容
3.必要时应分段展示关联条款
【免责声明】
每个回答结尾必须附加:
"温馨提示:本回答严格依据现有知识库生成,如需法律效力文本请咨询执业律师。"
这个版本通过:
更严格的知识库绑定要求
特别强调时间信息的逐字引用
增加结构化回答规范
强化免责声明
使用强调性措辞("必须""禁止""100%"等)
{{#context#}}



工作流测试:
# 提问问题
国家对民营经济组织及其经营者原始创新的保护是如何定义的。
# 原始内容答案
第三十三条 国家加强对民营经济组织及其经营者原始创新的保护。
加大创新成果知识产权保护力度,实施知识产权侵权惩罚性赔偿制度,依法查处侵犯商标专用权、专利权、著
作权和侵犯商业秘密、仿冒混淆等违法行为。
加强知识产权保护的区域、部门协作,为民营经济组织提供知识产权快速协同保护、多元纠纷解决、维权援助
以及海外知识产权纠纷应对指导和风险预警等服务。

更多推荐
所有评论(0)