Skip to content

AI 生成类工作流工程化经验

提炼自两个生产项目:上身图工作流(产品图 → 模特上身图 → 分镜 → 短视频三段式流水线)与元素提取 v3(POD 服装图案元素提取)。均为「飞书多维表格驱动 + 无头 worker 轮询 + 多厂商生成 API」形态。 最新更新: 2026-07-20


核心结论

  1. 小团队 AI 工作流的最优前端是飞书多维表格:省掉自建 UI、权限、通知三件事,机器人纯后台轮询,不需要公网暴露
  2. 生成类 API 的可靠性靠三层叠加:单厂商整链重试 → 跨厂商兜底 → 降级方案(固定提示词),任何一层失败都要有告警出口
  3. 厂商返回的结果 URL 几乎都会过期,必须立刻转存到自有存储,且「下载+上传」要整体重试——生成成功却因传输失败重跑,等于双倍扣费
  4. 失败不可怕,静默失败才可怕:轮询主循环假死比单任务失败严重得多,catch-all + 告警是底线
  5. 成本必须精确入账且失败也入账——按厂商返回的 creditsConsumed/usage 记,不按估算记

一、总体架构:表格即状态机

飞书多维表格(员工唯一操作界面)
  ├─ 「操作」列:员工写命令(提交/通过/打回),机器人消费后清空
  └─ 「状态」列:机器人写进度(生成中/待确认/完成/失败)

        │ 30s 轮询 + 结果回写附件列
  无头 worker(服务器 pm2 守护,无 Web 界面、无公网暴露)
        ├─ LLM 节点(提示词生成/转写)
        ├─ 生成厂商适配层(submit/poll 统一接口)
        └─ 监控埋点 + 告警

双列单写者设计(关键)

谁写作用
操作只有员工命令列:提交/通过/打回;机器人执行前先清空(消费即清,天然幂等)
状态只有机器人纯进度展示,员工不许改

两列分工严格、互不打架,避免了「谁改的这个字段」类并发问题。这是用表格做状态机能稳定运行的前提。

判定表驱动 + 按产物断点续跑

调度决策是一张判定表:(操作, 状态, 已有产物) -> 处理环节。其中「提交」不区分新任务/失败重跑/完成后重做——统一按已有产物推断从哪个环节续跑(无上身图跑环节①,有图无分镜跑环节②,其余跑环节③)。好处:

  • 员工只需要记一个动作:出问题就再选「提交」
  • 失败续跑不重复执行已完成环节,省钱省时间
  • 非法组合(如生成中点通过)清掉命令 + 群提示,不动状态

二、submit/poll 异步生成模式

生成类 API(生图 1~4 分钟、生视频约 6 分钟)一律走「提交拿 taskId → 轮询查状态」,不用回调(worker 可能在内网/本地,没有公网 IP)。

超时要分层设置:

请求类型超时策略理由
提交/上传(连接 15s, 读 180s) 放宽厂商用真 key 提交大图时响应慢
轮询查询(连接 15s, 读 30s) 收紧查询本应秒回,快速失败进入下一轮

轮询查询的单次网络失败要容忍(任务仍在厂商后台跑,断一次查询不代表任务失败),只有超过总时限才抛错。进度有变化才打日志,避免刷屏。


三、重试与兜底链(三层)

第一层  单厂商整链重试:提交+轮询算一次,失败 sleep 3s 再试,共 N 次
第二层  跨厂商兜底:kie 全败 -> 切 toapis 再重试 N 次
第三层  降级方案:LLM 主模型 -> 备模型 -> 第三家;全败回退固定提示词

要点:

  • 「一次重试」的粒度是提交+轮询整链,不是单个 HTTP 请求——轮询超时也算这次失败
  • 跨厂商兜底的前提是适配层统一 submit/poll 接口签名,厂商差异(字段名、负向提示词支持与否)全部封在 Provider 类内部
  • 降级不是无声的:回退固定提示词后任务仍能出图但质量下降,必须推送告警让人工关注上游通道
  • 与微服务的限流/熔断/降级同一思想:可用性优先,降级要有感知

四、失败处置:绝不静默吞错

