← 返回文章列表

给 AI 接上一双真干活的手——Agent 工作流里的人工审批怎么编排

📖 摘要:AI 应用交付里最常见的断档,是 AI 只会「说」不会「做」——建议给了,动手还是人。本文用一次发布前服务器巡检做完整实测:Dify 流程做确定性发起与审批,外部 Agent 在真实服务器上执行巡检并回写结果,约 10 秒执行完成、数据可与真实系统逐项对账;再让同款模型的无执行通道版本做同一道题——它如实拒绝:「我没有访问服务器的通道,请你们自己跑脚本把结果贴给我」。差异不在模型,在执行通道。适合正在评估「AI 只给方案、执行靠人」这类流程如何升级的交付方。


一、业务场景:发布前巡检,为什么要登服务器

假设你是运维负责人,团队每周要发两到三次版本。每次发布前有一道绕不开的工序:发布前巡检——确认目标服务器资源够不够、关键服务还活着、当前版本号对不对。理由很朴素:带着一个不健康的服务器上线,出了问题要背的锅就大了。

这道工序过去长这样:提交发布申请 → 审批通过 → 工程师登服务器 → 敲一串命令看内存、看磁盘、看服务进程、看版本 → 把结果贴回工单 → 审批人看完点头 → 发布。

问题不在命令难——free -mdf -h 谁都会敲。问题在每次都要人:发版窗口要有人守着敲命令;请假要等;手快的手慢的输出格式还不一样;巡检结果贴在工单里,没人复核它到底是不是刚从服务器上拷下来的。

你可能会想:这事不是早就该 AI 化了吗?让 AI 去巡检,把报告带回来。对——这正是我们一开始的想法。但真做起来,发现 AI 界的「巡检」和我们要的「巡检」是两码事。

二、断档:AI 只给建议,动手的还得是人

我们做了个对照实验,用的还是同一个模型(deepseek-v4-flash),同一个巡检任务描述:

工单 REL-20260903-002(应用服务器,紧急度高)发布前巡检:请对服务器执行发布前巡检,检查项包括主机名、内存、磁盘、demo-app 服务状态与 PID、应用版本、部署目录占用……

第一份答卷——普通 AI 助手(平台内 Agent,无外部执行通道):

我无法执行这项巡检任务。我没有任何工具、脚本或系统访问通道,无法真实连接或读取服务器……如果我现在生成一份结构化 JSON 巡检报告,其中的所有数值都将是凭空编造的……请直接在目标机上执行巡检脚本,并将结果贴给我,我会立即为您整理成规范的 JSON 报告。

这个回答是诚实的,甚至值得尊敬——它拒绝编造数据。但你注意它把球踢给了谁:踢回给了人。「跑脚本贴给我」——执行还是你的活。这就是断档:AI 负责出主意和整理格式,人负责所有和真实系统接触的部分。

第二份答卷——换一套架构:Dify 流程发起 + 外部 Agent 真执行(这就是本文主角)。同一道题,10 秒后回来一份这样的 JSON:

{

  "hostname": "目标服务器",

  "uptime": "up 4 days, 17 hours",

  "memory": "5261/7802MB",

  "disk": "1% used (949G free)",

  "app_service": {"name": "demo-app", "status": "running", "pid": "35725"},

  "app_version": "v2.4.1",

  "deploy_dir_size": "32K"

}

这不是 AI 编的——我们拿着这份报告回到服务器上手动重跑了一遍巡检脚本,主机名、服务 PID、版本号逐项对上了(内存数字略有浮动,因为两次取样间隔了几秒——这反而证明它是真读的,不是背的)。

同一个模型,同一种任务,一个说「做不到,请自己跑」,一个 10 秒交付可对账的真实结果。差距不在模型智商——在执行通道。

三、方案:断点式编排——Dify 负责发起与收口,Agent 负责真干活

要让 AI「真做」,技术上有几条路。我们最终采用的是断点式编排

