跳转到主要内容
本文档由 AI 自动翻译。如有任何不准确之处,请参考 英文原版
要让 Agent 安全地驱动 difyctl,需要四类失败处理逻辑:读取正确的通道、根据退出码分支处理、把已暂停的工作流当作成功,并只重试安全的操作。

读取正确的通道

每次程序化调用都加上 -o json。通道规则非常严格,可据此构建逻辑:
  • 成功:负载以可解析的 JSON 形式输出到 stdout,不含 ANSI 码,stderr 为空。
  • 失败:stdout 为空,stderr 是一个结构化的 JSON 对象。整段去除首尾空白的 stderr 都可解析为 JSON。
  • 暂停:因等待人工介入而停止的工作流也会在成功通道上以退出码 0 结束,stdout 上带有 "status": "paused"。应 将其视为成功,而非失败。
因此解析规则是:先看退出码,成功时对 stdout 执行 JSON.parse(stdout),失败时对 stderr 执行 JSON.parse(stderr)。错误对象的字段及完整示例详见 输出格式与退出码

根据退出码分支处理

完整的退出码表详见 输出格式与退出码。对 Agent 来说,需要关注的分支有:
  • 退出码 7,限流:服务器返回了 429。退避后重试。
  • 退出码 4,认证:没有会话,或会话已过期。先重建会话,再做其他任何事。不要原样重试同一命令,那只会白白消耗调用次数。参见 在 Agent 运行的位置进行认证
  • 退出码 1,通用错误或服务器错误:网络故障、服务器错误、应用未找到,或未知的标志或命令。解析错误对象并检查 error.code。不要盲目重试。
  • 退出码 2,输入无效:CLI 在发出任何请求前就拒绝了某个值:--inputs JSON 格式错误、应用 ID 不是 UUID,或像 --limit 0 这样超出范围的标志。修正调用;原样重试只会以同样的方式失败。
  • 已暂停的运行退出码为 0:触发人工介入步骤的工作流会以退出码 0 结束,stdout 上带有 "status": "paused",并非错误。该情况 单独处理

暂停意味着成功,而非错误

带有人工介入步骤的工作流应用会在运行中途暂停。命令以退出码 0 结束,并在 stdout 上报告暂停。stderr 上没有任何可捕获的内容。只检查退出码的 Agent 会把暂停误判为已完成的运行,因此完成检查必须读取负载:
import json, subprocess

r = subprocess.run(
    ["difyctl", "run", "app", app_id, "--inputs", json.dumps(inputs), "-o", "json"],
    capture_output=True, text=True,
)
if r.returncode == 0:
    payload = json.loads(r.stdout)
    if payload.get("status") == "paused":
        # Success-with-pending: collect input, then resume with
        # payload["form_token"] and payload["workflow_run_id"].
        ...
完整的暂停负载、恢复命令以及过期规则详见 工作流暂停时。恢复后的运行可能在后续步骤再次暂停,因此每次执行 resume app 后都要运行同样的检查。

根据 error.code 分支处理

错误对象的 error.code 是一个稳定的机器标识符:同一种失败在多次调用中产生相同的码,因此分支逻辑只需写一次。按恢复动作而非逐一枚举每个码来分组:
  • 重新认证后重试not_logged_inauth_expired。两者都退出码 4。
  • 退避后重试network_connectionserver_5xx。临时性的基础设施问题。
  • 不重试,检查原因server_4xx_other。服务器拒绝了请求:应用 ID 错误、输入有误,或权限不足。message 中带有服务器给出的原因。
  • 修正调用方式:随退出码 2 一同到达的用法类错误码。
错误对象还带有可读的 hint,提供建议的恢复动作。记录下来可加快调试。 当失败来自服务器时,错误对象可能还包含 error.server,即服务器自身的错误体。如果你的循环需要这种粒度,其 server.code(例如 not_found)能比 server_4xx_other 更精细地区分拒绝原因。

谨慎重试

difyctl 已经会在临时失败时以指数退避重试幂等请求(GET、PUT、DELETE)。预算及 --http-retry 覆盖项详见 全局标志 它从不自动重试的是 POST,而这恰恰是关键调用:每个 run app 都是 POST。当 run app 中途失败时,CLI 无法判断服务器是否已经开始执行,因此默认不会重新发送。 唯一的选择项是 run app --retry-on-limit,它专门在遇到 429 时以有界退避重试。它默认关闭,因为应用运行并非幂等。 同样的道理也适用于 Agent 的逻辑:重新运行一个失败的 run app 是一次新的执行,而不是对旧执行的恢复。对聊天助手来说,这通常可以接受(重新提问即可)。对带有副作用的工作流,则要根据工作流的行为来决定是否重试。 Agent 侧的重试只用于上述临时性错误,限制尝试次数,并记录每一次重试决策。Agent 静默地重新运行写操作,正是 effect 标签 要防范的失败模式。difyctl help -o json 中的每个命令都标记为 readwritedestructive,因此你的循环可以根据该标签来限定自动重试,绝不盲目重新发送 write 操作。
最后修改于 2026年6月25日