首页
/ Dify 工作流 DSL 的 Agent 原生封装:cli-anything-dify-workflow Harness 架构与实战指南

Dify 工作流 DSL 的 Agent 原生封装:cli-anything-dify-workflow Harness 架构与实战指南

2026-09-08 20:05:12作者:董斯意

导读

本文围绕仓库中 dify-workflow/agent-harness/DIFY_WORKFLOW.md 展开,深入解析 CLI-Anything 生态如何以"包装 Harness(wrapper harness)"的方式,把上游开源的 Dify 工作流 DSL 编辑器(dify-workflow CLI)改造成可被 AI Agent 发现、调用与托管的 cli-anything-dify-workflow 工具。读完本文,你将掌握该 Harness 的交互模型、完整命令面、安装方式、底层命令转发与后端发现机制、REPL 交互外壳以及测试验证策略,可直接上手让 Agent 通过 CLI 完成 Dify 工作流 YAML/JSON DSL 的创建、检查、校验、编辑与导出。

Harness 设计背景:为什么做"包装"而非"重写"

DIFY_WORKFLOW.md 开篇即点明一个关键架构决策:上游项目(来自开源 dify-ai-workflow-tools)已经是一个成熟、具备真实工作流创作能力的 CLI,其自身承载了 Dify DSL 文件的创作引擎,因此 CLI-Anything 不重复实现 Dify 工作流引擎,而是遵循仓库既有的 wrapper 模式,把上游 CLI 通过一个 CLI-Anything 包暴露出来,从而获得四项能力:

  • CLI-Anything 打包:统一挂在共享的 cli_anything 命名空间下,便于统一发现、统一依赖管理;
  • AI 可发现的 SKILL.md:为 Agent 提供标准化的技能元数据与使用指引;
  • 统一 REPL 外壳(repl skin):与仓库内其它 Harness(如 shotcut、gimp、blender)保持一致的终端交互体验;
  • CLI-Hub 注册表集成:Agent 可以从 CLI-Hub 中检索到该 Harness 并加载其技能元数据。

这一"借力上游、聚焦 Agent 化适配"的思路在 包内 README 中得到同样表述:该包并不重新实现 Dify 工作流引擎,而是包装现有 dify-workflow CLI,让 Agent 能通过 CLI-Anything 生态与 CLI-Hub 发现并使用它。

从包结构可以清楚看到这种"薄壳"设计的落地形态:

dify-workflow/agent-harness/
├── DIFY_WORKFLOW.md                  # 架构说明(本文主体文档)
├── MANIFEST.in                       # 打包清单
├── setup.py                          # 包元数据与入口点
└── cli_anything/
    └── dify_workflow/
        ├── __init__.py               # 版本号 __version__ = "0.1.0"
        ├── __main__.py               # 支持 python -m cli_anything.dify_workflow
        ├── dify_workflow_cli.py      # click 包装 CLI:命令面 + REPL
        ├── skills/SKILL.md           # Agent 技能元数据
        ├── tests/
        │   ├── test_core.py          # 后端发现 / 命令构建 / 元数据测试
        │   └── test_full_e2e.py      # 依赖上游 CLI 的端到端转发测试
        └── utils/
            ├── dify_workflow_backend.py  # 上游命令解析与子进程转发
            └── repl_skin.py              # 统一 REPL 皮肤实现

交互模型与整体调用链

DIFY_WORKFLOW.md 用一段精简的示意图刻画了分层调用关系,概括为三层:

AI Agent
  -> cli-anything-dify-workflow
     -> installed dify-workflow CLI / dify_workflow Python package
        -> local Dify YAML/JSON DSL files

其含义是:

  1. 顶层是 AI Agent:Agent(或交互式用户)只与 cli-anything-dify-workflow 这个统一入口对话;
  2. 中间层是 Harness:包装 CLI 负责参数透传、命令转发与结果回显;
  3. 底层是上游 CLI:真正的工作流 DSL 读写逻辑由已安装的 dify-workflow CLI(或 dify_workflow Python 包)提供,最终操作的是本地 Dify YAML/JSON DSL 文件。

环境要求与两步式安装

