Dify v1.15.0 Chatflow附件上传存储机制调研报告

Dify v1.15.0 Chatflow附件上传存储机制调研报告

一、文件上传完整流程

用户在 chatflow 中上传附件(图片、文档、视频、音频)时,流程如下:

bash 复制代码
用户上传文件 (multipart/form-data)
    │
    ▼
API Controller ── POST /files/upload
    ├── Web 应用:     api/controllers/web/files.py
    ├── Service API:  api/controllers/service_api/app/file.py
    └── Console:      api/controllers/console/files.py
    │
    ▼
FileService.upload_file()  ── api/services/file_service.py:43
    ├── 1. 校验扩展名黑名单 (UPLOAD_FILE_EXTENSION_BLACKLIST)
    ├── 2. 校验文件大小(按类型区分限制)
    ├── 3. 生成存储 key: upload_files/{tenant_id}/{uuid}.{ext}
    ├── 4. storage.save(key, content) → 写入存储后端
    ├── 5. 创建 UploadFile 数据库记录
    └── 6. 生成签名访问 URL (source_url)

二、文件存储在哪里?

存储后端类型

由环境变量 STORAGE_TYPE 控制,支持 13 种存储后端(storage_type.py):

类型 说明
opendal (默认) OpenDAL 统一存储,支持 fs/s3/azblob/gcs 等多种 scheme
s3 AWS S3
azure-blob Azure Blob Storage
aliyun-oss 阿里云 OSS
tencent-cos 腾讯云 COS
huawei-obs 华为云 OBS
google-storage Google Cloud Storage
volcengine-tos 火山引擎 TOS
oci-storage Oracle Cloud
supabase Supabase Storage
local (已废弃) 底层仍使用 OpenDAL fs scheme

存储路径

  • 逻辑路径upload_files/{tenant_id}/{uuid}.{extension}
  • Docker 本地存储物理路径./volumes/app/storage → 映射到容器内 /app/api/storage/
    • 完整路径示例:/app/api/storage/upload_files/{tenant_id}/{uuid}.jpg

数据库记录

文件信息记录在 upload_files 表中(api/models/model.py:2255),关键字段:

字段 说明
id UUID
tenant_id 租户 ID
storage_type 存储类型
key 存储路径
name 原始文件名
size 文件大小(字节)
extension / mime_type 文件类型
hash SHA3-256 哈希
source_url 签名访问 URL
created_at 创建时间

文件与消息的关联通过 message_files 表(api/models/model.py:1876)中的 upload_file_id 字段关联。

三、文件存储多久?是否会自动删除?

⚠️ 核心结论:上传的附件文件不会自动删除,会永久保留

Dify 没有 针对 upload_files 的 TTL/过期自动清理机制。具体分析:

1. clean_messages 定时任务 --- 只删数据库记录,不删文件

clean_messages.py 中的 clean_messages 任务(默认关闭 ,需 ENABLE_CLEAN_MESSAGES=true):

  • ✅ 删除 messages 表记录
  • ✅ 删除关联表记录:MessageFileMessageFeedbackMessageChainMessageAgentThought
  • 不删除 upload_files 表记录
  • 不删除 存储后端中的实际文件

关键代码(messages_clean_service.py:570-580):

python 复制代码
# _batch_delete_message_relations 方法中:
session.execute(delete(MessageFile).where(MessageFile.message_id.in_(message_ids)))
# ↑ 只删除 message_files 关联记录,不触碰 upload_files 表和存储
2. 其他定时任务也不涉及上传文件清理
任务 说明 删除存储文件?
clean_embedding_cache_task 清理 embedding 缓存
clean_unused_datasets_task 清理未使用的数据集
clean_workflow_runlogs_precise 清理 workflow 日志记录
mail_clean_document_notify_task 发送邮件通知
3. 唯一会自动删除文件的场景:删除 App

当删除整个 App 时,remove_app_and_related_data_task(remove_app_and_related_data_task.py)会级联删除关联的存储文件。

四、如何手动删除?

方法 1:通过 API 删除单个文件

FileService.delete_file()api/services/file_service.py:260):

python 复制代码
def delete_file(self, file_id: str):
    with self._session_maker() as session, session.begin():
        upload_file = session.scalar(select(UploadFile).where(UploadFile.id == file_id))
        if not upload_file:
            return
        storage.delete(upload_file.key)    # 删除存储中的实际文件
        session.delete(upload_file)         # 删除数据库记录

方法 2:删除整个 App(级联删除)

删除 App 时会自动清理该 App 关联的所有上传文件。

方法 3:直接操作存储和数据库

