Files
llm-speed-tester/API.md
T

313 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# LLM 速度测试台 · API 文档
> 系统所有页面功能均通过 REST API 提供,前端(网页)只是这些 API 的一个可视化客户端。
> 任何页面可见/可操作的数据都可以通过下面的接口调用或访问。
- **服务地址:** `http://<IP>:16097`
- **数据格式:** 请求/响应均为 `application/json`(导出类接口除外)
- **鉴权:** 内部工具,当前无鉴权;如需对外暴露,建议在网关/Nginx 层加访问控制
- **测试启动为异步**`POST /api/tests` 返回后,任务在后台线程执行,用 `GET /api/tests/<id>` 或日志轮询接口跟踪进度
---
## 目录
1. [健康检查](#1-健康检查)
2. [提供商配置](#2-提供商配置-configs)
3. [连接测试](#3-连接测试)
4. [速度测试](#4-速度测试-tests)
5. [测试详情与日志](#5-测试详情与日志)
6. [折线图(data-chart-tool](#6-折线图data-chart-tool)
7. [导出(Excel / JSON](#7-导出excel--json)
8. [数据模型](#8-数据模型)
9. [curl 使用示例](#9-curl-使用示例)
---
## 1. 健康检查
### `GET /api/health`
返回服务状态与正在运行的测试。
**响应:**
```json
{ "ok": true, "port": 16097, "running_tests": [] }
```
---
## 2. 提供商配置(Configs
### `GET /api/configs`
列出所有已保存配置(不返回 API Key 明文,仅 `has_key` 标记)。
**响应:**
```json
[
{ "id": 2, "name": "epyc-test", "provider": "openai",
"base_url": "http://121.40.164.32:18003/v1",
"model": "unsloth/Qwen3.8-27B-Q4_K_M", "temperature": 0.7, "has_key": 1 }
]
```
### `POST /api/configs`
新增配置。请求体字段:`name`(必填), `provider`, `base_url`, `api_key`, `model`, `temperature`
**请求:**
```json
{ "name": "DeepSeek", "provider": "openai",
"base_url": "https://api.deepseek.com/v1",
"api_key": "sk-xxx", "model": "deepseek-chat", "temperature": 0.7 }
```
**响应:** `{ "ok": true, "id": 3 }`
### `GET /api/configs/<id>`
获取单个配置(**含 API Key 明文**,用于前端回填;注意保管)。
### `PUT /api/configs/<id>`
更新配置,**局部更新**(只改请求里出现的字段)。
**请求:** `{ "model": "deepseek-v4-flash" }` → 响应 `{ "ok": true, "id": 3 }`
### `DELETE /api/configs/<id>`
删除配置。响应 `{ "ok": true }`
---
## 3. 连接测试
### `POST /api/configs/test`
验证 API Key / Base URL / 模型名连通性。只要流式请求成功返回(HTTP 200 + 收到响应流)即视为连通;支持推理型模型(Qwen3/DeepSeek 思维链)。
**请求:** 同配置对象(`provider`, `base_url`, `api_key`, `model`, `temperature`
**成功响应:**
```json
{
"ok": true, "total_ms": 1308.2,
"note": "",
"metrics": { "prompt_tokens": 63, "output_tokens": 32, "output_chars": 110,
"ttft_ms": 715.9, "prefill_speed": 86.7, "decode_speed": 52.7, "total_ms": 1308.2 }
}
```
> `note` 非空表示连接正常但未返回正文(可能为只输出思维链的模型)。
**失败响应:** `{ "ok": false, "error": "HTTP 401: ..." }`
---
## 4. 速度测试(Tests
### `POST /api/tests`
启动一次速度测试(异步,立即返回测试 id)。
**请求体:**
```json
{
"config": {
"provider": "openai",
"name": "Qwen3 对比",
"base_url": "http://121.40.164.32:18003/v1",
"api_key": "sk-xxx",
"model": "unsloth/Qwen3.8-27B-Q4_K_M",
"temperature": 0.7
},
"gen": {
"name": "Qwen3 不同上下文长度速度对比",
"context_lengths": [512, 2048, 4096, 8192, 16384, 32768, 65536, 131072],
"max_tokens": 128,
"samples": 2,
"warmup": true,
"avoid_cache": true
}
}
```
**gen 字段说明:**
| 字段 | 类型 | 默认 | 说明 |
|------|------|------|------|
| `name` | string | `""` | 测试名称/主题(会存入测试记录并展示在历史与详情) |
| `context_lengths` | number[] | `[512,2048,4096,8192,16384,32768,65536,131072]` | 要测试的上下文长度列表,每个长度独立校准+预热+采样 |
| `max_tokens` | number | `128` | 解码输出 token 长度 |
| `samples` | number | `2` | 每个上下文长度的采样次数 |
| `warmup` | bool | `true` | 测试前空转预热(不计速度) |
| `avoid_cache` | bool | `true` | 随机前缀避免缓存命中 |
**响应:** `{ "ok": true, "id": 9 }`
### `GET /api/tests?limit=<n>`
测试历史列表(按 id 倒序)。`limit` 默认 100,最大 1000。
**响应:**
```json
[
{ "id": 9, "created_at": "2026-08-23 18:52:00", "status": "done",
"provider": "openai", "model": "unsloth/Qwen3.8-27B-Q4_K_M",
"name": "Qwen3 不同上下文长度速度对比",
"error": "",
"summary": { "samples_ok": 2, "samples_total": 2, "avg_ttft_ms": 1808.7, ... } }
]
```
### `POST /api/tests/<id>/cancel`
停止正在运行的测试。响应 `{ "ok": true, "msg": "正在停止..." }`
### `DELETE /api/tests/<id>`
删除测试及其全部采样与日志。响应 `{ "ok": true }`
---
## 5. 测试详情与日志
### `GET /api/tests/<id>`
完整测试详情:基本信息 + 配置(API Key 已打码)+ 生成参数 + 汇总 + 每次采样 + 完整日志。
**响应结构:**
```json
{
"id": 9, "created_at": "...", "status": "done",
"provider": "openai", "model": "...", "name": "...", "error": "",
"config": { "base_url": "...", "api_key": "sk-x****", ... },
"gen": { "name": "...", "context_lengths": [512, 2048], "max_tokens": 128, "samples": 1, "warmup": true, "avoid_cache": true },
"summary": {
"samples_total": 2, "samples_ok": 2,
"calibration_chars_per_token": 1.82,
"avg_ttft_ms": 1808.7, "min_ttft_ms": 1122.8, "max_ttft_ms": 2494.6,
"avg_prefill_speed": 694.2, "min_prefill_speed": 515.7, "max_prefill_speed": 872.7,
"avg_decode_speed": 54.7, "min_decode_speed": 54.4, "max_decode_speed": 55.0,
"avg_prompt_tokens": 1378.0, "avg_output_tokens": 128.0,
"avg_total_ms": 4148.4, "min_total_ms": 3449.9, "max_total_ms": 4846.9,
"by_length": {
"512": { "samples_total": 1, "samples_ok": 1, "avg_ttft_ms": 1122.8, "avg_prefill_speed": 515.7, "avg_decode_speed": 55.0, "avg_prompt_tokens": 579, "avg_output_tokens": 128, "avg_total_ms": 3449.9 },
"2048": { "samples_total": 1, "samples_ok": 1, "avg_ttft_ms": 2494.6, "avg_prefill_speed": 872.7, "avg_decode_speed": 54.4, "avg_prompt_tokens": 2177, "avg_output_tokens": 128, "avg_total_ms": 4846.9 }
}
},
"runs": [
{ "run_index": 1, "context_length": 512,
"metrics": { "prompt_tokens": 579, "output_tokens": 128, "cached_tokens": 0,
"ttft_ms": 1122.8, "prefill_speed": 515.7, "decode_speed": 55.0, "total_ms": 3449.9 },
"error": "" }
],
"logs": [ { "id": 1, "level": "INFO", "msg": "═══ 开始速度测试 ═══", "rel": 0.0, "ts": "..." } ]
}
```
### `GET /api/tests/<id>/logs?after=<id>`
增量日志(前端轮询用)。`after` 为上次取到的最大日志 id,返回其后新增日志 + 最新状态/汇总/最后采样。
**响应:**
```json
{
"status": "running", "error": "",
"summary": {},
"last_run": { "...": "..." },
"logs": [ { "id": 68, "level": "METRIC", "msg": "...", "rel": 3.21 } ],
"after": 73
}
```
---
## 6. 折线图(data-chart-tool
> 调用 [data-chart-tool](http://192.168.2.8:12007/hz4th_coder/data-chart-tool.git) 的 `/api/chart` 接口生成**双Y轴折线图**:左轴=预填充速度(虚线)、右轴=解码速度(实线)、X 轴=上下文长度。本系统在服务端代理转发,前端只需请求本服务的两个接口。
### `GET /api/tests/<id>/chart`
生成折线图 PNG 图片(内部调用 data-chart-tool `/api/chart`,地址可在 `config.py``CHART_API_BASE` 修改)。
**成功响应:** `Content-Type: image/png`(可直接用于 `<img>` / 下载)
**失败响应:**
```json
{ "ok": false, "error": "无成功采样数据,无法画图" } // 400
{ "ok": false, "error": "测试不存在" } // 404
{ "ok": false, "error": "图表服务不可用: ..." } // 502
```
### `GET /api/tests/<id>/chart-data`
返回画图所用的 CSV 数据与图表请求配置,方便手动快速复制。
**响应:**
```json
{
"ok": true,
"csv": "上下文长度, 预填充速度(tok/s), 解码速度(tok/s)\n4096, 126.90, 22.80\n8192, 132.20, 22.40",
"rows": [[4096, 126.9, 22.8], [8192, 132.2, 22.4]],
"payload": {
"data": "...", "chartType": "line", "title": "...",
"dualYAxis": true,
"leftAxisName": "预填充速度(tok/s)", "rightAxisName": "解码速度(tok/s)",
"seriesTypes": ["line", "line"], "seriesAxis": [0, 1],
"seriesStyles": ["dashed", "solid"], "width": 1000, "height": 560, "pixelRatio": 2
}
}
```
> `csv` 即画图数据(第一列=上下文长度,第二列=预填充速度,第三列=解码速度),前端「复制画图数据」按钮复制的就是它。
---
## 7. 导出(Excel / JSON
### `GET /api/tests/<id>/export.xlsx`
导出 Excel 报告(**3 个 Sheet**:汇总 / 采样明细 / 日志),`Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet`
- **汇总**:测试信息 + 整体统计指标(平均/最大/最小)+ 按上下文长度分组
- **采样明细**:每次采样的上下文长度与全部指标
- **日志**:完整测试日志
### `GET /api/tests/<id>/export.json`
导出完整测试数据为 JSON(与 `GET /api/tests/<id>` 一致,API Key 打码),`Content-Type: application/json`
---
## 8. 数据模型
| 表 | 说明 | 关键字段 |
|----|------|----------|
| `configs` | 保存的接口配置 | id, name, provider, base_url, api_key, model, temperature |
| `tests` | 测试记录 | id, status(running/done/error/canceled), provider, model, **name**, config_json, gen_cfg_json, summary_json, error |
| `test_runs` | 每次采样 | id, test_id, run_index, **context_length**, metrics_json, error |
| `logs` | 测试日志 | id, test_id, level, msg, rel |
**summary 整体指标字段:**
`avg_/min_/max_` 前缀 × `ttft_ms` / `prefill_speed` / `decode_speed` / `total_ms`,以及 `avg_prompt_tokens` / `avg_output_tokens` / `avg_cached_tokens` / `best_ttft_ms`= min_ttft_ms)。
---
## 9. curl 使用示例
```bash
BASE=http://<IP>:16097
# 健康检查
curl $BASE/api/health
# 新增配置
curl -X POST $BASE/api/configs -H 'Content-Type: application/json' \
-d '{"name":"Qwen3","provider":"openai","base_url":"http://121.40.164.32:18003/v1","api_key":"sk-xxx","model":"unsloth/Qwen3.8-27B-Q4_K_M","temperature":0.7}'
# 测试连接
curl -X POST $BASE/api/configs/test -H 'Content-Type: application/json' \
-d '{"provider":"openai","base_url":"http://121.40.164.32:18003/v1","api_key":"sk-xxx","model":"unsloth/Qwen3.8-27B-Q4_K_M"}'
# 启动速度测试(异步)
curl -X POST $BASE/api/tests -H 'Content-Type: application/json' -d '{
"config": {"provider":"openai","base_url":"http://121.40.164.32:18003/v1","api_key":"sk-xxx","model":"unsloth/Qwen3.8-27B-Q4_K_M"},
"gen": {"name":"各长度对比","context_lengths":[512,2048,8192],"max_tokens":128,"samples":2,"warmup":true,"avoid_cache":true}
}'
# 查询测试列表 / 详情
curl "$BASE/api/tests?limit=10"
curl $BASE/api/tests/9
# 画图数据(CSV
curl $BASE/api/tests/9/chart-data
# 折线图 PNG(预填充左轴虚线 / 解码右轴实线)
curl -o chart.png $BASE/api/tests/9/chart
# 导出
curl -OJ $BASE/api/tests/9/export.xlsx
curl $BASE/api/tests/9/export.json
```