CLAUDE.md
本目录是公司 GPU 服务器 192.168.110.67(4 × RTX 2080 Ti 22G)的工作区。真正的服务和模型都在那台远程机器上,这里只放手册、脚本和记录。
目前有两条并行的工作线:
| 目录 | 工作线 | 状态 |
|---|---|---|
llm-setup.md / deploy-scripts/ / CHANGELOG.md |
LLM 推理服务(llama.cpp,对外 8000 端口) | Qwen3.8-27B 已上线 |
minimax-h3/ |
MiniMax-H3 FL2VA 文生视频+音频(NF4 量化,sm_75) | 探查/调试中 |
两条线共用同一批 GPU,改动前先 nvidia-smi 看余量——LLM 服务常驻约 29 GB / 88 GB,剩下的才是可用的。下面第「硬件的三条硬限制」一节对两条线都适用(尤其 bf16 不可用这条,minimax-h3/scripts/probe-turing-caps.py 就在探这个)。
接入
ssh admin@192.168.110.67 # 密码 P@ssw0rd
没装 sshpass。建议用 ControlMaster 复用连接(socket 路径必须短,否则超 Unix domain socket 长度限制):
# 一次性建连(用 expect 喂密码),之后所有命令走复用 socket 免密
ssh -o ControlMaster=yes -o ControlPath=~/.ssh/cm67 -o ControlPersist=30m -N admin@192.168.110.67 &
ssh -o ControlPath=~/.ssh/cm67 admin@192.168.110.67 '<命令>'
sudo 用 echo "P@ssw0rd" | sudo -S -p "" <命令>。注意 /data 是 root 属主,admin 直接 mkdir 会失败。
先读这个
HANDOFF.md 是每次进来的入口——现在是什么状态、哪些服务停着、下一步该干什么、
已经踩过哪些坑。它比本文件更新得勤,因为它记的是"此刻"。
权威文档
llm-setup.md 是这台机器的完整运维手册——模型清单、启动命令、显存核算、回滚流程、FRP/nginx 映射、硬件限制全在里面。动手前先读它,不要凭记忆回答。
⚠️ 本地这份是服务器上 /home/admin/llm-setup.md 的副本,两边会漂移。 以服务器上那份为准(SSH 进去的人读的是它)。同步:
# 从服务器拉最新
ssh -o ControlPath=~/.ssh/cm67 admin@192.168.110.67 'cat /home/admin/llm-setup.md' > llm-setup.md
# 推回服务器(改完本地后)
cat llm-setup.md | ssh -o ControlPath=~/.ssh/cm67 admin@192.168.110.67 'cat > /home/admin/llm-setup.md'
硬件的三条硬限制
细节见 llm-setup.md 第二、三节,这里只列最容易白费功夫的:
- 4 × RTX 2080 Ti = Turing / compute capability 7.5。装不了 FP8 模型(原生需 Ada 8.9+,vLLM 的
fp8_marlin回退也需 Ampere 8.0+),不支持 bf16。 LLM 走 GGUF + llama.cpp 是唯一实际路径。扩散/视频模型不受此限——PyTorch + bitsandbytes NF4 在 sm_75 上实测可用,见minimax-h3/。 bf16 的坑比想象中深:sm_75 上 bf16 没有任何高效 attention kernel,PyTorch 不报错、静默掉到 MATH 后端物化整个注意力矩阵,长序列表现为莫名 OOM。全链路改 fp16 才行。 - llama.cpp build 有下限。qwen35 架构需 ≥ b10450,低于此加载正常、显存正常、tok/s 正常、但输出全是乱码。上线前必须
--version查 build 号。 - 网络:
huggingface.co与ghcr.io的 blob 层都不通,改用hf-mirror.com和ghcr.nju.edu.cn。出口带宽约 5.9 MB/s 封顶,并行下载不会更快,只会互相抢——下载必须用curl -C -断点续传 +setsid nohup脱离 SSH 会话。
目录约定(迁移工作内容时按此放)
一个工作负载一个顶层目录,目录名 = 服务/模型的短名。目录内固定三样:
<workload>/
README.md # 这个负载是什么、跑在哪张卡、怎么起、怎么停、怎么回滚
scripts/ # 服务器上对应目录的副本(保持文件名一致,方便双向 diff)
notes.md # 可选:踩坑记录、被推翻的假设、实测数据
顶层只放跨负载的东西:本文件、CHANGELOG.md(按时间倒序,一次变更一节)、llm-setup.md(整机手册)。
迁移进来的工作必须补三件事,否则等于没迁:
- 在下面「当前负载」表里加一行(占哪张卡、多少显存、对外端口)。
- 在
CHANGELOG.md顶部加一节,写清结果、被推翻的假设、实测数据——CHANGELOG 的价值在踩坑记录,不在流水账。 - 说明脚本对应服务器上的哪个绝对路径。本地全是副本,服务器上那份才是运行的那份,会漂移。
当前负载
| 目录 | 跑什么 | 卡 | 显存 | 对外 |
|---|---|---|---|---|
deploy-scripts/ |
Qwen3.8-27B-Q5_K_M(llama.cpp,容器 llm38) |
0-3 分片 | 57.3 GB(256K 上下文,2 槽位) | 8000 → qwen.wudaima.com |
minimax-h3/ |
MiniMax-H3 FL2VA/Ref2VA NF4 文生视频,api.py 常驻四实例(GPU0-3,端口 8010-8013)+ gateway.py 调度层(端口 8000) |
四卡各一进程 | 单卡 fp32 峰值约 9-14 GB(视时长/分辨率),另占 CPU 内存约 32 GB/worker | 8000(内部,gateway.py) |
h3-console/ |
H3 Web 管理台:上传/生成/预览三界面 + 任务持久化 + fl2va/ref2va 弹性调度器。两个进程共享同一份 sqlite/assets:8080(局域网直连,BASE_PATH 空,开弹性调度器)+ 8081(H3_CONSOLE_BASE_PATH=/console,不开调度器,专供公网子路径用) |
不占显存(自己不跑模型,管理 minimax-h3 的四卡) | — | 局域网 http://192.168.110.67:8080;公网 http://qwen.wudaima.com/console(frp locations=/console 分流,gateway.wudaima.com 那条独立域名确认走不通,缺口在 frp 服务端 60.205.214.169,见 CHANGELOG) |
| (常驻) | whisper | GPU3 | 3.2 GB | — |
排卡前先 nvidia-smi 看实际余量:GPU3 被 whisper 占着,llama.cpp 默认 tensor-split 按总显存而非剩余显存均分,起新负载不加 -ts 容易把公网服务挤 OOM。
⚠️ 2026-08-18 上下文提到 256K 后余量大幅收紧:四卡合计已用 61.4 / 88 GB,只剩约 26 GB,GPU2 最紧只剩 5.4 GB。minimax-h3 按「空闲显存 − 2 GB」自适应,等于它的可用显存被同步压缩了。两条线同时跑之前先看 nvidia-smi。
部署脚本
deploy-scripts/ 下是服务器 /home/admin/qwen38-deploy/ 的副本:
| 脚本 | 作用 |
|---|---|
cutover.sh |
切换到 Qwen3.8(校验完整性 → 停旧容器 → 起新容器 → 等健康) |
restore.sh |
一键回滚到 Qwen3.6,约 3-5 分钟 |
download.sh |
断点续传下载模型 |
pull2.sh |
从 NJU 代理拉镜像并 retag |
ctx256k.sh |
把单请求上下文切到 256K(旧容器改名保留,失败自动回滚) |
ggufmeta.py |
读 GGUF 元数据(查模型原生上下文上限、层数、KV 头维度)——别凭记忆猜上下文上限,跑这个 |
回滚依赖三样东西,都不要删:镜像 tag llamacpp-rollback:b9570、模型文件 /data/models/Qwen/Qwen3.6-27B-GGUF/、脚本 restore.sh。
MiniMax-H3 脚本
minimax-h3/scripts/ 对应服务器 /data/models/minimax-h3/scripts/(run.sh 在
/data/models/minimax-h3/run.sh)。权威文档是 minimax-h3/README.md——为什么官方示例
照抄跑不起来、Turing 的 dtype/attention/量化实测结论、多卡为什么只能做独立 worker。
其中 probe-*.py 四件套是当初得出兼容性结论的探测脚本。
换硬件或升级 torch / bitsandbytes 后,先跑这四个再动别的。
当前状态(2026-08-18)
对外服务 http://qwen.wudaima.com(仅 HTTP,无鉴权),经 FRP 指向本机 8000,跑 Qwen3.8-27B-Q5_K_M。
上下文:单请求 256K(--parallel 2 --ctx-size 524288,每槽 262144)。256K 是模型原生上限——GGUF 元数据 qwen35.context_length = 262144,不是 128K;早期文档里的 128K 是低估。已用 150K token 大海捞针实测通过(truncated=0)。代价是并发从 4 降到 2,且 256K 提示光 prefill 约 4.5 分钟。
回滚:docker rm -f llm38 && docker rename llm38_prev llm38 && docker start llm38(约 15 秒)。旧容器 llm38_prev 停着保留,稳定后再删(/ 只剩 29 GB)。
⚠️ 已知安全问题:公网可无鉴权直调 27B 推理;SSH 22 端口经 FRP 映射到公网 6000 且允许密码登录、admin 在 sudo 组。
这是一台测试机(2026-08-18 用户明确)
这台机器的用途就是测试各种模型,不是生产环境。 显存不够时直接停 llm38 给别的负载让路是允许的、也是预期做法,不需要为此设计复杂的共存方案。
这条推翻了本文件早期版本里「8000 是对公网服务的,停服务是对外可见动作」的前提。不要再把显存争抢当成需要精巧规避的约束——串行跑就行:
docker stop llm38 # 让出 ~57 GB,四卡各回到约 21 GB 空闲
# ... 跑 minimax-h3 / 别的模型 ...
docker start llm38 # 跑完起回来,约 15 秒
副作用:这样测出来的数字才是干净的(不被抢占扭曲),比在争抢状态下测更有参考价值。
操作纪律
- 改动线上服务前先确认回滚路径可用。停服务本身不敏感(测试机),但起不回来会很麻烦。
- 大文件下载和镜像拉取一律后台跑(
setsid nohup),不要占着前台等。 - 不要凭记忆回答这台机器的事。 先读
llm-setup.md和CHANGELOG.md——里面记的坑(build 号下限、FP8 不可行、MTP 不激活)都是已经花过时间验证的,重复踩一遍是纯浪费。 - 多个进程可能同时在这个目录里干活。改共享文件(本文件、
CHANGELOG.md、llm-setup.md)用追加/局部编辑,不要整文件覆写。