ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Dify 中级实验(18):插件开发入门——如何把工作流变成 Agent 可调用的工具?

Dify 中级实验(18):插件开发入门——如何把工作流变成 Agent 可调用的工具? Dify 中级实验18插件开发入门——如何把工作流变成 Agent 可调用的工具Dify 实验系列 · 中级 18/20 | 实验编号DIFY-102-19基于 Dify 1.16.1 实测2026-081. 业务场景先讲一个我们实际遇到的场景。一家公司的内部 CRM 系统没有现成的插件销售团队的 AI 助手想查客户信息却查不了——模型只能闲聊一问「客户 1001 的订单情况」它就答「我无法访问你们的系统」。公司的 Agent 应用明明能力很强却因为接不上内部系统变成了一个高级聊天机器人。他们想过让开发团队写接口但排期要三周想过等官方插件但内部系统大概率永远不会有官方插件。我们第一次接这类需求时第一反应也是「等官方插件或者让开发排期写接口」。后来才想明白——内部系统大概率永远不会有官方插件等插件等于放弃好在 Dify 给了第三条路任何工作流发布即工具。这不是个例。任何「Agent 要对接公司内部系统」的场景都是这个模式查 CRM 客户、查 ERP 库存、查工单系统、查内部 Wiki——官方插件市场覆盖的是通用服务公司内部系统只能自己造工具。好在 Dify 给了答案任何工作流发布后都可以变成「自定义工具」被 Agent 自动发现和调用。2. 场景痛点这个场景的痛点在这家公司的销售 AI 助手项目上体现得最直接Agent 接不上内部系统模型能力再强没有工具就查不了数据Agent 对业务数据「睁眼瞎」销售问什么它都答不上来。等插件遥遥无期内部系统几乎不会有官方插件等插件等于放弃找开发排期写接口一个查询功能就要等几周。工具参数不可控就算接了接口如果参数设计随意Agent 会「自由发挥」——传错客户 ID、传错查询类型查询结果全乱。查询语义不诚实查不到客户时有的实现会返回一个「默认客户」的假数据糊弄过去——这在业务上是绝对不能接受的。本质上工具不在于复杂而在于输入输出契约清晰——把查询语义做真、把参数枚举收窄Agent 才能可靠地自主调用。3. 方案为什么是「工作流发布为自定义工具」Dify 的扩展机制很直接任何 Workflow 保存并发布后都可以变成自定义工具被 Agent/其他工作流调用。本实验就走通「构建 CRM 查询工作流 → 发布为工具 → 供 Agent 调用」的完整链路。选它的理由零等待自建工具不用等官方插件不用排期开发工作流搭好即发布即用输入输出契约天然清晰工具的入参就是工作流的开始变量用枚举select把参数收窄成合法值Agent 没有自由发挥的空间查询语义可控查不到就返回「未找到」语义foundfalse 空信息绝不塞默认数据——下游 LLM 会引导用户核对而不是编造答案。这篇文章我们就用它搭一个「CRM 查询工具」工作流输入customer_id和query_type查询客户基本信息/订单/工单发布为工具后挂载给 Agent 自主调用。4. 整体架构开始customer_id query_type模拟CRM APICode内置客户表按 query_type 分发found/data_json/summary格式化回复LLM把结构化结果转成自然语言结束链路很清晰入口收两个参数 → 代码节点按 query_type 分发查询 → LLM 把结构化结果格式化成自然语言。4 个节点、3 条边——工具不在于复杂而在于输入输出契约清晰发布后 Agent 只要知道「传 customer_id 和 query_type拿回文本」就能自主调用。5. 模块设计5.1 开始节点query_type用下拉枚举把 Agent 的「自由发挥」收窄成三个合法值——枚举约束是工具参数设计的第一原则-label:客户IDrequired:truetype:text-inputvariable:customer_id-label:查询类型options:[basic,orders,support]required:truetype:selectvariable:query_type5.2 模拟 CRM APICode核心真实 CRM 接口GET /customers/{id}在实验里用代码节点模拟重点是查询语义要真实——查不到就返回「未找到」绝不塞默认客户数据defmain(customer_id:str,query_type:str)-dict:importjson,time time.sleep(0.3)# 模拟真实 CRM API 延迟cidstr(customer_idor).strip()qtquery_typeorbasiccustomers{1001:{name:张三,level:vip,total_orders:12},1002:{name:李四,level:normal,total_orders:3},1003:{name:王五,level:new,total_orders:0},}customercustomers.get(cid)ifnotcustomer:return{found:false,data_type:qt,data_json:{},summary:未找到客户 {}.format(cid)}ifqtorders:data[{order_id:ORD-1001-1,product:产品A,amount:299.0,status:已完成}]summary客户 {} 的订单列表{} 笔.format(customer[name],len(data))elifqtsupport:data[{ticket_id:TK-9001,title:产品A 无法登录,status:处理中}]summary客户 {} 的支持工单{} 张.format(customer[name],len(data))else:datacustomer summary客户 {}等级 {}累计 {} 笔订单.format(customer[name],customer[level],customer[total_orders])return{found:true,data_type:qt,data_json:json.dumps(data,ensure_asciiFalse),summary:summary}要点found展平成 stringtrue/false——下游 IF-ELSE 才能判断boolean 类型在节点间不可见data_json输出 JSON 字符串保结构summary输出文本给 LLM——双形态输出是工具节点的通用约定5.3 发布为工具保存并发布这个 Workflow 应用进入「工具 → 自定义工具 → 通过工作流创建工具」选择刚发布的应用工具自动生成参数面板对应 start 变量配置后即可在 Agent 的「工具」列表里挂载⚠️ 发布为工具后工具内部注册 IDprovider_id是发布时生成的 UUID不是应用 ID子工作流重新导入并重新发布后注册 ID 会变化调用方必须同步更新。6. 运行验证场景输入预期实测结果查询基本信息customer_id1001, query_typebasicfoundtrue返回张三的等级与订单数模拟 API 命中LLM 正常格式化 ✓查询订单customer_id1001, query_typeorders返回订单列表 JSON 摘要订单分支触发 ✓客户不存在customer_id9999, query_typebasicfoundfalse提示「未找到客户 9999」未找到分支正确返回不编造数据 ✓Agent 调用在 Agent 应用挂载工具后说「查一下客户 1001」Agent 自动调用工具并组织回答Agent 识别意图并触发工具调用 ✓7. 实战坑坑现象修复模拟 API 查不到也返回默认客户问不存在的客户 ID得到一份「默认客户」的假信息兜底分支返回「未找到」语义foundfalse 空信息让下游 LLM 引导用户核对found用 boolean 输出下游 IF-ELSE 判断不到展平为 stringtrue/false用customer_id当参数名但代码签名写别的运行报main() got an unexpected keyword argumentcode 节点 variables 的 variable 名必须等于def main(...)签名参数名Dify 按名传参工作流发布为工具后 provider_id 写死旧值重新导入发布后调用方报「workflow provider not found」每次重新发布后从工具列表动态查询最新 provider_id 并同步真实 API 场景直接写 http-request 没接降级外网 CRM 超时整条链路失败生产接入时用 http-request 超时重试 失败分支见实验 17 容错架构采坑点来自本实验 DSL 生成与运行验证的真实记录代码模拟 API 约定、found 语义、按名传参、provider_id 变化。8. 实验文档及源码获取实验文档完整操作步骤DIFY-19插件开发入门.md源码可直接导入dify102_19_CRM查询工具.ymlDSL 目录dify-102/dsl/文章聚焦核心配置与采坑点实验文档还包含正式插件开发plugin.json/main.py/providers/tools 结构、凭据 secret-input、OpenAPI/Swagger 导入建工具、多工具组合插件包的完整示例。下一篇Dify 中级实验19综合实战——如何把 19 个实验串成一条生产级流水线 你在这个实验的场景里踩过什么坑欢迎评论区分享你的实战经验。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进