今天下午本来只想清一下 Open WebUI 里的聊天文件。
说白了,就是那些生成图片、上传文件、文件管理里一长串 generated-image.png。我以为最多几条命令就完事,结果越清越不对:目录空了,界面还在;数据库查了,前端还显示;刚把文件列表弄干净,Open WebUI 又因为 embedding 模型缓存被删开始报错。
当时心态有点炸。很多自部署工具都是这样,表面上看是一个按钮、一个目录,背后连着数据库、文件目录、缓存、模型和前端状态。少清一处,界面就继续装作什么都没发生。

报错还好,至少它承认有事。最折磨的是界面还在,像刚才那些命令都白敲了。
先把 volume 名字改短
一开始让我不舒服的是 volume 名字:
openwebui_openwebui_open-webui
它太长了,看着就容易删错。原因倒不复杂,Docker Compose 会按下面这个规则给卷加前缀:
项目名_卷名
原来的卷名里已经带了 openwebui,再被 compose 项目名套一层,就成了这串东西。后来我把 compose 里的 volume 改成显式命名:
services:
open-webui:
image: ghcr.io/open-webui/open-webui:latest
container_name: openwebui
ports:
- "127.0.0.1:3000:8080"
volumes:
- open-webui:/app/backend/data
volumes:
open-webui:
name: open-webui
driver: local
管用的是:
name: open-webui
这样 Docker 最后创建出来的卷就叫 open-webui,不会再自动变成 openwebui_open-webui。
/var/lib/docker/volumes/ 下面不是普通文件夹管理区。Docker 自己有元数据,直接改目录名不等于改 volume 名,反而可能让容器找不到数据。
改完以后,数据位置就清楚了:
容器内:/app/backend/data 宿主机:/var/lib/docker/volumes/open-webui/_data
这步本身没什么技术含量,但后面少了很多疑神疑鬼。要删东西时,先知道自己正在碰哪个卷。
uploads 空了,文件列表还在
卡住我的其实是文件管理。
我先删了上传目录:
#rm -rf /var/lib/docker/volumes/open-webui/_data/uploads/*然后打开 Open WebUI,文件列表里还是一堆 generated-image.png。有 png,也有 gif,日期全是今天。
那一刻很容易怀疑自己删错了。于是开始查:
docker inspect openwebui --format '{{range .Mounts}}{{println .Name "->" .Destination}}{{end}}'
确认结果没问题:
open-webui -> /app/backend/data
也就是说,容器确实用的是这个卷,路径也没错。问题不在目录。
后来才想明白:Open WebUI 的文件列表不是现扫 uploads/ 得来的。uploads/ 只是实体文件,UI 读的是数据库里的文件记录。文件没了,数据库还记着,界面当然继续显示。
- 删目录
删
uploads/,实体图片没了。- 查挂载
查 volume,确认容器确实挂着
open-webui。- 查数据库
进正在运行的容器,直接查
/app/backend/data/webui.db。
最后定位问题靠的是这条:
docker exec -i openwebui python - <<'PY'
import sqlite3
con = sqlite3.connect("/app/backend/data/webui.db")
cur = con.cursor()
cur.execute("SELECT COUNT(*) FROM file")
print("file", cur.fetchone()[0])
cur.execute('SELECT id, filename, path FROM "file" ORDER BY created_at DESC LIMIT 5')
for row in cur.fetchall():
print(row)
con.close()
PY
输出里很直接,file 表里就是那些 generated-image.png。路径也都指向:
/app/backend/data/uploads/xxx_generated-image.png
到这里就不用再猜了。界面上的残留在 webui.db 的 file 表里。
别再绕临时容器
我前面绕了几次临时容器,又是 main 镜像,又是 latest 镜像,还要手动挂 volume。能做,但没必要。
后面我换了思路:既然 UI 是当前这个容器跑出来的,那就进这个容器查库。它正在用哪个数据库,我就处理哪个数据库。
docker exec -i openwebui python - <<'PY'
import os, shutil, sqlite3
db = "/app/backend/data/webui.db"
con = sqlite3.connect(db)
cur = con.cursor()
cur.execute("PRAGMA foreign_keys=OFF")
for table in ["channel_file", "chat_file", "knowledge_file", "document", "file"]:
cur.execute("SELECT name FROM sqlite_master WHERE type='table' AND name=?", (table,))
if cur.fetchone():
cur.execute(f'SELECT COUNT(*) FROM "{table}"')
print("before", table, cur.fetchone()[0])
cur.execute(f'DELETE FROM "{table}"')
print("cleared", table)
con.commit()
con.execute("VACUUM")
con.close()
for p in ["/app/backend/data/uploads", "/app/backend/data/vector_db"]:
if os.path.isdir(p):
shutil.rmtree(p)
os.makedirs(p, exist_ok=True)
print("cleared", p)
print("done")
PY
然后重启:
#docker restart openwebui这次再进文件管理,空了。
它不需要猜 volume,不需要新拉镜像,也不需要关心临时容器用 main 还是 latest。它直接进当前正在跑的容器,处理当前容器正在用的 /app/backend/data/webui.db。
cache 不能乱删
文件清完以后,我又顺手踩了另一个坑。
我之前把 /app/backend/data/cache 也清了。结果 Open WebUI 启动时开始报:
Cannot find an appropriate cached snapshot folder Network is unreachable No embedding model is loaded
这不是文件管理残留,而是 RAG 的 embedding 模型缓存没了。
Open WebUI 默认会找这个模型:
sentence-transformers/all-MiniLM-L6-v2
我当时 compose 里配了:
RAG_EMBEDDING_MODEL_AUTO_UPDATE=false
一开始我以为这就是“不下载模型”。其实不是。它更接近“不自动更新模型”。本地缓存还在时,Open WebUI 可以直接用;缓存被删了,它还是得找模型。找不到,又连不上 HuggingFace,就启动失败。
最后是用镜像源重新下载了一次:
docker run --rm \
-e HF_ENDPOINT=https://hf-mirror.com \
-e HF_HUB_OFFLINE=0 \
-v open-webui:/data \
--entrypoint python \
ghcr.io/open-webui/open-webui:latest - <<'PY'
from huggingface_hub import snapshot_download
snapshot_download(
repo_id="sentence-transformers/all-MiniLM-L6-v2",
cache_dir="/data/cache/embedding/models",
local_files_only=False,
)
print("done")
PY
看到日志里出现这两行,我才放心:
Loading weights: 100% Started server process
以后我不会再把 cache 当垃圾目录清了。
清文件时处理 uploads、vector_db 和数据库里的文件表就够了。cache 里可能有 embedding 模型,删掉以后还要重新下载。
我为什么绕了一圈
回头看,问题不算复杂。我绕路,是因为一开始把几件事混在了一起。
uploads/里放的是实体文件。webui.db的file表决定文件管理里显示什么。chat_file、knowledge_file、channel_file是关联表,也要一起清。vector_db是知识库向量数据。cache里可能有 RAG 模型,不该顺手删。
这次最有用的教训其实很土:能 docker exec 就别在外面猜。
查挂载:docker inspect openwebui 查文件表:docker exec openwebui python 清记录:DELETE FROM file 清实体:uploads 清向量:vector_db 保留模型:cache
这些命令不优雅,但排障时优雅不重要。少猜一次路径,少拉一次不相关镜像,比什么都强。
留一份短记忆
最后我把配置写到本地:
C:\Users\Mius\Desktop\项目1\openwebui\openwebui-config.md
里面只记几行:
容器名称:openwebui 镜像:ghcr.io/open-webui/open-webui:latest 端口:3000 -> 8080/tcp Volume:open-webui 数据目录:/var/lib/docker/volumes/open-webui/_data
这类东西写太多反而没用。以后真出问题,能马上看到容器名、卷名和数据目录就够了。
今天这事像整理抽屉。文件本体是纸,数据库记录是索引卡。纸扔了,索引卡还在,柜台当然还说有货。
下次再清 Open WebUI,我会先看两处:容器到底挂着哪个 volume,UI 这块数据到底是从目录读,还是从数据库读。
至于 cache,以后我会单独看待。它不是垃圾桶,里面可能有模型。先确认,再动手。省时间,也省火气。
评论区
评论加载中...