
Directus AI Operations 工具深度解析Flow 操作的 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 模块的operations工具指令文件 prompt.md 为主体完整讲解 AI Agent 对 Directus Flow 操作Operations执行 CRUD 的方法、必须遵守的关键语法规则、各内置操作类型的配置示例并结合 工具实现源码、OperationsService 与 FlowManager 的执行链路说明这些规则背后对应的真实运行时行为。读完本文你将能够准确使用 UUID 与 key 构建操作链、掌握每种操作的options配置写法、规避文档列举的 11 类常见错误并理解 flow 引擎如何按resolve/reject链调度操作、把结果写入数据链。一、operations 工具是什么AI 对 Flow 操作的 CRUD 入口Directus 的 Flows 是自动化引擎由事件、计划、Webhook 等触发器驱动若干Operations操作顺序执行。Operations 是 flow 的构建块每个操作是一个独立动作在 flow 中按顺序执行通过数据链data chain对数据进行加工与传递。在 AI 模块中operations工具就是让 LLM 能够读取和修改 Directus 中的 flow 操作、构建或检查自动化流程中的操作链的专用工具。它定义在 api/src/ai/tools/operations/index.ts工具名operations标记admin: true仅管理员可用readOnly仅在action read时成立其余三个动作create/update/delete被标记为destructiveHint: trueinstructions字段通过requireText(resolve(__dirname, ./prompt.md))加载本文的指令文件 prompt.md也就是说这份 Markdown 就是喂给模型的操作手册搜索关键词为flow steps、automation steps、data chain、resolve、reject、operation key用于工具路由时匹配用户意图。其 Zod 校验模式OperationsValidationSchema是一个按action字段区分的可辨识联合只允许create/read/update/delete四种动作分别对应不同的必填参数组合// 摘自 api/src/ai/tools/operations/index.ts export const OperationsValidationSchema z.discriminatedUnion(action, [ z.strictObject({ action: z.literal(create), data: OperationItemValidateSchema }), z.strictObject({ action: z.literal(read), query: QueryValidateSchema.optional() }), z.strictObject({ action: z.literal(update), data: OperationItemValidateSchema, key: z.string(), query: QueryValidateSchema.optional() }), z.strictObject({ action: z.literal(delete), key: z.string() }), ]);从源码结构看四种动作最终都委托给 OperationsService该服务继承自ItemsServiceOperationRaw并绑定系统表directus_operations每次createOne/updateMany/deleteMany成功后都会调用getFlowManager().reload()触发 flow 引擎重新加载保证数据库中的改动立即反映到运行中的 flow 定义上。二、核心概念操作、key 与 resolve/reject 链路指令文件的key_concepts部分定义了四个关键概念这是理解整个工具的基石Operations是 flow 的构建块每个操作有一个唯一的key用于在数据链中标识它操作之间通过resolve成功路径与reject失败路径相互连接每个操作的执行结果都会以它的 key 为名称存入数据链。UUID 与 key 的关键区别指令文件用专门的uuid_vs_keys小节强调二者是关键区别混用是最常见的失败原因UUID系统标识符形如abc-123-def-456使用场景resolve、reject、flow字段以及 CRUD 中的操作key字段即操作的主键注意此处key 字段指的是directus_operations表的主键 UUID而非下面的人工命名 key创建操作时自动生成连接操作构建 resolve/reject 链时必须使用。Keys人类可读名称形如send_email、check_status使用场景数据链变量{{ operation_key }}由你在创建操作时自行定义用于在后续操作中访问前序操作的结果。这个双命名设计在 flow 执行引擎中得到了印证。api/src/flows.ts 中executeFlow的主循环以flow.operation入口操作的 UUID为起点每执行一步就把结果按nextOperation.key写入keyedData再沿operation.resolve/operation.reject指针跳转到下一个操作——也就是说UUID 负责图结构连接key 负责数据链寻址两者分工明确不可互换。// 数据链寻址示意结果以 key 存入数据链 // keyedData[nextOperation.key] data // flows.ts#L420关键语法规则必须牢记指令文件的critical_syntax小节列出四条记忆级规则每条都给出错误与正确写法对照1. 条件过滤器使用嵌套对象绝不能用点号路径错误$trigger.payload.status正确{$trigger: {payload: {status: {_eq: published}}}}2. Request 请求头对象数组不是普通对象错误{Authorization: Bearer token}正确[{header: Authorization, value: Bearer token}]这一写法与 request 操作的实现 完全一致其Options类型定义为headers?: { header: string; value: string }[] | nullhandler 内部通过reduce把数组折叠成真正的 headers 对象交给 axios若未显式指定Content-Type且 body 是对象或合法 JSON 字符串则自动补上application/json。3. Request Body字符串化 JSON不是原生对象错误body: {data: value}正确body: {\data\: \value\}4. 数据链变量使用操作 key避免$last错误{{ $last }}flow 顺序调整后会失效正确{{ operation_key }}可靠从 flows.ts 源码 可以看到数据链内置变量确有$trigger、$accountability、$last、$env四个保留键TRIGGER_KEY/ACCOUNTABILITY_KEY/LAST_KEY/ENV_KEY$last会在每一步执行后刷新为最近一次结果keyedData[LAST_KEY] data因此一旦 flow 中途插入新操作$last指代的对象就变了——这正是文档要求优先使用{{ operation_key }}的原因。而$env的内容受FLOWS_ENV_ALLOW_LIST环境变量白名单控制flows.ts#L80只有白名单内的环境变量才能通过{{ $env.XXX }}在流程中引用。三、必填字段与 CRUD 四种动作必填字段一览指令文件的required_fields部分规定所有操作都必须具备的字段字段说明flow所属父 flow 的 UUIDkey操作的唯一标识符人类可读名称type操作类型position_x/position_y网格坐标resolve/reject成功/失败后下一个操作的 UUID初始为 nullread- 列出 flow 中的操作{ action: read, query: { fields: [id, name, key, type, flow, resolve, reject], filter: { flow: { _eq: flow-uuid } }, sort: [position_x, position_y] } }create- 向 flow 添加操作{ action: create, data: { flow: flow-uuid, // 必填操作所属 flow key: notify_user, // 必填操作唯一 key type: notification, // 必填操作类型 name: Send Notification, // 可选显示名称 position_x: 19, // 必填网格 X 坐标取 19, 37, 55, 73... position_y: 1, // 必填网格 Y 坐标取 1, 19, 37... options: { // 可选按操作类型定制的配置默认 {} }, resolve: null, // 必填成功后的下一操作 UUID初始 null reject: null // 必填失败后的下一操作 UUID初始 null } }update- 修改操作{ action: update, key: operation-uuid, data: { options: { // 更新后的配置 }, resolve: operation-uuid-here } }delete- 删除操作{ action: delete, key: operation-uuid }需要强调update/delete中的key参数传的是操作的主键 UUIDOperationRaw的主键而不是数据链用的notify_user这类命名 key。这一点在 operations 工具 handler 中可以直接验证updateOne(args.key, ...)与deleteOne(args.key)都是按主键定位记录。工作流创建顺序workflow_creation小节给出了构建完整自动化流程的关键顺序先创建 flow创建操作resolve/reject初始置为 null通过 UUID 把各操作连接起来最后更新 flow 的入口操作flow.operation。指令文件同时注明完整的工作流示例与详细步骤请见flows工具对应仓库中的 flows/prompt.md 与 flows 工具实现。这与执行引擎一致executeFlow从flow.operation入口操作 UUID开始遍历flows.ts#L407如果该字段未设置流程将无处启动——这也是下文不执行排障的第一检查项。网格定位系统positioning_system小节规定坐标规则规则每个节点占 14x14 单位按 18 单位间隔排布示例19 / 37 / 55 / 73禁止 (0,0)起始position_y: 1布局模式线性布局 (19,1) → (37,1) → (55,1)分支布局时成功路径放 (37,1)失败路径放 (37,19)。四、可用操作类型与配置示例指令文件的available_operations小节列出 Directus 内置的 15 种操作与仓库 api/src/operations 目录下的 15 个子目录一一对应condition、exec、item-create、item-read、item-update、item-delete、json-web-token、log、mail、notification、request、sleep、throw-error、transform、trigger。若安装了 Marketplace 扩展还可能有更多操作——可用read动作查看现有操作是否引用了扩展类型。condition - 求值过滤规则决定执行路径{ type: condition, options: { filter: { $trigger: { payload: { status: { _eq: published } } } } } } // 多条件{_and: [{status: {_eq: published}}, {featured: {_eq: true}}]}item-create / item-read / item-update / item-delete - 数据表 CRUD{type: item-create, options: {collection: notifications, permissions: $trigger, payload: {title: {{ $trigger.payload.title }}}}} {type: item-read, options: {collection: products, query: {filter: {status: {_eq: active}}}}} {type: item-update, options: {collection: orders, key: {{ $trigger.payload.id }}, payload: {status: processed}}} {type: item-delete, options: {collection: temp_data, key: [{{ read_items[0].id }}]}}exec - 沙箱内执行自定义 JavaScript/TypeScript沙箱环境无文件系统与网络访问{ type: exec, options: { code: module.exports async function(data) {\n const result data.$trigger.payload.value * 2;\n return { result, processed: true };\n} } }注意code是少数必须以字符串而非原生对象传入的字段见第八节第 10 条。mail - 发送邮件markdown/wysiwyg/template 三种模式{ type: mail, options: { to: [userexample.com], subject: Order Confirmation, body: Order {{ $trigger.payload.order_id }} } } // 模板模式{type: template, template: welcome-email, data: {username: {{ $trigger.payload.name }}}}notification - 站内通知{ type: notification, options: { recipient: [{{ $accountability.user }}], subject: Task Complete, message: Export ready } }request - 对外发起 HTTP 请求请求头必须是对象数组、body 为字符串化 JSON前文已说明原因{ type: request, options: { method: POST, url: https://api.example.com/webhook, headers: [{ header: Authorization, value: Bearer {{ $env.API_TOKEN }} }], body: {\data\: \{{ process_data }}\} } }实现侧operations/request/index.ts补充了文档未展开的两个行为细节请求体若未声明Content-Type且可解析为 JSON会自动补application/jsonHTTP 层报错如 4xx/5xx 响应会被序列化为包含status/statusText/headers/data的 JSON 字符串抛出从而进入该操作的reject链路。json-web-token - 签名/验证/解码 JWT{ type: json-web-token, options: { operation: sign, payload: { userId: {{ $trigger.payload.user }} }, secret: {{ $env.JWT_SECRET }}, options: { expiresIn: 1h } } } // 验证{operation: verify, token: {{ $trigger.payload.token }}, secret: {{ $env.JWT_SECRET }}}transform - 构造自定义 JSON 负载{ type: transform, options: { json: { combined: { user: {{ $accountability.user }}, items: {{ read_items }} } } } }trigger - 调用另一个 flow{ type: trigger, options: { flow: flow-uuid, payload: { data: {{ transform_result }} }, iterationMode: parallel } }sleep / log / throw-error - 工具类操作{type: sleep, options: {milliseconds: 5000}} {type: log, options: {message: Processing {{ $trigger.payload.id }}}} {type: throw-error, options: {code: CUSTOM_ERROR, status: 400, message: Invalid data}}五、数据链变量、权限选项与日志脱敏data_chain_variables小节总结数据链的用法用{{ operation_key }}访问前序操作的结果用{{ $trigger.payload }}访问触发器数据避免使用{{ $last }}重排后失效完整语法见flows工具。结合 flows.ts#L394-L403数据链初始包含四个保留键$trigger触发器数据payload meta$accountability当前执行上下文用户、角色、admin 状态等$last最近一次操作结果每步刷新勿依赖;$env受FLOWS_ENV_ALLOW_LIST白名单过滤后的环境变量。此外从 flows.ts 执行循环 可以看到两个容易被忽略的实现事实每个操作的结果会先做JSON.stringify校验保证可序列化否则错误在流程内被捕获随后undefined值会被递归替换为null——因为 JSON 结构不允许undefined否则下一步的applyOptionsData模板插值无法正常工作。permission_options小节规定支持permissions选项的操作如 item 系列的取值$trigger- 使用触发上下文的权限默认$public- 使用 public 角色权限$full- 使用完整系统权限role-uuid- 使用指定角色的权限。一个值得注意的配套细节log操作在接收数据链数据前会经过redactObject脱敏flows.ts#L529-L551headers.authorization、payload.password、各类 API key 等敏感字段会被替换为占位符再输出因此在流程中打日志不会意外泄露令牌。六、11 条常见错误清单指令文件的common_mistakes小节是全文浓缩的避坑指南逐条对应构建 flow 时的典型翻车点先建 flow绝不在没有 flow 的情况下建操作——flow字段外键约束决定了这一点resolve/reject中使用UUID不是 key先创建操作再去引用它——否则引用一个不存在的 UUID同一 flow 内key 不可重复避免 resolve/reject 成环必须设置坐标不能是 (0,0)过滤器中用嵌套对象不用点号路径request 请求头用对象数组body 用字符串化 JSONdata中一律传原生对象除 request body 外再次强调data中必须传原生对象仅有的两个例外是request操作的 body 与exec操作的code不存在$NOW变量——需要当前时间请用 exec 操作return { now: new Date().toISOString() };七、故障排查速查表指令文件troubleshooting小节给出三类典型症状与处置方式症状原因与处理Invalid foreign key无效外键引用的操作 UUID 不存在。UUID 固定 36 位字符且必须使用 UUID 而非 key被引用的操作必须先创建流程不执行检查 resolve/reject 链路是否连续、确认flow.operation入口已设置、确认所有必填 options 已提供节点重叠在 (0,0)用 update 修正坐标{action: update, key: uuid, data: {position_x: 19, position_y: 1}}流程不执行的排查项与引擎实现逐条对应executeFlow从flow.operation起步若为 null 则 while 循环根本不进入flows.ts#L407-L426而executeOperation在找不到operation.type对应 handler 时只会打一条Couldnt find operation ...警告并返回unknown状态终止flows.ts#L519-L523——这提示排查装了扩展操作但 API 侧不可见时应核对操作类型是否在 api/src/operations 注册列表中。八、从指令文件到执行引擎一次完整调用链把本文涉及的仓库证据串起来AI Agent 通过operations工具修改一个操作后的完整链路是模型按 prompt.md 的语法规则生成{ action: update, key: uuid, data: { ... } }参数operations 工具 的OperationsValidationSchema做严格结构校验z.strictObject拒绝多余字段read动作的查询会经buildSanitizedQueryFromArgs按权限清洗OperationsService绑定directus_operations表完成落库并调用flowManager.reload()发布flows总线消息FlowManager 收到 reload 事件后先unload()解绑事件监听、停止定时任务、清空 flow 与 handler 缓存再load()重建全部触发器与操作 handler下一次触发发生时executeFlow从入口操作开始沿resolve/reject指针逐步执行每步结果按操作 key 写入数据链并刷新$last最终按 flow 的return选项如$all返回整个数据链或指定 key 路径产出结果。理解这条链路后指令文件中看似规定的每条规则都能找到对应的工程解释UUID 与 key 的区分来自图连接 vs 数据寻址的分工禁用$last源于其每步刷新的语义request 的头数组与字符串 body 源于操作实现的实际入参类型(0,0) 禁令与 18 单位网格则是可视化编辑器的排版约定。九、适用前提与限制本文所有语法与示例以当前仓库 api/src/ai/tools/operations/prompt.md 为准operations工具带admin: true标记仅管理员上下文可用且除read外均具有破坏性destructiveHint: true15 种内置操作类型以 api/src/operations 目录为准Marketplace 扩展可能引入额外类型可通过read动作检查现有流程是否使用了扩展操作{{ $env.XXX }}引用依赖服务端配置FLOWS_ENV_ALLOW_LIST白名单未加入白名单的环境变量在数据链中不可见更完整的 flow 定义触发器类型、入口设置、return选项请参见 flows/prompt.md它与本文的指令文件是配套的姊妹文档。【免费下载链接】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),仅供参考