机制做法
人话错误自定义 WorkflowError(reason),reason 直接回写表格报错列给员工看,含处理方法
工作线程兜底线程池任务 catch-all,任何异常都走失败处置,绝不让异常消失在线程池里
失败处置自身兜底_safe_fail:失败回写/通知本身再出错,降级为日志 + pushplus 告警
主循环兜底轮询循环 catch-all + 告警——循环假死意味着所有任务停摆,比单任务失败严重
失败也入账失败前已产生的真实扣费必须累计进成本列

孤儿恢复

进程重启会把正在跑的任务永远留在「生成中」状态,没人再管。每轮轮询先扫一遍运行态记录:

  1. 不在本进程在办集合里的即孤儿
  2. 二次拉取最新字段确认(搜索结果可能滞后,刚完成的任务已改状态)
  3. 确认后置失败 + 写明续跑方法,通知提交人

关键决策:不自动重跑——中断前提交给厂商的任务可能实际已完成并扣费,自动重跑会双倍计费。让人工确认无重复扣费后再点「提交」续跑。


五、结果转存:厂商 URL 会过期

厂商URL 有效期
常见生图/生视频 API1~24 小时
kie约 14 天

结论:结果 URL 不能直接回写表格,必须下载 → 上传到自有存储(飞书附件字段/对象存储)→ 删临时文件。飞书附件永久有效且原生预览,是多维表格方案的天然归宿。

实测坑:视频约 16MB,下载/上传易网络超时。生成已成功、只是传输瞬时失败,如果整环节报失败,员工续跑就会重新生成、重复扣费。所以「下载+上传」要作为整体重试 3 次,重试的是传输而不是生成。


六、成本与监控

成本精确记账

  • 按厂商返回的 creditsConsumed × 单价记账,LLM 按 usage 记,不估算
  • ctx 上下文贯穿单步全程累计成本/耗时,环节结束累加回写表格
  • 链式环节(②直接链入③)之间要清零 ctx,防止重复累计
  • 无按单计费口径的厂商记 0,由月账对齐

监控与告警

组件做法
埋点metrics 模块原子写 webmon/metrics.json(调用数/重试数/错误分类/日统计)
监控页纯静态 HTML 5 秒自刷新,nginx alias 托管——零依赖、零框架
告警pushplus 推送,按标题分桶冷却 600s 防刷屏(一波集中失败只推一次)
告警函数纪律绝不抛异常、未配 token 静默跳过——告警挂了不能反过来搞挂业务
余额巡检daemon 后台线程 5 分钟查一次各厂商余额,低于阈值告警(厂商专属阈值优先于全局阈值)

余额巡检踩坑:某厂商返回 unlimited_quota=true 只是配额策略标记,真正会耗尽的是 remain_credits。曾因「无限额度就跳过告警」漏报,剩 81 积分被限流却无任何告警。判断余额永远看会耗尽的那个字段。

更通用的监控体系见监控告警


七、LLM 节点设计模式

模式做法收益
创作者/执行者分离LLM① 负责创作(识别产品 → 定风格 → 写提示词 + 脚本双产出);LLM② 只做执行转写,明确「不做创作」人工只需确认一次创作结果,后续环节可控
提示词语言分层模型接口全英文(生图/生视频提示词、一致性关键词);人工确认界面用中文(脚本方案),拼给支持中文的视频模型时直传原文零翻译损耗模型效果与人工可读兼得
占位符 + 一致性关键词脚本用 {角色}/{产品} 占位符,配英文一致性关键词锚定外观脚本与图解耦,跨镜头外观统一
双段输出解析防御双产出用标记分段,解析时校验缺段/过短,不合格自动走兜底链LLM 输出格式不稳定不至于炸流程
业务红线三处落位内容红线同时写进 LLM 提示词规则、固定模板 Avoid 段、代码硬拼后缀单点失效不破线
人工确认点可配置唯一强制确认点 + 次要确认点做成开关(如 SB_CONFIRM),试运行攒数据后评估关闭质量与效率的闸门可调

八、环境坑

  • 本机代理会卡死大图上传:Clash 等代理对 API 大文件上传极不友好,生成类 API 请求默认强制直连(proxies={"http": None, "https": None}),做成 NO_PROXY_FOR_API 开关
  • 开视频音频生成易触发「音频含敏感信息」审核拒绝——纯展示类视频直接关音频,既守内容红线又避免无谓失败

相关笔记

基于 VitePress 构建