HANDOFF.md 19.1 KB

交接文档 · 2026-09-03(最新)

给下次进来的人(或进程)。先读这份,再读 CLAUDE.md。 权威细节在 llm-setup.md(整机)、raylight/README.md(视频线,2026-08-22起的生产 后端)、h3-console/README.md(Web 管理台)。时间线在 CHANGELOG.md。 这里只写「现在是什么状态、下一步该干什么」——下面 2026-08-20 及更早的几节是历史记录, 架构已经变了(minimax-h3 旧代码已删除,raylight 是现在的生产后端),仍有效的踩坑经验 保留,但状态类的表格/结论以这一节为准,不要用旧的。

2026-09-03:现在是什么状态

一句话:生产 H3 后端是 raylight/(ComfyUI + Raylight 插件,4卡当一个 FSDP 集群, 详见 CLAUDE.md「当前负载」表),minimax-h3/ 旧架构代码已经在 8/24 删除只剩权重。 今天这轮会话围绕 raylight + h3-console 做了一批修复/功能,全部已部署到服务器验证通过、 已提交推送到 git(最新 46fa265),细节见 CHANGELOG.md 2026-09-03 那两节:

  1. 修了一个真实 bug:参考图/参考视频文件名带中文时,raylight/server.py 的 _fetch_to_input() 用 urllib.request.urlopen 直接崩 UnicodeEncodeError (HTTP 请求行必须纯 ASCII,中文没 percent-encode)。
  2. 排队优先级/插队:Job 加 queue_seq,Q 从 queue.Queue() 换成 queue.PriorityQueue(),新增 POST /v1/videos/{jid}/prioritize,console 详情页/ 列表菜单都加了"优先插队"按钮。
  3. 重启不再清空排队任务:这是顺带发现的架构问题——start.sh 重启前,排队中的任务 会被无条件标记 cancelled(内存队列重启即空,sqlite 里的记录没有任何路径被重新入队)。 现在重启会把排队中的任务原样保留、按序重新入队,只有"正好卡在重启瞬间"那条真运行中的 任务救不回来(这个改不了,GPU 执行状态确实丢了)。这条改动很重要:以后改 raylight/server.py 要重启,不用再担心把排队任务清空了,只需要挑当前没有任务在跑 的时机(或者接受损失那一条正在跑的)。
  4. 补回一个 8/24 提交过、但从未真正部署到服务器的 ComfyUI 存活探测(_comfyui_alive, 修 /health 在 ComfyUI 进程崩溃后仍骗人报 ready 的监控盲区)。顺带把本地长期分叉的 raylight/server.py(顶层)和 raylight/scripts/server.py 两份文件同步一致。
  5. h3-console 的 GET /v1/models 之前硬编码 3 档过期数据(模型文件名指向已删除的 api.py/gateway.py 旧架构),改成实时问 raylight 新增的 GET /v1/resolutions (RESOLUTION_CEILINGS 的镜像),现在正确返回全部 8 档。
  6. 任务详情页加了两个排查用字段(默认折叠):原始参数(req 原样 JSON)、 ComfyUI History(懒加载,问 raylight 新增的 GET /v1/videos/{jid}/comfy_history, 透传 ComfyUI 自己的 /history/{prompt_id}——这份数据在 ComfyUI 内存里,进程重启就没了, 不是 bug)。生成结果视频从页面底部挪到了状态/操作按钮那一行下面。

当前各服务实际状态(2026-09-03 晚实测,不是文档推测)

服务 状态 说明
raylight(ComfyUI 8188 + server.py 8100) 在跑,4卡满载 100% 16 条排队 + 1 条运行中(正常工作负载,不是卡住)
h3-console(8080,LAN) 在跑 systemctl is-active → active,今天带新代码重启过
h3-console(8081,公网 /console 子路径) 在跑 同上
llm38 / whisper / m3e-embedding(docker) 停(Exited,2周前) 不是本次操作停的,沿用既有目标状态(这台机器当前只跑 H3)
GPU 显存 4×22528MiB 卡各用 ~11.5G,100% 利用率 raylight 一直有任务在跑,正常
磁盘 / 81% used,剩 43G 没报警但在收紧,留意
磁盘 /data 89% used,剩 199G 同上

