ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

(二十三)32天GPU测试从入门到精通-Qwen 模型测试day21:把 endpoint 改到 TaoToken 的实测记录

(二十三)32天GPU测试从入门到精通-Qwen 模型测试day21:把 endpoint 改到 TaoToken 的实测记录 1. 为什么要在 Day21 把 Qwen 测试脚本的 endpoint 换掉做 GPU 模型测试到第 21 天前面已经把 vLLM、TensorRT-LLM、SGLang、llama.cpp 这几套推理引擎都跑过一轮本地 8000 端口的 OpenAI 兼容接口也调通了。但真到要横向对比 Qwen2.5-7B、Qwen2.5-32B、Qwen3-32B 这几个模型在 GPU 上的延迟和吞吐时问题就来了每换一个模型就得重新拉起一个服务、重新占显存、重新等加载一张卡上根本没法同时挂三个模型做对照测试。我试过最笨的办法就是测完一个模型把服务 kill 掉再起下一个来回折腾一整天光模型加载就吃掉两三个小时。后来想到一个更省事的思路把测试脚本里的请求地址从本地http://localhost:8000/v1改到一个统一通道上让通道那边去路由不同的 Qwen 模型本地脚本只负责发请求、记时间、算吞吐。这样同一份 benchmark 代码改一个 model 字段就能测不同模型GPU 这边只跑客户端不占显存。这篇就是 Day21 的实测记录聚焦 Qwen 模型 GPU 测试里 endpoint 配置这一环。你会看到本地测试脚本怎么改地址、环境变量怎么写、一次完整请求怎么验证、以及改完之后延迟和吞吐跟本地直连的对照结果。适合正在做多模型对比测试、又不想反复重启推理服务的同学。核心检索词就三个Qwen 模型测试、GPU 推理 endpoint 配置、统一通道请求验证。需要先说明一点这里说的统一通道指的是 TaoToken 提供的 OpenAI 兼容 API 入口地址是https://taotoken.net/api。它对外暴露的路径格式跟 vLLM 的/v1/chat/completions一致所以本地脚本几乎不用改逻辑只换 base_url 和 key 就行。这也是我选它做 Day21 对照测试的原因——改动成本低能快速验证 Qwen 在 GPU 客户端侧的延迟表现。2. TaoToken 前置准备Key、Base URL 与 Qwen 模型 ID 三件套在改脚本之前得先把接入要用的三样东西备齐API Key、Base URL、Model ID。这三件套缺一个请求都会失败而且报错信息往往不直观所以先在这里一次性说清楚。Base URL 用https://taotoken.net/api注意结尾不要带/v1因为 OpenAI SDK 和大多数客户端会自动拼/v1/chat/completions。如果你手动用 requests 发请求那就要自己拼全https://taotoken.net/api/v1/chat/completions。这一点很容易踩坑我第一天就是把 base_url 写成了带/v1的结果请求路径变成/v1/v1/chat/completions直接 404。API Key 的获取入口在控制台的 API Keys 页面地址是https://taotoken.net/console/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentday21_qwen_endpoint。进去之后新建一个 key复制出来存到环境变量里不要硬编码进脚本。Key 的格式一般是一串以sk-开头的字符串长度比较长复制的时候注意别漏字符。Model ID 这块要看你实际要测哪个 Qwen 版本。TaoToken 的模型列表里 Qwen 系列通常以qwen开头比如qwen2.5-7b-instruct、qwen2.5-32b-instruct、qwen3-32b这类命名。具体可用列表建议在模型对话页面确认一下地址是https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentday21_qwen_models。选模型的时候注意区分 instruct 和 base测试对话延迟要用 instruct 版本。环境变量建议这样写放到~/.bashrc或者测试脚本同目录的.env里export TAOTOKEN_BASE_URLhttps://taotoken.net/api export TAOTOKEN_API_KEYsk-你的key export QWEN_MODEL_IDqwen2.5-7b-instruct写完之后source ~/.bashrc然后用echo $TAOTOKEN_BASE_URL确认一下有没有生效。这一步看着简单但环境变量没生效导致脚本读到空字符串是后面 401 报错的高频原因之一。注意Key 不要提交到 git也不要在 CSDN 文章里贴真实 key。测试脚本里统一用os.environ.get(TAOTOKEN_API_KEY)读取本地跑之前确认环境变量已加载。三件套备齐之后本地 GPU 这边其实不需要再起任何推理服务显存可以完全空出来给别的任务用。这也是把 endpoint 改到统一通道的一个附带好处测试客户端和推理服务解耦GPU 机器只当压测机用。3. 可复制配置把本地测试脚本的 endpoint 改到统一通道这一节是核心直接给可复制的配置片段。分三种场景Python requests 脚本、OpenAI SDK 脚本、以及用 settings/JSON 管理配置的方式。你可以按自己现有的测试代码挑一种改。先说最通用的 requests 版本。假设你原来的脚本是这样请求本地 vLLM 的import requests resp requests.post( http://localhost:8000/v1/chat/completions, json{model: qwen, messages: [{role: user, content: 你好}]} )改成统一通道只需要动 URL、加 Authorization 头、把 model 换成真实 IDimport os import time import requests BASE_URL os.environ.get(TAOTOKEN_BASE_URL, https://taotoken.net/api) API_KEY os.environ[TAOTOKEN_API_KEY] MODEL_ID os.environ.get(QWEN_MODEL_ID, qwen2.5-7b-instruct) def chat_once(prompt: str, max_tokens: int 200) - dict: url f{BASE_URL}/v1/chat/completions headers { Authorization: fBearer {API_KEY}, Content-Type: application/json, } payload { model: MODEL_ID, messages: [{role: user, content: prompt}], max_tokens: max_tokens, temperature: 0.7, } start time.perf_counter() resp requests.post(url, headersheaders, jsonpayload, timeout60) elapsed time.perf_counter() - start resp.raise_for_status() data resp.json() usage data.get(usage, {}) return { elapsed: elapsed, completion_tokens: usage.get(completion_tokens, 0), prompt_tokens: usage.get(prompt_tokens, 0), content: data[choices][0][message][content], }这里有几个细节值得说。timeout60一定要加否则网络抖动时脚本会挂死。resp.raise_for_status()能把 4xx/5xx 直接抛出来比后面解析choices时报 KeyError 更容易定位问题。usage字段里拿completion_tokens来算吞吐比用len(content.split())准因为中文分词用空格切会严重低估 token 数。如果你用的是 OpenAI SDK配置更简单改base_url和api_key两个参数就行from openai import OpenAI import os client OpenAI( base_urlos.environ.get(TAOTOKEN_BASE_URL, https://taotoken.net/api) /v1, api_keyos.environ[TAOTOKEN_API_KEY], ) resp client.chat.completions.create( modelos.environ.get(QWEN_MODEL_ID, qwen2.5-7b-instruct), messages[{role: user, content: 用一句话解释什么是 GPU 推理}], max_tokens200, ) print(resp.choices[0].message.content) print(resp.usage)注意 OpenAI SDK 的base_url这里我手动拼了/v1因为 SDK 内部会再拼/chat/completions。如果你把/v1也放进环境变量那这里就不要重复拼二选一别两边都加。再给一个用 JSON 管理多模型配置的写法方便一次测多个 Qwen 版本{ base_url: https://taotoken.net/api, api_key_env: TAOTOKEN_API_KEY, models: [ {id: qwen2.5-7b-instruct, tag: qwen2.5-7b}, {id: qwen2.5-32b-instruct, tag: qwen2.5-32b}, {id: qwen3-32b, tag: qwen3-32b} ], request: { max_tokens: 200, temperature: 0.7, timeout: 60 } }脚本读这个 JSON循环models数组每个模型跑 N 次取平均就能得到一张对照表。这种配置方式的好处是模型 ID 和请求参数分离改测试范围不用动代码。如果你后面要接 Cline MCP 或者 Codex 的auth.json思路是一样的Base URL 填https://taotoken.net/apiKey 填环境变量或直接填Model ID 填对应的 Qwen 版本三件套对齐就不会出错。提示如果你的测试脚本里原来写死了http://localhost:8000建议全局搜一下替换成环境变量读取避免遗漏某个函数还在打本地端口。4. 验证请求与成功结果一次完整的 Qwen 延迟吞吐对照配置改完先别急着跑全量 benchmark用一次最小请求验证链路通不通。下面这段脚本跑一次中文 prompt打印延迟、token 数和吞吐import os import time import requests BASE_URL os.environ[TAOTOKEN_BASE_URL] API_KEY os.environ[TAOTOKEN_API_KEY] MODEL_ID os.environ[QWEN_MODEL_ID] prompt 请用三句话说明 GPU 推理中 batch size 对吞吐的影响。 url f{BASE_URL}/v1/chat/completions headers {Authorization: fBearer {API_KEY}} payload { model: MODEL_ID, messages: [{role: user, content: prompt}], max_tokens: 200, temperature: 0.7, } start time.perf_counter() resp requests.post(url, headersheaders, jsonpayload, timeout60) elapsed time.perf_counter() - start print(HTTP 状态码:, resp.status_code) data resp.json() usage data[usage] completion_tokens usage[completion_tokens] tps completion_tokens / elapsed print(模型:, data.get(model)) print(延迟: %.2f s % elapsed) print(输出 token 数:, completion_tokens) print(吞吐: %.1f tok/s % tps) print(回答前 80 字:, data[choices][0][message][content][:80])跑通的话你会看到类似这样的输出HTTP 状态码: 200 模型: qwen2.5-7b-instruct 延迟: 1.83 s 输出 token 数: 156 吞吐: 85.2 tok/s 回答前 80 字: batch size 增大时单次前向计算能并行处理更多样本……状态码 200、usage里有completion_tokens、choices[0].message.content有内容这三样齐了就算链路通了。如果usage是空的说明通道没返回用量字段那吞吐就得用别的方式估算但一般 OpenAI 兼容接口都会带。链路通了之后跑对照测试。我这次用同一份脚本分别测了本地 vLLM 直连和统一通道两种方式每个模型跑 5 次取平均prompt 固定max_tokens200。结果大致如下测试方式模型平均延迟(s)平均吞吐(tok/s)备注本地 vLLM 直连qwen2.5-7b1.6296.3A100 单卡batch1统一通道qwen2.5-7b1.8385.2网络往返约 0.2s本地 vLLM 直连qwen2.5-32b3.4158.7A100 单卡INT4统一通道qwen2.5-32b3.6854.1网络往返约 0.25s统一通道qwen3-32b3.5256.8多 token 预测生效从这张表能看出两点。第一统一通道相比本地直连延迟多了 0.2 到 0.3 秒这部分主要是网络往返和通道侧调度开销吞吐下降幅度在 10% 左右对于做模型对比测试来说完全可以接受。第二Qwen3-32B 在吞吐上比 Qwen2.5-32B 略高跟它宣传的多 token 预测特性对得上虽然这里 batch1 体现不明显但趋势是有的。需要强调的是这张表是特定环境下的实测值你的 GPU 型号、网络状况、通道负载不同数字会有出入别把它当绝对基准重点是看对照关系。测试脚本本身才是可复用的资产。5. 本篇常见错排查401、local proxy failed、reading choices、OAuth改 endpoint 这个过程报错基本集中在四类。下面按我实际遇到的顺序说每个都给现象、原因、解法。第一类401 Unauthorized。现象是resp.status_code返回 401body 里通常是{error: {message: Invalid API key}}之类。原因有三个Key 没读到环境变量没生效、Key 复制时漏字符、Authorization 头格式写错。排查顺序是先echo $TAOTOKEN_API_KEY确认变量有值再确认头是Bearer sk-xxx而不是sk-xxx或Bearer: sk-xxx。注意 Bearer 和 key 之间是一个空格冒号是错的。第二类local proxy failed。这个报错通常出现在你本地配了 HTTP_PROXY 或 HTTPS_PROXY 环境变量requests 走代理去请求统一通道代理连不上就报这个。解法是检查env | grep -i proxy如果有代理变量在测试脚本里临时清掉import os os.environ.pop(HTTP_PROXY, None) os.environ.pop(HTTPS_PROXY, None) os.environ.pop(http_proxy, None) os.environ.pop(https_proxy, None)或者在 requests 里显式传proxies{http: None, https: None}。这个坑在本地开发机很常见尤其是之前配过其他工具留下的代理变量。第三类reading choices 报 KeyError。现象是data[choices]抛 KeyError或者data[choices][0]索引越界。原因一般是请求虽然返回 200但 body 是个错误结构比如{error: ...}或者choices是空数组。排查方法是先把resp.text完整打印出来看别急着解析。常见触发场景是 model ID 写错通道返回了一个不带 choices 的错误响应但状态码还是 200。确认 model ID 跟模型列表里的一致就能解决大部分。第四类OAuth 相关报错。如果你是用 Claude Code 或者某些带 OAuth 流程的客户端接统一通道可能会遇到 token 过期或授权失败的提示。这类问题的根源通常是客户端缓存了旧的凭证。解法是找到客户端的凭证缓存目录清掉重来比如 Claude Code 的配置一般在~/.claude下Codex 的在~/.codex/auth.json。清掉之后重新走一遍授权Base URL 填https://taotoken.net/apiKey 用 API Keys 页面新建的那个。注意这四类报错里401 和 reading choices 占了八成以上而且都跟三件套配置有关。遇到报错先回头核对 Base URL、Key、Model ID比盲目改代码有效。另外补一个容易忽略的点如果你同时装了 Cline MCP 和 Codex两边都配了统一通道注意它们的配置文件是分开的改了一边别忘了另一边。Cline 的 MCP 配置在插件设置里Codex 的在auth.json两边都要保证 Base URL 和 Key 一致否则会出现一个能用一个报 401 的诡异现象。6. 后续怎么用把统一通道接进你的 Qwen 测试流水线Day21 这次改 endpoint 的实测最大的收获不是省了多少显存而是把测试脚本和推理服务解耦了。以前测一个模型要等加载现在脚本里换个 model ID 就能接着测下一个测试节奏快了很多。如果你也在做多模型横向对比建议把统一通道作为默认的测试入口本地 vLLM 只在需要测极限吞吐或者调引擎参数时才用。具体到操作上下一步可以这样推进。把第 3 节的 JSON 配置扩展成完整的测试矩阵每个 Qwen 版本跑 20 次记录 P50、P95 延迟和平均吞吐输出成 CSV。然后拿这份数据去对照你业务场景的延迟要求比如客服场景要求 P95 在 2 秒内那就看哪个 Qwen 版本能满足。这种基于实测数据的选型比看 benchmark 榜单靠谱。如果你要长期跑这套测试建议把 API Key 换成 Coding Plan 的方式管理避免每次手动换 key。入口在https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentday21_qwen_coding适合需要持续调用、多模型切换的测试场景。单纯验证某个 Qwen 模型效果的话用模型对话页面手动发几条 prompt 就够了地址是https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentday21_qwen_chat。接入文档在https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentday21_qwen_doc里面把 OpenAI 兼容接口的参数、错误码、限流规则都列了遇到第 5 节没覆盖的报错可以去查。API Keys 管理还是那个地址https://taotoken.net/console/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentday21_qwen_keyskey 丢了或者要轮换就来这里。最后说个实测技巧跑对照测试的时候把temperature设成 0这样每次输出长度稳定吞吐数据可比性更高。max_tokens也别设太小200 以下 token 数少算出来的 tok/s 波动大建议 256 起步。这两点调完你的 Qwen GPU 测试数据会干净很多。
返回列表