Dify 流程(确定性)

  表单提交工单 → 审批判定 → 投递执行任务

        │

        ▼

执行服务(断点承接)

  收任务 → 转交 Agent → 盯状态 → 收结果 → 回写

        │

        ▼

Agent(自主执行)

  真在目标服务器上跑巡检脚本 → 结构化输出

        │

        ▼

Dify 流程(收口)

  接收结果 → 分支处理 → 输出巡检报告 / 失败走人工兜底

为什么这么拆,而不是让一端全包?

Dify 端把「手」放在编排之外。Dify 的强项是确定性编排——流程固定、节点可调试、输出可预期,这是它不可替代的底座。但它流程里的 AI 默认不接触真实系统:对照组里同款模型的纯平台内形态没有接任何执行工具,于是只能如实说「我没有访问服务器的通道」。严格讲,Dify 并不是不能长手——自研执行插件也能把命令通道做成工具塞进平台(我们做过插件开发,这条路可行)。但实测后我们选择把执行外置给独立执行体,理由有三:一是安全边界,执行体的权限、审批、审计能独立管理,不混进编排平台;二是复用,一个执行体可以同时服务多个 Dify 流程,不用每个流程各自接一套工具;三是自主性,巡检这类任务不是一问一答,要会拆解、会看中间结果、会处理异常——独立执行体天生干这个,平台内工具节点做的是单次调用。所以本文的架构判断是:编排留在 Dify,执行外置给带受控终端通道的执行体——两层各干各的强项。

Agent 端不接「流程」。Agent(这里指 Hermes Agent 这类自主执行体)天生会拆任务、会调工具、能在真实环境干活——但它是自主的,路径不可预测。让一个不可预测的执行体去管审批流、管多步业务编排,交付方晚上会睡不着。

于是中间的执行服务成了关键件:它接 Dify 的确定性指令,转给 Agent 自主执行,再把结果送回确定性流程——两端都不越界,断点由它承接。这套形态我们拆成了五个职责:投递接收、任务状态机、结果回写、失败兜底、安全闸门(后两个下文会讲到,它们是「能真干活」敢不敢交给 AI 的分水岭)。

再说执行体内部发生了什么——这是最容易黑盒化的部分。一次巡检任务,Agent 收到任务包后的实际动作是:先解析任务包(任务类型、要巡检什么、约束条件、预期输出格式),判断执行方案(跑哪些脚本、按什么顺序、要不要先探活),然后依次执行——每一步工具调用都会看中间结果,异常了当场判断是重试、跳过还是上报——最后把所有结果汇总成结构化 JSON 回写。实测里「约 10 秒」就是这四步的完整耗时:拆解秒级、脚本执行秒级、汇总与结构化回写秒级。不是「丢出去等 10 秒」,是它真的在拆任务、跑命令、看结果、汇总结论。

执行体我们选用的是开源通用 Agent 框架(Hermes Agent)——选它没有花哨理由:自带终端与文件操作通道、支持任务级授权控制、可本地部署不依赖云服务。其他 Agent 框架我们没有在这条链路上做同等深度的实测,不展开对比——选型结论是「够用、可授权、能本地部署」三个条件筛选出来的,不是生态偏好。

版本说明:以下实测基于 Dify 1.17.0 社区版 + Hermes Agent v0.21.0(Agent 官方 API 服务)。

四、整体架构与关键模块

先看整体架构——它回答了「各组件放哪、怎么衔接」:

graph TD subgraph dify["Dify 流程(确定性编排端)"] A["表单提交工单:工单号、服务器角色、审批结果"] B["审批判定:未通过直接拒绝出口"] C["投递执行任务:任务包 JSON 直发"] G["流程收口:成功出报告 / 失败出人工兜底指引"] A --> B --> C end subgraph exec["执行服务(断点承接,可交付件)"] D["投递接收:秒回任务 ID,流程不阻塞"] E["状态机 + 转交 Agent:提交、盯状态、收结果"] F["兜底与闸门:失败双态回写 / 高危任务默认拒绝"] end subgraph agent["Agent(自主执行体)"] H["真执行:terminal 工具跑巡检脚本 + 授权"] end subgraph target["目标系统"] I["演示服务器:demo-app 服务 + 巡检脚本"] end C --> D D --> E E --> H H --> I E --> F F --> G