下一步 / 需要留意的点

  1. 没有阻塞性待办——这轮改动都已验证上线,git 已推送。
  2. 排队积压 16 条是正常业务量(用户在批量提交任务测试),不是系统故障,仅供下次进来的人 了解上下文,别误判成"卡住了"。
  3. h3-console 的 /v1/models 里 partitions 字段的模型文件名这次顺手改成了 raylight 现在实际用的(minimax_h3_fl2va_pruned_int8_convrot.safetensors 等),去掉了对不上号 的 lora 字段——这块用户没有明确要求改,只是顺手核实清楚了,如果有外部消费者依赖旧字段 形状需要留意。
  4. 磁盘两边都过 80% 了,暂时没影响什么,但没有余量报警,紧张起来会跟其它任务一样直接写 失败——跟 llm-setup.md 里旧的磁盘提醒是同一类风险,值得找时间清一次。

交接文档 · 2026-08-20(历史,状态类结论已过时,见上面最新一节)

⚠️ 下面这节写的时候 minimax-h3/gateway.py 还是生产后端,raylight/ 还没上线。 2026-08-22 起 raylight 才是生产默认后端,minimax-h3 代码已在 8/24 删除。看这节纯为 保留历史踩坑记录,不要照着下面的服务状态表操作。

2026-08-20 夜:现在是什么状态

一句话:h3-console(Web 管理台)今天从零做到部署上线并经过好几轮真实使用反馈迭代 (重跑、回收站、任务记录落盘、假运行中修复、公网子路径接入),本地代码已建 git 仓库推到 git@gitlab-wuwei.hexpm.com:yibo/2080tiserver.git。同时发现一个容易踩的坑: qwen.wudaima.com 这个域名现在实际没有在提供 Qwen LLM 服务——见下面「重要」。

⚠️ 重要:qwen.wudaima.com 现在不是 LLM,是 minimax-h3 的 gateway.py

  • docker ps 是空的——llm38 容器现在没有在跑(不是本次改的,是之前某个时间点被停的, 可能是之前的会话为了腾显存给 H3 四卡停的,没有记录明确是谁什么时候停的)。
  • 端口 8000 现在被 minimax-h3/gateway.py 占着(ss -lptn 能看到是个 python 进程,不是 llama.cpp)。frp 的 qwen-llm 代理转发的正是本机 8000 端口,所以公网 http://qwen.wudaima.com/health 现在返回的是 gateway.py 的 JSON({"ready":4,...,"backends": [...]}),不是 Qwen 的 /health,qwen.wudaima.com/v1/videos 现在也是能直接无鉴权提交 视频生成任务的(跳过了 h3-console 那层)。
  • 要恢复 Qwen LLM 公网服务:先确认 minimax-h3 的四个 worker 不在关键任务中途, 停掉占着 8000 的 gateway.py(ss -lptn "sport = :8000" | grep -o "pid=[0-9]*" 找 PID 再 kill——不是 PM2 托管的,直接 kill 有效),再 docker start llm38(约 15 秒)。 两者不能共存在同一个 8000 端口上。

当前各服务实际状态(2026-08-20 深夜实测,不是文档推测)

服务 状态 说明
llm38(Qwen3.8-27B,docker) 停(docker ps 为空) 恢复见上面「重要」一节
whisper(docker,8002) 停 同上,docker 里没有容器在跑
PM2 m3e / sd-forge 停 沿用 2026-08-19 就定的目标状态,没有变化
minimax-h3 四个 api.py worker(8010-8013) 在跑 分区会被弹性调度器动态 flip,此刻实测是 3 张 fl2va + 1 张 ref2va(GPU0 ref2va,GPU1/2/3 fl2va),不是固定的,正常
minimax-h3/gateway.py(8000) 在跑,占着 qwen.wudaima.com 见上面「重要」
h3-console(8080) 在跑 局域网直连 http://192.168.110.67:8080,开着弹性调度器(H3_ENABLE_SUPERVISOR=1)
h3-console(8081,子路径专用) 在跑 公网 http://qwen.wudaima.com/console,H3_CONSOLE_BASE_PATH=/console,不开弹性调度器(两个调度器同时抢会重现"一个请求切三张卡"的老 bug),跟 8080 那个共享同一份 console.sqlite3/assets/
GPU 显存(nvidia-smi) GPU0 5.3G / GPU1 21.3G / GPU2 19.4G / GPU3 18.5G(共 88G) llm38 停着,所以余量看着比 CLAUDE.md 顶部旧表格写的宽松,但四张卡跑满 minimax-h3 也会吃紧,起新负载前还是先看一眼

