1. 为什么要在云服务器上自己跑 Qwen3.6-27B
Qwen3.6-27B 是通义千问系列里比较适合单机部署的一档尺寸,FP8 量化后权重约 27GB,一张 80GB 显存的卡就能同时装下模型和推理缓存。它适合谁?适合需要私有化推理、又不想被公有 API 的限流和计费绑住的开发者,也适合想拿自己的业务数据做轻量微调、让模型学会特定输出格式的团队。
我这次的整体思路是:云服务器上租一张 A800-80GB,用 vLLM 起推理服务,再用 LiteLLM 做一层 OpenAI 兼容网关,最后把网关的 Base URL 和 Key 统一收敛到 TaoToken 的接入方式上。这样本地代码、CI 脚本、甚至 Claude Code 这类工具,都只需要认一套 Key 和一套地址,切换模型时改一个 Model ID 就行。
为什么中间要加 LiteLLM?因为 vLLM 自己虽然也提供 OpenAI 兼容接口,但多模型路由、Key 管理、请求日志这些事它不管。LiteLLM 相当于一个翻译层加路由层,对外暴露统一的/v1/chat/completions,对内可以指向本地 vLLM,也可以指向远端模型。你后面做微调、做 A/B 对比、做灰度,都在这层改配置,不用动业务代码。
整条链路的关键词就三个:Qwen3.6-27B、云服务器部署、vLLM + LiteLLM 微调。下面按「准备 → 部署 → 配置 → 验证 → 排障」的顺序走一遍,每一步都给可复制的命令和配置。
先说清楚硬件和软件基线,避免你租错机器:
| 项目 | 推荐配置 | 说明 |
|---|---|---|
| GPU | A800-80GB / H800-80GB | FP8 权重约 27GB,留足 KV Cache |
| 镜像 | PyTorch 2.x + CUDA 12.x + Python 3.12 | 与 vLLM 轮子匹配 |
| 系统盘 | ≥ 50GB | 装依赖和日志 |
| 数据盘 | ≥ 100GB | 放模型权重和微调数据 |
| 端口 | 6006(网关)/ 8000(vLLM) | 云厂商安全组要放行 |
模型权重你可以从官方渠道下载,也可以提前打包上传到云盘空间。文件结构建议保持这样,后面脚本路径才对得上:
/root/autodl-tmp/qwen/ ├── qwen-deploy/ │ ├── start_vllm.sh │ ├── litellm_config.yaml │ └── requirements.txt ├── lora/ │ ├── train_lora.py │ ├── test_lora.py │ └── train_data.jsonl ├── logs/ └── models/Qwen3.6-27B-FP8/目录先建好,日志目录一定要存在,否则nohup ... >> logs/vllm.log会因为找不到文件直接失败,这个坑我踩过。
2. TaoToken 统一 Key 的前置准备与 LiteLLM 接入配置
这一节解决「Key 从哪来、怎么配进 LiteLLM」的问题。核心目标是:不管底层是本地 vLLM 还是远端模型,业务侧只用一个 Base URL 和一个 Key。
第一步,去 TaoToken 控制台创建一个 API Key。地址是https://taotoken.net/console,登录后在 API Keys 页面新建,复制出来的字符串形如sk-xxxxxxxx。这个 Key 就是后面 LiteLLM 配置里的master_key,也是你 curl 测试时Authorization: Bearer后面那串。
第二步,确认你要用的模型 ID。TaoToken 的模型列表在文档里有,地址是https://taotoken.net/doc。本地 vLLM 起的模型,Model ID 由你启动参数里的--served-model-name决定,比如qwen3.6-27b-fp8。远端模型则用平台约定的 ID。LiteLLM 的model_list里,model_name是对外暴露的名字,litellm_params.model是实际路由目标。
第三步,写 LiteLLM 配置文件。这是整条链路的核心,路径放在/root/autodl-tmp/qwen/qwen-deploy/litellm_config.yaml:
model_list: - model_name: qwen3.6-27b-fp8 litellm_params: model: openai/qwen3.6-27b-fp8 api_base: http://127.0.0.1:8000/v1 api_key: sk-local-vllm - model_name: qwen3.6-27b-remote litellm_params: model: openai/qwen3.6-27b api_base: https://taotoken.net/api/v1 api_key: os.environ/TAOTOKEN_API_KEY general_settings: master_key: os.environ/LITELLM_MASTER_KEY database_url: "" litellm_settings: drop_params: true request_timeout: 600这里有几个细节要说明。api_base指向本地 vLLM 时用127.0.0.1:8000/v1,因为 vLLM 默认监听 8000。指向 TaoToken 时用https://taotoken.net/api/v1,注意 API 地址不带 UTM 参数,保持干净。api_key用os.environ/前缀表示从环境变量读取,避免把明文 Key 写进文件。
第四步,设置环境变量。在启动 LiteLLM 之前 export:
export TAOTOKEN_API_KEY="sk-你的TaoToken密钥" export LITELLM_MASTER_KEY="sk-你的网关主密钥"LITELLM_MASTER_KEY是你自己定的,客户端拿它来访问网关。它和 TaoToken 的 Key 是两层:客户端 → LiteLLM 用 master key,LiteLLM → 远端用 TAOTOKEN_API_KEY。本地 vLLM 那路其实不校验 Key,但 LiteLLM 要求api_key字段非空,随便填一个占位即可。
第五步,如果你要在 Claude Code 这类工具里用,配置三件套是 Base URL、Key、Model ID:
{ "env": { "ANTHROPIC_BASE_URL": "https://taotoken.net/api", "ANTHROPIC_API_KEY": "sk-你的TaoToken密钥", "ANTHROPIC_MODEL": "qwen3.6-27b" } }这段 JSON 可以放进 Claude Code 的 settings 文件,路径按官方文档来。注意 Base URL 这里用https://taotoken.net/api,不带/v1,因为不同客户端拼接规则不一样,以文档为准。Model ID 必须和你在 TaoToken 侧看到的名称完全一致,大小写和连字符都不能错,否则会报 model not found。
第六步,如果你用 Codex 或 Cline 这类工具,它们的auth.json或 MCP 配置里同样要写全三件套。以 Codex 的auth.json为例:
{ "OPENAI_BASE_URL": "https://taotoken.net/api/v1", "OPENAI_API_KEY": "sk-你的TaoToken密钥", "OPENAI_MODEL": "qwen3.6-27b" }Cline 的 MCP 配置则在mcpServers里指定 command 和 env,env 里同样放 Base URL、Key、Model ID。这三件套缺一个都会连不上,最常见的错就是只填了 Key 没填 Base URL,结果请求打到了默认的官方地址。
到这里,前置准备和配置就齐了。下一节进入实际的启动和可复制配置。
3. 可复制的 vLLM 启动脚本与 LiteLLM 网关配置
这一节给完整的、能直接跑的脚本。先看 vLLM 启动脚本start_vllm.sh:
#!/bin/bash set -e MODEL_PATH="/root/autodl-tmp/qwen/models/Qwen3.6-27B-FP8" SERVED_NAME="qwen3.6-27b-fp8" LOG_DIR="/root/autodl-tmp/qwen/logs" mkdir -p "$LOG_DIR" python -m vllm.entrypoints.openai.api_server \ --model "$MODEL_PATH" \ --served-model-name "$SERVED_NAME" \ --host 0.0.0.0 \ --port 8000 \ --dtype float16 \ --quantization fp8 \ --tensor-parallel-size 1 \ --gpu-memory-utilization 0.90 \ --max-model-len 32768 \ --max-num-seqs 64 \ --trust-remote-code \ --disable-log-requests参数逐个解释。--dtype float16配合--quantization fp8,让权重以 FP8 存储、计算时转半精度,显存和速度比较平衡。--tensor-parallel-size 1是单卡,多卡才改。--gpu-memory-utilization 0.90表示最多用 90% 显存,留一点给系统,设太高容易 OOM。--max-model-len 32768是上下文长度,越长 KV Cache 占用越大,80GB 卡上 32K 比较稳。--max-num-seqs 64控制并发序列数,并发高吞吐好但显存吃紧。--trust-remote-code对 Qwen 系列通常需要。
启动命令:
cd /root/autodl-tmp/qwen/qwen-deploy chmod +x start_vllm.sh nohup ./start_vllm.sh >> /root/autodl-tmp/qwen/logs/vllm.log 2>&1 & tail -f /root/autodl-tmp/qwen/logs/vllm.log看到Application startup complete.就说明 vLLM 起来了,按 Ctrl+C 退出日志跟踪(不会杀掉进程)。首次加载权重通常要 2 到 4 分钟,取决于磁盘 IO。
接着启动 LiteLLM 网关,绑定 6006 端口:
cd /root/autodl-tmp/qwen/qwen-deploy export TAOTOKEN_API_KEY="sk-你的TaoToken密钥" export LITELLM_MASTER_KEY="sk-你的网关主密钥" nohup litellm --config litellm_config.yaml --port 6006 --host 0.0.0.0 \ >> /root/autodl-tmp/qwen/logs/litellm.log 2>&1 & tail -f /root/autodl-tmp/qwen/logs/litellm.log看到Uvicorn running on http://0.0.0.0:6006即正常。同样 Ctrl+C 退出日志。
如果你更习惯用settings.json或 TOML 管理配置,LiteLLM 也支持。比如把上面的 YAML 换成等价的 TOML:
[[model_list]] model_name = "qwen3.6-27b-fp8" [model_list.litellm_params] model = "openai/qwen3.6-27b-fp8" api_base = "http://127.0.0.1:8000/v1" api_key = "sk-local-vllm" [general_settings] master_key = "os.environ/LITELLM_MASTER_KEY"启动时用litellm --config litellm_config.toml即可。YAML 和 TOML 二选一,别同时放两个文件让工具猜。
这里再强调一次三件套的对应关系,用表格对照:
| 层级 | Base URL | Key | Model ID |
|---|---|---|---|
| 本地 vLLM | http://127.0.0.1:8000/v1 | 占位即可 | qwen3.6-27b-fp8 |
| LiteLLM 网关 | http://0.0.0.0:6006/v1 | LITELLM_MASTER_KEY | qwen3.6-27b-fp8 |
| TaoToken 远端 | https://taotoken.net/api/v1 | TAOTOKEN_API_KEY | qwen3.6-27b |
| Claude Code | https://taotoken.net/api | TAOTOKEN_API_KEY | qwen3.6-27b |
配置写完后,先别急着测外网,先在服务器内网 curl 一把,确认网关本身是通的。下一节就是验证动作。
4. 验证请求:内网 curl、外网连通与微调任务提交
验证分三步:内网测网关、外网测端口映射、微调任务提交。
内网测试直接打 LiteLLM 的 6006 端口:
curl http://localhost:6006/v1/chat/completions \ -H "Content-Type: application/json" \ -H "Authorization: Bearer sk-你的网关主密钥" \ -d '{ "model": "qwen3.6-27b-fp8", "messages": [{"role": "user", "content": "你好,用一句话介绍你自己"}], "max_tokens": 128 }'正常返回是一个 JSON,choices[0].message.content里有模型输出。如果返回 401,说明 master key 不对;如果返回 model not found,说明model字段和model_list里的model_name不一致。
外网测试需要云厂商把 6006 端口映射出去。在控制台找到「自定义服务」,拿到形如https://xxxx.seetacloud.com:8443的外网地址,然后本地终端执行:
curl -X POST https://xxxx.seetacloud.com:8443/v1/chat/completions \ -H "Content-Type: application/json" \ -H "Authorization: Bearer sk-你的网关主密钥" \ -d "{\"model\": \"qwen3.6-27b-fp8\", \"messages\": [{\"role\": \"user\", \"content\": \"你好\"}]}"注意外网地址的端口是映射后的 8443,不是 6006,别搞混。如果连不上,先检查安全组和映射是否生效。
微调之前必须先停掉 vLLM,释放显存,否则训练脚本申请不到显存:
pkill -f "vllm serve" pkill -f "start_vllm.sh" sleep 5 nvidia-smi确认显存已经释放。然后进入微调目录:
cd /root/autodl-tmp/qwen/lora python train_lora.pytrain_data.jsonl是内置的模拟数据,每行一个 JSON,格式是{"instruction": "...", "output": "..."}。训练脚本会加载基座模型、挂 LoRA 适配器、跑若干 epoch,最后把适配器权重存到output/目录。训练日志里关注 loss 是否下降、有没有 NaN。
训练完成后测试:
python test_lora.py这个脚本会加载基座加 LoRA 权重,喂一条测试输入,看输出是否符合微调数据的风格。如果输出还是基座的原味回答,说明 LoRA 没加载上,检查适配器路径。
微调任务提交这块,如果你想把训练也走统一入口,可以在 LiteLLM 之外单独跑一个训练任务队列,但推理和训练不要同时占卡。80GB 卡上 27B 模型做 LoRA,batch size 设 1 到 2、gradient accumulation 设 8 左右比较稳。
验证通过后,你的本地代码就可以把 Base URL 指向网关,Key 用 master key,Model ID 用qwen3.6-27b-fp8,完全不用改业务逻辑。
5. 常见报错排查:401、local proxy failed、reading choices、OAuth
这一节按真实报错来对。我把踩过的坑列出来,你对照日志定位。
401 Unauthorized。两种可能:一是客户端 Key 和 LiteLLM 的master_key不一致;二是 LiteLLM 转发到远端时TAOTOKEN_API_KEY没设置或过期。排查顺序:先看 LiteLLM 日志里有没有Authentication Error,再看环境变量是否在当前 shell 生效。注意export只在当前会话有效,nohup启动的进程如果没继承到变量,就会 401。稳妥做法是把 export 写进启动脚本。
local proxy failed / connection refused。这通常是 LiteLLM 连不上 vLLM。检查api_base是不是http://127.0.0.1:8000/v1,vLLM 是否真的在 8000 端口监听。用ss -tlnp | grep 8000确认。如果 vLLM 启动失败,日志里会有CUDA out of memory或Failed to load model,前者降--gpu-memory-utilization,后者检查模型路径和--trust-remote-code。
reading choices / KeyError choices。这个报错说明返回体里没有choices字段,通常是上游返回了错误 JSON,但 LiteLLM 按成功解析了。去 LiteLLM 日志里找原始响应,多半是远端返回了{"error": {...}}。常见原因是 Model ID 写错、额度不足、或者请求参数不被支持。drop_params: true能过滤掉部分不支持的参数,但不能解决 Model ID 错误。
OAuth / token expired。如果你在 Claude Code 或类似工具里看到 OAuth 相关报错,说明工具在走它自己的登录流程,而不是用你配的 API Key。检查 settings 文件里ANTHROPIC_API_KEY是否被正确读取,有些工具会优先读系统 keychain。把环境变量显式写进配置文件,重启工具。
再补几个容易忽略的:
| 报错关键词 | 大概率原因 | 处理 |
|---|---|---|
| model not found | Model ID 不匹配 | 对照 model_list 的 model_name |
| context length exceeded | 输入超过 max-model-len | 调大或截断输入 |
| CUDA OOM | 显存不够 | 降 gpu-memory-utilization 或 max-num-seqs |
| port already in use | 端口被占 | pkill 旧进程或换端口 |
| no such file logs | 日志目录不存在 | mkdir -p logs |
排查时养成一个习惯:先看 LiteLLM 日志,再看 vLLM 日志,最后看客户端。三层日志按顺序看,能省很多时间。LiteLLM 日志在logs/litellm.log,vLLM 在logs/vllm.log。
还有一个隐蔽的坑:pkill -f "vllm serve"有时候匹配不到,因为实际进程名是python -m vllm.entrypoints...。更稳的写法是pkill -f "vllm.entrypoints",或者用nvidia-smi找到 PID 再 kill。
6. 把统一 Key 用起来:从本地脚本到长期编码
链路跑通之后,真正的价值在于「一套 Key 走天下」。你本地写个 Python 脚本,只需要这样:
from openai import OpenAI client = OpenAI( base_url="https://taotoken.net/api/v1", api_key="sk-你的TaoToken密钥", ) resp = client.chat.completions.create( model="qwen3.6-27b", messages=[{"role": "user", "content": "把这段日志归类"}], ) print(resp.choices[0].message.content)如果指向本地网关,把base_url换成http://你的服务器:6006/v1,api_key换成 master key,model换成qwen3.6-27b-fp8,其他代码一行不用改。这就是统一 Key 的意义:环境切换只改三个字符串。
对于长期编码和 Agent 场景,建议用 Coding Plan,地址是https://taotoken.net/coding-plan。它适合需要持续调用、跑自动化任务的场景,比按次调用更省心。日常验证模型效果,用模型对话页面https://taotoken.net/chat快速试就行。接入文档在https://taotoken.net/doc,API Keys 管理在https://taotoken.net/api-keys。
最后给一个实用技巧:把 Base URL、Key、Model ID 写进项目的.env,用python-dotenv加载,别硬编码在代码里。团队协作时,每个人用自己的 Key,Base URL 和 Model ID 统一,这样既安全又一致。微调完的 LoRA 权重,可以在 vLLM 启动时用--enable-lora挂上,让推理服务同时支持基座和微调版本,切换只改 Model ID。
整条链路的核心就三件事:vLLM 把模型跑起来,LiteLLM 把接口统一,TaoToken 把 Key 收敛。剩下的都是配置和排障的体力活。