四个模块里,有三个点值得单独展开——它们决定了这套东西能不能真的交付。

模块一:任务怎么传——别让 JSON 死在半路

Dify 表单里收了五六个字段(工单号、服务器角色、紧急度、备注……),要变成 Agent 能执行的任务,我们把它打包成一个任务包 JSON:任务类型、上下文(业务字段全集)、期望输出(要求什么格式、什么字段)、约束(几条硬规则:数据必须来自脚本真实输出、禁止编造、不要多余解释)。

打包容易,传过去才是坑。第一次实跑,Agent 收到的任务包被截断成一截残缺前缀——排查发现是 Dify 的 HTTP 请求模板在变量值含引号时会把 JSON 截断(实测断在第一个内嵌双引号处)。解法是让请求体直接裸引用变量、任务包原文直发。这类坑排掉之后,Agent 对任务包的理解是完整的:我们把工单描述里的每一个细节(故障持续两天、一天出现四五次、重启交换机短暂缓解)都放进任务包,Agent 的输出逐条命中这些细节并展开成推理——上下文零丢失。

模块二:执行服务——为什么同步不行,要异步

最早的通道是同步调用:Dify 流程发请求,等 Agent 答完再继续。实测里,简单问答 8-15 秒能回来,但深度任务动辄一分钟起——让用户的表单流程干等一分钟,体验和稳定性都不可接受。

所以执行服务走了异步投递:Dify 提交任务 → 执行服务秒回「任务已受理 + 任务 ID」,流程立刻结束,用户不用等;执行服务在后台把任务转给 Agent、轮询执行状态、等结果回来再触发 Dify 的收口流程。实测链路:表单提交 0.6 秒返回受理,Agent 真执行约 10 秒,收口流程拿到结果——发起端全程不阻塞。任务 ID 贯穿两端(Dify 工单号 → 执行服务任务 ID → Agent 执行 ID),任何一个环节出了问题,顺着 ID 链就能定位。

模块三:敢不敢让它真干——兜底与闸门

执行体不可靠时流程不能死——这是交付可信度的底线。我们做了两类故障注入实测:把 Agent 服务停掉、把执行中的任务强制中断、让任务超时。结果一致暴露一个裸行为:失败信号根本回不到 Dify。表单显示「已提交」,实际上任务永远悬空,没有人知道。

兜底方案是执行服务加双态回写:失败也回调 Dify 流程(带着失败原因),Dify 的收口流程区分成功/失败两个出口——失败出口直接生成一条人工兜底指引:任务 ID、失败原因、处置选项(重新提交或人工处理)。三类故障注入后全部走到兜底出口,成功路径不受影响。

验收视角:这三类故障注入(执行体停摆、执行中断、任务超时)不是实验期的临时测试,而是这类交付的必检验收项——验收标准不是「正常路径跑通了」,而是「任何故障都能回到确定性流程并生成人工兜底指引」。做独立验收时,报告会按三层覆盖:正常路径端到端验证、异常路径覆盖(至少三类故障注入)、安全闸门有效性验证。