DIFY_WORKFLOW.md 的 Requirements 部分明确了运行前提:Python 3.10+,且上游 Dify workflow CLI 需要单独安装(推荐从 GitHub 安装,若上游后续发布到 PyPI 亦可走常规 PyPI 安装)。

setup.py 中可以看到 python_requires=">=3.10"cli-anything-dify-workflow 控制台入口点(entry point 指向 dify_workflow_cli:main),依赖为 click>=8.0.0prompt-toolkit>=3.0.0

完整的两步安装流程如下(见包内 READMESKILL.md):

# 第 1 步:先安装上游 Dify workflow CLI
python -m pip install "dify-ai-workflow-tools @ git+https://github.com/Akabane71/dify-workflow-cli.git@main"

# 第 2 步:再安装 CLI-Anything Harness(从本仓库的 agent-harness 子目录)
pip install git+https://github.com/HKUDS/CLI-Anything.git#subdirectory=dify-workflow/agent-harness

注意:两步安装顺序不可颠倒。若上游项目后续发布到 PyPI,第 1 步可替换为普通 PyPI 安装。本 Harness 不依赖上游在 PATH 中可用——详见下文"后端发现机制"。

完整命令面:从包装入口到上游子命令

DIFY_WORKFLOW.md 的 Command Surface 一节列出了包装 CLI 对外暴露的顶层命令组;而在 dify_workflow_cli.py 中,这些命令被逐一实现为 click 命令或命令组,并通过 editconfig 两个子命令组扩展出更细粒度的操作。合并两处信息可以得到下表:

顶层命令 作用 对应上游转发前缀
guide 展示上游教程 guide
list-node-types 列出支持的 Dify 节点类型 list-node-types
create 创建新的 Dify 应用/工作流 create
inspect 检查一个工作流文件 inspect
validate 校验工作流文件 validate
checklist 生成/输出检查清单 checklist
edit ... 工作流图变更子命令组 edit <subcommand>
config ... 模型/提示词等配置变更子命令组 config <subcommand>
export 导出 YAML 或 JSON export
import 导入并规范化工作流文件 import
diff 比较两个工作流文件 diff
layout 自动布局节点 layout

其中 editconfig 的子命令面(由 dify_workflow_cli.py 中定义的子命令实现)为:

  • editadd-noderemove-nodeupdate-nodeadd-edgeremove-edgeset-title
  • configset-modelset-promptadd-variableset-openingadd-questionadd-toolremove-tool

典型用法示例

以下是包内 README 与 SKILL.md 中给出、且可直接复制的示例命令:

# 展示上游教程
cli-anything-dify-workflow guide

# 列出 Dify 支持的节点类型
cli-anything-dify-workflow list-node-types

# 基于 llm 模板创建新工作流到 workflow.yaml
cli-anything-dify-workflow create -o workflow.yaml --mode workflow --template llm

# 以 JSON 输出检查工作流文件
cli-anything-dify-workflow inspect workflow.yaml -j

# 以 JSON 输出校验工作流文件
cli-anything-dify-workflow validate workflow.yaml -j

# 向工作流图添加一个 code 类型节点
cli-anything-dify-workflow edit add-node -f workflow.yaml --type code --title "Process"

# 修改应用模型的 provider/模型名
cli-anything-dify-workflow config set-model -f app.yaml --provider openai --name gpt-4o

关于 JSON 输出的约定

大部分上游命令都支持 -j / --json-output,这在 SKILL.md 的 Agent Guidance 中被特别强调:Agent 应优先使用 JSON 输出以获得结构化结果。这在端到端测试中也有印证——test_full_e2e.pycreate -j 的输出可直接被 json.loads 解析出 {"status": "created"},随后 validate <file> -j 返回的报告中 report["valid"] is Trueinspect <file> -j 的输出则以 JSON 对象起始。

命令转发与后端发现机制(源码级原理)

整个 Harness 的技术内核在 utils/dify_workflow_backend.pydify_workflow_cli.py 中,其核心设计可以概括为"参数透传 + 子进程转发"。

透传机制:未知参数全部放行

dify_workflow_cli.py 顶部定义了统一的 click context 配置:

