Directus AI 的 files 工具:文件元数据 CRUD 与远程文件导入实战指南
【免费下载链接】directusThe flexible backend for all your projects 🐰 Turn your DB into a headless CMS, admin panels, or apps with a custom UI, instant APIs, auth & more.项目地址: https://gitcode.com/GitHub_Trending/di/directus
导读
在 Directus 的 AI Agent / MCP 能力体系中,files是面向「文件资产」的核心工具:它允许 AI 在不接触二进制内容的前提下,查询文件元数据、批量更新标题与描述、维护标签与焦点坐标,以及从外部 URL 直接导入远程文件。本指南以 files 工具提示词 为主干,结合其 工具实现、Schema 定义 与 FilesService 服务层 源码,系统讲解files工具的四个动作(read/update/delete/import)、全部元数据字段、真实业务用法与底层调用原理,帮助你掌握在 Directus 中构建「内容素材管理」「资产清洗归档」「远程图片入库」等 AI 工作流的具体方法。
工具定位:什么是 Directus AI 的 files 工具
files是 Directus 面向 AI 暴露的一组工具之一,与collections、fields、items、folders、schema、relations等并列,统一在 AI 工具入口 中注册导出。它在代码中的完整定义为:
export const files = defineTool({ name: 'files', description: 'Reads and changes Directus file metadata or imports remote files. Use for uploads, media metadata, folders, titles, and file records.', instructions: requireText(resolve(__dirname, './prompt.md')), keywords: ['media', 'upload', 'import', 'asset metadata', 'attachments', 'documents'], annotations: { title: 'Directus - Files', destructiveHint: true, }, inputSchema: FilesInputSchema, validateSchema: FilesValidateSchema, output: FilesOutputSchema, readOnly: (input) => input.action === 'read', // ... });从源码可以看出几个关键设计点(见 工具实现):
- 工具名固定为
files,供 Agent 在注册表中通过execute({ name: "files", input })精确调用(工具分发逻辑见 registry.ts)。 - 提示词即指令:上面这份
prompt.md通过requireText原样加载为工具的instructions,它是引导大模型正确构造请求参数的「行为说明书」。 readOnly是一个函数:当action === 'read'时该调用被判定为只读,从而可能跳过耗时的审批流程;其余写操作(update/delete/import)被标记为需要额外确认。工具的 MCP annotations 中destructiveHint: true也提示消费方「该工具可能造成破坏」。
要理解files的运行边界,还需知道整个工具注册表的执行模型:
- Agent 先用根工具
search发现并加载工具详情,再用根工具execute真正执行(工具详情中会包含此处加载的instructions,见 registry.ts); - 如果调用上下文设置了
allowDeletes === false,任何action: 'delete'都会直接被拒绝并抛出InvalidPayloadError({ reason: 'Delete actions are disabled' })(见 registry.ts); - 执行前请求参数会先经过 Zod
validateSchema校验、再由isToolCallApproved决定是否需要用户批准(见 registry.ts); - 每个工具内部使用
new FilesService({ schema, accountability })操作directus_files集合,因此完整遵循 Directus 的权限系统(accountability 即当前登录用户上下文)。
支持的动作:read / update / delete / import
根据 files 工具提示词 及 Schema 定义 中的 discriminated union,工具按顶层action字段区分四种操作:
| action | 用途 | 必填参数 |
|---|---|---|
read | 按 query 列出/查询元数据,或按 keys 获取指定文件 | keys(可选)或query(可选),二选一 |
update | 修改已有文件的元数据 | data(对象或数组)+keys或query之一 |
delete | 按 keys 删除文件(含元数据与底层存储文件) | keys(必填,数组) |
import | 从 URL 导入远程文件并创建/更新其元数据 | data(数组,每项含url与file) |
对应地,工具实现 的handler将四种动作分别映射到 FilesService 的方法调用链上:
read:有keys时调用service.readMany(keys, sanitizedQuery);否则调用service.readByQuery(sanitizedQuery),最终返回{ type: 'text', data };update:按data形态分流——data为数组走service.updateBatch(data)(批处理,每个元素必须含id);data为对象且提供keys走service.updateMany(keys, data);两者皆无则按query定位走service.updateByQuery(sanitizedQuery, data)。更新成功后统一回读readMany(updatedKeys)作为返回值;delete:调用service.deleteMany(args.keys)并返回被删除的主键列表;import:对data数组中的每一项循环调用service.importOne(file.url, file.file),收集保存后的主键返回。
所有涉及查询的动作都会先经buildSanitizedQueryFromArgs把 AI 构造的查询对象清洗、校验为 Directus 标准 Query,与 REST/GraphQL 走的查询管线保持一致(见 utils.ts)。
操作示例详解
下面完整继承提示词中的四类典型调用。
1. 读取文件元数据(批量查询)
{ "action": "read", "query": { "fields": ["id", "title", "type", "filesize", "width", "height"], "filter": { "type": { "_starts_with": "image/" } }, "limit": 10 } }含义:只返回图片类文件(MIME 以image/开头)的 6 个字段,最多 10 条。query支持完整 Directus 查询能力,包括fields、filter、limit、offset、page、sort、search、deep、alias、aggregate、groupBy等,全部字段可参考 QueryInputSchema。
2. 读取单个文件元数据(按主键)
{ "action": "read", "keys": ["file-uuid-here"] }keys必须是数组(["item"]而非"item"),元素为主键(string 或 number,见 PrimaryKeyInputSchema)。同时省略query与keys时,等价于不带任何条件地读取整个文件集合。
3. 通过 URL 导入文件
{ "action": "import", "data": [ { "url": "file-url", "file": { "title": "New Title", "description": "Updated description", "tags": ["tag1", "tag2", "category"], "folder": "folder-uuid" } } ] }url为要抓取的远程文件地址,file为导入后要写入的元数据(支持FileItemInputSchema任意子集)。可一次传入多条记录批量导入。在底层,每次导入都会调用 FilesService 的importOne(见 files.ts),其核心逻辑为:
- 先做访问校验(
validateAccess,要求当前 accountability 对directus_files具备create权限); - 通过 axios 以
stream方式请求该 URL,失败则抛ServiceUnavailableError(错误码服务名external-file); - 从响应的最终重定向地址解析出文件名、从
content-type解析 MIME; - 依次校验全局 MIME 白名单(环境变量
FILES_MIME_TYPE_ALLOW_LIST)与字段级 MIME 限制,不合规则抛InvalidPayloadError。
提示:这里的“文件元数据导入”不等同于本地文件上传。如果你需要让 AI 读取已上传文件的图像内容,应配合提示词中提到的
assets工具获取 base64 内容后再做视觉分析。
4. 更新文件元数据
单个文件(按 keys + 对象 data):
{ "action": "update", "keys": ["file-uuid"], "data": { "title": "New Title", "description": "Updated description", "tags": ["tag1", "tag2", "category"], "folder": "folder-uuid" } }批量更新(data 为带 id 的数组):
{ "action": "update", "data": [ { "id": "file-uuid-1", "title": "New Title 1" }, { "id": "file-uuid-2", "title": "New Title 2" } ] }当data是数组时,其每个元素必须携带id,走updateBatch路径;这与仅按keys定位的“同一条更新作用于多个 key”是两种不同的语义,实际对应测试用例可参见 files 工具测试,其中分别验证了 keys 单对象、批量数组两种更新方式分别命中updateMany与updateBatch。
5. 常用组合过滤器
{ "query": { "filter": { "_and": [ { "type": { "_icontains": "/png" } }, // PNG 文件 { "folder": { "_eq": "folder-uuid" } }, // 指定文件夹 { "filesize": { "_lt": 5000000 } }, // 小于 5MB { "uploaded_on": { "_gte": "$NOW(-7 days)" } } // 最近一周上传 ] } } }要点:
- Directus 过滤器运算符均可用(
_eq、_starts_with、_icontains、_lt、_gte、_null等); _and/_or用于组合多个条件;- 时间字段支持
$NOW(...)这类相对时间动态值,如上例的“最近 7 天”; - 注意
_icontains的子串不包含前导点,匹配/png而不是image/png的"image/"段,可同时命中image/png等具体子类型。
文件元数据字段清单
提示词完整列出了directus_files的可写/可查元数据字段(这些字段与 FileItemInputSchema 基本一一对应,schema 还额外覆盖了charset、embed、tus_id、tus_data等内部字段):
| 字段 | 含义 |
|---|---|
id | 唯一标识符 |
storage | 使用的存储适配器(local / s3 / gcs…) |
filename_disk | 磁盘上的实际文件名 |
filename_download | 建议下载文件名 |
title | 展示标题 |
type | MIME 类型(如image/jpeg、application/pdf) |
folder | 父文件夹 ID |
uploaded_by | 上传用户 |
uploaded_on | 上传时间戳 |
modified_by | 最后修改者 |
modified_on | 最后修改时间 |
filesize | 字节数 |
width/height | 图片像素尺寸 |
duration | 音视频时长 |
description | 文件描述 |
location | 地理位置数据 |
tags | 标签字符串数组(如["product", "red", "handbag"]) |
metadata | 附加元数据对象 |
focal_point_x | 水平焦点(距左边缘的像素值) |
focal_point_y | 垂直焦点(距顶部边缘的像素值) |
特别说明:keys与tags都必须以数组形式传递(["item"]而非"item"),这也是提示词「Key Points」中的硬性要求;否则会在参数校验阶段被 Zod schema 拒绝。
真实业务场景:从素材检索到资产治理
提示词为files工具规划了两大类实际用途,下面完整展开并补充实现层面的解读。
场景一:为内容选择合适素材(Asset Selection for Content)
典型诉求:“在我们的素材库里,为新的帮助中心文章找出与客户支持相关的图片。”
{ "action": "read", "query": { "fields": ["id", "title", "description", "tags", "type"], "search": "help center" } }search会对多个文本字段做模糊匹配,是最轻量的全文检索手段。对于海量素材,可配合filter先缩小范围(如type、folder),再结合fields控制返回体积,避免把大文件二进制拉入上下文。
场景二:素材组织与清洗(Asset Organization & Cleanup)
把一堆无元数据的文件变成可检索、可分类的资产,三步走:
① 找出缺失描述的文件:
{ "action": "read", "query": { "fields": ["id", "filename_disk", "title", "description"], "filter": { "description": { "_null": true } } } }② 用视觉分析内容:如需理解图片语义,可调用assets工具获取图片的 base64 数据,交给视觉模型生成标题、描述与标签。
③ 回写结构化元数据:
{ "action": "update", "keys": ["image-uuid"], "data": { "title": "Red leather handbag product photo", "description": "Professional e-commerce photo with white background", "tags": ["handbag", "leather", "red", "product-photo", "accessories"], "focal_point_x": 512, "focal_point_y": 300 } }提示词特别注解了焦点坐标的意义:当图片被裁剪成不同宽高比(缩略图、横幅图等)时,focal_point_x/focal_point_y能确保重要主体始终处于可视区域,坐标以原图左上角为原点、单位为像素。为图片写入准确焦点是电商、新闻类项目保证“自动裁剪不裁掉主体”的关键元数据资产。
上述「查缺失 → 分析 → 回写」是一个可由 Agent 自主循环的经典流程:read是只读操作(readOnly: action === 'read'),而update触达写路径并经由工具注册表进入审批/权限流程,形成「批量只读侦察 + 单点人工确认写回」的安全模式。
Key Points:调用 files 工具必须遵守的约定
以下五条约束来自 提示词 的 Key Points,是让 AI 调用稳定成功的关键:
- 始终以原生对象传参:
data、query、filter必须是对象/数组结构,不要传字符串化(stringified)的 JSON。实现侧,注册表在执行前会用coerceJsonFields做一次宽松的类型纠正,再用 Zod 严格校验(见 registry.ts),传字符串化 JSON 极易在strictObject校验处失败。 - 只管理元数据,不处理内容:
files工具负责文件记录与元数据,二进制上传不在其职责范围;真正的上传走 Directus Files API/界面。 - 遵守权限:所有操作在 FilesService 内部执行,会基于当前
accountability做访问校验(如importOne中的validateAccess要求create权限),Agent 权限不会越过用户权限。 - 数组参数:
keys和tags必须为数组形式。 - 性能:大文件会被自动流式处理,但导入/读取超大文件仍可能影响整体性能,应限制导入并发与单次查询量。
从源码看整体调用链:一次 files 调用发生了什么
把上面的信息串起来,一次完整调用在 Directus 中经过的链路为(可对照 工具实现、registry.ts、FilesService 阅读):
- Agent(MCP/聊天等场景)通过根工具
execute以{ name: "files", input: { action, query/keys/data } }发起调用; MountedToolRegistry.execute按名找到工具,先执行validateSchema.safeParse做 Zod 校验(同时受allowDeletes、isToolCallApproved门控,见 registry.ts);- 进入
files.handler,实例化携带当前用户上下文的FilesService; - 依据
action分流到readMany/readByQuery/updateBatch/updateMany/updateByQuery/deleteMany/importOne; - 返回
{ type: 'text', data },若数据为单条且配置了PUBLIC_URL,注册表还会通过工具的endpoint为其拼接管理后台详情页 URL(#addUrl与buildURL,见 registry.ts 与 工具实现),方便用户直接跳转到后台核对记录。
测试覆盖与验证
想要验证你对files行为的理解,可直接运行仓库中已有的单元测试:files 工具测试 使用 vitest + 对FilesService的 mock,覆盖了四类关键断言:
- read by keys:验证
read+keys会以(keys, {})调用readMany; - update 两种形态:keys + 对象 data →
updateMany;数组 data →updateBatch; - delete:
delete+ keys →deleteMany(keys)并返回 keys; - Schema 可接受性:对
FilesValidateSchema.safeParse分别验证对象 data、数组 data 两种更新负载均通过校验; - 非法动作:
action: 'invalid'会抛出Invalid action.异常; - 工具配置:工具名称为
files、非 admin 工具、description 与 input/validate schema 均已定义。
在本地开发调试时,可以vitest run api/src/ai/tools/files/index.test.ts单独执行该测试文件,作为理解工具行为与回归验证的入口。
总结
files工具的价值在于把 Directus 强大的文件资产管理能力封装成一个语义清晰、参数校验严格的 AI 函数式接口:对 Agent 而言它是一份自带 Zod 契约的「元数据操作说明书」,对人类开发者而言它是通往 FilesService 数据管线的桥梁。掌握read/update/delete/import四种动作的语义边界、记住「数组参数、原生对象、元数据优先」三条铁律,再结合 Directus 的权限与 MIME 白名单机制,你就可以在聊天、MCP 或自定义 Agent 中安全地搭建素材检索、资产清洗、远程取图入库等自动化工作流。
【免费下载链接】directusThe flexible backend for all your projects 🐰 Turn your DB into a headless CMS, admin panels, or apps with a custom UI, instant APIs, auth & more.项目地址: https://gitcode.com/GitHub_Trending/di/directus
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考