AI 生成类工作流工程化经验
提炼自两个生产项目:上身图工作流(产品图 → 模特上身图 → 分镜 → 短视频三段式流水线)与元素提取 v3(POD 服装图案元素提取)。均为「飞书多维表格驱动 + 无头 worker 轮询 + 多厂商生成 API」形态。 最新更新: 2026-07-20
核心结论
- 小团队 AI 工作流的最优前端是飞书多维表格:省掉自建 UI、权限、通知三件事,机器人纯后台轮询,不需要公网暴露
- 生成类 API 的可靠性靠三层叠加:单厂商整链重试 → 跨厂商兜底 → 降级方案(固定提示词),任何一层失败都要有告警出口
- 厂商返回的结果 URL 几乎都会过期,必须立刻转存到自有存储,且「下载+上传」要整体重试——生成成功却因传输失败重跑,等于双倍扣费
- 失败不可怕,静默失败才可怕:轮询主循环假死比单任务失败严重得多,catch-all + 告警是底线
- 成本必须精确入账且失败也入账——按厂商返回的 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 + 告警——循环假死意味着所有任务停摆,比单任务失败严重 |
| 失败也入账 | 失败前已产生的真实扣费必须累计进成本列 |
孤儿恢复
进程重启会把正在跑的任务永远留在「生成中」状态,没人再管。每轮轮询先扫一遍运行态记录:
- 不在本进程在办集合里的即孤儿
- 二次拉取最新字段确认(搜索结果可能滞后,刚完成的任务已改状态)
- 确认后置失败 + 写明续跑方法,通知提交人
关键决策:不自动重跑——中断前提交给厂商的任务可能实际已完成并扣费,自动重跑会双倍计费。让人工确认无重复扣费后再点「提交」续跑。
五、结果转存:厂商 URL 会过期
| 厂商 | URL 有效期 |
|---|---|
| 常见生图/生视频 API | 1~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开关 - 开视频音频生成易触发「音频含敏感信息」审核拒绝——纯展示类视频直接关音频,既守内容红线又避免无谓失败
相关笔记
- 云服务器部署与运维:这套 worker 的宿主机部署、更新与备份策略
- 监控告警:Prometheus/Grafana 体系化监控
- 大模型应用开发 L7: 部署与运维