针对 OpenAI 兼容 API 及 Anthropic Messages API 的交互式压测工具(TUI),支持三种 API 类型:
- Embedding 模式:测试
/v1/embeddings端点的吞吐与延迟 - Chat Completion 模式:测试
/v1/chat/completions端点的流式生成性能,包含 TTFT、TPOT、E2E 等指标 - Anthropic Messages 模式:测试 Anthropic Messages API(
/v1/messages),使用x-api-key鉴权,功能与 Chat Completion 完全一致
支持以下测试模式(Embedding 仅支持前两种):
- Single Provider:单 Provider 压测
- Single Response View:向单个 Provider 发送一条 Prompt,查看原始 JSON 响应及 HTTP 响应头
- PK Mode:两个 Provider 同时压测,结果并排对比,优胜指标绿色高亮
- Response Compare:向两个 Provider 发送同一条 Prompt,左右分栏展示原始 JSON 响应及 HTTP 响应头
- Prompt Cache Hit Test:仅 Chat Completion 支持,重复发送同一大段 Prompt,并从
usage.prompt_tokens_details.cached_tokens展示缓存命中情况
- Go 1.23+
- 无额外运行时文件:
cl100k_base.tiktoken已嵌入可执行文件,工具不会联网下载
项目提供 Makefile,构建产物统一输出到 build/ 目录。
make # 构建全部平台(macOS / Linux / Windows,各含 amd64 + arm64)
make macos # 仅构建 macOS
make linux # 仅构建 Linux
make windows # 仅构建 Windows
make clean # 删除 build/ 目录每个平台独立子目录仅包含可执行文件,解压即可离线运行:
build/
├── embedding_benchmark-darwin-arm64/
│ └── embedding_benchmark
├── embedding_benchmark-linux-amd64/
│ └── embedding_benchmark
└── ...
版本号自动从 git tag 注入。
Windows 注意事项:TUI 界面依赖 VT/ANSI 转义序列。Windows 10 1903+ 及 Windows 11 的 Windows Terminal、PowerShell 7+、WSL 均支持;旧版 cmd.exe 显示可能异常,建议使用 Windows Terminal。
# 使用内嵌 BPE 词表
./embedding_benchmark
# 可选:指定外部 BPE 文件覆盖内嵌词表
./embedding_benchmark --bpe-file /path/to/cl100k_base.tiktoken默认 BPE 词表已嵌入可执行文件。仅在指定
--bpe-file时,外部文件必须存在。
启动后进入 TUI 界面,按提示依次选择:
- API 类型:Embedding / Chat Completion / Anthropic Messages
- 测试模式:Single Provider / Single Response View / PK Mode / Response Compare
- 参数配置:填写 URL、API Key、模型名等(占位符根据 API 类型自动切换)
ctrl+s启动,实时显示进度(压测模式)或直接进入响应查看界面- 压测完成后查看结果;
r重新配置,esc返回上级菜单,ctrl+c退出
| 快捷键 | 说明 |
|---|---|
↑ / ↓ |
在列表中导航 |
enter |
确认选择 |
tab / shift+tab |
在配置项之间切换 |
ctrl+s |
开始压测 / 发送请求 |
esc |
返回上一步 / 取消压测 |
ctrl+c |
退出 |
| 快捷键 | 说明 |
|---|---|
↑ / ↓(或 j / k) |
逐行滚动(内容超出终端高度时) |
pgup / pgdn |
向上 / 向下翻页 |
ctrl+u / ctrl+d |
向上 / 向下翻半页 |
r |
重新配置并再次压测 |
e |
查看错误日志(有错误时可用) |
ctrl+e |
导出结果到文本文件 |
esc |
返回上级菜单 |
ctrl+c |
退出 |
| 快捷键 | 说明 |
|---|---|
j / k |
逐行向下 / 向上滚动 |
ctrl+d / ctrl+u |
向下 / 向上翻半页 |
tab |
切换左/右面板焦点(仅 Response Compare) |
ctrl+e |
导出响应内容到文本文件 |
esc |
返回配置页 |
Chat Completion 模式支持两种并发模型,通过配置界面的 Load Model 单选切换。Embedding 和 Anthropic Messages 模式仅支持 Closed-loop。
固定数量的 worker 持续消费任务队列。每个 worker 发送请求 → 等待响应 → 立即发送下一个请求。
- Concurrency:同时工作的客户端 worker 数
- 请求发送速率受服务端延迟影响:服务端越快,客户端发送越快;服务端越慢,发送自然下降
- 实际吞吐 ≈
Concurrency / 平均请求延迟 - 适合测试固定客户端并发下的吞吐与延迟
示例:Concurrency = 10,平均延迟 = 2s
→ 大约维持 10 个请求在途,理论吞吐 ≈ 5 req/s
请求生成器按 Poisson 分布以固定速率产生请求,semaphore 限制最大在途请求数。请求到达率与服务端响应速度解耦。
- Request Rate:请求到达速率(req/s),间隔服从指数分布
- Max In-Flight:最大同时在途请求数(相当于 closed-loop 的 Concurrency)
- 当请求到达率超过服务端处理能力时,超出部分在 semaphore 前排队等待,产生 Queue Time
- 适合模拟真实流量、观察排队行为、测量过载表现
示例:Request Rate = 20 req/s,Max In-Flight = 8
→ 每秒约产生 20 个请求,但最多 8 个同时执行
→ 若服务端只能处理 5 req/s,请求排队,Queue Time 增长
| 维度 | Closed-loop | Open-loop |
|---|---|---|
| 并发控制 | 固定 worker 数 | Semaphore 限制最大在途数 |
| 请求速率 | 受服务端延迟影响(自适应) | 独立可控(Request Rate) |
| 到达模式 | 上一个完成 → 立即发下一个 | Poisson 分布间隔 |
| 排队行为 | 无排队(worker 阻塞在请求上) | 有排队(semaphore 满时等待) |
| Queue Time | 无 | 有(Avg/P50/P90/P99) |
| 典型用途 | 固定并发吞吐测试 | 真实流量模拟、过载测试 |
注意:Open-loop 的 generator 在 semaphore 满时会阻塞,因此当服务端处理不过来时,实际到达率会低于设定的 Request Rate。Queue Time 指标反映的是每个请求从"生成"到"实际发出"的等待时间。
Embedding、Chat Completion、Anthropic Messages 压测会根据用户填写的 Input Tokens 自动生成输入文本。工具内置大规模英文候选语料,运行时按确定性顺序拼接候选文本;目标超过语料长度时会循环使用语料,不会退化为重复单 token 填充。
最终输入会严格校准到用户指定的 token 数;如果句子拼接略微超过目标,会按 token 截断到目标长度。Single Response View、Response Compare、Prompt Cache Hit Test 使用用户直接输入的 prompt,不走自动生成逻辑。
| 指标 | 说明 |
|---|---|
| RPS | 每秒成功完成的请求数 |
| Input TPS | 每秒处理的输入 Token 数 |
| Input TPM | 每分钟处理的输入 Token 数 |
| Latency Avg/P50/P90/P99 | E2E 延迟分布(ms) |
延迟与吞吐指标完全基于客户端本地时间测量。用于 TPOT、Output TPS / TPM、Avg Output Tokens 的输出 token 数仍通过本地 tiktoken(cl100k_base) 统计,保证在 Provider 不返回 usage 时也能计算性能指标。
| 指标 | 说明 |
|---|---|
| TTFT | Time To First Token,从发送请求到收到第一个输出 token 的延迟 |
| TPOT | Time Per Output Token,decode 阶段每生成一个 token 的平均耗时 |
| E2E | End-to-End Latency,从发送请求到收到最后一个 token 的总延迟 |
| Output TPS / TPM | 输出 token 吞吐量(每秒 / 每分钟) |
| Avg Output Tokens | 每次请求平均输出的 token 数 |
| API Prompt Tokens | API 响应 usage 中输入 token 的累计值,仅统计成功且返回 usage 的请求 |
| API Completion Tokens | API 响应 usage 中输出 token 的累计值,仅统计成功且返回 usage 的请求 |
| API Total Tokens | API 响应 usage 中总 token 的累计值;Anthropic Messages 按 input + output 汇总 |
| API Usage Samples | 成功请求中实际返回 usage 的次数,例如 3 / 10 表示 10 次成功请求里 3 次返回 usage |
| Queue Time Avg/P50/P90/P99 | 请求从生成到实际发送的排队等待时间(ms),仅 Open-loop 模式显示 |
OpenAI 兼容 Chat Completions 流式请求默认附带
stream_options: {"include_usage": true}以请求 usage chunk;如 Provider 不支持或不返回usage,结果页会显示N/A/ missing 计数,不影响性能指标统计。Custom Params 仍可覆盖该字段。
该模式使用非流式 Chat Completions 请求,每隔 3 秒重复发送用户粘贴的同一段 Prompt,并读取响应体中的 usage.prompt_tokens_details.cached_tokens。Max Output Tokens 为可选参数,留空时请求体不发送 max_tokens。
| 指标 | 说明 |
|---|---|
| Cached Tokens | 响应 usage.prompt_tokens_details.cached_tokens 的累计值 |
| Overall Hit Rate | 累计 cached tokens / 累计 prompt tokens |
| Avg Request Hit Rate | 每次请求命中率的平均值 |
若 Provider 不返回 usage 或不返回 cached_tokens 字段,结果中会显示 N/A / missing 计数,不会按 0 命中处理。可通过 Custom Params 传入 prompt_cache_key、prompt_cache_retention 等兼容参数。
压测过程中失败请求不会计入延迟、RPS、TPS/TPM 等成功指标,但会单独计入失败数。结果页会展示错误分类摘要,按 e 可打开错误日志查看分类汇总和原始错误详情。
当前错误分类包括:
| 分类 | 说明 |
|---|---|
rate_limit |
HTTP 429 限流 |
auth |
HTTP 401 / 403 认证或权限问题 |
bad_request |
HTTP 400 请求参数问题 |
server_error |
HTTP 5xx 服务端错误 |
timeout |
请求超时或 context deadline |
connection |
DNS、连接失败、连接重置等网络连接问题 |
empty_output |
流式响应成功但没有收到非空 content |
stream_error |
SSE 流读取失败 |
parse_error |
响应 JSON 解析失败 |
client_error |
本地请求构造、序列化等客户端错误 |
other |
未匹配到以上类型的错误 |
Chat Completion 单 Provider 压测支持请求日志:在配置页将 Request Logging 切换为 on(默认 off)后,本次压测每个请求与响应的完整线上内容都会落盘,便于事后核对 Provider 实际收发的数据。Closed-loop 与 Open-loop 均支持;Embedding、Anthropic Messages 与 PK 模式不提供该开关。
日志写入当前工作目录下的两个 JSONL 文件(每行一条 JSON 记录),文件名中的 <runID> 为本次运行启动的时间戳(YYYYMMDD-HHMMSS):
| 文件 | 每行字段 |
|---|---|
bench_requests_<runID>.jsonl |
request_id、ts(UTC 时间)、method、url、headers、body(实际发送的完整请求体) |
bench_responses_<runID>.jsonl |
request_id、ts、duration_ms、status(HTTP 状态)、headers、chunks(原始 SSE 行)、body(非 200 时的错误响应片段)、error(请求级错误信息) |
两个文件通过 request_id(格式 <runID>-<6位序号>)逐条关联;该 ID 仅用于本地日志,不会发送给 Provider。日志文件已被 .gitignore 忽略。
- 凭证脱敏:
Authorization头写入前会被替换为Bearer ***<末4位>,日志中不会出现完整 API Key。 - 全异步写入:请求 goroutine 只做非阻塞投递,序列化与磁盘 IO 由独立 writer goroutine 完成;日志记录位于计时点之外,不影响 TTFT / E2E / TPOT 测量与整体 wall time。磁盘写入跟不上时多余条目会被丢弃并计数,不会拖慢压测。
- 结果页提示:压测结束后结果页显示两个日志文件的路径;如有条目丢弃或写盘错误,会显示
⚠ N log entries dropped (disk too slow)/⚠ log write error: ...警告。
压测(Embedding / Chat Completion / Anthropic Messages,单 Provider 与 PK)和 Prompt Cache Hit 测试完成后,会在当前目录自动生成一份 markdown 报告,无需手动操作:
- 压测报告:
bench_report_YYYYMMDD_HHMMSS.md(PK 模式为单个合并文件,含两家对比) - Cache Hit 报告:
cache_hit_report_YYYYMMDD_HHMMSS.md(含逐请求明细表)
报告内容:
- Test Parameters:本次测试使用的全部参数(API Key 脱敏为
***last4) - Results:与 TUI 结果页一致的指标,markdown 表格展示(PK 模式胜出值加粗,全部失败的 provider 显示
N/A) - Logs:开启 Request Logging 时列出请求/响应 JSONL 日志文件名及丢弃/写错误警告
结果页底部显示 Report saved: <文件名>;写入失败仅显示警告,不影响结果展示。每次测试生成新文件,不会覆盖历史报告。手动 ctrl+e 纯文本导出功能不受影响。
kimi-k2.6 默认开启深度思考(thinking 参数默认值 {"type": "enabled"}),模型会先输出推理过程(reasoning_content),再输出正文。此时 max_tokens 是思考与正文共用的总预算:如果 Max Output Tokens 设置过小,思考可能烧光全部预算,正文一个 token 都产不出,流最终以 finish_reason: "length" 被截断。
这种情况下本工具会把该请求计为错误(empty_output),错误日志中显示:
only reasoning tokens received, no answer content (thinking exhausted max_tokens?)
响应 usage 里的 completion_tokens_details.reasoning_tokens 可以看出预算被思考占用的比例,例如:
"completion_tokens": 256, "completion_tokens_details": {"reasoning_tokens": 255}表示 256 个输出 token 中 255 个是思考,正文为 0。
应对方式(二选一):
- 调大 Max Output Tokens:思考模型需要"思考预算 + 回答预算",建议 ≥1024
- 关闭思考:在 Custom Params 中传入
{"thinking": {"type": "disabled"}}
max_tokens 语义、思考开关与思考深度的参数设置因模型 / 供应商而异,例如:
- 输出上限字段名不同:OpenAI 兼容 API 多用
max_tokens;Kimi 已弃用max_tokens,推荐max_completion_tokens;Anthropic Messages 的max_tokens为必填 - 思考开关参数不同:Kimi K2.x 用
{"thinking": {"type": "enabled|disabled"}},Kimi K3 用顶层reasoning_effort,Qwen 用enable_thinking,其他供应商另有字段,且默认是否开启思考各不相同 - 思考深度控制不同:有的支持档位(如
reasoning_effort: low/high/max),有的支持 token 预算(如 Anthropic 的thinking.budget_tokens),有的不支持调节 - 采样参数可能被固定:部分模型在思考模式下固定温度(如 kimi-k2.6 思考模式固定 temperature 1.0),显式传入其他值会报错
本工具不针对具体模型做适配。使用前请查阅具体模型或 token 供应商的官方文档,确认上述参数的语义与默认值,然后在配置界面的 Custom Params 中以 JSON 形式自行传入(Custom Params 会合并进每个请求体并覆盖同名字段),例如:
{"thinking": {"type": "disabled"}, "max_completion_tokens": 1024}工具的 TTFT Includes Reasoning 开关只影响 TTFT 计时点(首 reasoning token 是否停表),与供应商侧的思考开关无关;reasoning/thinking 内容永远不计入输出 token 统计。
- 默认 BPE 词表已嵌入可执行文件,工具不会联网下载;可通过
--bpe-file指定外部文件覆盖它 - Completion / Anthropic Messages 压测使用流式输出(
"stream": true),目标 API 须支持 SSE - Anthropic Messages 模式 SSE 以
event: message_stop结束,max_tokens为必填字段(默认 4096) - Response Compare / Single Response View 使用非流式请求(
"stream": false),响应头与 JSON body 均展示 - 所有压测统计仅包含成功请求,失败请求不计入延迟分布
- 非 200 响应的错误信息会包含服务端响应体(最多 512 字节),并按状态码归类,便于排查认证、限流问题