# 变更记录 ## 2026-08-20(晚)— h3-console 任务详情页加「重跑」按钮 **结果**:`/task.html/` 详情页状态行旁加了「重跑」按钮。**第一版直接后台再 `POST /v1/videos` 一次,用户反馈不对**——应该是把参数带回新建任务表单让人看一眼再手动提交,不是静默重新提交。 改成:点击后把这条任务当初的 `req`(prompt/分辨率/帧数/turbo/steps/seed/首尾帧或参考图 URL) 灌回对应的 tab(文生/首尾帧/参考图,按 req 里有没有 `first_frame_url`/`reference_image_urls` 自动判断)、跳到 `/newtask.html`,用户确认无误后自己点「提交」——跟手动新建任务走的是同一条 路径、同一次人工确认。**没改后端**——`server.py` 的 `POST /v1/videos` 还是原来那个入口, 只是前端多了一步"回填表单"而不是直接调用。只改了 `static/index.html`(新增 `prefillCreate()`/`setThumbs()` + detail 模板里的按钮),纯静态文件, 直接 `cat > .../console/static/index.html` 覆盖就生效,不需要重启 console 进程。 ⚠️ 用这个按钮验证时顺手发现任务 `8755c5600378` 失败是**参数校验拒绝**,不是 bug: `width=832,height=480` 配 `frames=362` 被 api.py 拒了(`frames` 上限 124,跟上一节 「15 秒时长实测」结论一致——832×480 这个分辨率撑不住 362 帧)。重跑会用同样的参数、 同样会失败,这是预期行为(按用户原话"一样的配置"重跑),**不是**这个按钮该吞掉或改的错误; 真要让这条任务跑通,需要换成 448×256 或降帧数,属于用户自己改参数重新提交的范畴。 --- ## 2026-08-20(下午)— h3-console 部署上线,弹性 fl2va/ref2va 调度全链路验证通过 **结果**:`h3-console` 从本地实现推进到部署(服务器 `/data/models/minimax-h3/console/`,端口 8080), 用真实 GPU 完整验证了一遍"提交 fl2va 任务 → 排队 → 自动 flip 一张空闲卡 → 任务自动提交并跑完", 过程中揪出并修好两个真实 bug(细节见 `h3-console/README.md`「部署过程中揪出的两个真实 bug」): 1. **PID 提取从来没匹配上过**:`ss -lptn` 输出里 pid 嵌在 `users:(("python",pid=NNNN,...))` 里, 不是独立空格分隔 token,`tok.startswith("pid=")` 永远不命中,`kill` 从来没真的执行——旧进程 全须没被杀,新进程因端口冲突立刻退出。改用正则 `re.findall(r"pid=(\d+)", ...)`。 2. **调度器不知道"已经在切换中"**:api.py 冷启动 13-20 秒跨了不止一个 10 秒 tick,中间几轮 误判需求没满足,一个 `pending=1` 的请求把三张卡都切了过去。加 `flipping` 字典记账修复。 3. (操作事故,非代码 bug)**`pkill -f ""` 杀了自己的 SSH 会话**——命令行本身包含被 搜索的文本,`start-all.sh` 注释早警告过这个坑,这次真踩了一遍。以后一律用 `ss` 按端口找 PID。 四卡已恢复到干净的全 ref2va 基线状态(测试期间临时 flip 的那张卡已经切回去、验证过 `ready:4/4`)。 --- ## 2026-08-20(上午)— 15 秒时长实测 + 新增 h3-console 管理台(设计+本地实现) **结果**:两件事都完成,console 本地跑通并冒烟测试通过(部署见上一节)。 ### 15 秒时长边界实测 MiniMax-H3 官方规格 4–15 秒(362 帧/24fps)不是脚本瞎设的限制——`t2va.py`/`api.py` 里的 124 帧上限是**我们自己测出的显存边界**,不是抄错官方示例(`API.md` 早就写明这点)。 实测 362 帧在不同分辨率下: | 分辨率 | 结果 | 峰值显存 | 单步耗时 | |---|---|---|---| | 448×256 | ✅ 正常 | 12.0G | ~90s | | 576×320 | ✅ 但吃紧(震荡换入换出) | 14.5G | 217s(慢 2.4×) | | 640×384 | ❌ OOM | 撞到 20.6G 才崩 | — | | 832×480(线上默认) | ❌ OOM(空卡也不行) | 撞到 20.65G 才崩 | — | **结论**:15 秒能做到,但线上默认的 832×480 做不到,实用上限在 448×256~576×320 之间。 测试过程中临时停了 GPU3 的 ref2va 后端腾显存(这是测试机,`CLAUDE.md` 里明确允许), 测完已恢复,四卡 `ready: 4/4`。 ### 被纠正的两个误解(用户转述 ChatGPT 的建议) 1. "该先怀疑 Turbo 4-step 加速而不是 NF4"——**方向对**,我们自己的 A/B 数据支持:同一套 NF4 权重,只关 Turbo、步数 4→50,帧间差异从 16.99 降到 7.366,音频从 −34dB 升到 −27dB, 量化没变、画质肉眼可判断变好,说明 Turbo/步数是比 NF4 量化更大的画质杠杆。 2. "该下载原版 BF16/FP16 权重,88GB 显存够跑更高精度"——**这条路已经被昨天的实验堵死, 不是没试过**:bf16 在 sm_75 上无 attention kernel(`RuntimeError: No available kernel`), fp16 会让模型输出溢出变黑屏(已用 A/B 实验证伪)。这台硬件上 compute dtype 只能是 fp32, 跟权重存储精度是 NF4 还是 BF16 无关——bitsandbytes NF4 本来就是反量化到 fp32 再算。 "88GB=4×22G 独立显存,H3 不支持模型并行"这条误解也再次被纠正(`README.md` 第四节早有结论)。 下载 BF16 权重(约 NF4 的 3-4 倍体积)在 5.9MB/s 出口带宽下要 4-5 小时,换来的只是去掉 NF4 约 9% 的量化误差,性价比远不如已经验证过的"关 Turbo、加步数"。 ### 新增 h3-console/(设计文档 + 本地实现,未部署) 需求:给 minimax-h3 的四后端 API 加 Web 管理台(文生/首尾帧/参考图三个界面 + 上传 + 任务列表 + 按需 fl2va/ref2va 弹性分卡)。设计文档 `h3-console/DESIGN.md`、实现见 `h3-console/README.md`。 架构上不重做 `gateway.py` 已经做好的调度/限流/健康聚合,只加它没有的 Web UI/上传/持久化/ 弹性分卡决策。本地端到端冒烟测试通过(上传→提交→轮询→下载全链路 + 浏览器 UI 手测), 弹性 partition 调度器(kill+restart GPU 后端切分区)只能在服务器上验证,还没测。 --- ## 2026-08-18/19 — MiniMax-H3 文生视频从零到出片 **结果**:成功。两档都出片并通过 ffprobe + 逐像素 + 音频样本验收。 **但环境未恢复**——见文末「遗留」。 ### 最重要的一条:`minimax-h3/README.md` 原第一节是错的 原文写「`torch.bfloat16` → `torch.float16`(致命)」,把改用 fp16 当作**必须的修正**。 **实测相反:改成 fp16 才是这条线一直出不了片的原因。** 对照实验(448×256×28f,唯一变量是 `torch_dtype`): | | fp32 | fp16 | |---|---|---| | 视频像素 | mean 140.9 **std 50.6** | mean 0 **std 0** | | 音频 | finite | NaN | | 结果 | **正常出片 ✅** | **124 帧纯黑 ❌** | 根因:模型按 bf16 训练(bf16 有 fp32 的动态范围),sm_75 无 bf16, fp16 的 65504 上限装不下——`dit.blocks.0` 输入 absmax 89 就放大到 38176,50 层残差累积必爆。 ### 被推翻的假设(六条,都实测过) | 原以为 | 实际 | |---|---| | fp16 是 Turing 上的正确选择 | **fp16 出全黑视频**,fp32 才行 | | `--fp32-accum` 是降级第一档 | 开关生效但**输出逐字节相同**,对此故障完全不对症 | | NF4 合成 probe 通过 ⇒ 真实模型可用 | 单层不溢出**推不出** 50 层残差不溢出 | | `condition_proj` 的 inf 是根因 | 修好后问题依旧——它只是同一个 bug 的一个实例(库里有 100 处 `.to(x.dtype)`) | | 钳位到 fp16 上限可规避溢出 | **反而更糟**:残差 `x + attn(...)` 中 x 恰为最大可表示值,再加任何正数立刻 inf | | m3e / sd-forge 无 systemd ⇒ 手工拉起、恢复有风险 | 它们由 **PM2**(God Daemon PID 1467)托管,`kill` 会被 60 秒内拉回,必须 `pm2 stop` | ### 实测数据(fp32,单任务) | 分辨率 | 步数 | 耗时 | 每步 | 峰值显存 | 像素 std | |---|---|---|---|---|---| | 448×256×28f | 4 turbo | 62 s | 15.5 s | 16.3 G | 50.6 | | 640×384×61f | 4 turbo | 171 s | 42.8 s | 11.4 G | 51.7 | | **832×480×124f** | **4 turbo** | **556 s** | **107 s** | **12.3 G** | **57.85** | | **832×480×124f** | **50 全质量** | **5364 s** | **107.3 s** | **9.1 G** | **59.68** | **每步 107 s 在 turbo 与 50 步下完全一致**,是这台机器 fp32 全分辨率的稳定值。 加载:首次从机械盘读 fp32 权重 238 s;page cache 命中后 12–20 s。 fp16 是 36.8 s/步(快 2.9×)但**根本出不了片**——不是速度取舍。 ### 产物验收 - Turbo:7,859,869 字节 · 帧间差异 **16.99** · 音频 mean −34.0 dB / rms 0.0199 / 非零 100% - 50 步:6,726,194 字节 · 帧间差异 **7.366** · 音频 mean −27.2 dB / max −9.2 dB - 两者均 832×480 · 24 fps · 124 帧 · 5.17 s · 含 aac 32 kHz 立体声 ### 顺带修掉的 1. **`t2va.py` 退出码不可信**:原脚本只查 audio,**从不检查 video**,全黑视频照样打印 `[done]` 并返回 **0**。 已补 video 有限性 + 纯色检查(std < 1.0 判失败),坏产物**退出码 3**。 2. **`--vram-reserve` 按 dtype 自适应**:fp32=14 / fp16=5。实测 `vram_limit` 7.3 G 时全分辨率跑通,19.3 G 时 OOM。 3. **`PYTORCH_ALLOC_CONF=expandable_segments:True`** 写进 `run.sh`——22 G 卡上碎片曾达 2.49 G 并直接压垮运行。 4. **4 个 probe-*.py 补齐到服务器**:README 第九节要求「换硬件后先跑 probe-* 四个」,但服务器上原本只有 3 个脚本。 ### 新增 - `minimax-h3/api.py` + `api-run.sh`:异步任务式 HTTP API(提交拿 id → 轮询 → 下载)。 worker 在写文件前自验像素 std 与音频有限性,**不会返回"成功但没用"的产物**。 - `minimax-h3/API.md`:调用说明、参数范围与理由、错误码、Python 轮询示例。 - `HANDOFF.md`:交接文档,`CLAUDE.md` 已加入口指引。 - `deploy-scripts/RESTORE-GPU.md`:停机/恢复 runbook(含 PM2 那条更正)。 ### 方法教训 - **诊断配置必须与故障配置逐项一致**:前几轮用中文 prompt 诊断、英文默认 prompt 复现, 溢出点不同,定位出的路径在真实故障里不触发,白跑几轮。 - **自检要守在会失败的位置**:查 `.to(fp16)` **之前**的 fp32 张量永远显示"正常",溢出恰在转换处。 - **`cmd1 && cmd2 &` 的 `&` 作用于整条链**:`cat > file && ... &` 会让文件写入与执行竞争, 曾因此跑了一个 0 字节脚本还以为它成功。上传与启动要分两步。 - **`pgrep -f "gunicorn.*7590"` 会匹配到自己那条 SSH 命令行**,照着 kill 会误杀; 用 `nvidia-smi --query-compute-apps=pid` 反查。 - **`ffmpeg -af volumedetect` 输出易被 grep 漏掉**,误报"无音频流";用 PyAV 解码算 rms 更可靠。 - **prompt 必须从文件读**:三层 shell 会吃掉引号,传进去是空串,报错是 `cannot reshape tensor of 0 elements`——看着像 transformers 的 bug,实际是输入为空。 ### ⚠️ 遗留(未完成) 1. ~~四个服务仍是停的~~ → **已决策,不是遗留项**。2026-08-19 16:40 用户明确「停止 llm38」「只留着 h3 即可」, 所以 `llm38` / `whisper` / `m3e` / `sd-forge` 停着即为目标状态;仅 H3 API(8010 + 8011)保留运行。 四者的恢复命令备在 `deploy-scripts/RESTORE-GPU.md`,需要时再起。 2. **llm38 与 H3 共存的显存约束(将来恢复时才需处理)**:llm38 跑 256K 需四卡各约 14.3 G, 而 GPU1 现被 8010 实例占着只剩 8.95 G。共存需 `--parallel 1 --ctx-size 262144` (单请求仍 256K,并发降为 1,省 16 G),或先停一个 H3 实例。 3. **`t2va.py:47` 的 `max(6.0, ...)` 地板值**:空闲显存 < 8 G 时会申请一个不存在的额度而非报错。串行跑绕开了,多负载共存时会咬人。 4. **API 无鉴权**,与这台机器上其他服务一致;任务状态存在内存,进程重启即丢(本次已实际发生)。 ## 2026-08-18 — 单请求上下文 32K → 256K(llm38) **结果**:成功。中断 **11 秒**(17:47:14 停 → 17:47:25 就绪,远快于预估的 2 分钟,因为 CUDA JIT 缓存已热)。 ### 用户问的那个问题:不,上限不是 128K GGUF 元数据里 **`qwen35.context_length = 262144`**——模型原生 **256K**,之前所有文档写的 128K 都是低估。 ```bash python3 /home/admin/qwen38-deploy/ggufmeta.py /data/models/Qwen/Qwen3.8-27B-GGUF/Qwen3.8-27B-Q5_K_M.gguf ``` `llm-setup.md` 旧表里只列到 `--parallel 2 --ctx-size 262144`(128K/请求),那不是硬件极限,也不是模型极限,只是当时没查元数据。 ### 改了什么 只动两个参数,其余(模型、镜像、采样参数、健康检查、挂载)逐字未变: | | 改前 | 改后 | |---|---|---| | `--ctx-size`(总池) | 131072 | **524288** | | `--parallel`(槽位) | 4 | **2** | | 单请求上限 | 32K | **256K** | | 并发槽位 | 4 | 2 | **不需要 YaRN**:524288 是总池,被 2 槽均分后每槽 262144 = 正好等于 `n_ctx_train`,没有外插。`llm-setup.md` 第 65 行「524288 (YaRN 2x)」把总池和单请求上限混为一谈了,已订正。 ### 实测数据 | 指标 | 改前(32K×4) | 改后(256K×2) | |------|-------------|---------------| | `n_ctx_slot` | 32768 | **262144** | | 显存(llm38 自身) | 29.4 GB | **57.3 GB** | | 四卡合计占用(含 whisper) | 32.7 GB | **61.4 GB / 88 GB** | | 生成速度(短上下文) | 23.4 tok/s | 23.4 tok/s(无变化) | | 生成速度(150K 上下文) | — | **16.7 tok/s** | | 提示处理(11K 提示) | 1491 tok/s | 1491 tok/s | | 提示处理(150K 提示) | — | **979 tok/s** | 四卡分布:GPU0 15264 / GPU1 14310 / GPU2 16620 / GPU3 15254 MiB。**GPU2 只剩 5.4 GB 最紧**,起新负载时避开它。 ### 验收:大海捞针(150K token) 把一条真信息埋在 4000 条填充记录的第 1800 条,提示总长 **149,880 token**——这个长度连**改前的 131072 总池都放不下**,是硬证明而非软验证。 - `truncated = 0`(关键:没有静默截断) - 精确取出「QX-7741-KM / 周敏」,thinking 里明确引用了「条目1800」 - 中文连贯无乱码 - 3 路并发全部正常返回,healthcheck `healthy` / FailingStreak=0 ### 代价,明说 1. **并发从 4 降到 2。** 第 3 个请求不会被拒,会排队。公网 `qwen.wudaima.com` 若真有多人同时用,排队会变明显。 2. **长提示很贵。** 256K 提示光 prefill 就约 **4.5 分钟**(按 979 tok/s 算),且期间独占一个槽位。150K 那次端到端 2m43s。 3. **显存余量从 55 GB 掉到 26 GB。** minimax-h3 是按「空闲显存 − 2 GB」自适应的,这条线的可用显存被同步压缩了,两边共用一台机器时要注意。 ### 回滚 旧容器**改名保留**没删: ```bash docker rm -f llm38 && docker rename llm38_prev llm38 && docker start llm38 # 约 15 秒 ``` 切换脚本 `/home/admin/qwen38-deploy/ctx256k.sh` 自带失败自动回滚(容器起不来或 8 分钟不健康就自动退回)。**确认稳定后再 `docker rm llm38_prev`**——`/` 分区只剩 29 GB。 ### 想要 256K × 4 并发?可以,但没做 `-ctk q8_0 -ctv q8_0` 把 KV 量化到 8 bit,KV 从 64 GiB 降到 32 GiB,256K×4 就放得下。没做的原因:用户要的是最大上下文不是最大并发,而量化 KV 会引入质量变化,不值得在一次变更里叠两个变量。要做的话单独做,单独测。 ## 2026-08-18 — MiniMax-H3 文生视频部署(进行中) **结果**:环境就绪并通过全部兼容性实测;**模型下载中(33 GB / 6 MB/s),尚未完成首次出片**。 详见 `minimax-h3/README.md`。 **服务器侧**:`/data/models/minimax-h3/`。**系统级零改动**——没装 CUDA、没动驱动、 没碰 `/usr`、没改 `~/.local`。venv 用 `--system-site-packages` 复用已有的 `torch 2.9.0+cu128`(其 `arch_list` 含 `sm_75`),只额外装了 bitsandbytes 0.50.1 和 diffsynth。 ### 被推翻的假设 | 原以为 | 实际 | |--------|------| | **照抄官方 NF4 示例即可** | ❌ 三处必改:全篇 `torch.bfloat16` → `float16`;`vram_limit` 取的是 `mem_get_info()[1]`(**总**显存),四张卡都有常驻服务,必须改 `[0]`(空闲);low-vram 示例的 `offload_device="disk"` 在 7200rpm 机械盘上是 87 秒/步的 I/O 灾难,改 CPU 内存 offload。 | | **bf16 只是慢一点** | ❌ sm_75 上 bf16 **没有任何高效 attention kernel**(EFFICIENT 和 FLASH 都报 `No available kernel`),PyTorch **不报错**、静默掉到 MATH 后端物化整个注意力矩阵。14k token 序列必 OOM,且症状伪装成显存不足而非 dtype 问题。**光测 `bf16 matmul` 会得出错误结论**——它是能跑的(cuBLAS 升位模拟)。 | | **4×22 GB 可以合起来跑一个大任务** | ❌ DiffSynth 的序列并行(`utils/xfuser/`)只被 `wan_video.py` 和 `mova_audio_video.py` 引用,H3 pipeline 零引用。叠加四卡无 P2P + 跨 NUMA,只能做**独立 worker 并发**,且并发数由**内存**(每 worker 约 32 GB / 共 128 GB → 2–3 个)而非显存卡死。 | | **Turing 上只能走 llama.cpp** | ❌ 那是 LLM 的结论。PyTorch + bitsandbytes NF4 在 sm_75 上实测可用(bnb 4-bit 的最低要求正好是 sm_75)。 | | **`nohup` 足够让下载脱离 SSH** | ❌ 不够,SSH 通道关闭仍会带走进程,必须 `setsid`(手册第三节其实写了,没照做)。另外**开两个下载进程会互相破坏同一个 `._____temp` 分片**——出口带宽是瓶颈,并行毫无收益。 | ### 实测数据(RTX 2080 Ti / sm_75 / torch 2.9.0+cu128) ``` SDPA bfloat16 EFFICIENT → No available kernel SDPA float16 EFFICIENT → OK SDPA bfloat16 FLASH → No available kernel SDPA float16 FLASH → 仅 sm80–sm121 SDPA bfloat16 MATH → OK(朴素实现,会 OOM) 真实 H3 形状 S=14100 H=56 D=128 的 fp16 SDPA EFFICIENT → 0.21s fp16 GEMM 有效算力 → 54.3 TFLOPS(张量核满血) fp16 深链数值稳定性 → finite NF4 fp16 前向 → finite,rel_err 0.0913;prequantized 重载 → match=True ``` DiT 是稠密 30.9B(50 层 / hidden 5376 / 56×128 heads / ffn 14336,无 MoE), 480×832×124 帧约 14,100 token、830 TFLOP/步。故 50 步估 20–35 分钟, **Turbo 4-step LoRA 估 2–4 分钟**——LoRA 可叠在 NF4 上(`AutoWrappedQuantizedModule` 继承 `LoRAHotLoadMixin`,在量化输出之后做加法,不需反量化基座)。 ### 环境里两个坑 - `~/.local` 的 **bitsandbytes 0.45.1 是坏的**(`'NoneType' object has no attribute 'cquantize_blockwise_fp16_nf4'`),venv 内装 0.50.1 覆盖。 - **不要设 `PYTHONNOUSERSITE=1`**:这台机器的 `torch` / `transformers` / `av` 都在 `~/.local`,屏蔽掉会连 torch 一起丢。venv 的 site-packages 本就排在它前面。 ### 容器变更(用户授权,可逆) 停了 `llm`(旧 llama.cpp,unhealthy 5 天,已被 `llm38` 取代)——恢复 `docker start llm`。 `whisper` 停后**已恢复**(只用单卡,停它零收益)。**`llm38` 全程未碰**。 启动参数备份在 `/data/models/minimax-h3/backup/`。 ## 2026-08-18 — Qwen3.6-27B → Qwen3.8-27B **结果**:成功。中断 1 分 51 秒(17:03:14 停 → 17:05:05 就绪)。 ### 起因 用户想部署 `Qwen/Qwen3.8-27B-FP8`。**结论是 FP8 版本装不了**,改用 GGUF。 ### 为什么 FP8 不行(三道坎,第一道是硬的) 1. 2080 Ti 是 Turing,compute capability **7.5**。FP8 原生需 Ada(8.9)/Hopper(9.0);vLLM 的 `fp8_marlin` 回退内核要求 Ampere(8.0+)。7.5 连回退路径都够不着——不是配置能绕的,是芯片里没有那个电路。 2. Turing 不支持 bf16,而 FP8 权重的 scale 用 bf16 存。(机器上现有 vLLM compose 全带 `--dtype=half` 就是这堵墙留下的痕迹。) 3. 即便前两条不存在,机器上最新的 vLLM 镜像是 v0.10.2(11 个月前),不认识 Qwen3.8 的 Gated DeltaNet + Gated Attention 混合架构。 ### 最终方案 `bartowski/Qwen3.8-27B-GGUF` 的 **Q5_K_M**(19.32 GiB / 20,752,787,040 字节),llama.cpp **b10481** 镜像,容器名 `llm38`,端口 8000。 选 Q5_K_M 而非平移 IQ4_XS:四卡 88 GB 只用了 29 GB,余量充足,质量提升是白拿的。 ### 过程中被推翻的三个假设 对抗性验证阶段推翻了三条原本打算照做的事,都值得记住: | 原计划 | 为什么错 | |--------|---------| | **新旧模型并存在 8000/8001 上 A/B 对比** | ❌ GPU3 只剩 10.7 GB(whisper 常驻 3.2 GB),而 llama.cpp 默认 tensor-split 按**总显存**而非**剩余显存**均分,不加 `-ts` 必 OOM。更要命的是现有服务的 context checkpoint 是**惰性分配**的(149.626 MiB × 4 slot × 8,上限约 4.7 GB),新容器吃光余量后**公网服务会在某次多轮长对话时突然 OOM 挂掉**。改为串行切换。 | | **沿用 Qwen3.6 的采样参数** | ❌ Qwen3.8 thinking 模式官方推荐 `temp 1.0 / top-k 20 / min-p 0.0`;照抄 3.6 的 `0.7/40/0.01` 会让 thinking 质量下降。且 llama.cpp 默认是 `top_k=40 / min_p=0.05`,不显式写就是错的。 | | **靠 MTP 推测解码提速** | ❌ `--spec-type draft-mtp` 在 sm_75 上对 hybrid 模型**根本不激活**(llama.cpp issue #24670)。网上「+33~39%」的说法在这台机器上吃不到。而且 MTP 头是独立 sidecar 文件,bartowski 仓库根本没有。 | ### 差点踩中的静默陷阱 **llama.cpp build 必须 ≥ b10450**(DeltaNet CUDA 修复 commit `ece963f4`)。b10419~b10450 的症状是**加载正常、显存正常、tok/s 正常、输出全是乱码**——机器上原有的 b9570 正好在雷区里。 上线前验证:`docker run --rm --entrypoint /app/llama-server <镜像> --version`,实得 `build 10481, commit 25ae3a9b3`。 ### 实测数据 | 指标 | Qwen3.6-27B IQ4_XS | Qwen3.8-27B Q5_K_M | |------|-------------------|-------------------| | 权重 | 15.77 GB | 19.32 GB | | 生成速度 | 28 tok/s | **23.4 tok/s** | | 显存(四卡合计) | 29.3 GB | **29.4 GB** | | 上下文 | 131072 | 131072 | 权重大了 3.5 GB 显存却几乎没变:Qwen3.8 的 64 层里只有 16 层是标准注意力(`full_attention_interval=4`),48 层是 Gated DeltaNet,KV cache 只有同规格纯注意力模型的约 27%。 四卡分布:GPU0 7448 / GPU1 7336 / GPU2 8110 / GPU3 6532 MiB。 ### 验证结果 - SHA256 `e731e180460b906f373294a4e2de10541e80ee676af7f8c949a84dbb6ed3caa8` 与官方逐字节一致 - 中文输出语义连贯,**无乱码**(本次最大风险,已排除) - healthcheck `healthy` / FailingStreak=0 - 5 轮连续请求显存恒定 29426 MiB,无 CUDA graphs 泄漏 - 下游硬编码旧模型名 `Qwen_Qwen3.6-27B-IQ4_XS.gguf` 仍返回 200 + 正常内容(服务端不校验 model 字段) ### 顺带修掉的 镜像自带的 healthcheck 写死 `curl localhost:8080`,而服务在 8000,导致旧容器从启动起连续失败 16321 次、常年显示 `unhealthy`。新容器用 `--health-cmd` 覆盖指向 8000。**这个假红灯之前会掩盖真故障。** ### 遗留项 - **单请求上下文实际是 32K 不是 128K**:`--ctx-size 131072` 是总池,被 `--parallel 4` 均分。要单请求 128K 需改成 `--parallel 2 --ctx-size 262144`(约 42 GB,显存够)。**待用户决定。** - 多模态 `mmproj-Qwen3.8-27B-f16.gguf`(885 MB)已下载在同目录,但**未挂载**,首轮保持纯文本。需要图像输入时加 `--mmproj` 重启。 - CUDA graphs 被 `GGML_CUDA_DISABLE_GRAPHS=1` 关掉以规避 Turing 显存泄漏(issue #25835),上游修复后可 A/B 试着开。 ### 同期发现的其他问题(未处理) - `/` 分区仅剩 29 GB(87%),docker 镜像和日志都写这里。 - nginx 的 `4016`/`4018` 两个前端后端 `4017`/`4019`/`4020` **全部无监听**,聊天应用是坏的。 - FRP 的 `gateway.wudaima.com → 8080` 和 `comfyui.wudaima.com → 8188` 两条隧道空挂,本地无服务。 - 公网 `qwen.wudaima.com` **无鉴权**;SSH 22 经 FRP 映射到公网 6000 且允许密码登录。