From 901232c75f066574d53ef857976d0642ffc9348c Mon Sep 17 00:00:00 2001 From: hz4th_coder Date: Sun, 6 Sep 2026 02:17:40 +0800 Subject: [PATCH] =?UTF-8?q?v2.5.1=20=E4=BF=AE=E5=A4=8D=E8=A7=A3=E7=A0=81?= =?UTF-8?q?=E9=80=9F=E5=BA=A6=E8=8D=92=E8=B0=AC=E5=80=BC=EF=BC=9A=E5=85=BC?= =?UTF-8?q?=E5=AE=B9=20vLLM=20reasoning=20=E5=AD=97=E6=AE=B5=E6=80=9D?= =?UTF-8?q?=E7=BB=B4=E9=93=BE=20+=20=E5=B9=BB=E5=BD=B1token=E9=98=B2?= =?UTF-8?q?=E6=8A=A4(usage=E6=9C=89token=E4=BD=86=E6=B5=81=E6=97=A0?= =?UTF-8?q?=E6=AD=A3=E6=96=87=E6=97=B6=E8=A7=A3=E7=A0=81=E9=80=9F=E5=BA=A6?= =?UTF-8?q?=E7=BD=AE=E7=A9=BA)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 7 ++++--- llm_providers.py | 9 +++++++-- tester.py | 4 ++++ 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 039af52..b907806 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ - **访问地址:** `http://: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 但流无正文时解码速度置空)) diff --git a/llm_providers.py b/llm_providers.py index 21f971d..55aabb4 100644 --- a/llm_providers.py +++ b/llm_providers.py @@ -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() diff --git a/tester.py b/tester.py index 833ab37..e7e0881 100644 --- a/tester.py +++ b/tester.py @@ -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,