对于本地存储,可直接删除文件系统中的文件:

bash 复制代码
# Docker 环境
rm /app/api/storage/upload_files/{tenant_id}/{file_uuid}.{ext}

同时清理数据库记录:

sql 复制代码
DELETE FROM upload_files WHERE key = 'upload_files/{tenant_id}/{file_uuid}.{ext}';

五、相关环境变量/全局配置

存储配置

环境变量 默认值 说明
STORAGE_TYPE opendal 存储后端类型
OPENDAL_SCHEME fs OpenDAL scheme
OPENDAL_FS_ROOT storage 本地存储根目录
S3_ENDPOINT / S3_BUCKET_NAME / ... - S3 配置

文件上传限制

环境变量 默认值 说明
UPLOAD_FILE_SIZE_LIMIT 15 通用文件大小上限 (MB)
UPLOAD_IMAGE_FILE_SIZE_LIMIT 10 图片上限 (MB)
UPLOAD_VIDEO_FILE_SIZE_LIMIT 100 视频上限 (MB)
UPLOAD_AUDIO_FILE_SIZE_LIMIT 50 音频上限 (MB)
UPLOAD_FILE_BATCH_LIMIT 5 单次上传批量上限
WORKFLOW_FILE_UPLOAD_LIMIT 10 Workflow 上传文件数上限
UPLOAD_FILE_EXTENSION_BLACKLIST (空) 禁止上传的扩展名
FILES_ACCESS_TIMEOUT 300 签名 URL 过期时间(秒)

清理任务配置

环境变量 默认值 说明
ENABLE_CLEAN_MESSAGES false 启用消息清理任务(不删文件
SANDBOX_EXPIRED_RECORDS_RETENTION_DAYS - 消息保留天数
ENABLE_WORKFLOW_RUN_CLEANUP_TASK false 启用 workflow run 清理

六、总结

flowchart TD A[用户上传附件] --> B[FileService.upload_file] B --> C[存储到 STORAGE_TYPE 指定的后端] B --> D[记录到 upload_files 表] D --> E[关联到 message_files 表] C --> F["⚠️ 永久保留\n无自动清理"] D --> F G[clean_messages 定时任务] -->|仅删除| H[message_files 关联记录] G -.->|❌ 不删除| D G -.->|❌ 不删除| C I[手动删除方式] --> J[FileService.delete_file] I --> K[删除 App 级联删除] I --> L[直接操作存储+DB]
问题 答案
文件存储在哪里? STORAGE_TYPE 决定,默认 OpenDAL 本地文件系统 (/app/api/storage/upload_files/{tenant_id}/)
存储多久? 永久,没有 TTL 或过期机制
是否自动删除? clean_messages 任务只删消息数据库记录,不删上传文件
如何手动删除? FileService.delete_file(file_id) / 删除 App 级联删除 / 直接操作存储
全局变量控制? STORAGE_TYPE 控制存储位置;ENABLE_CLEAN_MESSAGES 控制消息清理(但不清理文件);各类 UPLOAD_* 控制上传限制

⚠️ 重要提示 :如果你需要自动清理上传的附件文件,目前 Dify 没有内置此功能 ,需要自行实现定时任务,扫描 upload_files 表中未被引用的记录并调用 storage.delete() 清理。

相关推荐
天辛大师15 小时前
天心大师:不确定中锚定自我,AI生活的哲学命题
人工智能·算法·决策树·机器学习·生活·启发式算法
冬奇Lab15 小时前
开源项目第174期:AirLLM — 4GB 显存跑 70B,8GB 跑 405B,3.7GB 跑 2.8 万亿参数的 Kimi K3
人工智能
雪隐16 小时前
个人电脑玩AI-15让5060 Ti给你打工——MiniMax H3 本地部署实录:一个自带录音棚的视频模型,和它的 NVFP4 瘦身奇遇
前端·人工智能·后端
数字供应链安全产品选型16 小时前
中国版 Anthropic Mythos,为何是悬镜安全?
人工智能·安全
甲维斯16 小时前
Qoder+Qwen3.8Max白嫖测试!这次真牛逼了?和K3比如何?
人工智能
一个数据大开发16 小时前
Skill、Tool、SOP、MCP 文章合集
大数据·人工智能·知识图谱
紫禁玄科16 小时前
公共WiFi流量安全全解析
网络·人工智能·web安全·网络安全·系统安全
梦想三三16 小时前
LangChain RAG PDF 智能问答实战:用 Streamlit 构建本地知识库(完整代码)
人工智能·python·langchain·大模型·rag
不加辣椒16 小时前
第11章:性能优化与成本控制
人工智能