fl2va-ref2va-mutual-exclusive-bug.md 4.18 KB

api.py 的坑:同时传首尾帧和参考图,references 会静默吃掉 keyframes

背景:用户问"H3 怎么把首尾帧和人物设定图一次性都给模型",对照 DiffSynth-Studio 官方 MiniMaxH3Pipeline.__call__ 源码查清楚了——不是我们代码的锅,是这个 pipeline 本身的设计: keyframes(FL2VA,首尾帧)和 references(Ref2VA,参考图)在打包序列这一层是互斥的, MiniMax H3Unit_PackedSequenceBuilder 里 if ref_blocks is not None 走 ref2va 分支, 否则才用 keyframes——只要 references 非空,keyframes 会被直接忽略,不报错,静默丢弃。

官方倒是有个 H3-Context-IR(真实存在,查到了官方 API 文档),专门负责编排"首帧/尾帧/身份参考图/ 参考视频各自扮演什么角色"这种复杂多模态输入,但官方原话明确写了"不包含在开源发布里"——只有 调用 MiniMax 付费云端 API 才能用,本地部署这条路走不通。

更麻烦的:我们自己的 api.py 没有任何防护,而且已经真的踩过

worker() 里无条件把 keyframes(来自 first_frame_url/last_frame_url)和 references (来自 reference_image_urls/reference_video_urls)一起传给 pipe(),GenReq 这个 pydantic 模型也完全没有互斥校验——用户完全可以同时填首尾帧 URL 和参考图 URL 提交,系统照单全收, 但底层会按 references 非空走 ref2va 打包,首尾帧完全不起作用,没有任何报错或警告。

查了今天真实提交的任务 ed3663dcda7f:请求里 reference_image_urls 是空数组 []。 prompt 文本里写的"女子、捕快面部由@图片3、@图片5锁定"这类 @图片N 写法是照抄官方 Context-IR 的约定,但我们本地这条链路根本不认识这个约定——那两张"设定图"从来没真的作为 图片数据挂载给模型,纯粹是 prompt 里的文字,模型只是把这几个字当普通文字理解,没有对应的 图片输入。以后写 prompt 不要用这种 @图片N 的写法指望它会自动关联图片,除非真的把对应 URL 填进 reference_image_urls。

要做的事

  1. 给 GenReq 加一条 model_validator:如果 (first_frame_url or last_frame_url) 和 (reference_image_urls or reference_video_urls) 同时非空,直接 422 拒绝,错误信息写清楚 "FL2VA 首尾帧和 Ref2VA 参考图/参考视频不能同时传,pipeline 层会静默丢弃 keyframes"—— 参考 ROWS_LIMIT 那条校验的写法(api.py 里已有先例),不是新模式。
  2. h3-console 前端也要同步:现在"首尾帧生视频"(fl2va tab)和"多参考图生视频"(ref2va tab) 是两个独立表单,UI 层面本来就不会让用户在同一次提交里同时填两种,这条主要是防后端被绕过 (比如有人直接调 API 不走 console),前端不用大改,但可以在 fl2va tab 的 hint 里加一句 "这个模式不支持额外挂参考图做身份锁定,要锁身份得改用 Ref2VA 模式",减少以后再犯同样的 prompt 写法误解。
  3. 给用户的实际建议(不是代码改动,是使用方式):像"延长视频+保持人物身份"这种场景, 本地开源版做不到"首尾帧强约束 + 身份参考图"同时要,只能二选一改用纯 Ref2VA:不设 first_frame_url/last_frame_url,把"原视频最后一帧截图 + 女子设定图 + 捕快设定图" 都塞进 reference_image_urls(最多 9 张),需要运镜连贯性的话再加 reference_video_urls (2026-08-20 新加的字段,还没在真实 GPU 上跑过一次,见 verify-video-reference-on-gpu.md)。 代价是失去"第一帧/最后一帧精确锁定"这个强约束,换成"多张参考图做柔性引导",不是等价替换。

优先级

不着急——这是个"用错了会静默出错"的边界情况,不是现在正在发生的故障。但比起线上突然出现 "明明传了首尾帧却不起作用"的困惑,加一条清晰的 422 报错成本很低(半小时内能写完,参考 ROWS_LIMIT 校验抄一遍就行),建议跟 quality-tuning-plan.md 里的实测一起顺手做掉, 不用单独排期。