另一道闸门管「高危动作」:巡检是只读的没事,但如果任务描述里是删文件、清库、重启服务这类破坏性动作呢?实测发现 Agent 自己的原生审批在这条无人值守链路上并不拦(官方行为待核),所以安全闸门放在了执行服务层——内置高危模式库(递归删除、根路径强删、关机重启、格式化、SQL 清表……),高危任务默认拒绝,执行体零接触;要放行必须由流程显式授权。演示里我们验证了完整语义:默认提交返回「高危任务被闸门拦截」,带授权标记后放行、真执行成功。这里也如实说一个边界:关键词模式会误伤正常业务描述(比如任务里提到「覆盖」配置就可能被拦),所以生产形态我们改成了任务包显式声明高危动作 + 审批环节授权置位——机器判断粗筛、人工授权终审,两层配合。具体设计:任务包内带一个高危动作声明字段(任务发起方在包结构里显式声明本次任务是否含破坏性动作、是哪些),执行服务只在「声明含高危 + 授权位置位」双条件满足时才放行;授权位由审批环节置入(演示里就是审批节点通过后给任务包附上授权标记),单次有效、不跨任务复用——不是「授权一次终身免检」,是「每笔高危任务单独批一次」。

这里把安全边界再补完整一层,避免误解:闸门管的是「任务要不要放行」,但放行之后执行体能碰什么范围,由另一道防线兜底——生产部署时执行体以专用最小权限账号运行(非管理账号),目录与命令权限按白名单授权(巡检账号能读巡检数据、跑白名单命令,碰不到生产目录)。审批授权管「能不能做」、执行身份管「能做到哪」——两层叠起来才是完整的安全边界;账号权限的具体配置属交付级细节,随交付文档提供。

五、端到端实证:同题两答,数据对账

把整套串起来的演示场景是「发布前巡检」。流程与实测数据如下:

环节 实测 说明
表单提交(工单号/服务器角色/紧急度/审批结果) 即时 演示用审批字段模拟;生产形态走平台原生人工审批节点(见 FAQ:审批链接推给审批人,点开批/驳,通过才继续投递——全链实测)
审批未通过 秒回拒绝出口 不投递、不产生任何执行动作
审批通过 → 投递 0.6s 返回「已受理 + 任务 ID」 流程不阻塞,用户不用等执行
Agent 真执行巡检 约 10s 在目标服务器真实运行巡检脚本,收集 8 项指标
回写收口流程 立即 输出完整巡检报告(JSON)

交叉验证——报告是不是真的,拿服务器实测对账:

报告字段 Agent 报告值 服务器手动实测值 对账
demo-app 服务状态 running (pid 35725) running (pid 35725) ✓ 一致
应用版本 v2.4.1 v2.4.1 ✓ 一致
主机名 目标服务器 目标服务器 ✓ 一致
内存 5261/7802MB 5249/7802MB ✓ 两次取样自然浮动

同一道题的对照组(同款模型、无执行通道)表现前面已经贴过——如实拒绝 + 把执行推回给人。结果到哪里看:发起流程在投递完的那一刻就结束了——表单提交、审批通过、任务投出,它的使命完成,用户不用等执行。执行结果由独立的收口流程承接整理(见 FAQ「为什么收口是独立的第二个流程」),收口完成后把报告推送给审批人/发起人(企微/邮件),并在收口流程里留一份正式记录可回溯。结果不是回到原发起流程——那个流程在投递时已经办结,这正是「断点式」的含义。

到这里,差异不再是观点,是可复现的实验结果:纯平台内 AI 读世界,这套架构让 AI 碰世界——真实读取、真实回写。

六、适用边界与下一步

这套方案适合什么、不适合什么,我们实测后的判断(单看本方案;与知识问答型 AI 链路的完整选型对比会另文展开):

适合

不适合/边界(实测确认)

下一步演进:当前是实验验证形态,生产化要做四件事——执行服务任务台账落盘(现在是内存态,重启会丢记录)、高危授权从全文关键词改成任务包显式声明字段(关键词会误伤正常描述)、执行服务加鉴权与多租户隔离、执行体以最小权限专用户部署(系统权限兜底,非管理账号)。这四件做完,这套「Dify 编排 + Agent 真执行」就从能演示变成能交付。


常见问题

为什么不用 Dify 自己的 Agent,要外接执行体?