今天做的事(详细踩坑记录都在 CHANGELOG.md,这里只列条目)

  1. h3-console 任务详情页加「重跑」按钮(第一版直接后台重投,被否决后改成回填表单跳转新建页)。
  2. 修复「后端进程重启后任务永远显示假运行中」——_refresh_from_gateway 遇到 404 现在正确判 failed。
  3. api.py 的 frames 硬顶 124 改成按 rows(分辨率×帧数)动态判定,ROWS_LIMIT=20000 (支持 H3_ROWS_LIMIT 环境变量临时覆盖,仅供边界探测用)。
  4. start-all.sh 冷启动默认分区从「4 张全 ref2va」改成 2/2 固定分裂(GPU0/1 ref2va,GPU2/3 fl2va)。
  5. 左下角后端状态行补上 running×N/queued×N,之前明明有任务在跑也只显示 ok。
  6. api.py 任务记录改成落盘(jobs_gpu{N}.sqlite3),弹性调度器 kill+restart 某张卡时不再 把这张卡上正在跑的任务从内存里一起清空。
  7. 任务列表加软删除/回收站(deleted_at 列 + ?trash=true + 恢复接口)。
  8. 排查清楚 gateway.wudaima.com 独立域名为什么公网打不通——缺口在 frp 服务端 60.205.214.169,不是这台机器能改的,没有再等它。
  9. 改走 qwen.wudaima.com/console 子路径对外开放 h3-console(H3_CONSOLE_BASE_PATH 支持
    • 起第二个 8081 实例 + frp locations=/console 分流),验证通过、qwen.wudaima.com 原有 服务没受影响(因为它现在本来就不是 LLM,见上面「重要」)。
  10. 补齐了本地 minimax-h3/ 镜像里此前一直缺失的 gateway.py 等 13 个文件(和服务器漂移的 缺口),本地建了 git 仓库并推到 git@gitlab-wuwei.hexpm.com:yibo/2080tiserver.git。 CLAUDE.md 里明文写着的 SSH 密码也一起提交了,跟用户确认过、这是有意为之。

下一步(按优先级)

  1. 决定 Qwen LLM 要不要恢复——现在公网 qwen.wudaima.com 实际在裸露 minimax-h3 的 gateway API(无鉴权),如果这不是有意的,需要判断是先恢复 llm38 还是先给 gateway.py/ h3-console 补鉴权。这是产品/安全决策,需要用户拍板,不要擅自停 gateway.py 起 llm38 ——四个 api.py worker 现在正被 gateway.py 管着,直接停可能打断正在跑的生成任务。
  2. gateway.wudaima.com 独立域名:如果还想要这条线(而不是永久用 qwen 子路径顶替), 需要找到能登录 60.205.214.169 的人补一条 nginx vhost 转发规则。
  3. 鉴权:h3-console 和 gateway.py 现在都无鉴权,公网可直调。h3-console/DESIGN.md 问题3 有现成方案(Authorization: Bearer + 环境变量),跑通了再加,一直没排上。
  4. 磁盘 / 只剩 29G,/data 83% 满——暂时没出问题,但没有余量报警,真紧张时会和其它任务一样 直接写失败。

交接文档 · 2026-08-18(历史,状态类结论已过时,见上面最新一节)

一句话

今天做了两件事:llm38 单请求上下文 32K → 256K(已完成、已验收、已恢复), MiniMax-H3 文生视频从零部署到出片 + 封了 HTTP API(已出片、已验收,服务当前在跑,环境未恢复)。