PASS_ARGS = {
    "ignore_unknown_options": True,
    "allow_extra_args": True,
}

每个包装命令(如 createinspect)都带 context_settings=PASS_ARGS,从而让 click 不去解析那些真正属于上游 CLI 的参数(例如 --template llm--provider openai)。命令触发后,统一的 _forward(*prefix) 帮助函数会把"转发前缀 + 当前上下文中的原始参数"拼接后交给出底层执行:

def _forward(*prefix: str) -> None:
    output = run_dify_workflow([*prefix, *list(click.get_current_context().args)])
    _emit(output)

例如输入 cli-anything-dify-workflow edit add-node -f workflow.yaml --type code,则前缀为 ("edit", "add-node"),其余参数 -f workflow.yaml --type code 原样透传,最终拼成 ["dify-workflow", "edit", "add-node", "-f", "workflow.yaml", "--type", "code"]

后端三级解析:可执行文件 → Python 模块 → 报错提示

dify_workflow_backend.py 中的 require_dify_workflow_command() 实现了上游后端的弹性发现,这是本 Harness 的核心适配逻辑:

  1. 先用 shutil.which("dify-workflow") 探测上游可执行文件是否在 PATH 中,命中则返回 ["dify-workflow"]
  2. 若未命中,再通过 importlib.util.find_spec("dify_workflow") 探测 dify_workflow Python 包是否已安装,命中则回退为 [sys.executable, "-m", "dify_workflow.cli"]
  3. 两者皆无时,抛出携带完整安装指引的 RuntimeError(提示用户先执行上游 pip 安装命令)。

build_command(args) 负责把解析结果与透传参数拼成最终子进程命令;has_upstream_cli() 则是探测包装入口(供上层判断能力可用性);run_dify_workflow(args) 通过 subprocess.run(...) 以捕获输出方式执行上游命令:非零退出码会从 stderr/stdout 提取错误消息并抛 RuntimeError,正常时返回去尾空白后的 stdout 字符串。这里对子进程输出统一按 utf-8 解码(errors="replace"),并配合 dify_workflow_cli.py 的 _configure_stdio(),保证跨 Windows 等非 UTF-8 locale 环境下转发输出的可读性。

REPL 入口:无子命令时自动进入交互模式

dify_workflow_cli.py 的根命令设置了 invoke_without_command=True:当直接执行 cli-anything-dify-workflow(不带任何子命令)时,会 ctx.invoke(repl) 进入转发式 REPL。在 REPL 中,用户可以直接输入不带二进制名的上游命令(如 guidecreate -o app.yaml --template llm),help 列出包装命令,quit/exit 退出;非交互模式下则支持 --version 输出版本信息。

统一 REPL 皮肤与技能发现

REPL 的外观与交互能力由 utils/repl_skin.py 提供,这是 CLI-Anything 各 Harness 共用的"统一皮肤"组件。从源码结构看,ReplSkin 类提供以下能力:

  • 启动横幅(banner):自动探测 SKILL.md 位置(优先仓库根 skills/<skill-id>/SKILL.md,回退到打包目录 cli_anything/<software>/skills/SKILL.md),并在横幅中展示 npx skills add 安装命令与全局技能路径,供 Agent 读取技能信息;
  • 着色与品牌化输出:通过 ANSI 256 色为各软件配置独立强调色,并支持 NO_COLOR / CLI_ANYTHING_NO_COLOR 环境变量与 isatty 检测自动降级;
  • 信息方法族success / error / warning / info / hint / section / status / table / progress 等格式化消息方法;
  • prompt_toolkit 会话create_prompt_session 返回带历史文件、历史搜索与自动建议的 PromptSession(历史默认存于 ~/.cli-anything-dify_workflow/history),在 prompt_toolkit 不可用时自动回退到普通 input()
  • 底部工具栏bottom_toolbar 可构建多栏目状态栏。

