infra-dify-ops

SkillWeb & browsing

Dify platform usage-layer ops Skill: DSL creation/validation/dual-track import (Console API first, Playwright fallback), DSL export, app inspection, local asset archiving, workflow drafts, model provider configuration, and production acceptance; does not handle the deployment layer. Ships with the C

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the infra-dify-ops skill

What this skill tells your AI

The instructions your AI receives, as published by seed-forge/harness-ai-kit in skills/infra-dify-ops/SKILL.md and read by ahel’s review.

配套 CLI difyctldifyresctl 旧包与 shim 已下线)。

用途

用于在 组织内部集群 场景中做 Dify 平台的使用层资源运维与 workflow DSL 创作,而不是处理部署层。它作为 AI 平台基础设施治理的一部分纳入 infra-*,但不接管 Dify Compose、数据库或容器生命周期。

这个 Skill 主要覆盖:

  • Dify app / workflow / chatflow / agent 等资源的本地归档
  • DSL 创作:从业务需求生成 import-ready DSL(workflow-create + spec v2)、本地校验(dsl validate
  • 双轨 DSL 导入:优先 Console API(dsl import --via auto),5xx/网络错误自动降级 Playwright;不再默认依赖 RPA
  • DSL 导出:经 Console API 拉取现网 app 的 DSL(dsl export
  • 导出的 DSL 文件校验、摘要、快照与 current 版本维护
  • 基于 app API key 的使用层检查
  • 模型 provider 配置(openai_api_compatible 加模型,联动 newapictl 消费)
  • Dify 1.13.x workflow DSL / graph 兼容性排障与生产验收
  • Studio 导入后 graph 损坏、未发布 app、输出结构漂移等使用层救援
  • 资源清单 resources.yml 的登记与批量筛选计划
  • 把后续新 workflow 及时沉淀到统一资源目录

DSL 创作与导入(0.2.0 新增)

三步创作流程

  1. difyctl workflow-create intake ... --spec-out ./specs/x.yml:从业务需求生成结构化 spec(默认 v2)
  2. difyctl workflow-create scaffold --spec ./specs/x.yml --output ./drafts/x.dify.yml:产出 import-ready DSL(含 app/kind: app/version: "0.6.0"/workflow.features/完整 graph node wrapper + position + edges)
  3. difyctl dsl validate ./drafts/x.dify.yml:本地校验(version/mode、图端点可达性、环检测、edge 引用、LLM 必填字段、变量引用语法、if-else handle)

双轨导入决策

  • difyctl dsl import --dsl ./drafts/x.dify.yml --via auto(推荐):
    • Console API 成功 → 返回 app_id + app_url
    • Console API 返回 5xx 或网络错误 → 自动降级 Playwright 浏览器导入
    • Console API 返回 4xx(配置/鉴权错误)→ 直接报错,不降级
  • --via api:只走 Console API,失败即报错(CI / 无 GUI 环境)
  • --via browser:只走 Playwright(现网 API 不可用时的兜底)

导入前默认自动跑一次 dsl validate;用 --skip-validate 跳过。

详细 DSL 结构、节点 schema、布局与踩坑见:

  • references/REFERENCE-DSL-AUTHORING.md
  • references/REFERENCE-DSL-GOTCHAS.md

输入

  • 当前资源目标,例如 appworkflowchatflow
  • 本地 DSL 导出文件路径
  • Dify app base URL 与 app API key(如需远端检查)
  • 资源 ID、标题、标签、app_id、app_name
  • 当前项目的资源工作区目录

输出

  • 规范化的资源目录
  • resource.json 元数据
  • dsl/current.*dsl/snapshots/* 快照
  • 远端 app 信息或参数检查结果
  • 对后续沉淀方式的明确建议

工作流

  1. 先判断这是“远端 app 检查”还是“本地资源沉淀”。
  2. 若需要远端检查:
    • 优先使用 difyctl app info
    • 必要时再用 difyctl app parameters
    • 如需补充环境描述,可再用 difyctl app meta
    • 若任务涉及命名、描述、发布对象或 Studio 卡片展示,先确认 live app 事实,再讨论本地 DSL 或 registry
  3. 若需要沉淀资源:
    • 先用 difyctl resource init <resource_id> --mode ...
    • 再把导出的 DSL 用 difyctl resource capture ... 归档
    • 默认维护 dsl/current.* 与时间戳快照
  4. 若要维护项目级资源清单:
    • 先用 difyctl registry init
    • 再用 difyctl registry upsert ...
    • 批量筛选时用 difyctl batch plan ...
  5. 若需要从零生成一个业务需求对应的 workflow:
    • 先用 difyctl workflow-create intake ...draft --from-demand ...
    • 再用 difyctl workflow-create validate-spec ...
    • 然后用 difyctl workflow-create scaffold ... 产出 DSL 草稿
  6. 若需要把本地资源同步回 Dify Studio:
    • 先用 difyctl studio create-plan ...
    • 或对已有资源用 difyctl studio export-plan ...
    • 或用 difyctl studio duplicate-plan ...
  7. 若准备切到真实浏览器自动化执行:
    • 先用 difyctl studio browser-doctor
    • 再用 difyctl studio import-dsl-run --dsl ...
    • 当前阶段要预期登录页和按钮选择器仍需现场微调
  8. 若只想快速理解一个 DSL:
    • 先用 difyctl dsl summarize <path>
  9. 每次新增或明显改造 workflow 后,都要判断是否应该:
    • 继续补当前资源目录
    • 新增一个独立资源目录
    • 回填到项目级知识卡片或 SOP
  10. 若导入后的 workflow 在 Dify 1.13.x 中无法运行或 Studio 无法正常打开:
  • 先把问题分层为 graph schemapublish stateruntime invoke 三类
  • 优先用黑盒 app API 调用和只读数据库检查定位,不要一上来就改库
  • 确认是旧 DSL 兼容性问题后,再决定是“最小字段补丁”还是“整图原生重建”
  1. 若需要做生产救援:
  • 先确认 draft graph、published workflow、apps.workflow_id、api_tokens 四个对象是否齐全
  • 再确认 startllmend 三类节点是否符合当前 Dify 原生 schema
  • 最后用真实样例做健康路径与异常路径双验证,结果通过后再宣布可用
  1. 若任务同时涉及 Git 台账、本地 DSL、Studio 页面和 live app:
  • 先把四层对象分开看,不要假设它们天然一致
  • 优先核对 live app,再核对 resources.yml / resource.json / dsl/current.*
  • 若只是 Studio 资产漂移,先修正 Studio,再把本地台账回写到一致状态
  1. 若需要查询/新增 Dify 模型提供商下的模型(模型台账):
  • difyctl provider login --username-env ... --password-env ... --headed 取 Console 会话,用返回的 full_cookie_header(含 csrf_token,纯 session_cookie 会 401)作为 --console-key
  • difyctl provider models --provider <full-path> 查某提供商已配置模型(台账视图),随时看清现状
  • difyctl provider add-model --provider <full-path> --model <name> --endpoint-url <base>/v1 --api-key <key> 给 openai_api_compatible 类可自定义模型的提供商加单个模型;先 --dry-run 预览 payload(无需 Console 会话)
  • newapi 消费 key 无法经 Admin API 读取(服务端全程脱敏、忽略客户端传入 key),必须从 newapi Web UI 复制或由用户提供;获取后 newapi/v1/chat/completions 冒烟测试确认模型可用再注册
  1. 若需要改某 workflow 的 LLM 节点模型:
  • GET /console/api/apps 定位 app_id → GET .../workflows/draft 取 graph
  • data.type=="llm" 节点的 model.providermodel.namePOST .../workflows/draft 保存 → POST .../workflows/publish 发布
  • POST .../workflows/draft/run(SSE 流)跑一次,确认 node_finished/workflow_finishedstatus=succeedederror=None

一致性校验与命名漂移

四层事实源

处理 Dify 使用层问题时,至少区分以下四层:

  • live app:/v1/info/v1/parameters/v1/meta 实际返回的对象
  • Studio asset:/apps 卡片、应用标题、描述、发布态和可见名称
  • local registry:resources.ymlresource.json 中登记的 resource_idtitleapp_idapp_name
  • local DSL:dsl/current.*dsl/snapshots/*drafts/* 中沉淀的 graph 与元数据

不要因为其中一层已经更新,就推断其他三层也已经同步。

推荐校验顺序

  1. 先确认当前问题属于 live app、Studio asset、local registry、local DSL 中的哪一层,或是否多层叠加。
  2. 只要任务涉及 app 名称、描述、默认 workflow 绑定或“页面显示不对”,优先执行 difyctl app info
  3. 若 组织内部集群 本地网络、代理或浏览器自动化环境不稳定,优先以内网可达机器上的 live app 检查结果为准。
  4. 确认 live app 事实后,再决定是:
    • 更新本地 registry / DSL
    • 更新 Studio app 信息
    • 同时做两边对齐
  5. 完成修改后,至少做一次双验证:
    • live app 验证
    • 本地资源验证

命名治理规则

命名格式的权威真源在 fleet-platform/resources/dify/README.md「资源命名规范」章节(resource_id 正则 ^[a-z][a-z0-9]*(-[a-z0-9]+)*$、文件布局、扩展名、ledger v2 schema)。本节只讲漂移治理,不重复定义命名格式;difyctl 亦在代码/--help 内置同一正则并硬校验非法 id。

  • resource_id 是稳定标识,优先保持稳定,不要因为展示名称变化就频繁改动。
  • titleapp_name 可以随业务语义演进,但改名后要主动检查 Studio 与 live app 是否同步。
  • drafts/*dsl/snapshots/* 允许保留历史名称,但不能拿历史快照代表当前现网事实。
  • 浏览器自动化如果按名称查找 app,默认要警惕 registry 名称与现网名称已经漂移。

处理顺序建议

遇到“代码里已经叫新名字,但 Dify 页面还是旧名字”这类问题时,默认按下面顺序处理:

  1. 用 app API 先确认现网 name / description / mode
  2. 再核对 resources.ymlresource.jsondsl/current.*
  3. 若只是 Studio / live app 漂移,先修正 Studio
  4. 再把本地 registry 和 README 等元数据回写到最终一致状态
  5. 最后保留一次可追溯验证结果,避免下次会话重新猜

Dify 1.13.x 修复策略

故障分层

  • graph schema:Studio 打不开、运行前即报 validation errors,通常是旧 DSL 与当前 start / llm / end 节点 schema 不兼容。
  • publish state:app 存在但不可调用,常见特征是 apps.workflow_id 为空、未指向 published workflow,或只有 draft 没有 published 版本。
  • runtime invoke:API 可进业务层但 blocking 运行异常、超时、输出漂移,通常需要看 workflow runs 和 API logs。

推荐排查顺序

  1. 先做黑盒调用,确认错误是在鉴权、参数校验、graph 校验还是节点执行阶段。
  2. 再检查 app 发布态是否完整:
    • apps.workflow_id 应指向 published workflow,而不是 draft
    • 同一个 app 通常至少有一条 draft workflow 和一条带时间戳版本号的 published workflow
    • 若需要使用 service API,还要确认存在 api_tokens.type = app
  3. 再检查 graph 结构是否是当前 Dify 原生格式:
    • start.variables 应是 variable / label / type: text-input 这类 VariableEntity
    • llm 节点至少要有 modelcontextvision
    • end.outputs 应是 variable + value_selector + value_type
  4. 只有在 Studio 已不可用、且黑盒与只读检查都证明是元数据损坏时,才进入 break-glass 数据层修复。

Break-Glass 原则

  • 这类修复属于使用层资源救援,不是常规路径,必须有明确授权。
  • 优先做“可回滚的最小改动”,例如先补齐缺失字段,再验证是否足够。
  • 若旧 graph 与当前 Dify 版本差异过大,不要持续缝补,直接重建成当前原生 graph。
  • 不在总结里扩散完整 API token、数据库密码等凭证;验证时只汇报是否成功与关键输出形状。

生产可用判定

  • published workflow 已存在,且 apps.workflow_id 已切到该 published 版本。
  • app API 黑盒调用成功,不再停留在 schema 校验或参数缺失报错。
  • 至少完成两类验证:
    • 健康样例:应返回稳定的 titlemarkdown_bodyplain_text_body
    • 异常样例:正文必须贴合输入事实,不能复用历史样例或编造新数字
  • 最新 workflow_runs 记录应能落库并收敛到 succeeded,必要时辅以 API logs 核对。

Dify 1.13.x Graph 约定

优先选择

  • 对监控日报、通知封装、结构化摘要这类场景,优先用 start -> 单个 llm(structured_output) -> end
  • 不要默认串多个自由文本 LLM 节点再靠 end 兜底拆字段,这样更容易产生幻觉和字段漂移。

原生字段约定

  • start.variables 使用当前 VariableEntity 结构,例如 variablelabeltype: text-input
  • llm 节点在 Dify 1.13.x 下应显式带上:
    • model
    • context
    • vision
    • retry_configdifyctl scaffold 默认注入 3 次重试)
    • error_strategydifyctl scaffold 默认注入 default_value fallback)
    • 需要结构化结果时加 structured_output_enabledstructured_output.schema
  • 新建 workflow 的默认 LLM 模型使用 langgenius/deepseek/deepseek / deepseek-v4-flashmode: chattemperature: 0.1
  • end.outputs 直接映射到上游 structured_output 字段,例如:
    • ["llm_node", "structured_output", "title"]
    • ["llm_node", "structured_output", "markdown_body"]
    • ["llm_node", "structured_output", "plain_text_body"]

提示词约束

  • 明确写出“只能依据 snapshot_json 中已有事实,不允许猜测、补造、外推”。
  • 明确要求空区块输出“未观测到异常”或“无数据”。
  • 对正文结构写死章节名,而不是依赖模型自行发挥。
  • 若需要多语言,只让 language 影响表述语言,不影响事实本身。

LLM 节点容错默认行为(0.4.0 新增)

difyctl workflow-create scaffold 默认为每个 LLM 节点注入两层容错:

  1. retry_config{retry_enabled: true, max_retries: 3, retry_interval: 1000}

    • 触发条件:模型返回 429 / 5xx / 超时
    • 与 newapi 侧的 proxy 重试 + 渠道 fallback 互补:newapi 处理上游不可用,Dify 侧处理模型响应本身的异常
    • retry_config=None 可禁用(仅限调试)
  2. error_strategy{type: default_value, default_value: ""}

    • 触发条件:重试全部耗尽后
    • 效果:输出空值让下游节点继续执行,而非整个 workflow 崩溃
    • 对于 structured_output 节点,default_value 应是一个含全部必填字段的空对象,例如 {"title":"","markdown_body":"","plain_text_body":""}
    • error_strategy=None 可禁用(不推荐用于生产)

difyctl dsl validate 会对缺失这两项的 LLM 节点发出 warning,提示手动补齐。

手写或从 Dify 导出的 DSL 如果缺少 retry_config / error_strategy,建议用 difyctl dsl lint 检查后再导入。

App 服务密钥 / 调用 / 运维(0.7.0 新增)

创建工作流后「取 key → 调用」现已在 CLI 内闭环,覆盖各类应用:

# 1) 取 app 的 service API key(Console API):完整 token 仅打印一次 + 存 config.yaml assets.difyctl.app_keys
difyctl app keys create --app-id <app_id>
difyctl app keys list --app-id <app_id>        # 只显示掩码前缀
difyctl app keys delete --app-id <app_id> --key-id <kid>

# 2) 调用应用(mode 自动从 ledger/--mode 解析,覆盖全类型)
difyctl app run --app-id <app_id> --inputs '{"text":"hi"}'          # workflow -> /v1/workflows/run (blocking)
difyctl app run --app-id <app_id> --query "你好"                     # chat/advanced-chat/chatflow -> /v1/chat-messages (blocking)
difyctl app run --app-id <app_id> --mode agent-chat --query "你好"    # agent-chat -> /v1/chat-messages (streaming,Dify 拒绝 blocking,自动改流式聚合)
difyctl app run --app-id <app_id> --mode completion --query "写首诗"  # completion -> /v1/completion-messages

# 3) 导入即可用(opt-in 闭环)
difyctl dsl import --dsl draft.dify.yml --via api --resource-id my-wf --create-key --smoke --smoke-inputs '{"text":"hi"}'
# 导入默认带重名去重守卫:现网已存在同名 app 时 block(列出 existing app_id);确需重复用 --allow-duplicate。
# 排查现网重复:difyctl registry audit 的 duplicate_names 段列出同名 app 分组。

# 3b) 渐进式:原地更新已有 app(不产生副本)
difyctl dsl export --app-id <app_id> --output cur.dify.yml   # 拉当前线上 DSL
difyctl dsl diff --app-id <app_id> --dsl new.dify.yml        # 推送前预览差异
difyctl dsl import --dsl new.dify.yml --via api --app-id <app_id>   # 原地更新(同 app_id,无副本)
difyctl dsl import --dsl new.dify.yml --via api --update-if-exists  # 或按同名自动定位单个 app 更新
difyctl app publish --app-id <app_id>                        # workflow/advanced-chat 更新后需 publish 才能 /v1 run
difyctl dsl lint --dsl new.dify.yml                          # 推送前静态检查:硬编码密钥/悬空变量/空模型
difyctl dsl retarget --dsl new.dify.yml --provider <p> --model <m>  # 批量改绑模型
difyctl dsl apply --dir ./dify-apps --dry-run                # 声明式:目录 DSL 幂等同步(新建/原地更新/歧义跳过)
difyctl dsl apply --dir ./dify-apps --publish                # 执行同步并发布

# 3c) 长期治理:台账回填 + 重复清理
difyctl registry sync --dry-run          # 预览把未登记的线上 app 回填进台账(分页全量)
difyctl registry sync                     # 执行回填
difyctl registry prune-duplicates         # dry-run:列出同名冗余 app 的删除计划(保留最新)
difyctl registry prune-duplicates --apply # 执行删除(破坏性,保留 --keep newest/oldest 之一)

# 3d) 知识库(RAG 数据集)+ 全量备份
difyctl dataset list                                   # 列出所有知识库(分页全量)
difyctl dataset list --name 营销                        # 按名称子串过滤
difyctl dataset documents --dataset-id <id>            # 某知识库的文档列表
difyctl dataset create --name "KB" --indexing-technique high_quality   # 建库(high_quality 需 embedding 模型)
difyctl dataset add-doc --dataset-id <id> --name doc --text "..."      # 加文本文档(/v1 + 自动取 dataset key)
difyctl dataset add-doc --dataset-id <id> --name doc --file ./a.md     # 或从文件读入
difyctl dataset delete --dataset-id <id> --yes         # 删库(破坏性,需 --yes)
difyctl app annotations --app-id <id>                  # 列出 app 标注(问答缓存)
difyctl dsl export --all --output-dir ./dify-backup    # 全量备份每个 app 的 DSL(灾备)

# 输出约定:stdout 恒为纯 JSON(可直接管道消费);人类可读的错误/告警走 stderr。全局 --quiet 静默 stderr、--verbose 追踪、-q 简写。

# 4) 运维车队
difyctl app rename --app-id <app_id> --name "New Name"    # Console PUT + 同步 ledger
difyctl app delete --app-id <app_id>                       # Console 删除 + ledger status→deprecated
difyctl registry audit                                     # live apps vs ledger:僵尸/未登记/漂移

# 5) /v1 运行时全覆盖(0.8.0,均用 app-* service token)
difyctl app run --app-id <id> --mode agent-chat --query "你好" --stream   # 强制流式聚合
difyctl app run-status --app-id <id> --run-id <workflow_run_id>           # 运行明细/状态
difyctl app stop --app-id <id> --task-id <task_id> --user <u>            # 中止流式任务
difyctl app upload --app-id <id> --file ./a.png --user <u>               # 文件/图片输入
difyctl app logs --app-id <id> --limit 20                                 # 运行日志/审计
difyctl app conversations --app-id <id> --user <u>                        # 会话列表
difyctl app messages --app-id <id> --conversation-id <cid> --user <u>     # 会话消息
difyctl app conversation-rename --app-id <id> --conversation-id <cid> --name "X" --user <u>
difyctl app conversation-delete --app-id <id> --conversation-id <cid> --user <u>
difyctl app feedback --app-id <id> --message-id <mid> --rating like --user <u>   # 点赞/踩
difyctl app suggested --app-id <id> --message-id <mid> --user <u>         # 追问建议
difyctl app audio-to-text --app-id <id> --file ./a.wav --user <u>         # 语音转文字
difyctl app text-to-audio --app-id <id> --text "你好" --output ./o.mp3 --user <u>  # 文字转语音

安全红线:完整 app-* token 只存本地 ~/.harness-ai-kit/config.yaml(app_keys 映射,禁入 Git);app keys create 完整 token 仅一次性打印,其余输出与 ledger 一律掩码(prefix+****)。key 解析优先级:--app-key > config.yaml app_keys[app_id] > app_api_key。

配置上下文

本技能依赖以下配置,AI 在运行时按如下优先级解析:

  1. 用户对话中明确提供的值(最高优先级)
  2. ~/.harness-ai-kit/config.yamlassets.difyctl(配套 CLI 配置段)或 global
  3. config.defaults.yaml 中的默认值

如用户未提供且无默认值的 required 字段,必须主动询问用户。 禁止从 AGENTS.md 或脚本中读取硬编码配置值。

推荐输出格式

执行完毕后按以下结构输出:

状态:✅ / ⚠️ / ❌

资源ID类型(app/workflow/chatflow)动作(init/capture/reconcile/validate)DSL 快照 / live 校验结果

(漂移排查场景补充四层事实源对照:live app / Studio asset / local registry / local DSL 的一致性结论;生产救援场景注明 published workflow、apps.workflow_id、健康/异常双验证是否通过。)

约束

  • 这个 Skill 不负责 Docker、Compose、Nginx、容器启停与 Dify 升级。
  • 优先把 Dify 资源沉淀为项目内可跟踪文件,而不是只留在 Dify UI 中。
  • 公开稳定的使用层入口先以 app API key 与导出 DSL 为主,不默认依赖不稳定的控制台私有接口。
  • 数据库直修只作为 break-glass 救援手段,不作为常规导入、发布或编辑路径。
  • 当前已对齐中文 Dify Studio 登录页与 /apps -> 创建空白应用 / 导入 DSL 文件 / 更多 -> 导出 DSL / 复制 / 编辑信息 流程。
  • 新资源命名应稳定、可检索、可长期复用,不要使用一次性临时名称。
  • 不要把本地 drafts/*、历史 snapshot 名称或 .env 中的展示名,直接当成现网 app 事实;涉及展示层问题时必须再做 live app 校验。

命令约定

初始化本地配置:

difyctl config init --base-url https://dify.example.com --workspace-dir ./fleet-platform/resources/dify

推荐最小环境变量:

DIFY_BASE_URL=https://dify.example.com
DIFY_STUDIO_USERNAME=you@example.com
DIFY_STUDIO_PASSWORD=your-password

远端检查解析顺序:

  1. 显式命令参数 --base-url / --app-api-key
  2. difyctl 已保存配置
  3. 环境变量 DIFY_BASE_URL
  4. workspace_dir 附近 .env 中的 DIFY_BASE_URLDIFY_API_KEYDIFY_APP_API_KEY

DIFY_BASE_URL/v1 结尾,CLI 会自动收口到站点根地址。

检查 readiness:

difyctl doctor

远端 app 检查:

difyctl app info
difyctl app parameters
difyctl app meta

命名或描述漂移校验:

difyctl app info
difyctl reconcile diff-only sales-intake
difyctl reconcile show sales-intake
difyctl registry show sales-intake
difyctl resource show sales-intake

本地资源沉淀:

difyctl resource init my-workflow --mode workflow --title "My Workflow" --dsl ./exports/my-workflow.yml
difyctl resource capture my-workflow --dsl ./exports/my-workflow-v2.yml --label exported-2026-05-11
difyctl resource list
difyctl resource show my-workflow

DSL 快速摘要:

difyctl dsl summarize ./exports/my-workflow.yml

资源清单与批量计划:

difyctl registry init
difyctl registry upsert sales-intake --mode workflow --title "Sales Intake" --tag sales --dsl-path resources/sales-intake/dsl/current.yml
difyctl batch plan --mode workflow --tag sales

从零生成 workflow 草稿:

difyctl workflow-create intake --name "Sales Intake" --mode workflow --goal "Triage inbound leads" --input lead_text --output final_reply --step "Classify intent" --step "Generate reply" --spec-out ./specs/sales-intake.yml
difyctl workflow-create validate-spec --spec ./specs/sales-intake.yml
difyctl workflow-create scaffold --spec ./specs/sales-intake.yml --output ./drafts/sales-intake.dify.yml

Studio 操作计划:

difyctl studio create-plan --name "Sales Intake" --mode workflow --dsl ./drafts/sales-intake.dify.yml
difyctl studio export-plan sales-intake
difyctl studio duplicate-plan sales-intake

浏览器自动化入口:

difyctl studio browser-doctor
difyctl studio import-dsl-run --dsl ./drafts/sales-intake.dify.yml --headed

生产验收建议:

curl -X POST "$DIFY_BASE_URL/v1/workflows/run" \
  -H "Authorization: Bearer $DIFY_APP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "inputs": {
      "snapshot_json": "{\"summary\":{\"overall_status\":\"healthy\"},\"hosts\":[],\"containers\":[],\"entrypoints\":[],\"alerts\":[],\"links\":[]}",
      "period_label": "2026-05-12",
      "audience": "ops-oncall",
      "language": "zh-CN"
    },
    "response_mode": "blocking",
    "user": "smoke-test"
  }'

示例

示例 1:刚从 Dify 导出一个 workflow DSL,想立即沉淀

  1. difyctl resource init sales-intake --mode workflow --title "Sales Intake" --dsl ./exports/sales-intake.yml
  2. 确认 resource.jsondsl/current.yml 与首个 snapshot 已生成
  3. 后续版本继续用 capture 累积快照

示例 2:想先看当前 app 的运行参数

  1. 配置 base_urlapp_api_key
  2. 运行 difyctl app parameters
  3. 把结果作为后续资源整理和比对依据

示例 3:从业务需求直接起一个 workflow 草稿

  1. workflow-create intake 生成结构化 spec
  2. validate-spec 校验 spec
  3. scaffold 生成 starter DSL
  4. 再进入 resource init / capture 与后续 Studio 导入流程

示例 4:对已登记资源生成 Dify Studio 操作计划

  1. 先确认该资源已存在于 resources.yml
  2. 运行 difyctl studio export-plan sales-intake
  3. 按计划把导出的 DSL 回填到本地资源目录

示例 5:导入后的 workflow 在 Dify 1.13.x 中无法运行

  1. 先用 app API 做黑盒调用,记录它卡在鉴权、参数校验、graph 校验还是节点执行
  2. 对照一个正常 app,检查 draft / published workflow、apps.workflow_id 和 app token 是否齐全
  3. 若报 VariableEntityEndNodeDataLLMNodeData 校验错误,优先按当前原生 schema 重建 graph
  4. 修复后至少跑一条健康样例和一条异常样例,再确认 workflow_runssucceeded

示例 6:本地 registry 已改名,但 Studio 页面仍显示旧名称

  1. 先运行 difyctl app info,确认 live app 当前 namedescription
  2. 再核对 resources.ymlresource.jsondsl/current.* 是否已经切到新语义
  3. 若确认只是 Studio asset 漂移,再执行 studio edit-info-run
  4. 修改完成后重新做一次 live app 校验,不要只看 Studio 页面标题

示例 7:新开会话时想先快速确认是否存在漂移

  1. 先运行 difyctl reconcile diff-only sales-intake
  2. 若只有 live app 网络错误,优先切到内网可达环境复核
  3. 若存在 observations,再运行 difyctl reconcile show sales-intake 看完整上下文

给 LLM 应用加"联网搜索/工具"能力(Dify 1.x 插件版)

关键事实:Dify 的 LLM 节点本身没有内置"联网搜索"开关。联网搜索通过**工具(1.x 里是插件)**提供,两种接法:

  • Agent 应用 / Agent 节点:把搜索工具挂到 Agent,由模型自主决定何时搜(依赖模型 function-calling 能力,不够确定)。
  • Chatflow/Workflow 的 Tool 节点(推荐,确定性):显式放一个搜索 Tool 节点在 LLM 节点前,把检索结果通过 context 拼进 LLM 上下文。不依赖模型 tool-calling,最稳。

可用 web-search 工具(本实例,GET /console/api/workspaces/current/tools/builtin 探测)

工具provider(1.x 全名)tool_name授权/密钥
Wikipedialanggenius/wikipedia/wikipediawikipedia_search(query+language 必填)已授权·免密钥·稳定
DuckDuckGolanggenius/duckduckgo/duckduckgoddgo_search(query 必填,max_results 必填)已授权·免密钥·免费端点常被限流(202 Ratelimit)
Tavilylanggenius/tavily/tavilytavily search已授权·需 key·生产推荐
Google/Bing/SearchApi/Brave/Jina对应插件需各自 API key

工具节点 DSL 关键 schema(1.x,workflow.graph.nodes[].data)

type: tool
provider_id: langgenius/wikipedia/wikipedia      # 与 provider_name 一致,用插件全名
provider_name: langgenius/wikipedia/wikipedia
provider_type: builtin
tool_name: wikipedia_search
tool_configurations: {}                           # provider 级配置(proxy 等)
tool_parameters:
  query:    {type: mixed,    value: "{{#<start_node_id>.query#}}"}   # 变量引用
  language: {type: constant, value: zh}                              # 常量
retry_config: {max_retries: 2, retry_enabled: true, retry_interval: 1000}

LLM 节点消费工具输出:context.enabled: true + context.variable_selector: [<tool_node_id>, "text"],prompt 里引用 {{#<tool_node_id>.text#}}。节点外壳统一 type: custom,真实类型在 data.type

CLI 一键运维闭环(已真机验证 GREEN)

# 1) 作者一个 start -> tool(wikipedia_search) -> llm(ollama) -> end 的 workflow DSL(见上 schema)
# 2) 导入(带重名去重) + 建 key
difyctl dsl import --dsl websearch.dify.yml --via api --resource-id web-search-pilot-wiki --create-key
# 3) 发布(workflow 必须 publish 才能 /v1 run)
difyctl app publish --app-id <app_id>
# 4) 试点跑通:联网检索 -> LLM 汇总
difyctl app run --app-id <app_id> --mode workflow --inputs @q.json   # q.json: {"query":"..."}
# 排错:run_status=failed 时看 error(如 DuckDuckGo 202 Ratelimit 即免费端点限流,非配置错误)

踩坑与选型:DuckDuckGo 免费端点在服务器 IP 上常返回 202 Ratelimit(节点结构正确、确实发起了真实搜索,但被限流);生产联网搜索优先 Tavily / SearchApi(配 key) 或给 DDG 配 proxy_server。零成本试点/演示用 Wikipedia 最稳(wikipedia_search,免密钥、无限流)。

Tool 节点参数放置(关键坑,已真机踩过 3 次)

  • 运行时输入form: llm,如 query)→ 放 tool_parameters必须包裹 {type: mixed|variable|constant, value: ...}
  • 静态配置项form: form,如 max_results/search_depth/include_answer)→ 放 tool_configurations用原始值、不要包裹(写成 {max_results: 5, include_answer: "advanced"};写成 {type:constant,value:...} 会报 value {...} not in options)。
  • select 型但默认值是布尔的配置项(Tavily 的 include_answer/include_raw_content必须显式赋一个合法字符串选项(如 include_answer: "advanced"include_raw_content: "false"),否则默认 False 触发 value False not in options

本实例 web-search 现状(探测结论,随时可复查)

  • Tavily 已授权且已配 keytavily_api_key: <set>),5 个工具 tavily_search/tavily_extract/tavily_crawl/tavily_map/tavily_researchsearch+read 开箱即用,已真机 GREEN(tavily_search→LLM 返回带来源 URL 的实时答案)。生产联网搜索首选它。
  • SearXNG 插件未安装(无 provider):自托管要先装 marketplace 插件 + 部署 SearXNG 容器 + 配 base_url + 上游引擎国际出口代理。
  • Firecrawl 插件在册但未配base_url/api_key 空):需云端 key 或自托管 base_url;旧 app 里 provider_id: firecrawl 短名是遗留写法,新建用插件全名 langgenius/firecrawl/firecrawl

自托管 SearXNG + Firecrawl 接入(已真机 GREEN)

CLI/API 授权 tool provider(difyctl 暂无此命令,走 Console API):

POST /console/api/workspaces/current/tool-provider/builtin/<provider>/add
body: {"credentials": {...}, "type": "api-key", "name": "self-hosted"}
  • :该接口常返回 400 Cannot release a lock that's no longer owned,但凭据其实已保存——以 GET tools/builtinis_team_authorization=True 为准,别盲目重试(会建重复凭据)。

SearXNGlanggenius/searxng/searxng,cred 字段 searxng_base_url,免密钥):

  • 搜索工具 searxng_searchquery(llm) + search_type(form,必填,options: general/images/videos/news/map/music/it/science/files/social_media) + time_range(form,可选)。
  • 关键坑:SearXNG 节点结果只在 json(array[object],含 title/url/content)里,text 为空!prompt 必须引用 {{#节点.json#}}(非 text),context 关掉或指 json。真机 GREEN:MCP 查询→9501 tokens、带来源 URL。
  • 直连自检:GET http://<searxng>/search?q=...&format=json 返回 results[] + unresponsive_engines(本实例 google cse+duckduckgo 正常、brave 挂)。

Firecrawllanggenius/firecrawl/firecrawl,creds base_url+firecrawl_api_key,自托管 key 任意非空):

  • scrapeurl(llm) + formats/onlyMainContent/timeout(form)。输出走 text(与 SearXNG 不同)。真机 GREEN:抓 runoob 页→摘要。

联网搜索 workflow spec 模板库(一键脚手架)

技能自带 3 个可直接脚手架的 spec(references/specs/),difyctl workflow-create scaffold --spec <spec> --output x.dify.yml 一键生成 DSL:

Shortened here. Read the whole file on GitHub.

Signals

GitHub stars
22
Forks
2
Last commit
Aug 2026
Advanced
Catalog kind
skill
Gateway key
infra-dify-ops
Source
github.com/seed-forge/harness-ai-kit