1. P40 跑 vllm 报 no kernel image 到底卡在哪
你手里有一张 Tesla P40,24G 显存,二手价格便宜到让人心动,拿来跑 7B、13B 的量化模型本来挺香。结果 pip 装完 vllm,一启动就给你甩一句CUDA error: no kernel image is available for execution on the device,进程直接退出。这个报错的意思是:你编译出来的 CUDA kernel,里面没有任何一份机器码能在当前这张卡上执行。换句话说,程序带着一堆为别的显卡编译好的二进制,到了 P40 面前发现"没有一个能跑"。
P40 的计算能力是 6.1,属于 Pascal 架构。而 vllm 官方安装文档里写得很清楚,CUDA 后端要求计算能力不低于 7.0,也就是 Volta 起步。你升级 vllm 到 0.8.1 甚至更新版本都没用,因为这不是版本新旧的问题,是预编译 wheel 里压根没打包 sm_60/sm_61 的 kernel。很多人第一反应是"版本太旧",折腾半天升级降级,最后才发现方向从一开始就错了。
这篇内容面向三类人:手上还留着 P40/P100 这类老卡想榨干余热的、正在被这个报错卡住不知道往哪查的、以及想搞清楚"算力架构—wheel 编译目标—驱动版本"这三者关系的人。我会先讲清楚报错的三个根因,再给一套可复制的配置骨架,把 TaoToken 统一 Key 的接入方式一并放进去,最后给你 nvcc 架构校验和最小复现动作,让你五分钟内确认自己的卡到底能不能跑 vllm。
2. 先搞清楚三处根因,别急着升级 vllm
2.1 算力架构不匹配是主因
no kernel image is available这个报错,本质是 CUDA 运行时在 fatbin 里找不到匹配当前 device 的 SASS 或 PTX。P40 是 sm_61,vllm 官方 wheel 在构建时用的TORCH_CUDA_ARCH_LIST通常只覆盖 7.0、7.5、8.0、8.6、9.0 这些。你装上去,PyTorch 和 vllm 自带的算子库里没有 sm_61 的机器码,一调用自定义 kernel 就炸。
你可以用一条命令确认自己的卡算力:
nvidia-smi --query-gpu=name,compute_cap --format=csvP40 会输出Tesla P40, 6.1。只要这个数字小于 7.0,官方 vllm wheel 基本没戏。
2.2 vllm 预编译 wheel 的 arch 列表
vllm 发布到 PyPI 的 wheel 是预编译的,不会为每张卡单独编译。它的构建脚本里TORCH_CUDA_ARCH_LIST决定了打包哪些架构。你可以装完之后自己验证一下当前环境支持的架构:
python -c "import torch; print(torch.cuda.get_arch_list())"如果输出里没有sm_61,那 P40 就是跑不了。这不是 bug,是设计取舍——维护 sm_60/61 会显著增加构建体积和 CI 时间,而 Pascal 在数据中心已经属于淘汰梯队。
2.3 驱动与 CUDA 版本只是次要因素
驱动和 CUDA 版本不匹配会引发别的报错,比如CUDA driver version is insufficient,但不会直接导致no kernel image。你 excerpt 里提到用的是 CUDA 12.6,这个版本本身对 Pascal 还是支持的,问题不在 CUDA 版本,而在编译目标。所以别把时间浪费在反复重装 CUDA Toolkit 上。
注意:如果你坚持要在 P40 上用 vllm,唯一的路是从源码编译,并且显式设置
TORCH_CUDA_ARCH_LIST="6.1"。但即便编译成功,vllm 的部分 attention 算子和量化 kernel 在 Pascal 上也可能有兼容问题,稳定性没保证。生产环境不建议这么干。
3. TaoToken 前置:统一 Key 把模型通道先理顺
在纠结显卡能不能跑之前,有个更实际的问题:你跑推理是为了调模型,而调模型不一定非得本地跑。P40 这种卡适合跑量化后的小模型做实验,但如果你要的是稳定的 API 通道,本地折腾显卡的性价比其实很低。
TaoToken 在这里的角色是统一 Key 和统一 API 通道。你可以在 https://taotoken.net/?utm_source=taotoken_aicg_blog_end 注册后拿到一个 Key,然后用它同时访问多个模型,不用为每个厂商单独维护一套鉴权和 base_url。对于本地跑 vllm 的场景,你可以把 TaoToken 当作对照通道——本地跑不通的时候,先用 API 通道验证你的业务代码逻辑是不是对的,把"模型问题"和"显卡问题"分开。
接入方式很简单,OpenAI 兼容格式,base_url 指向https://taotoken.net/api。下面给一份可复制的配置骨架。
3.1 config.toml 骨架
# ~/.config/taotoken/config.toml # TaoToken 统一 Key 配置骨架 [default] base_url = "https://taotoken.net/api" api_key = "sk-你的TaoToken密钥" timeout = 60 max_retries = 3 [models] # 本地 vllm 通道(P40 编译成功后可用) local_vllm = "http://127.0.0.1:8000/v1" # TaoToken 远程通道(对照验证用) remote_default = "gpt-4o-mini" remote_reasoning = "claude-3-5-sonnet" [logging] level = "info" file = "~/.config/taotoken/taotoken.log"3.2 settings.json 骨架
{ "provider": "taotoken", "base_url": "https://taotoken.net/api", "api_key_env": "TAOTOKEN_API_KEY", "default_model": "gpt-4o-mini", "fallback": { "enabled": true, "local_endpoint": "http://127.0.0.1:8000/v1", "local_model": "your-local-model" }, "request": { "temperature": 0.7, "max_tokens": 2048, "stream": true } }把 Key 放到环境变量里,别硬编码进文件:
export TAOTOKEN_API_KEY="sk-你的TaoToken密钥"这样你的业务代码只认一个 base_url 和一个 Key,本地 vllm 跑通就切本地,跑不通就切 TaoToken 远程通道,排查问题时不会两头乱。
4. 可复制配置:从校验到最小复现
4.1 nvcc 架构校验
先确认你的 CUDA 工具链认识 sm_61:
nvcc --list-gpu-arch输出里应该能看到compute_61和sm_61。如果没有,说明你的 CUDA Toolkit 版本太新,已经移除了 Pascal 支持。CUDA 12.x 还保留,13.x 开始逐步移除。
再确认 PyTorch 编译时带了哪些架构:
python - <<'PY' import torch print("torch:", torch.__version__) print("cuda:", torch.version.cuda) print("arch list:", torch.cuda.get_arch_list()) print("device cap:", torch.cuda.get_device_capability(0)) PY如果arch list里没有sm_61,而device cap是(6, 1),那no kernel image就是必然的。
4.2 最小复现验证动作
写一个最小脚本,直接触发报错,确认问题边界:
# repro_p40.py import torch assert torch.cuda.is_available(), "CUDA 不可用" cap = torch.cuda.get_device_capability(0) print(f"设备算力: sm_{cap[0]}{cap[1]}") # 一个简单的矩阵乘,会调用 cuBLAS kernel a = torch.randn(1024, 1024, device="cuda") b = torch.randn(1024, 1024, device="cuda") c = a @ b print("矩阵乘成功,kernel 可执行") # 如果上面通过但 vllm 报错,说明是 vllm 自定义 kernel 的问题跑这个脚本:
python repro_p40.py如果矩阵乘能过,但 vllm 启动时报no kernel image,那就锁定是 vllm 自定义算子没有 sm_61 的编译产物。这时候你有两个选择:源码编译 vllm 并指定TORCH_CUDA_ARCH_LIST="6.1",或者换 llama.cpp 路线。
4.3 源码编译 vllm 的尝试(不保证稳定)
如果你非要试,可以这样:
export TORCH_CUDA_ARCH_LIST="6.1" export VLLM_TARGET_DEVICE=cuda pip install -e . --no-build-isolation编译过程可能几十分钟,而且大概率会在某些算子处报错。实测下来,P40 上编译 vllm 的成功率不高,即使编译过了,推理速度也远不如预期。所以这条路我只建议做技术验证,不建议上生产。
4.4 用 TaoToken 通道做对照验证
在本地折腾的同时,用 TaoToken 跑一遍同样的请求,确认你的业务代码没问题:
# check_taotoken.py import os from openai import OpenAI client = OpenAI( base_url="https://taotoken.net/api", api_key=os.environ["TAOTOKEN_API_KEY"], ) resp = client.chat.completions.create( model="gpt-4o-mini", messages=[{"role": "user", "content": "用一句话解释什么是 CUDA 计算能力"}], ) print(resp.choices[0].message.content)如果这段能正常返回,说明你的网络、Key、SDK 都没问题,问题纯粹在本地显卡和 vllm 的兼容性上。这样排查范围一下就缩小了。
5. 本篇常见错排查
5.1 升级 vllm 后报错依旧
这是最常见的误区。no kernel image不是版本问题,是编译目标问题。升级到 0.8.1、0.9.x 都一样,因为官方 wheel 的 arch 列表没变。别在这上面浪费时间。
5.2 装了 CUDA 12.6 还是报错
CUDA 版本和 kernel 编译目标是两回事。你装 CUDA 12.6 只是让运行时可用,但 wheel 里没有 sm_61 的机器码,运行时照样找不到。检查torch.cuda.get_arch_list()才是关键。
5.3 报错信息里出现 sm_70 相关字样
有些报错会提示PTX was compiled for sm_70,这说明 wheel 里带了 PTX 但没有 SASS。PTX 理论上可以 JIT 编译到 sm_61,但 vllm 的构建通常禁用了 JIT fallback,所以还是跑不了。你可以在启动时加CUDA_FORCE_PTX_JIT=1试试,但成功率很低。
5.4 换 llama.cpp 后模型加载失败
llama.cpp 走的是 GGUF 格式,你需要先把 safetensors 转成 GGUF。转换脚本在 llama.cpp 仓库的convert_hf_to_gguf.py。转换时注意量化等级,P40 上 Q4_K_M 比较稳。转完之后用 ollama 加载,P40 是能正常跑的,这条路比硬刚 vllm 靠谱得多。
5.5 TaoToken 请求返回 401
先确认环境变量TAOTOKEN_API_KEY有没有正确 export,再确认 base_url 是不是https://taotoken.net/api(注意结尾没有多余斜杠)。如果用的是 settings.json 里的api_key_env,确认程序真的读到了这个环境变量。401 基本都是 Key 没传对,不是通道问题。
6. 把通道和显卡解耦,才是长期解法
P40 这张卡的价值在于显存大、价格低,适合跑量化模型做实验。但 vllm 的官方支持已经明确把门槛设在 7.0,你硬刚只会不断撞墙。我的建议是把两件事分开:本地用 llama.cpp + ollama 跑 P40 能支持的模型,做离线实验;需要稳定推理或者跑更大模型时,走 TaoToken 的统一 API 通道,用同一个 Key 切换模型,不用为每张显卡的兼容性买单。
如果你正在做 coding agent 或者长期跑的编码任务,可以看看 Coding Plan 那条线,把模型调用和本地环境彻底解耦,显卡换不换都不影响业务。接入文档在 https://taotoken.net/api 对应的 doc 页面,API Keys 在 console 里管理。先把通道理顺,再决定要不要为 P40 折腾编译,顺序别搞反了。