2026-08-19 16:30 更新:断连 13 小时后重连

  • 50 步全质量已完成并验收(6.4 MB · 5364 s · 107.3 s/步 · 峰值 9.1 G · 帧间差异 7.366 · 音频 −27.2 dB)。 两档都出片,详见 minimax-h3/README.md 验收记录。
  • 断连原因是本地网络:Mac 到 192.168.110.x 的路由被 VPN 隧道(utun7 / 198.18.0.1)劫持。 期间 nc -z 对所有端口都返回成功(连 9999 和只听 127.0.0.1 的 7860 也"通")—— 那是假阳性,别据此判断服务状态。用 ping + route -n get 确认路径。
  • 期间另有进程在这台机器上工作:两个 H3 API 实例常驻(8010 → GPU1 13.0 G / 8011 → GPU2 7.7 G, 两者 /health 均 ok),api.py 被改过(新增 PARTITION 字段),新增 restart-8010.sh, outputs/ 里有 6 个非本次生成的视频。

★ 当前是用户指定的目标状态:只留 H3 ★

2026-08-19 16:40 用户明确:「停止 llm38」「只留着 h3 即可」。 所以下面这四个停着是对的,不要"顺手"起回来:

服务 状态 说明
llm38(8000) 停 配置已是 256K 单请求上下文并验收过,需要时 docker start llm38
whisper(8002) 停 docker start whisper
PM2 m3e(7590) 停 /usr/local/node/bin/pm2 start m3e
PM2 sd-forge(7860) 停 /usr/local/node/bin/pm2 start sd-forge
H3 API 8010 / 8011 运行中 唯一保留的负载,占 GPU1+GPU2 共 20.8 G

GPU0 与 GPU3 全空(各 22002 MiB)。恢复命令详见 deploy-scripts/RESTORE-GPU.md。

⚠️ 要恢复 llm38 时注意:它跑 256K 需四卡各约 14.3 G,而 GPU1 现被 8010 占着只剩 8.95 G。 要共存就用 --parallel 1 --ctx-size 262144(单请求仍 256K,并发降为 1,省 16 G), 或先停一个 H3 实例。

⚠️ 立刻要知道的三件事

  1. 四个服务当前是停的,而这是用户要的状态(见上一节),不是未完成的收尾。 需要时按 deploy-scripts/RESTORE-GPU.md 恢复,恢复后验 7590 / 7860 / 8000 / 8002 四个端口。
  2. m3e 和 sd-forge 由 PM2 托管(God Daemon PID 1467)。kill 它们没用, 60 秒内会被拉回来;必须 /usr/local/node/bin/pm2 stop m3e sd-forge。恢复是 pm2 start。 pm2 不在默认 PATH 里,非交互 shell 下写全路径。
  3. 一条 50 步全质量视频还在跑(GPU2,22:22 启动,约 90 分钟,预计 23:50 左右完), H3 的 API 服务也在跑(GPU1,端口 8010)。恢复环境前先确认这两个结束/停掉。

状态速查

东西 状态 位置
llm38(Qwen3.8-27B) 已停。配置已改成 256K 单请求上下文,验收过 deploy-scripts/ctx256k.sh
llm38 旧容器 llm38_prev 保留着(32K 配置),确认稳定后可 docker rm / 只剩 29 G,别忘
whisper / m3e / sd-forge 已停 deploy-scripts/RESTORE-GPU.md
MiniMax-H3 权重 34 GB 下载完 + 字节级校验 ALL GOOD /data/models/minimax-h3/models/
H3 出片 成功,已验收(见下) outputs/t2va_20260818-223136.mp4
H3 API 在跑,GPU1:8010 minimax-h3/API.md
50 步全质量 进行中,结果未验 logs/real-full50.log

今天最重要的一条结论

minimax-h3/README.md 原第一节写「bfloat16 → float16(致命)」是错的。 改成 fp16 才是这条线一直出不了片的原因。

对照实验(唯一变量是 dtype,448×256×28f):

fp32 fp16
视频 mean 140.9 std 50.6 mean 0 std 0
音频 finite NaN
结果 出片 ✅ 纯黑 ❌

