Dify 工作流 DSL 的 Agent 原生封装:cli-anything-dify-workflow Harness 架构与实战指南
导读
本文围绕仓库中 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
其含义是:
- 顶层是 AI Agent:Agent(或交互式用户)只与
cli-anything-dify-workflow这个统一入口对话; - 中间层是 Harness:包装 CLI 负责参数透传、命令转发与结果回显;
- 底层是上游 CLI:真正的工作流 DSL 读写逻辑由已安装的
dify-workflowCLI(或dify_workflowPython 包)提供,最终操作的是本地 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.0 与 prompt-toolkit>=3.0.0。
完整的两步安装流程如下(见包内 README与 SKILL.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 命令或命令组,并通过 edit、config 两个子命令组扩展出更细粒度的操作。合并两处信息可以得到下表:
| 顶层命令 | 作用 | 对应上游转发前缀 |
|---|---|---|
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 |
其中 edit 与 config 的子命令面(由 dify_workflow_cli.py 中定义的子命令实现)为:
edit组:add-node、remove-node、update-node、add-edge、remove-edge、set-title;config组:set-model、set-prompt、add-variable、set-opening、add-question、add-tool、remove-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.py 中 create -j 的输出可直接被 json.loads 解析出 {"status": "created"},随后 validate <file> -j 返回的报告中 report["valid"] is True,inspect <file> -j 的输出则以 JSON 对象起始。
命令转发与后端发现机制(源码级原理)
整个 Harness 的技术内核在 utils/dify_workflow_backend.py 与 dify_workflow_cli.py 中,其核心设计可以概括为"参数透传 + 子进程转发"。
透传机制:未知参数全部放行
在 dify_workflow_cli.py 顶部定义了统一的 click context 配置:
PASS_ARGS = {
"ignore_unknown_options": True,
"allow_extra_args": True,
}
每个包装命令(如 create、inspect)都带 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 的核心适配逻辑:
- 先用
shutil.which("dify-workflow")探测上游可执行文件是否在 PATH 中,命中则返回["dify-workflow"]; - 若未命中,再通过
importlib.util.find_spec("dify_workflow")探测dify_workflowPython 包是否已安装,命中则回退为[sys.executable, "-m", "dify_workflow.cli"]; - 两者皆无时,抛出携带完整安装指引的
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 中,用户可以直接输入不带二进制名的上游命令(如 guide、create -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_data(cli_anything.dify_workflow: ["skills/*.md"])与 MANIFEST.in(recursive-include cli_anything *.md、include 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"];两者皆缺时抛带安装提示的RuntimeError;build_command正确追加参数;has_upstream_cli在解析失败时返回False;TestWrapperCLI用 click 的CliRunner验证--help渲染,断言帮助文案与edit、config命令组出现;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 的自动化编排提供了结构化、可验证的工作流操作入口。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0629
MiniCPM5-2BMiniCPM5-2B 是一款面向端侧、本地部署和资源受限场景的 2B 稠密 Transformer,能够达到同尺寸开源模型 SOTA 水平。Markdown00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
HivisionIDPhotos⚡️HivisionIDPhotos: a lightweight and efficient AI ID photos tools. 一个轻量级的AI证件照制作算法。Python07
DragonOSDragonOS is an operating system developed from scratch using Rust, with Linux compatibility. It is designed for **Serverless** scenarios. 使用Rust从0自研内核,具有Linux兼容性的操作系统,面向云计算Serverless场景而设计。Rust00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00