Dify 的编排与流程里的 AI 默认不接触真实系统——对照实验里,纯平台内形态(同款模型、未接执行工具)对巡检任务如实回答「我没有访问服务器的通道,请你们自己跑脚本」;要让平台内 AI 获得通道,需要自研执行插件把命令能力做成工具塞进编排平台(这条路可行)。我们实测后选择把执行外置给独立执行体,是因为权限/审计能独立管理、一个执行体能服务多个流程、且巡检这类任务要会拆解与处理异常——独立执行体天生干这个。详细选型理由见正文第三节。

这套方案需要额外部署什么?

三段:Dify(流程编排,docker 部署)+ 执行服务(自研的轻量 Python 服务,约 160 行、零第三方依赖,五职责:投递/状态机/回写/兜底/闸门;架构足够简单,交付文档提供完整说明)+ Agent(自主执行体,官方 API 服务默认只监听本机回环地址,不暴露公网)。三者同机部署即可跑通,模型 key 由使用方自备。演示级复现(本文场景照做)约一到两天;生产化落地(任务台账落盘、鉴权与多租户隔离等)按 TR 交付流程分阶段验收,另计周期。

这套方案能复现吗?技术细节公开到什么程度?

本文定位是方案实证展示:架构、模块职责、实测数据与验收方法已尽量讲透,读者可以按文中结构评估与复现演示级链路。执行服务接口协议、状态机与超时/重试参数、Agent 工具配置模板这类交付级技术细节,随 TR 交付文档在项目交付时提供(含正常路径、异常路径、安全闸门三项验收报告)——公开文章给方向与证据,交付文档给图纸。

AI 会不会乱操作服务器?怎么兜底?

三层防护:高危任务默认拒绝(执行服务层闸门,含删除/格式化/清库等破坏性模式,需显式授权才放行)、执行过程任务 ID 贯穿可追溯(工单号到执行 ID 全链可查)、失败必回写(任何故障都回调 Dify 流程出人工兜底指引,不会无声悬空)。实测三类故障注入(服务停摆/执行中断/超时)全部走了兜底出口。

为什么收口是独立的第二个流程?结果为什么不是回到发起流程?

Dify 的 workflow run 是一次性的:从开始跑到结束就办结,不能「等执行完再接着跑」。而执行发生在发起流程结束之后(桥调度 Hermes 要 10-60 秒)——所以执行完成后必须重新进入一次 Dify,这次进入就是独立的收口流程(第二个流程)。收口流程的另一层价值:执行结果在这里回到 Dify 的正式体系——留下可审计的记录,未来可接下游(知识库沉淀、工单回写、报表)——它是执行结果进入 Dify 生态的接驳点,不只是把结果格式化输出。

审批人怎么知道有任务要审批?通知怎么送达?

流程在人工审批节点会暂停等待,同时生成一个带令牌的审批链接——把链接送给人就完成了通知。送达路径有两条:邮件是 Dify 节点原生通知(配置 SMTP 后平台自动发信);企微没有 Dify 原生通道,是经由外部消息推送送达的(本链路中由执行体系的消息通道负责推送)。审批人打开链接,看到的是完整任务内容与「批准 / 驳回」按钮——点一下流程自动恢复:批准则继续投递执行,驳回则走拒绝出口。链接一次性有效、带有效期,过期任务自动终止不悬空。通知走企微还是邮件、发给谁,由交付方按团队习惯配置,链接本身不依赖登录态——审批人拿到链接就能批。


相关文章:AI 执行服务怎么搭:任务调度中枢拆解(调度中枢详解)|AI 自动化工作流从零搭:断点续跑式编排指南(手把手搭建指南)

本文基于 Dify 1.17.0 社区版 + Hermes Agent v0.21.0 实测。AI 参与创作声明:本文由 AI 辅助写作,内容基于作者真实实测记录。

想让 AI 助理接入您的业务与沟通工具?看看方案与服务 →

联系我

邮箱contact@fishsun.cn

点击邮箱直接写信 · 扫码加微信沟通

微信

微信二维码

扫码加微信 · 备注「门户」更快通过