Ollama 模型文件被自动清理的排查与修复笔记
事故概述
在调整 Ollama 模型存储路径后重启服务,导致约 5.6GB 的本地模型文件(Qwen3.5-9B.Q4_K_M)被 Ollama 自动清理机制(Prune)永久删除,回收站中不可见。
一、Ollama 的文件组织结构
OLLAMA_MODELS/
├── blobs/ # 所有模型数据文件(按 SHA256 哈希命名)
│ ├── sha256-8fbbc7b0... # 模型权重层
│ ├── sha256-41c16094... # 模板/参数层
│ └── sha256-382fbaa7... # 配置层
└── manifests/ # 模型清单(索引文件,指向 blobs)
└── registry.ollama.ai/
└── library/
├── qwen3-embedding/
│ └── 0.6b # 清单文件(JSON)
└── qwen3.5/
└── 9b # 清单文件(JSON)
关键关系:manifest 是 blob 的"户口本"。没有 manifest 的 blob = 孤儿 = 会被清理。
Manifest 样例
{
"schemaVersion": 2,
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"config": {
"mediaType": "application/vnd.docker.container.image.v1+json",
"digest": "sha256:9202febe...",
"size": 266
},
"layers": [
{
"mediaType": "application/vnd.ollama.image.model",
"digest": "sha256:06507c7b...",
"size": 639150592
}
]
}
每个 layer 的 digest 对应 blobs 目录下的一个文件。
二、Prune 机制详解
触发时机
Ollama 服务启动时会自动执行 prune,扫描 blobs/ 目录:
- 遍历所有 manifest,收集被引用的 blob digest
- 遍历 blobs 目录中的所有文件
- 未被任何 manifest 引用的 blob → 视为"unused" → 永久删除
日志特征
level=INFO source=images.go:477 msg="total blobs: 0"
level=INFO source=images.go:484 msg="total unused blobs removed: 0"
注意:removed: 0 可能是因为路径不对(读的旧路径),但如果你改了路径指向正确的目录,且有孤立 blob,数字会变成非零。
危险之处
- 直接永久删除,不经过回收站
- 静默执行,服务启动日志中的
removed 数字容易被忽略
- 默认行为,没有配置开关可以在安装时禁用
三、事故复现路径
1. 用户手动将 .gguf 文件放入 blobs/ 目录(没有创建 manifest)
2. 我修改 OLLAMA_MODELS 环境变量,指向包含这些 blob 的目录
3. 我重启 Ollama 服务,未设置 OLLAMA_NOPRUNE=1
4. Ollama 启动 → 扫描 blobs → 发现孤立 blob → 删除
5. 5.6GB 模型文件永久丢失
四、正确导入本地 GGUF 模型
第一步:创建 Modelfile
FROM /path/to/your-model.Q4_K_M.gguf
TEMPLATE """{{- if .System }}<|im_start|>system
{{ .System }}<|im_end|>
{{- end }}
<|im_start|>user
{{ .Prompt }}<|im_end|>
<|im_start|>assistant
{{ .Response }}<|im_end|>"""
PARAMETER stop "<|im_start|>"
PARAMETER stop "<|im_end|>"
PARAMETER temperature 0.6
PARAMETER top_p 0.95
PARAMETER num_ctx 4096
第二步:设置防清理环境变量
# 临时(当前会话)
$env:OLLAMA_NOPRUNE = "1"
# 永久(用户级别)
[System.Environment]::SetEnvironmentVariable("OLLAMA_NOPRUNE", "1", "User")
第三步:导入模型
$env:OLLAMA_MODELS = "F:\kaifaENVs\ollama\models"
$env:OLLAMA_NOPRUNE = "1"
ollama create qwen3.5:9b -f Modelfile.qwen35
Ollama 会自动:
- 计算 GGUF 文件的 SHA256
- 将其复制(或硬链接)为
blobs/sha256-xxx
- 生成 template/params 的 blob
- 生成 config blob
- 写入 manifest 文件
第四步:验证
ollama list
# NAME ID SIZE MODIFIED
# qwen3.5:9b 3341c3eba6f1 5.6 GB 8 seconds ago
# qwen3-embedding:0.6b ac6da0dfba84 639 MB 2 months ago
五、关键环境变量速查
| 变量 | 作用 | 推荐值 |
|------|------|--------|
| OLLAMA_MODELS | 模型存储根目录 | F:\kaifaENVs\ollama\models |
| OLLAMA_NOPRUNE | 禁止启动时自动清理孤立 blob | 1(强烈建议开启) |
| OLLAMA_HOST | 监听地址 | http://127.0.0.1:11434 |
| OLLAMA_KEEP_ALIVE | 模型卸载前的保持时间 | 5m(默认) |
六、教训总结
| # | 教训 | 具体做法 |
|---|------|----------|
| 1 | 了解工具的清理逻辑再操作 | 重启任何有 prune/gc 机制的服务前,先读文档了解触发条件 |
| 2 | 重要操作前先设 NOPRUNE | OLLAMA_NOPRUNE=1 应该是默认配置,不是事后补救 |
| 3 | 用正规流程导入,不要手动放文件 | ollama create 会生成完整 manifest;手动放 blob 没有索引,下次必被删 |
| 4 | 没有 manifest 的 blob 就是定时炸弹 | 任何不在 manifest 索引中的文件,在 Ollama 眼里都是垃圾 |
| 5 | 服务重启 ≠ 无害操作 | 重启可能触发启动时的清理、迁移、初始化逻辑 |
| 6 | 先备份,再动配置 | 5.6GB 的模型文件,改路径前至少确认一下 manifest 是否完整 |
七、排查命令备忘
# 查看 Ollama 服务日志中的 prune 记录
Select-String -Path "$env:LOCALAPPDATA\Ollama\server.log" -Pattern "prune|delete|remove|unused|blob"
# 查看当前模型列表
ollama list
# 查看 blobs 目录中的文件
Get-ChildItem "F:\kaifaENVs\ollama\models\blobs" | Select-Object Name, Length
# 查看 manifests 目录结构
Get-ChildItem "F:\kaifaENVs\ollama\models\manifests" -Recurse -File
# 检查环境变量
[System.Environment]::GetEnvironmentVariable("OLLAMA_MODELS", "User")
[System.Environment]::GetEnvironmentVariable("OLLAMA_NOPRUNE", "User")
# 搜索被删的 gguf 文件
cmd /c "dir /s /b F:\kaifaENVs\ollama\*.gguf"
记录时间:2026-04-09 18:48
血泪教训:5.6GB 模型文件因未设 OLLAMA_NOPRUNE 被 Ollama 自动清理永久删除