估 FLUX 批量出图的成本,先别急着套单价,先把「一次批量任务要出多少张图」这个口径定下来。需求方给的往往只是最终要交出去的那一档,而实际向接口发出的提交次数通常更多:有备选要一起跑,有被否掉要重出,还有超时和失败返回要重试。合理的做法是先拆档、再做一次小批量试跑拿到提交倍率,用倍率回推正式批量的张数区间,最后在用量或账单页面按提交次数核对。判断依据是配置、日志和页面数字,不是凭感觉估一个数。
批量出图成本应按「实际提交次数」估,而不是按最终交付张数。通常把需求拆成必出、备选、返工三档,返工档最不确定;再跑一次小批量试跑,记录实际提交次数与试跑张数的比值,把失败重试单独计一列,用这个倍率反推正式批量的张数区间。跑完在用量或账单页核对提交次数,偏差大时先查重试是否集中,再调口径。前提是计费按提交计、模型与出图参数保持一致。
把需求张数拆成必出、备选、返工三档
三档的区别在于「谁来决定要不要」:必出是交付清单上写死、必须交出去的;备选是给需求方挑选或留作备份的,可能被否掉一部分;返工是被否掉之后需要重新生成的。它们的来源不同,合计方式也不同。
- 必出:来源是需求方确认的交付清单或合同条目,数量明确,写进任务单时就能对上。
- 备选:来源是「多给几张挑」这类要求,或者自己为风格对照预留的候选。数量可以谈,通常在需求确认时一并定下。
- 返工:来源是验收反馈,事前无法准确知道,只能靠历史反馈情况或试跑结果估一个比例,这一档最不确定。
合计方式建议写成两步:先算「总需求张数 = 必出 + 备选 + 预期返工」,再算「预计提交次数 = 总需求张数 × 提交倍率」。把返工单独写成一行、而不是揉进必出里,后面核对时才能看出偏差出在哪一档。
# 任务单里建议先落这几个字段,后面回推和核对都用得上
batch_name: poster_2024q3
must_deliver: 120 # 必出
optional_pick: 40 # 备选
expected_rework: 30 # 预期返工(试跑后再填)
submit_ratio: 待试跑 # 提交倍率,来自试跑记录
记录一次小批量试跑里实际提交了多少次
试跑的目的不是看画得好不好,而是拿到「需求张数」和「实际提交次数」之间的比例。选和正式批次同一类提示词、同一分辨率、同一步数的小样本,规模不用大,够看出比例即可。记录表建议至少留下面四列,每列都要能从日志或脚本输出里对上:
- 试跑张数:这次试跑按需求算要出几张。
- 被弃用张数:跑出来了但没用上的张数,属于内容判断,不是请求失败。
- 重出张数:因为被弃用而重新生成的张数。
- 实际提交次数:向接口发出的请求总数,包含失败和重试的那些。
提交次数从日志里数比手工记更可靠。建议每次提交写一行结构化日志,再用一条命令按状态汇总:
# 每行一条 JSON:{"event":"submit","task_id":"...","status":"ok|failed|timeout"}
jq -r 'select(.event=="submit") | .status' trial_runs.jsonl | sort | uniq -c
# 提交总次数
jq -r 'select(.event=="submit") | .task_id' trial_runs.jsonl | wc -l
试跑结束后算一个比值:提交倍率 = 实际提交次数 ÷ 试跑张数。这个比值就是正式批量的放缩依据,它本身不是成本,只是口径换算系数。
把失败重试单独计一列
重试最容易漏算,因为它看起来「不算一张图」。但按提交计费的场景里,一次超时或失败返回已经产生了一次调用,重试只是又产生一次。触发重试的条件常见有三类:请求超时、接口返回失败状态、返回结果不可用(空图、明显损坏、被审核拦截)。对应的计数规则建议统一成一条:
- 每一次向接口发出的请求,无论成功失败,都计 1 次提交。
- 同一张图的多次重试,逐次累加,不合并。
- 「弃用」和「重试」分开计数:弃用是内容不合用,重试是请求没拿到可用返回,两者不能互相抵扣。
如果日志里只有成功记录,可以先在接入层加一个计数器或一条 submit 日志,把失败分支也写进去。验证方式是:拿一次试跑的日志,分别数出 ok、failed、timeout 三类行数,看三者之和是否等于提交总次数。
用试跑比例回推正式批量的张数区间
回推不要只给一个数,给区间更稳。原因是试跑样本小,倍率本身有波动。可以先从试跑里取一个保守值和一个乐观值(例如把重试偏多的那几次单独看一下是否属于偶发),再分别乘正式批次的总需求张数。
正式提交次数下限 ≈ 总需求张数 × 提交倍率(乐观)
正式提交次数上限 ≈ 总需求张数 × 提交倍率(保守)
一个完整算例(下面数字是假设值,用来演示算法,不是任何环境的结果):某批海报需求为必出 400 张、备选 80 张,预期返工按 5% 计约 20 张,总需求张数 = 500 张。试跑按需求 20 张跑,实际提交 27 次,提交倍率 = 27 ÷ 20 = 1.35;把重试偏多的那几次视为偶发后取乐观值 1.25。则正式提交次数区间约为 500 × 1.25 = 625 次到 500 × 1.35 = 675 次。
need = 500
ratio_low, ratio_high = 1.25, 1.35
print(round(need * ratio_low), round(need * ratio_high)) # 625 675
这个区间成立依赖几个假设,写进估算说明里更清楚:计费口径按提交次数而不是成功张数;正式批次的模型版本、分辨率、步数与试跑一致;超时阈值和并发设置没有明显变化;试跑的提示词类型能代表正式批次。任一条不成立,倍率应当重测,而不是直接套用。
在用量或账单页面核对实际消耗
跑完之后用页面数字验证前面的口径。要看的主要是三个字段:计费单位的统计口径(按提交次数还是按成功张数)、统计周期内的提交总次数、以及成功返回的张数。核对时间点建议放在试跑结束后立刻看一次、正式批次跑完当天看一次、跨结算周期前再看一次,避免统计窗口没闭合造成误判。
偏差超出预期时,按方向调整:如果实际提交次数明显高于估算上限,先看重试是否集中在超时这一类,再检查脚本有没有对同一条提示词重复提交;如果明显低于估算下限,检查批量任务有没有做去重或合并,以及部分请求是否走了不计费的缓存返回。核对完把实际倍率回填到任务单的 submit_ratio 字段,下一批就能用更贴近的口径来估。