在技能发现层面,skills/SKILL.md 的 YAML frontmatter 声明了技能名 cli-anything-dify-workflow 与描述(创建、检查、校验、编辑、导出 Dify 工作流文件),正文给出了两步安装命令、命令组清单与面向 Agent 的使用指引;该文件同时被 setup.py 的 package_datacli_anything.dify_workflow: ["skills/*.md"])与 MANIFEST.inrecursive-include cli_anything *.mdinclude DIFY_WORKFLOW.md)纳入打包,保证安装后技能元数据依然可用。DIFY_WORKFLOW.md 中提到的"AI-discoverable SKILL.md"与"registry integration for CLI-Hub"即由此完成。

测试策略:包装器正确性如何被验证

DIFY_WORKFLOW.md 的 Testing Strategy 一节将测试划分为两个互补层级,分别对应仓库内两份测试文件:

  • test_core.py(纯单元级,不依赖上游 CLI):

    • TestBackendDiscovery 用 mock 验证三级后端发现:命中二进制时返回 ["/usr/bin/dify-workflow"];二进制缺失但包存在时回退到 ["python", "-m", "dify_workflow.cli"];两者皆缺时抛带安装提示的 RuntimeErrorbuild_command 正确追加参数;has_upstream_cli 在解析失败时返回 False
    • TestWrapperCLI 用 click 的 CliRunner 验证 --help 渲染,断言帮助文案与 editconfig 命令组出现;
    • TestPackagingFixtures 读取包内 README 与 SKILL.md,断言两步安装指引与 wrapper 行为说明确实落到了文档/技能文件中。
  • test_full_e2e.py(端到端子进程冒烟,前置条件为上游 CLI 已安装):

    • setup_class 先执行 _require_working_upstream(),要求上游 dify-workflow 能响应 --help,否则直接报错跳过;
    • test_help 验证包装入口 --help 输出含 create
    • test_create_and_validate_workflow 走通"create -o <tmp>/workflow.yaml --template llm -j → 解析 JSON 断言 status == "created"validate <file> -j → 断言 report["valid"] is True"的完整工作流生命周期;
    • test_inspect_json 校验 inspect <file> -j 的 stdout 以 JSON 对象起始。

从这一组合可以确认:Harness 只对包装行为负责(发现、透传、元数据、转发正确性),真正的 Dify DSL 语义正确性由上游 CLI 保证,这正是"wrapper 不该重写引擎"这一设计原则在测试层面上的贯彻。

使用边界与安全注意事项

作为对 Agent 与 CLI-Hub 的适配层,本 Harness 有几个值得明确的使用边界(散见于 DIFY_WORKFLOW.md、包内 README 与 SKILL.md 的 Notes / Safety 部分,SKILL.md 的 Agent Guidance 做了汇总):

  • 本地文件编辑边界:该 Harness 的所有操作都是对本地 Dify YAML/JSON DSL 文件的编辑,不涉及生产环境的在线调用;
  • 导入前人工复核:将生成的 YAML/JSON 导入生产 Dify 项目之前,应当先人工审查,避免结构异常或参数错误被带入线上;
  • 转发而非实现:Harness 本身只是转发层,真实的工作流逻辑来自上游项目;遇到 DSL 层面的语义问题应回溯上游 CLI 行为;
  • 安装依赖前提:所有命令的可用性都以"上游 CLI 已安装"为前提;若上游以 PyPI 形式发布,安装方式可相应简化为普通 pip 安装。

小结

cli-anything-dify-workflow 是 CLI-Anything "让所有软件 Agent 原生(Agent-Native)"理念下一个典型的包装型 Harness 案例:它不重复造轮子,而是通过"click 透传 + 子进程转发 + 弹性后端发现 + 统一 REPL 皮肤 + SKILL.md 技能元数据"这组标准化机制,让一个原本只面向人手的 Dify DSL 编辑 CLI 变得可被 Agent 从 CLI-Hub 中发现、加载并执行。其命令面完整覆盖工作流的创建、检查、校验、编辑、配置、导入导出与对比布局,配合 -j JSON 输出,为 Agent 的自动化编排提供了结构化、可验证的工作流操作入口。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.14 K
2.75 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
857
1.35 K
docsdocs
暂无描述
Markdown
898
5.82 K
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
921
1.84 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.8 K
1.02 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
531
596
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.02 K
519
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.36 K
1.46 K
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
548
391