原因:模型按 bf16 训练(bf16 有 fp32 的动态范围),sm_75 没有 bf16, fp16 的 65504 上限装不下——dit.blocks.0 输入 absmax 89 就放大到 38176,50 层残差累积必爆。

逐点修 fp16 是行不通的,我试了四条弯路全部失败(--fp32-accum 无效、替换 forward 绕过换入、 转换处溢出、钳位到上限反而自造故障),细节和实测数据都在 minimax-h3/README.md。 t2va.py 的 --dtype 现在默认 fp32,保留 fp16 只为复现故障。

验收数据(都是实测,没有推测)

H3 出片:832×480 · 24fps · 124 帧 · 5.17 s · 7.5 MB · 像素 std 57.85 · 帧间差异 16.99(证明是动态视频) · 音频 aac 32 kHz 立体声 mean −34.0 dB / rms 0.0199(证明不是静音)。

性能(fp32,单任务):全分辨率 Turbo 4 步约 107 s/步,峰值显存 12.2 G, 首次加载 238 s,page cache 命中后 12–20 s。fp16 是 36.8 s/步但出不了片。

llm38 256K:n_ctx_slot = 262144(模型原生上限,GGUF 元数据 qwen35.context_length), 150 K token 大海捞针 truncated=0 通过,显存 57.3 G,并发从 4 降到 2, 256 K 提示 prefill 约 4.5 分钟。

下一步(按优先级)

  1. 收尾:等 50 步跑完 → 验收(bash /tmp/verify-out.sh <文件>,脚本在服务器 /tmp, 要长期用得挪到 scripts/)→ 补 README.md 验收记录 → 恢复四个服务并验端口。
  2. 决定 llm38 与 H3 的共存策略。两者显存放不下(57.3 + 12.3 > 单卡余量)。 选项:H3 按需起停;或 llm38 降到 --parallel 1 --ctx-size 262144(保 256 K 单请求, 并发降为 1,省 16 G);或换卡。这是产品决策,需要用户拍板。
  3. 安全:qwen.wudaima.com 公网无鉴权可直调 27B;H3 API 也无鉴权。 SSH 22 经 FRP 映射到公网 6000 且允许密码登录、admin 在 sudo 组。都没动,等授权。
  4. 可选:t2va.py:47 的 max(6.0, ...) 地板值在空闲显存

踩过的坑(别重踩)

  • 退出码不可信:原 t2va.py 只查 audio,全黑视频照样 [done] + 退出码 0。 已补 video 纯色检查,坏产物退出码 3。API 的 worker 也会验 std 和音频有限性。
  • 诊断配置必须和故障配置逐项一致:我用中文 prompt 诊断、英文默认 prompt 复现, 溢出点不同,白跑几轮。
  • prompt 必须从文件读:ssh … bash -c "…" 三层 shell 会吃掉引号,传进去是空串, 报错是 cannot reshape tensor of 0 elements——看着像 transformers 的 bug,实际是输入为空。
  • cmd1 && cmd2 & 的 & 作用于整条链:cat > file && ... & 会让文件写入和执行竞争, 我因此跑了一个 0 字节的脚本还以为它成功了。上传和启动要分两步。
  • pgrep -f "gunicorn.*7590" 会匹配到你自己那条 SSH 命令行,照着 kill 会误杀。 用 nvidia-smi --query-compute-apps=pid 反查。
  • ffmpeg -af volumedetect 的输出容易被 grep 漏掉,误报"无音频流"。 用 PyAV 直接解码算 rms 更可靠。
  • 合成小张量的 probe 测不出真问题:probe-nf4-fp16.py 验证「单层 NF4 fp16 不溢出」通过, 但推不出「50 层残差不溢出」。

本地与服务器的对应

本地 服务器
deploy-scripts/ /home/admin/qwen38-deploy/
llm-setup.md /home/admin/llm-setup.md
minimax-h3/scripts/、API.md、README.md /data/models/minimax-h3/(run.sh/api.py/realrun.sh 在顶层)

服务器那份才是运行的那份,两边会漂移。今天就因为只在服务器上修了导入、 本地那份没同步,重新生成脚本时把旧 bug 带了回去,白跑一轮。