1. vLLM-Ascend 上 curl 验证没返回,问题到底卡在哪
如果你正在昇腾 Atlas 800I A2 上部署 Qwen2.5-7B,用 vLLM-Ascend 起服务,然后照着文档敲下curl http://ip:port/v1/completions,结果终端光标一直闪、没有任何 JSON 返回,或者返回了但格式对不上、模型名报错——这篇就是写给你的。vLLM-Ascend 是昇腾平台上的 vLLM 适配版本,负责把 Qwen2.5-7B 这类模型在 NPU 上跑起来并提供 OpenAI 兼容接口;它适合做模型服务化部署、精度测评和性能压测的工程师。curl 验证没返回,通常不是单一原因,而是服务启动参数、请求体字段、网络绑定地址、模型名四者中至少一个不一致。
我试过在 8 卡 A2 上反复起停服务,最常见的现象有三类:第一类,curl 完全无响应,等几十秒后超时,说明请求根本没到服务进程,或者服务还在加载权重;第二类,curl 返回了但报model not found,因为启动时--served-model-name写的是qwen-2.5b,而请求体里写的是Qwen2.5-7B-Instruct;第三类,返回 200 但内容是空数组或格式怪异,多半是--max-model-len和请求的max_tokens冲突,或者--enforce-eager没加导致图模式编译卡住。下面按原文第 5 节的排障视角,先把现象复现出来,再用 Codex 对照排查。
2. 先复现:npu-smi info、vllm serve 和 curl 三步走
排障的第一步不是改代码,而是把当前状态固定下来。你需要先确认 NPU 设备正常,再确认服务进程活着,最后确认 curl 请求本身没问题。
2.1 用 npu-smi info 确认设备与显存
在容器内执行:
npu-smi info正常输出会列出 8 张卡的温度、功耗、显存占用和进程。如果显存占用为 0 且没有 vllm 进程,说明服务根本没起来;如果某张卡显存接近 32GB 上限,说明模型加载了但可能卡在编译阶段。把这份输出截图或复制下来,后面让 Codex 对照时用得上。
2.2 用 vllm serve 启动服务并保留日志
原文第 4 节的启动脚本里有一串环境变量,先确认它们都 export 了:
export VLLM_USE_V1=1 export TASK_QUEUE_ENABLE=1 export HCCL_OP_EXPANSION_MODE="AIV" export PAGED_ATTENTION_MASK_LEN=max_seq_len export VLLM_ASCEND_ENABLE_FLASHCOMM=1 export VLLM_ASCEND_ENABLE_TOPK_OPTIMIZE=1然后启动:
vllm serve ./Qwen2.5-7B-Instruct/ \ --host 0.0.0.0 \ --port 8000 \ --served-model-name qwen-2.5b \ --trust-remote-code \ --dtype bfloat16 \ --max-model-len 32768 \ --tensor-parallel-size 1 \ --disable-log-requests \ --enforce-eager注意--host建议写0.0.0.0而不是某个具体 IP,否则跨容器或跨机器 curl 会连不上。启动后观察日志,直到出现Application startup complete和Uvicorn running on http://0.0.0.0:8000,才说明服务真正就绪。如果日志停在Loading model weights超过几分钟,先别急着 curl。
2.3 用 curl 复现三种典型现象
服务就绪后,按原文第 5 节发请求:
curl http://127.0.0.1:8000/v1/completions \ -H "Content-Type: application/json" \ -d '{"model": "qwen-2.5b", "prompt": "Beijing is a", "max_tokens": 5, "temperature": 0}'把结果分三类记录:
| 现象 | 终端表现 | 初步判断 |
|---|---|---|
| 无返回 | 光标闪烁,最终 timeout | 请求未达服务或服务未就绪 |
| 模型名报错 | The model qwen-2.5b does not exist | served-model-name 与请求不一致 |
| 返回空/格式怪 | 200 但 choices 为空或字段缺失 | max-model-len 或 max_tokens 冲突 |
把服务日志、启动参数、curl 结果三份材料整理到一个文本文件里,这是后面让 Codex 对照排查的输入。
3. 让 Codex 对照排查:Base URL 改到 TaoToken
当 curl 现象已经固定,但你不确定是--tensor-parallel-size写错、--max-model-len太小,还是 AISBench 里host_ip/host_port配错时,可以让 AI 编程工具帮你逐项对照。这里用 Codex,它需要一个可用的 Base URL 和 Key。
打开 https://taotoken.net/?utm_source=taotoken_aicg_blog_end 注册账号,进入控制台创建 API Key。然后把 Codex 的 Base URL 填成:
https://taotoken.net/api注意这里不带/v1,也不加任何 UTM 参数。Key 用刚创建的那一串。TaoToken 在这个环节只负责给 Codex 提供 Key 和 Base URL,它不替你部署 vLLM-Ascend,也不参与 NPU 上的推理,模型服务仍然跑在你自己的昇腾机器上。
配置完成后,你可以把第 2 节整理的三份材料贴给 Codex,让它做一致性检查。比如这样提问:
我在昇腾 A2 上用 vLLM-Ascend 起了 Qwen2.5-7B,启动参数如下: --served-model-name qwen-2.5b --max-model-len 32768 --tensor-parallel-size 1 curl 请求体 model 字段是 qwen-2.5b,但返回 model not found。 服务日志显示 Application startup complete。 请帮我列出可能不一致的字段。Codex 会逐项对照--served-model-name、--max-model-len、--tensor-parallel-size和请求体字段,指出哪里对不上。这一步的价值在于,它能把散落在启动脚本、curl 命令和 AISBench 配置里的参数拉到一个平面上比对,减少你来回翻文件的时间。
4. 可复制配置:把参数对齐到 AISBench
排查完不一致后,回到原文第 5、6 节验证服务状态和指标。这里给出一份对齐后的配置,你可以直接复制。
4.1 启动参数与 curl 请求对齐
启动时--served-model-name决定了请求体里model字段该写什么。如果你写的是qwen-2.5b,curl 就必须用qwen-2.5b:
curl http://127.0.0.1:8000/v1/completions \ -H "Content-Type: application/json" \ -d '{"model": "qwen-2.5b", "prompt": "Beijing is a", "max_tokens": 5, "temperature": 0}'--max-model-len 32768表示服务端最大上下文,请求里的max_tokens是生成长度,两者不冲突,但如果你把max-model-len设成 512 而请求max_tokens要 1024,就会报错。--tensor-parallel-size要和实际使用的卡数一致,单卡就是 1,4 卡就是 4。
4.2 AISBench 的 host_ip 与 host_port
原文第 5 节的vllm_api_general_chat.py里,host_ip和host_port必须指向服务实际监听的地址和端口:
from ais_bench.benchmark.models import VLLMCustomAPIChat models = [ dict( attr="service", type=VLLMCustomAPIChat, abbr='vllm-api-general-chat', path="", model="qwen-2.5b", request_rate=0, retry=2, host_ip="127.0.0.1", host_port=8000, max_out_len=512, batch_size=1, generation_kwargs=dict( temperature=0.5, top_k=10, top_p=0.95, seed=None, repetition_penalty=1.03, ) ) ]如果服务在另一台机器,host_ip要写那台机器的可达 IP,host_port写vllm serve的--port。model字段同样要和服务端--served-model-name一致,写空字符串会自动获取,但自动获取有时拿到的名字和预期不同,建议显式写。
4.3 验证服务状态与指标
启动时加上--metrics,然后访问:
curl http://127.0.0.1:8000/metrics可以看到队列长度、推理延迟等指标。日志层面加--log-level debug能输出更细的加载和推理信息。如果 curl 仍然没返回,先看/metrics是否可达,不可达说明服务进程没监听成功。
5. 本篇常见错排查
5.1 curl 完全无返回
先确认服务日志有没有Application startup complete。没有就是还在加载,等。有的话检查--host是不是写成了127.0.0.1而你在另一台机器 curl,改成0.0.0.0重启。再检查端口有没有被占用,netstat -tlnp | grep 8000看一眼。
5.2 模型名对不上
--served-model-name qwen-2.5b和请求体"model": "qwen-2.5b"必须逐字符一致。大小写、连字符、点号都算。AISBench 里的model字段同理。如果拿不准服务端注册了什么名字,访问http://127.0.0.1:8000/v1/models看返回列表。
5.3 返回格式不对
如果返回 200 但choices为空,检查max_tokens是否大于--max-model-len减去 prompt 长度。如果返回字段缺失,确认请求的是/v1/completions而不是/v1/chat/completions,两者请求体结构不同。原文第 6 节还提到用/generate接口测试,那是 vLLM 原生接口,和 OpenAI 兼容接口的字段不一样,别混用。
5.4 多卡负载不均衡
--tensor-parallel-size和实际卡数不一致时,部分卡显存高、部分空闲。用npu-smi info看各卡显存,如果只有一张卡在涨,说明张量并行没生效。确认ASCEND_RT_VISIBLE_DEVICES设置的卡数和--tensor-parallel-size匹配。
6. 配通之后:回到原文第 5、6 节验证
当 curl 能稳定返回 JSON,且 AISBench 的host_ip/host_port/model三项对齐后,就可以跑精度测评了:
export ASCEND_RT_VISIBLE_DEVICES=0,1,2,3,4,5,6,7 ais_bench --models vllm_api_general_chat --datasets demo_gsm8k_gen_4_shot_cot_chat_prompt --debug ais_bench --models vllm_api_general_chat --datasets demo_gsm8k_gen_4_shot_cot_chat_prompt --summarizer example结果和日志在benchmark/outputs/default/下。性能测评加--mode perf。如果这一步又出现请求失败,把 AISBench 的 debug 日志和 vLLM 服务日志一起贴给 Codex,让它对照host_ip、host_port、model和启动参数再查一轮。整个链路里,TaoToken 只负责 Codex 的 Key 和 Base URL,NPU 上的服务状态和指标仍然以你本地的npu-smi info、/metrics和 AISBench 输出为准。