推理服务(FAQ)
本页整理 serve.py 在评测/本地复现/云机器环境里最常见的问题与处理建议。
- 用法与定位:看 推理服务(用法与定位)
- 参数与环境变量:看 推理服务(参数与环境变量)
- 实现细节:看 推理服务(代码详解)
1) 健康检查一直是 warming / 超时
现象:GET / 长时间返回 {"status":"warming"},或评测机 health 阶段超时。
原因:启动阶段卡在模型加载/vLLM 初始化/预热上。
排查与处理:
- 确认
MODEL_DIR目录存在且包含可加载的模型文件(最少应有config.json、权重文件与 tokenizer 相关文件)。 - 优先减少 warmup 开销:
WARMUP_NUM_SAMPLES=0(禁用数据集抽样预热)WARMUP_REPEAT=1
- 如果 vLLM 初始化很慢或失败:
- 先让服务能跑起来:
USE_VLLM=false强制走 transformers 验证功能链路。 - 或保留 vLLM,但允许回退:不要设
FORCE_VLLM=1。
- 先让服务能跑起来:
2) 开了 batch 模式但 health 不是 batch
现象:你以为设置了 BATCH_MODE=1,但 GET / 仍返回 {"status":"ok"}。
结论:服务端 GET / 的 batch 判定是运行时读取 BATCH_MODE。
处理:
- 确认启动时环境变量确实传进进程(容器里可
printenv | grep BATCH_MODE)。 - 注意一些脚本可能覆盖环境变量:本项目约定是
run_model.sh“有就用、没有才给默认”,而env_force.sh会强制导入整套默认。
3) vLLM 初始化失败,自动回退了 transformers
现象:启动日志出现 vLLM init failed, fallback to transformers。
常见原因:
- 系统缺少 C 编译器(Triton 需要):
cc/gcc/clang不存在。 - CUDA 不可用或驱动不匹配。
- MetaX/平台插件对某些参数不兼容(
load_format/compilation_config等)。
处理建议:
- 如果你就是要 vLLM:
- 先确认工具链齐全(至少有
gcc或clang)。 - 确认
torch.cuda.is_available()为真。 - 必要时
FORCE_VLLM=1让问题尽早暴露(不回退)。
- 先确认工具链齐全(至少有
- 如果只是为了评测可用:允许回退即可(默认行为)。
4) 看到 “Device string must not be empty” 之类错误
原因:某些云运行时会把 CUDA_VISIBLE_DEVICES 或 VLLM_DEVICE 注入为空字符串。
服务端处理:启动时会把空字符串的设备变量删除(防御性修复)。
仍然失败时:
- 检查是否有其他设备相关变量被注入为空:
NVIDIA_VISIBLE_DEVICES。 - 显式设置
VLLM_DEVICE=cuda或清理相关环境变量再启动。
5) OOM、并发很低、或者 tokens/s 很差
5.1 OOM(KV cache 或权重加载)
优先顺序:
- 降低
MAX_MODEL_LEN(或在 MetaX 上调低DEFAULT_MAX_MODEL_LEN) - 降低
GPU_MEMORY_UTILIZATION - 限制 vLLM 容量参数:
VLLM_MAX_NUM_SEQS/VLLM_MAX_NUM_BATCHED_TOKENS
5.2 tokens/s 很差(尤其 batch)
最常见原因是:batch 路径没有充分 batching。
- 在 vLLM 离线 LLM 路线下,
serve.py已经做了关键优化:按max_tokens分桶批推理。 - 若你自行改动了 /predict,确保不要把 per-prompt
SamplingParams列表传给 vLLM,否则容易导致 batching 失效。
另外:
- 开启
FAST_CHAT_TEMPLATE=1(batch 模式默认就会开启)可以显著降低 chat template CPU 开销。 - 适当调大
BATCH_CONCURRENCY可能有助于喂饱引擎,但过大也可能让 Python 调度/内存顶爆。
6) 输出被截断 / Rouge 掉分
可能原因:
MAX_NEW_TOKENS太小;或分流没有命中,导致长题仍按短答上限生成。
处理:
- 如果是代码题:
- 适当调大
MAX_NEW_TOKENS_CODE_SOFT/MAX_NEW_TOKENS_CODE_HARD - 或追加
CODE_QUESTION_KEYWORDS/HARD_CODE_QUESTION_KEYWORDS
- 适当调大
- 如果是算子类长题:
- 确认
LONG_ANSWER_ENABLE_DEFAULT=1 - 或追加
LONG_ANSWER_KEYWORDS
- 确认
- 想快速验证分流情况:开启
LOG_TOKEN_ROUTING=1看每次请求的桶统计。
7) 输出里有 <think>...</think> 或者被清空了
服务端会调用 strip_think,其设计目标是:
- 尽量去掉思考过程,避免输出过长。
- 但如果模型把最终答案写在 think 里,也会尝试回退提取。
如果你发现答案仍然异常:
- 先确认模型本身是否总把答案放在
<think>里;这种模型通常不适合此评测设定。 - 可以临时关闭系统提示词中的“不要思考过程”相关描述做对比(通过
/system_prompt更新),但这往往会增加输出长度并拖慢吞吐。
8) STOP 过早截断 / 或者 stop 不生效
STOP_ON_DOUBLE_NEWLINE=1可能导致过早截断(尤其是答案本身需要空行时)。先关掉再观察。STOP_STRINGS需要与模型实际输出的结束标记匹配;默认是 Qwen 常见的<|im_end|>、<|endoftext|>。- transformers 路线只使用 stop token ids(
eos_token_id),不支持任意字符串 stop;因此字符串 stop 更依赖 vLLM 路线。
9) WebUI 动态更新 system prompt 没生效
- 更新接口是
POST /system_prompt。 serve.py用全局变量保存当前 prompt,后续format_as_chat会读取它;不需要重启。- 如果你自己写了反向代理或缓存层,确认没有缓存住旧结果。
10) 为什么还有 /info 和 /system_prompt 这些接口?会影响评测吗?
- 评测只依赖
GET /与POST /predict。 - 额外接口主要服务 WebUI 与调试。
/info对环境变量做了白名单过滤,避免把 token/密钥暴露出来。