vllm bench serve 压测 DeepSeek-V3.2:把 endpoint 改到 TaoToken 的实测脚本
1. 为什么我要把 vllm bench serve 的 endpoint 换掉vllm bench serve 是 vLLM 自带的一个压测子命令专门用来给 OpenAI 兼容接口打并发流量输出 TTFT、TPOT、ITL、吞吐这些关键指标。它原本的设计场景是压本地部署的推理服务比如你在 8008 端口起了一个 DeepSeek-V3.2-W8A8然后从同一台机器或者同网段机器上发请求。但实际做模型选型的时候我经常遇到一个尴尬本地只有一两张卡跑 DeepSeek-V3.2 这种量级的模型要么显存不够要么并发上不去压出来的曲线根本没法反映真实业务下的表现。这时候把 endpoint 指向一个统一的 API 通道就很有价值了。TaoToken 提供 OpenAI 兼容的接口Key 和 Base URL 一套走通模型 ID 直接写DeepSeek-V3.2就能调。vllm bench serve 的--backend openai模式本来就是发 HTTP 请求只要把 host、port、model 三个参数改对压测对象就从本地服务变成了远端通道。这样你能在笔记本上跑压测脚本拿到多并发下的 TTFT 和吞吐数据用来对比不同模型或者不同通道的响应特征。这篇要解决的问题很具体怎么用 vllm bench serve 对 DeepSeek-V3.2 做一轮完整的并发压测从环境准备、参数含义、可复制的脚本模板到把 endpoint 改到 TaoToken 后跑通并解读结果。适合正在做模型选型、需要一份可跟做压测流程的工程师。热词里提到的 vllm、bench、serve、DeepSeek-V3.2、压测都会在下面的命令和脚本里落到具体参数上。先说清楚一个前提vllm bench serve 压的是接口层不是 GPU 层。你拿到的 TTFT 包含网络往返、排队、prefill 时间TPOT 包含 decode 阶段的 token 间隔。如果压本地服务网络那部分可以忽略压远端通道网络延迟会进到 TTFT 里解读的时候要心里有数。这不是缺陷反而是它的用处——业务真实调用就是走网络的压出来的数字更接近用户体感。我试过用同一套脚本先压本地 8008再压 TaoToken 通道对比下来 TTFT 的差异主要来自网络 RTT 和通道侧的排队策略吞吐则受限于通道的并发承载。下面把整套流程拆开讲你可以直接抄命令和脚本。2. TaoToken 前置准备Base URL、Key 与模型 ID 三件套在改压测脚本之前先把接入需要的三样东西拿到手这是后面所有命令能跑通的基础。TaoToken 的接口是 OpenAI 兼容格式所以 vllm bench serve 用--backend openai就能直接对接不需要额外写适配层。第一件是 Base URL。API 地址是https://taotoken.net/api注意这里不带任何查询参数vllm bench serve 会在这个地址后面拼/v1/completions或/v1/chat/completions。如果你在代码里用 OpenAI SDKbase_url就填这个值。官网入口在https://taotoken.net/?utm_sourcetaotoken_aicg_blog_end注册和查看文档都从这里进。第二件是 API Key。登录后到控制台的 API Keys 页面创建一个格式通常是一串sk-开头的字符串。这个 Key 要填到压测命令的--api-key参数里或者写进环境变量OPENAI_API_KEY。Key 只显示一次创建后立刻复制保存丢了就重新生成一个。第三件是模型 ID。压 DeepSeek-V3.2 就填DeepSeek-V3.2这个字符串会作为请求体里的model字段发出去。注意它和本地部署时的--served-model-name不是一回事本地那个是你自己起的服务名这里是通道侧约定的模型标识。填错了会返回模型不存在的错误。把这三件套整理成一张对照表方便你填参数时核对参数项本地部署场景TaoToken 通道场景host172.16.98.78taotoken.netport8008443base urlhttp://172.16.98.78:8008/v1https://taotoken.net/api/v1model/data/ 或 DeepSeek-V3.2-W8A8DeepSeek-V3.2api key通常不校验sk- 开头的 Keybackendvllmopenai这里有个容易踩的点vllm bench serve 的--host和--port是分开传的不是直接传完整 URL。压 TaoToken 时 host 填taotoken.netport 填443它内部会走 HTTPS。如果你把https://前缀塞进 host会报地址解析失败。另外--base-url这个参数在部分 vLLM 版本里存在可以直接传完整路径但为了兼容性我建议还是用 host port 的方式稳一点。Key 的管理上建议在压测机器上设一个环境变量别把 Key 硬编码进脚本再传到 Git。命令是export TAOTOKEN_API_KEYsk-你的key脚本里用os.environ.get(TAOTOKEN_API_KEY)读取。这样脚本可以共享Key 不会泄露。如果你要长期跑压测去控制台建一个专用 Key用完随时吊销比共用一个主 Key 安全。模型对话入口可以用来先手动验证一下 Key 和模型 ID 是否配对https://taotoken.net/models。在页面上选 DeepSeek-V3.2 发一句话能正常返回就说明三件套没问题再去跑压测脚本能省掉很多排查时间。3. 可复制的压测脚本从本地 endpoint 改到 TaoToken这一节给出一份可以直接运行的 Python 脚本它封装了 vllm bench serve 的调用、多并发多长度组合的循环、指标解析和 CSV 报告生成。原始版本是压本地服务的我把它改成支持 TaoToken 通道核心改动集中在 host、port、model、api-key 和 backend 这几个参数上。先看单次压测命令长什么样这是脚本里run_bench函数拼出来的东西vllm bench serve \ --backend openai \ --host taotoken.net \ --port 443 \ --endpoint /api/v1/completions \ --model DeepSeek-V3.2 \ --api-key sk-你的key \ --dataset-name random \ --num-prompts 24 \ --random-input-len 2048 \ --random-output-len 1024 \ --max-concurrency 8 \ --request-rate 1.0 \ --metric-percentiles 95,99 \ --temperature 0 \ --save-result \ --result-dir ./concurrency_test几个参数值得展开说。--backend openai是关键它让 bench 走 OpenAI 兼容协议而不是 vLLM 私有协议。--endpoint指定具体路径TaoToken 的 completions 接口是/api/v1/completions如果你要压 chat 接口就换成/api/v1/chat/completions。--num-prompts是总请求数经验值是max-concurrency的 3 倍并发越高这个值要越大否则统计出来的均值波动很大。--request-rate是每秒发起的请求数设成 1.0 表示匀速发设成inf表示能发多快发多快压极限吞吐时用后者。下面是完整脚本保存成bench_taotoken.py在装了 vllm 的机器上跑#!/usr/bin/env python3 vllm bench serve 压测 DeepSeek-V3.2endpoint 指向 TaoToken 通道。 num-prompts 自动设为 max-concurrency 的 3 倍追求稳定均值可调大。 import subprocess import re import os import time from datetime import datetime import pandas as pd # 配置参数按需修改 API_HOST taotoken.net API_PORT 443 API_ENDPOINT /api/v1/completions API_KEY os.environ.get(TAOTOKEN_API_KEY, ) SERVED_MODEL_NAME DeepSeek-V3.2 REQUEST_RATE 1.0 TEMPERATURE 0 # 测试范围 CONCURRENCIES [1, 2, 4, 8, 16] INPUT_LENS [1024, 2048, 4096, 8192] OUTPUT_LENS [512, 1024, 2048] OUTPUT_DIR ./concurrency_test os.makedirs(OUTPUT_DIR, exist_okTrue) # def run_bench(concurrency, input_len, output_len): 执行一次 vllm bench serve 测试返回解析后的指标字典 num_prompts 3 * concurrency cmd [ vllm, bench, serve, --backend, openai, --host, API_HOST, --port, str(API_PORT), --endpoint, API_ENDPOINT, --model, SERVED_MODEL_NAME, --api-key, API_KEY, --dataset-name, random, --num-prompts, str(num_prompts), --random-input-len, str(input_len), --random-output-len, str(output_len), --max-concurrency, str(concurrency), --request-rate, str(REQUEST_RATE), --metric-percentiles, 95,99, --temperature, str(TEMPERATURE), --save-result, --result-dir, OUTPUT_DIR, ] print(f\n{*60}) print(f测试组合: 并发{concurrency} | 输入{input_len} | 输出{output_len} | 请求数{num_prompts}) print(f{*60}) try: proc subprocess.run(cmd, capture_outputTrue, textTrue, checkTrue) output proc.stdout except subprocess.CalledProcessError as e: print(f命令执行失败返回码 {e.returncode}) print(fstderr: {e.stderr}) return None metrics { concurrency: concurrency, input_len: input_len, output_len: output_len, num_prompts: num_prompts, Output token throughput (tok/s): None, Mean TTFT (ms): None, P95 TTFT (ms): None, P99 TTFT (ms): None, Mean TPOT (ms): None, P95 TPOT (ms): None, P99 TPOT (ms): None, Mean ITL (ms): None, P95 ITL (ms): None, P99 ITL (ms): None, } patterns { Output token throughput (tok/s): rOutput token throughput \(tok/s\):\s([\d\.]), Mean TTFT (ms): rMean TTFT \(ms\):\s([\d\.]), P95 TTFT (ms): rP95 TTFT \(ms\):\s([\d\.]), P99 TTFT (ms): rP99 TTFT \(ms\):\s([\d\.]), Mean TPOT (ms): rMean TPOT \(ms\):\s([\d\.]), P95 TPOT (ms): rP95 TPOT \(ms\):\s([\d\.]), P99 TPOT (ms): rP99 TPOT \(ms\):\s([\d\.]), Mean ITL (ms): rMean ITL \(ms\):\s([\d\.]), P95 ITL (ms): rP95 ITL \(ms\):\s([\d\.]), P99 ITL (ms): rP99 ITL \(ms\):\s([\d\.]), } for key, pattern in patterns.items(): match re.search(pattern, output) if match: metrics[key] float(match.group(1)) else: print(f警告: 未找到指标 {key}) log_file os.path.join(OUTPUT_DIR, flog_c{concurrency}_i{input_len}_o{output_len}.txt) with open(log_file, w) as f: f.write(output) return metrics def main(): if not API_KEY: print(错误: 未设置 TAOTOKEN_API_KEY 环境变量) return results [] total_tests len(CONCURRENCIES) * len(INPUT_LENS) * len(OUTPUT_LENS) test_idx 0 for concurrency in CONCURRENCIES: for output_len in OUTPUT_LENS: for input_len in INPUT_LENS: test_idx 1 print(f\n进度: {test_idx}/{total_tests}) metrics run_bench(concurrency, input_len, output_len) if metrics: results.append(metrics) time.sleep(1) df pd.DataFrame(results) columns [ concurrency, input_len, output_len, num_prompts, Output token throughput (tok/s), Mean TTFT (ms), P95 TTFT (ms), P99 TTFT (ms), Mean TPOT (ms), P95 TPOT (ms), P99 TPOT (ms), Mean ITL (ms), P95 ITL (ms), P99 ITL (ms) ] df df[columns] csv_path os.path.join( OUTPUT_DIR, fbenchmark_results_{datetime.now().strftime(%Y%m%d_%H%M%S)}.csv ) df.to_csv(csv_path, indexFalse) print(f\n所有测试完成结果已保存至: {csv_path}) if __name__ __main__: main()跑之前先装依赖pip install vllm pandas。vllm 的版本建议 0.6 以上bench serve子命令在旧版本里叫法不一样。然后设 Keyexport TAOTOKEN_API_KEYsk-你的key再执行python bench_taotoken.py。脚本里我把INPUT_LENS和OUTPUT_LENS的范围收窄了因为压远端通道时超长输入会显著拉高 TTFT组合太多跑一轮要很久。你可以按自己的业务场景调整比如你的业务主要是 4K 输入 1K 输出就重点压那几组。REQUEST_RATE设成 1.0 是保守值想压吞吐上限就改成inf但要注意通道侧可能有速率限制打太猛会收到 429。如果你更习惯用配置文件而不是命令行参数vllm bench serve 也支持从 YAML 读配置。不过对压测来说命令行参数更直观改一个值就能重跑我一般不用配置文件。脚本里的--save-result会把每次的原始 JSON 结果存到OUTPUT_DIR配合 CSV 一起看方便回溯。4. 跑通验证从单次请求到多并发结果解读脚本写好了先别急着跑全量组合用最小参数验证一次确认通道能通、指标能解析出来。这一步能帮你快速定位是配置问题还是脚本问题。先手动发一条请求确认 Key 和模型 ID 没问题curl https://taotoken.net/api/v1/completions \ -H Authorization: Bearer $TAOTOKEN_API_KEY \ -H Content-Type: application/json \ -d { model: DeepSeek-V3.2, prompt: 用一句话解释什么是 KV Cache, max_tokens: 64, temperature: 0 }返回里有choices数组和usage字段就说明通道正常。如果返回 401是 Key 的问题返回模型不存在是 model 字段写错了。这一步过了再跑单组压测vllm bench serve \ --backend openai \ --host taotoken.net \ --port 443 \ --endpoint /api/v1/completions \ --model DeepSeek-V3.2 \ --api-key $TAOTOKEN_API_KEY \ --dataset-name random \ --num-prompts 3 \ --random-input-len 1024 \ --random-output-len 256 \ --max-concurrency 1 \ --request-rate 1.0 \ --metric-percentiles 95,99 \ --temperature 0单并发跑完终端会打印一张指标表。我实测下来单并发 1K 输入 256 输出的组合TTFT 通常在几百毫秒量级TPOT 在几十毫秒每个 token。这个数字会随通道负载波动重点看它能不能稳定输出而不是绝对值。确认单组能跑通后再执行完整脚本。跑的过程中你会看到进度打印每组之间 sleep 1 秒避免把通道打得太满。全部跑完CSV 里会有几十行数据每行是一个并发和长度组合。解读结果时重点看三个维度。第一是吞吐随并发的变化并发从 1 涨到 16Output token throughput应该上升然后趋于平缓如果中途掉下来说明通道侧有排队或者限流。第二是 TTFT 的 P95 和 P99均值好看不代表体验好P99 才是长尾用户感受到的延迟如果 P99 比均值高好几倍说明有请求被卡住了。第三是 TPOT 的稳定性TPOT 反映 decode 速度理想情况下它不随并发大幅变化如果并发一高 TPOT 就飙升说明通道侧的资源被抢占了。把 CSV 拖进 Excel 或者用 pandas 画个折线图横轴并发纵轴吞吐和 P99 TTFT两条线一对比就能看出这个通道在你目标并发下的表现。我做模型选型时会拿这份数据和本地部署的数据放一起看判断远端通道能不能扛住业务的峰值。有个细节要注意压远端通道时--request-rate设成inf会让脚本瞬间发出大量请求如果通道侧有并发上限你会收到一批 429这些失败请求不计入成功统计但会拉长整体耗时。建议先用1.0或2.0的匀速跑摸清通道的承载边界再逐步加压。5. 常见报错排查401、local proxy failed 与指标缺失压测过程中最容易卡住的几个报错我按出现频率排一下每个都给排查路径。401 Unauthorized。这是 Key 的问题三种可能Key 没设进环境变量脚本读到的空字符串Key 复制时带了空格或换行Key 被吊销了。排查方法是先echo $TAOTOKEN_API_KEY看有没有值再用上面的 curl 命令手动发一次如果 curl 也 401就去控制台重新生成一个 Key。注意 vllm bench serve 的--api-key参数如果传了空值它不会报错而是发一个不带认证的请求然后收到 401所以脚本里我加了空值检查。local proxy failed / connection refused。这个报错通常出现在 host 或 port 填错的时候。压 TaoToken 要填taotoken.net和443如果你填了https://taotoken.net作为 host或者填了8008这种本地端口就会连不上。还有一种情况是机器本身的网络策略限制了出站 HTTPS这种需要检查机器的网络配置但不要用任何绕过网络管理的手段合规前提下找运维确认出站规则。reading choices 相关报错。这个一般出现在响应体解析阶段说明请求发出去了但返回的 JSON 结构不符合预期。常见原因是--endpoint路径写错比如写成了/v1/completions而实际应该是/api/v1/completions或者用了 chat 接口的路径去发 completions 请求。检查方法是看OUTPUT_DIR里保存的原始 log里面会有完整的响应体一眼就能看出返回的是什么。指标显示 None 或警告未找到指标。脚本里的正则匹配的是 vllm bench serve 的标准输出格式如果 vLLM 版本不同输出格式可能有差异导致正则匹配不上。排查方法是打开对应的 log 文件看实际的输出长什么样然后调整patterns里的正则。比如有些版本把Mean TTFT (ms)写成了Mean TTFT去掉单位正则就要跟着改。OAuth 或认证方式不匹配。如果你之前用 Claude Code 或者 Codex 的配置连过别的通道环境变量里可能残留了ANTHROPIC_API_KEY或OPENAI_BASE_URL之类的设置vllm bench serve 可能会读到这些变量导致认证方式混乱。排查方法是env | grep -i key和env | grep -i base_url把不相关的清掉只保留TAOTOKEN_API_KEY。并发一高就大量超时。这不是脚本 bug是通道侧的承载边界到了。处理方式是降低--max-concurrency或者把--request-rate从inf改成有限值让请求匀速发。压测的目的是找到边界不是把服务打挂看到超时率上升就该停手记录下当前的并发数作为参考上限。把这几类报错对应的检查点整理一下401 查 Keyconnection refused 查 host/portchoices 解析错查 endpoint 路径指标缺失查 vLLM 版本和正则认证混乱查环境变量残留。按这个顺序排查基本能覆盖九成以上的问题。6. 把压测接进你的选型流程跑完一轮压测你手里会有一份 CSV里面是 DeepSeek-V3.2 在不同并发和输入输出长度下的 TTFT、TPOT、ITL 和吞吐。这份数据的用法不是看绝对值而是做横向对比换一个模型 ID 再跑一遍两份 CSV 放一起就能看出哪个模型在你的业务场景下响应更快、吞吐更高。如果你要长期做这件事可以把脚本里的SERVED_MODEL_NAME抽成命令行参数用argparse接收这样一份脚本能压多个模型。再把CONCURRENCIES和长度组合做成配置文件不同业务场景用不同的压测矩阵。跑完自动生成对比图省去手动整理的时间。压测的频次上我一般在新模型上线前跑一轮通道侧有变更时再跑一轮平时不用天天压。压测本身会消耗 token 额度全量组合跑下来量不小建议先用小组合摸边界再针对性压重点场景。最后提醒一句压测脚本里的 Key 别提交到代码仓库用环境变量或者本地配置文件管理。CSV 结果里如果包含请求内容分享前检查一下有没有敏感信息。把 endpoint 改到统一通道之后你的压测机器不再需要 GPU一台普通开发机就能跑这是这套流程最实际的好处。
上一篇/下一篇内容由系统自动关联
返回资讯列表 →