1. 为什么我要把 DeepTutor 塞进 Docker 里
先说结论:DeepTutor 这套东西,如果你打算长期用、反复用、换机器用,那 Docker 化几乎是唯一正确的选择。我最早是在一台 Ubuntu 测试机上裸装 DeepTutor 的,Python 版本冲突、CUDA 驱动版本对不上、Embedding 模型下载路径写死、Ollama 服务端口被占……折腾了整整一个下午才跑通。后来换了一台机器,同样的流程又踩了一遍坑。那一刻我就决定,必须把它容器化。
DeepTutor 本质上是一个基于大语言模型的智能辅导/知识问答系统,它的核心链路是:用户提问 → 向量检索(Embedding)→ 上下文拼接 → 大模型生成回答。这条链路里涉及三个关键组件:DeepTutor 应用本体、Ollama 推理服务、Embedding 模型服务。任何一个组件的版本或配置出问题,整条链路就断了。Docker 的价值就在于把这套依赖关系固化下来,做到"一次构建,到处运行"。
这篇文章适合三类人看:第一类是想快速体验 DeepTutor 但不想折腾环境的新手;第二类是想把 DeepTutor 部署到内网服务器、做私有化知识库的运维同学;第三类是想基于 DeepTutor 做二次开发、需要一套干净可复现环境的开发者。我会从架构设计讲到实操步骤,再到踩坑排查,尽量把每个决策背后的"为什么"讲清楚。
需要提前说明的是,本文涉及的模型推理全部基于本地部署方案,所有数据和服务都在你自己的机器上闭环,不涉及任何外部网络依赖。这也是我选择 Ollama + 本地 Embedding 的核心原因——可控、可复现、可离线。
2. 整体架构设计与组件选型思路
2.1 三个核心组件的职责划分
在动手之前,先把架构想清楚,不然后面容器编排会一团乱。我把 DeepTutor 的部署拆成三个独立的服务单元:
| 组件 | 职责 | 技术选型 | 端口 |
|---|---|---|---|
| DeepTutor App | Web 界面 + 业务逻辑 + 检索编排 | Python FastAPI / 官方镜像 | 8000 |
| Ollama | 大模型推理(生成回答) | Ollama Server | 11434 |
| Embedding 服务 | 文本向量化(检索用) | Ollama 内置 embedding 或独立服务 | 11434 / 自定义 |
这里有个关键决策点:Embedding 到底用 Ollama 内置的,还是单独起一个服务?我的建议是,如果你只是个人使用、知识库规模在几万条以内,直接用 Ollama 拉一个 embedding 模型(比如nomic-embed-text或bge-m3)就够了,省一个容器。但如果你要做生产级部署、检索量很大、需要独立扩缩容,那就把 Embedding 单独拆出来,用专门的推理框架跑,避免和生成模型抢显存。
2.2 为什么选 Ollama 而不是其他推理框架
市面上本地推理方案不少,我最终选 Ollama 的理由很实际:
- 模型管理简单:
ollama pull一条命令搞定,不用手动下载 GGUF 文件、不用配 tokenizer 路径。 - API 兼容 OpenAI 格式:DeepTutor 如果用的是 OpenAI SDK 调用方式,改个 base_url 就能对接,几乎零改造。
- 跨平台:Windows、Linux、macOS 都有对应版本,团队里不同系统的同学都能用。
- 显存调度省心:Ollama 会自动管理模型加载和卸载,不用自己写显存回收逻辑。
当然它也有缺点,比如并发能力弱、不支持复杂的批处理调度。但对于 DeepTutor 这种以交互式问答为主的场景,够用了。
2.3 网络拓扑与容器通信设计
容器之间怎么通信,这是新手最容易翻车的地方。我见过太多人把 Ollama 装在宿主机、DeepTutor 装在容器里,然后容器里用localhost:11434去连,结果一直 connection refused。
正确的做法是:把所有服务放进同一个 Docker 网络,容器之间用服务名互相访问。比如 DeepTutor 容器里配置 Ollama 地址时,写http://ollama:11434,而不是http://localhost:11434。Docker 的内置 DNS 会把ollama这个服务名解析到对应容器的 IP。
如果你坚持 Ollama 跑在宿主机(比如为了直接用宿主机的 GPU 驱动),那容器里要用http://host.docker.internal:11434(Docker Desktop 环境)或者宿主机的实际局域网 IP。这个细节后面实操部分我会再展开。
3. 环境准备与 Docker 安装实操
3.1 Ubuntu 下的 Docker 安装
先解决 Docker 本身。Ubuntu 上我习惯用官方脚本装,比 apt 源里的版本新,也省得配一堆依赖:
# 卸载旧版本(如果有) sudo apt-get remove docker docker-engine docker.io containerd runc # 安装依赖 sudo apt-get update sudo apt-get install -y ca-certificates curl gnupg lsb-release # 添加官方 GPG key sudo mkdir -p /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg # 添加源 echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null # 安装 sudo apt-get update sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin装完之后有个必做动作:把当前用户加进 docker 组,否则每次敲 docker 命令都要 sudo,烦得很:
sudo usermod -aG docker $USER newgrp docker注意:
newgrp只对当前终端生效,其他已经打开的终端需要重新登录。如果执行 docker 命令还是报permission denied while trying to connect to the docker api,八成就是这个组权限没生效,退出 SSH 重连一次即可。
3.2 Windows 下的 Docker Desktop 安装
Windows 用户直接去官网下 Docker Desktop 安装包,双击一路下一步。但有三个坑必须提前说:
第一,WSL2 后端必须开启。Docker Desktop 默认用 WSL2,如果你机器上没装 WSL2,安装程序会提示你装。装完记得在 BIOS 里确认虚拟化(VT-x / AMD-V)是打开的,否则 WSL2 起不来。
第二,磁盘空间。Docker 的镜像和容器默认存在 C 盘,Ollama 的模型动辄几个 G,很容易把 C 盘撑爆。我建议在 Docker Desktop 设置里把 "Disk image location" 改到 D 盘或更大的盘。
第三,端口占用。Windows 上 11434 端口有时候会被其他服务占用,装之前先netstat -ano | findstr 11434查一下。
3.3 GPU 支持配置(NVIDIA 显卡)
如果你有 NVIDIA 显卡,想让 Ollama 用上 GPU 加速,需要额外装 NVIDIA Container Toolkit:
# 添加源 distribution=$(. /etc/os-release;echo $ID$VERSION_ID) curl -s -L https://nvidia.github.io/libnvidia-container/gpgkey | sudo apt-key add - curl -s -L https://nvidia.github.io/libnvidia-container/$distribution/libnvidia-container.list | sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list # 安装 sudo apt-get update sudo apt-get install -y nvidia-container-toolkit sudo nvidia-ctk runtime configure --runtime=docker sudo systemctl restart docker验证是否成功:
docker run --rm --gpus all nvidia/cuda:12.0-base nvidia-smi能打印出显卡信息就说明 OK。这一步不做的话,Ollama 会退化成纯 CPU 推理,速度慢到你怀疑人生。
4. Ollama 服务部署与模型拉取
4.1 用 Docker 跑 Ollama
Ollama 官方提供了 Docker 镜像,直接跑就行:
docker run -d \ --name ollama \ --gpus all \ -p 11434:11434 \ -v ollama_data:/root/.ollama \ --restart unless-stopped \ ollama/ollama:latest几个参数解释一下:--gpus all是让容器能用所有 GPU;-v ollama_data:/root/.ollama是把模型文件挂到命名卷上,这样容器删了模型还在;--restart unless-stopped保证开机自启。
实操心得:模型存储路径一定要挂出来。我见过有人没挂卷,容器一重建,几十 G 的模型全没了,又得重新下载。如果你想把模型存到特定盘(比如数据盘),把
ollama_data换成/data/ollama:/root/.ollama这种绝对路径挂载。
4.2 拉取 DeepSeek 与 Embedding 模型
Ollama 跑起来后,进容器拉模型:
# 拉取 DeepSeek 系列模型(按你的显存选尺寸) docker exec -it ollama ollama pull deepseek-r1:7b # 拉取 Embedding 模型 docker exec -it ollama ollama pull nomic-embed-text模型尺寸怎么选?给你一个粗略的参考表:
| 模型 | 参数量 | 显存需求(约) | 适用场景 |
|---|---|---|---|
| deepseek-r1:1.5b | 1.5B | 2-3 GB | 低配机器、快速验证 |
| deepseek-r1:7b | 7B | 6-8 GB | 个人使用、平衡之选 |
| deepseek-r1:14b | 14B | 12-16 GB | 效果更好、需要中端显卡 |
| deepseek-r1:32b | 32B | 24 GB+ | 专业级、高端显卡 |
Embedding 模型我推荐nomic-embed-text,768 维,体积小、速度快,中文效果也还行。如果你对中文检索要求高,可以换bge-m3,1024 维,效果更好但更吃资源。
注意:
ollama pull下载慢是常态,尤其是国内网络环境。如果实在拉不动,可以找离线模型包,手动放到/root/.ollama/models目录下。离线包的目录结构要和 Ollama 的存储格式一致,否则识别不了。
4.3 验证 Ollama 服务
拉完模型,验证一下服务是否正常:
# 列出已安装模型 curl http://localhost:11434/api/tags # 测试生成 curl http://localhost:11434/api/generate -d '{ "model": "deepseek-r1:7b", "prompt": "你好,请介绍一下你自己", "stream": false }'能返回 JSON 结果就说明 Ollama 工作正常。如果报错,先看容器日志:docker logs ollama。
5. DeepTutor 容器化部署全流程
5.1 用 docker-compose 编排所有服务
单个docker run命令管理多个服务太累,我强烈建议用 docker-compose。新建一个docker-compose.yml:
version: '3.8' services: ollama: image: ollama/ollama:latest container_name: ollama ports: - "11434:11434" volumes: - ollama_data:/root/.ollama deploy: resources: reservations: devices: - driver: nvidia count: all capabilities: [gpu] restart: unless-stopped deeptutor: image: deeptutor/deeptutor:latest container_name: deeptutor ports: - "8000:8000" environment: - OLLAMA_BASE_URL=http://ollama:11434 - LLM_MODEL=deepseek-r1:7b - EMBEDDING_MODEL=nomic-embed-text - VECTOR_DB_PATH=/app/data/vectors volumes: - deeptutor_data:/app/data depends_on: - ollama restart: unless-stopped volumes: ollama_data: deeptutor_data:这里的关键是OLLAMA_BASE_URL=http://ollama:11434,用服务名而不是 localhost。depends_on保证 Ollama 先启动。
5.2 启动与初始化
# 启动所有服务 docker compose up -d # 查看状态 docker compose ps # 看日志 docker compose logs -f deeptutor第一次启动 DeepTutor 时,它可能需要初始化向量数据库、下载一些依赖。耐心等几分钟,看到日志里出现 "Application startup complete" 之类的字样就说明好了。
5.3 访问与基础配置
浏览器打开http://你的服务器IP:8000,应该能看到 DeepTutor 的界面。第一次进去要做几件事:
- 配置模型:在设置里确认 LLM 模型名和 Embedding 模型名,要和 Ollama 里拉的一致。
- 上传知识库:把你的文档(PDF、Markdown、TXT)传进去,系统会自动切分、向量化、入库。
- 测试问答:问一个知识库里有的问题,看能不能正确检索并回答。
实操心得:知识库文档切分粒度很影响检索效果。切太碎,上下文不完整;切太大,检索精度下降。我一般把 chunk size 设在 500-800 字符,overlap 设 100-150 字符。这个参数在 DeepTutor 的配置里能调,具体看版本。
6. 常见问题排查与避坑指南
6.1 容器连不上 Ollama
这是最高频的问题。排查顺序:
| 现象 | 可能原因 | 解决方法 |
|---|---|---|
| connection refused | 用了 localhost | 改成服务名http://ollama:11434 |
| timeout | 不在同一网络 | 确认在同一 compose 文件里 |
| 404 | 模型名写错 | ollama list核对模型名 |
| 显存不足 | 模型太大 | 换小模型或加显卡 |
6.2 模型下载慢或失败
ollama pull卡住不动,先 Ctrl+C 中断,然后:
# 检查网络 docker exec -it ollama curl -I https://registry.ollama.ai # 重试,加长超时 docker exec -it ollama ollama pull deepseek-r1:7b如果反复失败,考虑离线方案:在能下载的机器上拉好模型,把/root/.ollama/models整个目录打包拷过来。
6.3 GPU 没被用上
跑推理时nvidia-smi看不到进程,说明 Ollama 在用 CPU。检查:
# 容器内能否看到 GPU docker exec -it ollama nvidia-smi如果容器内看不到,说明启动时没加--gpus all或者 NVIDIA Container Toolkit 没配好。回到 3.3 节重新配。
6.4 向量检索结果不准
如果问答答非所问,大概率是 Embedding 或切分的问题。排查思路:
- 换更强的 Embedding 模型(
bge-m3比nomic-embed-text中文效果好) - 调整 chunk size 和 overlap
- 检查文档是否真的入库了(看向量库文件大小)
- 确认查询语言和文档语言一致(中英文混用会影响效果)
6.5 容器重启后数据丢失
这是没挂卷的典型症状。检查 compose 文件里每个服务的volumes配置,确保模型、向量库、配置都挂出来了。已经丢了的只能重新拉、重新入库。
7. 性能调优与扩展思路
7.1 显存与并发调优
Ollama 默认一次只处理一个请求,并发上来会排队。如果你的场景并发高,可以:
- 设置
OLLAMA_NUM_PARALLEL环境变量提高并发数(吃显存) - 用多个 Ollama 实例 + 负载均衡
- 把 Embedding 拆到独立服务,避免和生成模型抢资源
7.2 向量库选型
DeepTutor 默认可能用轻量级向量库(如 Chroma、FAISS)。数据量大了之后,可以考虑换成 Milvus 或 Qdrant,支持分布式、更高性能。切换时注意 Embedding 维度要对齐,否则检索全乱。
7.3 反向代理与 HTTPS
生产环境别直接暴露 8000 端口,前面挂个 Nginx 做反向代理,配上 HTTPS。这样既安全,又能做访问控制。
server { listen 443 ssl; server_name your-domain.com; location / { proxy_pass http://127.0.0.1:8000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }7.4 备份策略
要备份的东西就三样:Ollama 模型目录、DeepTutor 数据目录、compose 文件。写个定时脚本打包到异地,出问题能快速恢复。
#!/bin/bash DATE=$(date +%Y%m%d) docker run --rm -v ollama_data:/data -v /backup:/backup alpine \ tar czf /backup/ollama_$DATE.tar.gz -C /data .这套 Docker 化方案我在三台不同配置的机器上都跑过,从 8G 显存的消费级显卡到 24G 的工作站,流程完全一致,唯一要改的就是模型尺寸。真正做到了"换个机器,改个模型名,五分钟重新跑起来"。如果你也在折腾 DeepTutor 的部署,希望这些踩坑记录能帮你少走点弯路。