175 lines
8.6 KiB
Markdown
175 lines
8.6 KiB
Markdown
# enginex-bi100-compat
|
||
|
||
天数智芯 **天垓100(Iluvatar_bi-100)** · 文本生成 · vLLM **兼容增强引擎**。
|
||
|
||
> **一句话**:不改模型、不改卡,只把「引擎镜像层」的结构性不兼容在容器启动前修掉。
|
||
> 这类失败的特征是——**换任何模型、换任何卡都会遇到**,所以修在引擎层比修在提交层更普适。
|
||
|
||
---
|
||
|
||
## 1. 动机:失败不是均匀分布的
|
||
|
||
我在信创模盒累计 **37 个验证失败**。把 74 份失败日志
|
||
(`log-extract/<taskId>/pod_runtime_log.txt` / `error_report_raw.json`)聚合后发现,
|
||
失败高度集中在几类「模型没坏、卡也没坏、纯粹是引擎/配置层不匹配」的问题上。
|
||
|
||
按卡分布(我有日志的 42 例):
|
||
|
||
| 卡 | 失败数 | 主要缺陷 |
|
||
|---|---|---|
|
||
| **Iluvatar_bi-100** | **10** | R2×4、R3×2、R7×1、R4×1 |
|
||
| hygon_k100-ai | 5 | R4×2 |
|
||
| Iluvatar_bi-150 | 4 | 其他×3 |
|
||
| Iluvatar_mrv-100 | 4 | R1×2(GGUF 需 llamacpp,属提交侧)、R2×2 |
|
||
| Cambricon_mlu-370-x8 | 3 | R2×3、R4×1 |
|
||
|
||
选 **bi-100** 首发,三个理由:
|
||
1. 失败最集中(10 例,全平台第一);
|
||
2. 该卡社区通过率约 **51%**(15 张卡里最低),修好收益最大;
|
||
3. 它的原生 build-config 最简单(`vllm serve /model --port 80 -tp 1`),改动面小、风险低。
|
||
|
||
---
|
||
|
||
## 2. 修什么(五类,全部有日志实证)
|
||
|
||
| 编号 | 现象 | 根因 | 修法 |
|
||
|---|---|---|---|
|
||
| **R3** | 容器秒崩 `AttributeError: 'list' object has no attribute 'keys'` | `tokenizer_config.json` 里 `extra_special_tokens` 写成 **list**,而 transformers 的 `SpecialTokensMixin` 会执行 `... + list(special_tokens.keys())` | 生成 tokenizer 覆盖目录,把该字段规范成 dict,用 `--tokenizer` 指过去 |
|
||
| **R3b** | tokenizer 加载异常 | `tokenizer_class` 是 `TokenizersBackend` / `TiktokenTokenizer` 这类镜像不认的类 | 按 fast/sentencepiece/bpe 归一化成正常类,并清掉 `backend` |
|
||
| **R2** | `/v1/chat/completions` 返回 400 或输出为空;启动参数里 `chat_template=None` | 模型自身没带 chat_template | 注入最小可用 Jinja 模板,用 `--chat-template` 指过去 |
|
||
| **R4** | `KeyError: 'xxx'` / `MODEL_NOT_SUPPORTED`,配置加载阶段就挂 | `config.json` 的 `architectures` 声明了引擎镜像**没注册**的类 | 用 `--hf-overrides {"architectures":[...]}` 把**已证实**的未注册类名映射到已注册类名 |
|
||
| **R7** | `ModuleNotFoundError: No module named 'ixformer.contrib.vllm.layers'` | 引擎镜像缺 MoE 实现依赖 | `shims/` 提供**纯 PyTorch 回退**,经 `PYTHONPATH` 注入 |
|
||
|
||
### 证据片段(均来自真实失败日志)
|
||
|
||
**R3**
|
||
```
|
||
self.SPECIAL_TOKENS_ATTRIBUTES = self.SPECIAL_TOKENS_ATTRIBUTES + list(special_tokens.keys())
|
||
AttributeError: 'list' object has no attribute 'keys'
|
||
```
|
||
**R4**
|
||
```
|
||
File ".../transformers/models/auto/configuration_auto.py", line N, in __getitem__
|
||
raise KeyError(key)
|
||
KeyError: 'olmo...'
|
||
```
|
||
**R7**
|
||
```
|
||
File ".../vllm/model_executor/models/mixtral.py", line N, in forward
|
||
from ixformer.contrib.vllm.layers import mixtral_decoder_layer_forward
|
||
ModuleNotFoundError: No module named 'ixformer.contrib.vllm.layers'
|
||
```
|
||
**R2**
|
||
```
|
||
startup args: ..., chat_template=None, ...
|
||
后续 MCQ 评测全部 HTTP Error 400 / 输出为空
|
||
```
|
||
|
||
---
|
||
|
||
## 3. 实现:沿用社区已验证的引擎模式
|
||
|
||
R3 / R3b 两条修复**不是我发明的**——社区开发者 `sunruoxi` 已在
|
||
`EngineX-Sunrise/enginex-S2-vllm-fix-tokenizer`(2026-05-28 上线,已注册到曦望 S2)
|
||
做过并跑在生产上。本引擎:
|
||
|
||
- **完全沿用它的结构**:`Dockerfile` + `entrypoint.sh` + 修补脚本 + `detect_tokenizer.py` + README,
|
||
`entrypoint.sh` 也是 `detect → fix → exec vllm serve "$MODEL_DIR" $EXTRA "$@"` 这一套;
|
||
- **合并它那两条修复**(`extra_special_tokens` list→dict 用同形的 `token→token`,
|
||
`tokenizer_class` 归一化用同一份坏类清单),保证两套引擎口径一致、可交叉验证;
|
||
- 在其上补了 R2 / R4 / R7 三条,把「只修 tokenizer」升级成「修 tokenizer + 模板 + 架构 + 缺模块」。
|
||
|
||
`extra_special_tokens` dict 的构造方式与社区上线版一致:
|
||
|
||
```python
|
||
cfg["extra_special_tokens"] = {token: token for token in orig_list}
|
||
```
|
||
|
||
---
|
||
|
||
## 4. 三条设计红线
|
||
|
||
1. **绝不写模型目录**——平台挂载的 `/model` 可能只读。所有修补只通过
|
||
「临时覆盖目录 + 命令行参数」实现;软链优先,软链不可用时**只拷贝 tokenizer 白名单文件**,
|
||
权重文件(`.safetensors/.bin/.gguf/.pt/...`)永远不碰(自测专门盯这条)。
|
||
2. **修补失败绝不阻断启动**——`entrypoint.sh` 里 preflight 非 0 退出也只打日志然后按原命令跑;
|
||
preflight 内部每步都有 try/except。最坏情况=没修上,不会比不装本引擎更差。
|
||
3. **干净模型零改动**——模型自带 chat_template、架构已注册、无 list 字段时,
|
||
preflight 不产出任何额外参数(自测用例 5 专门盯这条)。
|
||
|
||
---
|
||
|
||
## 5. 自测(不需要 GPU / vLLM / Docker)
|
||
|
||
```bash
|
||
python3 test_engine.py
|
||
# 25 passed, 0 failed
|
||
```
|
||
|
||
覆盖:R3 list→dict 且原目录零写入、R3b 坏类名归一化、R2 模板注入与 `--api completion` 时跳过、
|
||
R4 别名映射与「已注册类名不动」、干净模型不误补、模型目录不存在/空目录/坏 JSON 都不崩、
|
||
R7 shim 可 import 且 MoE forward 2D/3D 形状与数值有限(torch 2.13 cpu 实测)、
|
||
`entrypoint.sh` bash 语法、覆盖目录**不含权重文件**。
|
||
|
||
---
|
||
|
||
## 6. 使用方式
|
||
|
||
`Dockerfile` 以 `ENTRYPOINT ["/opt/entrypoint.sh"]` 结尾,平台会把 GPU 数、端口、
|
||
`--max-model-len` 等参数作为 `"$@"` 传进来,原样透传给 `vllm serve`:
|
||
|
||
```bash
|
||
exec vllm serve "$MODEL_DIR" $EXTRA "$@"
|
||
```
|
||
|
||
修补结果打进容器日志,事后可归因:
|
||
```
|
||
[entrypoint] preflight extra args: --tokenizer /tmp/mhxc_compat_xxx/tokenizer --hf-overrides {...}
|
||
[entrypoint] preflight: [preflight] patches=3 R3: ... | R4: ... | R7: ...
|
||
```
|
||
|
||
---
|
||
|
||
## 7. 如何注册为平台可用框架(本轮挖出的完整链路)
|
||
|
||
平台侧的「上传驱动」按钮在当前 UI 里不存在,但**引擎注册的完整链路藏在社区引擎的 CI 里**。
|
||
照 `EngineX-Sunrise/enginex-S2-vllm-fix-tokenizer` 的 `.gitea/workflows/` 复刻即可:
|
||
|
||
```
|
||
.gitea/workflows/docker-build-push.yml 平台官方引擎 CI(原样复制,勿改)
|
||
.gitea/workflows/task_info.env 声明三要素:FRAMEWORK / GPU_TYPE / TASK_TYPE
|
||
```
|
||
|
||
推送一个 **`v*` 标签**即触发,CI 会依次:
|
||
1. 读 `task_info.env` 取 `FRAMEWORK`/`GPU_TYPE`/`TASK_TYPE`(FRAMEWORK 必填);
|
||
2. 调 `GET https://modelhub.org.cn/adminApi/image-verify/validate?gpuType=…&taskType=…` 校验元数据;
|
||
3. `docker build` + `docker push` 到平台 registry;
|
||
4. 调 `POST https://modelhub.org.cn//adminApi/image-verify` 回填 `{framework, gpuType, imageUrl, taskType, createBy, repoUrl, tag}` —— **这一步就是注册**。
|
||
|
||
本仓的取值:`FRAMEWORK=vllm_compat`、`GPU_TYPE=Iluvatar_bi-100`、`TASK_TYPE=text-generation`,
|
||
并已推送标签 **`v1.0.0`**(commit `d78a92b3`)。
|
||
CI 运行记录:`actions/runs/1`,9 个步骤(Clone / Set metadata / Load Task Info / Validate Metadata /
|
||
Login / Build / Push / Notify / Complete)**全部 success**,其中 Build 2s、Push 1m1s。
|
||
|
||
> 注册生效后,提交适配任务时的「框架」下拉里会出现 `vllm_compat`(只对 Iluvatar_bi-100 × 文本生成)。
|
||
|
||
## 8. 已验证 / 未验证(分清楚,不把做了当成了成了)
|
||
|
||
**已验证**
|
||
- `python3 test_engine.py` → **25 passed, 0 failed**(不需要 GPU / vLLM / Docker)
|
||
- CI 9 步全部 success;`image-verify/validate` 返回 `code:0, data:true`(平台认可元数据)
|
||
|
||
**尚未验证**
|
||
- **框架还没出现在平台侧**:`Iluvatar_bi-100 × text-generation` 目前仍只有
|
||
`transformers / vllm / vllm-patch-tokenizer(个人开发者 zhengzhongwei) / vllm_fix_tokenizer` 四个,
|
||
`vllm_compat` 未出现,「我的驱动列表」也仍显示「暂无驱动」。
|
||
→ 注册是异步或需平台审核,**尚未生效**,需要继续观察(不能声称已注册成功)。
|
||
- **没在真卡上跑过**:本机没有天垓100,也拉不到该基础镜像,Dockerfile 未经真机验证。
|
||
风险已压到最小:基线镜像与官方基线一致、结构照搬生产引擎、修补全失败安全。
|
||
|
||
## 9. 已知边界
|
||
|
||
* R4 别名表只收已证实的 4 条(Qwen3_5 系列 + Gemma3 早期类名),不靠猜扩表。
|
||
* R7 shim 是兜底不是优化:保证「能出结果」,不追求吞吐。
|
||
* 提交任务的「框架」下拉要等平台注册生效后才看得到 `vllm_compat`。
|