Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
901232c75f |
@@ -4,7 +4,7 @@
|
||||
|
||||
- **访问地址:** `http://<IP>:16097/`
|
||||
- **技术栈:** Python 3 + Flask + SQLite(纯 REST,无额外依赖)
|
||||
- **版本:** v2.5.0
|
||||
- **版本:** v2.5.1
|
||||
|
||||
---
|
||||
|
||||
@@ -30,7 +30,8 @@
|
||||
### 📊 指标与结果
|
||||
- 实时指标卡:首字延迟、预填充速度、解码速度、上文/输出 tokens、总耗时
|
||||
- **整体统计(平均/最小/最大)**:详情弹窗与 Excel 汇总展示首字延迟、预填充速度、解码速度、总耗时的平均/最小/最大
|
||||
- **推理型模型兼容**:支持 Qwen3 / DeepSeek 等思维链模型(`reasoning_content` / `thinking` / `thought`),思维过程计入输出,不会误报“未收到输出”
|
||||
- **推理型模型兼容**:支持 Qwen3 / DeepSeek 等思维链模型(`reasoning_content` / `reasoning` / `thinking` / `thought`),思维过程计入输出,不会误报“未收到输出”
|
||||
- **解码速度防荒谬值**:兼容 vLLM/Qwen3.8-27B 用 `reasoning` 字段流式输出思维链(此前未识别导致 output_chars=0、解码时间≈0、解码速度飙到数百万 tok/s,已修复);另防“幻影 token”——usage 报了输出 token 但流里没收到任何文本时(如推理用满 max_tokens 没正文),解码速度标记为不可测(—)而非荒谬数字
|
||||
- **采样失败不中断**:单次采样失败会记录并继续,不会让整个测试半途终止;全部失败才标记 error
|
||||
- 实时控制台日志:校准、预热、每次采样明细全程可追溯
|
||||
- **每次完整测试**支持:
|
||||
@@ -178,4 +179,4 @@ llm-speed-tester/
|
||||
## Git
|
||||
|
||||
- **仓库:** `hz4th_coder/llm-speed-tester`
|
||||
- **版本:** v2.5.0(模型实时获取:接口配置区「📋 查看模型」按钮,Base URL+API Key 下实时拉取模型列表(GET /models),搜索/点击填入,仍支持手动输入)
|
||||
- **版本:** v2.5.1(修复解码速度荒谬值:兼容 vLLM `reasoning` 字段思维链 + 幻影token防护(usage 有 token 但流无正文时解码速度置空))
|
||||
+7
-2
@@ -63,6 +63,10 @@ def _metrics(start, first_token_at, end, prompt_tokens, output_tokens,
|
||||
total_ms = (end - start) * 1000
|
||||
prefill = (prompt_tokens / (ttft_ms / 1000)) if prompt_tokens and ttft_ms > 0 else None
|
||||
decode = (output_tokens / (decode_ms / 1000)) if output_tokens and decode_ms > 0 else None
|
||||
# 防“幻影 token”:usage 报了输出 token,但整个流没收到任何文本(如推理全用满 max_tokens
|
||||
# 或提供商只回 usage 不正文),此时解码时间无意义,不报出数百万的荒谬速度
|
||||
if output_tokens and decode is not None and not output_chars:
|
||||
decode = None
|
||||
return {
|
||||
"prompt_tokens": int(prompt_tokens or 0),
|
||||
"output_tokens": int(output_tokens or 0),
|
||||
@@ -132,8 +136,9 @@ def stream_openai(cfg, prompt, gen, log, should_stop=None):
|
||||
event_count += 1
|
||||
if obj.get("choices"):
|
||||
delta = obj["choices"][0].get("delta") or {}
|
||||
# 兼容推理型模型:Qwen3/DeepSeek 思维链在 reasoning_content
|
||||
piece = delta.get("content") or delta.get("reasoning_content") or ""
|
||||
# 兼容推理型模型思维链:DeepSeek 用 reasoning_content,部分 vLLM(Qwen3.8-27B-FP8) 用 reasoning,Anthropic/Gemini 分别在各自适配器处理
|
||||
piece = (delta.get("content") or delta.get("reasoning_content")
|
||||
or delta.get("reasoning") or "")
|
||||
if piece:
|
||||
if first_token_at is None:
|
||||
first_token_at = time.time()
|
||||
|
||||
@@ -200,6 +200,10 @@ class TestRunner(threading.Thread):
|
||||
total_ms = max((batch_end - batch_start) * 1000.0, 0.1)
|
||||
prefill = (total_prompt / (ttft_ms / 1000.0)) if total_prompt else None
|
||||
decode = (total_output / (decode_ms / 1000.0)) if total_output else None
|
||||
# 防“幻影 token”:所有流都没收到任何流式文本但 usage 报了输出 token(如推理用满 max_tokens),
|
||||
# 整批解码时间无意义,不报数百万的荒谬解码速度
|
||||
if total_output and decode is not None and not total_ochars:
|
||||
decode = None
|
||||
|
||||
agg = {
|
||||
"concurrency": concurrency,
|
||||
|
||||
Reference in New Issue
Block a user