SGLang GSM8K 基准测试实战:从服务启动到 few-shot 数学推理评测
【免费下载链接】sglangSGLang is a high-performance serving framework for large language models and multimodal models.项目地址: https://gitcode.com/GitHub_Trending/sg/sglang
GSM8K(Grade School Math 8K)是评测大语言模型小学数学推理能力的经典基准。本文围绕仓库内 benchmark/gsm8k/README.md 与配套脚本 benchmark/gsm8k/bench_sglang.py,完整讲解如何在 SGLang 上部署推理服务、以 few-shot 方式批量评测 GSM8K、使用修正标签的 GSM8K Platinum 数据集,以及如何解读准确率、吞吐量等指标。读完本文,你将能独立复现一次可发布的 GSM8K 评测,并理解脚本底层的数据加载、SGL Program 构建与结果落盘机制。
评测脚本是什么
bench_sglang.py是一个端到端基准脚本:它先连接已启动的 SGLang 推理服务,加载 GSM8K 测试集,用前若干条带标注的样本构造 few-shot 提示词,再通过 SGLang 前端语言(sgl.function)批量生成答案,最后从生成的文本中提取数字与标准答案比对,输出准确率、无效样本占比、总延迟和输出吞吐量。
在仓库中,与 GSM8K 评测相关的代码位于三个位置,功能各有分工:
- benchmark/gsm8k/bench_sglang.py:面向用户的评测入口脚本,即本文主角;
- python/sglang/test/test_utils.py:提供公共命令行参数注入(
add_common_sglang_args_and_parse)、后端选择(select_sglang_backend)与原始结果落盘(dump_bench_raw_result)等复用工具; - python/sglang/utils.py:提供 JSONL 读取(
read_jsonl)与文件下载缓存(download_and_cache_file)等基础函数。
此外,仓库中还存在一个被标记为 deprecated 的旧评测模块 python/sglang/test/few_shot_gsm8k.py,其文档字符串明确建议改用sglang.test.run_eval中的eval_name="gsm8k"统一评测框架。新评测应优先使用benchmark/gsm8k/bench_sglang.py或run_eval。
快速上手:三分钟跑通一次评测
评测分两步:先启动推理服务,再运行评测脚本。
第一步:启动 SGLang 推理服务
在 GPU 机器上启动一个模型服务,例如 Llama-2-7B-Chat:
python -m sglang.launch_server --model-path meta-llama/Llama-2-7b-chat-hf --port 30000需要说明的是,仓库中的 python/sglang/launch_server.py 在第 62-69 行会输出一条警告:python -m sglang.launch_server仍然受支持,但官方推荐使用更简洁的新入口sglang serve,例如:
sglang serve --model-path meta-llama/Llama-2-7b-chat-hf --port 30000服务默认监听127.0.0.1:30000,评测脚本的默认--host与--port恰好与之匹配,无需额外改动。
第二步:运行评测脚本
python3 bench_sglang.py --num-questions 200脚本默认连接本地30000端口服务,从 GSM8K 测试集中取前 200 题进行 5-shot 评测(--num-shots默认值为 5),运行完成后会在终端打印四项关键指标:
Accuracy: 0.xxx Invalid: 0.xxx Latency: 0.xxx s Output throughput: 0.xxx token/s数据集:原始 GSM8K 与 GSM8K Platinum
评测脚本支持两种数据来源,通过--platinum标志切换。
原始 GSM8K(默认):数据来自 OpenAI 发布的grade-school-math测试集test.jsonl。脚本的默认--data-path为本地文件test.jsonl,如果该文件不存在,python/sglang/utils.py 中的download_and_cache_file(第 396-430 行)会将其下载并缓存到/tmp/test.jsonl(文件名为 URL 最后一段),后续运行直接命中缓存。数据随后通过read_jsonl(第 135-141 行)逐行解析为{"question": ..., "answer": ...}结构。
GSM8K Platinum(--platinum):这是 GSM8K 测试集的修订版本,修正了错误标签并剔除了存在歧义的题目,评测结果比原始数据集更稳定,且与原始 GSM8K 完全兼容、可直接替换使用。启用方式只需在命令中追加--platinum:
python3 bench_sglang.py --num-shots 8 --num-questions 1209 --parallel 1209 --platinum该命令使用 8-shot 提示,对 Platinum 测试集全部 1209 道题进行评测,并将并发数(--parallel)设为 1209,即一次将全部题目并行发往服务端。
在代码层面,--platinum分支(benchmark/gsm8k/bench_sglang.py 第 64-69 行)通过 Hugging Facedatasets库加载madrylab/gsm8k-platinum数据集的test划分,并统一转换为与原始 GSM8K 相同的{"question", "answer"}字典格式,因此两条数据路径在下游完全一致。
完整命令行参数说明
脚本参数由两部分组成:脚本自定义参数与公共评测参数(由add_common_sglang_args_and_parse注入,见 python/sglang/test/test_utils.py 第 284-300 行)。
脚本自定义参数
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
--num-shots | int | 5 | few-shot 示例数量,取测试集前 N 条带答案样本拼接为提示前缀 |
--data-path | str | test.jsonl | 原始 GSM8K 本地数据路径;不存在时自动下载缓存 |
--num-questions | int | 200 | 参与评测的题目数量 |
--max-new-tokens | int | 512 | 单题生成的最大新 token 数 |
--temperature | float | 0.0 | 采样温度,0 为贪心解码 |
--top-p | float | 1.0 | 核采样概率阈值 |
--enable-thinking | flag | 关闭 | 启用思考模式,用 chat 模板包装提示词(详见后文) |
--chat-template-kwargs | JSON | {"enable_thinking": true} | 透传给tokenizer.apply_chat_template的参数字典;思考开关的键名因模型而异,如 Qwen 用enable_thinking、Kimi 用thinking |
--tokenizer-path | str | 无 | tokenizer 路径,--enable-thinking时必须指定 |
--platinum | flag | 关闭 | 使用 GSM8K Platinum 数据集(修正标签、去歧义的替代版本) |
公共评测参数
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
--parallel | int | 64 | 并发请求线程数,控制批量发送的并行度 |
--host | str | 127.0.0.1 | 服务主机地址 |
--port | int | 30000 | 服务端口 |
--backend | str | srt | 后端类型:srt(SGLang Runtime 服务)或gpt-*(OpenAI 兼容后端),另支持srt-no-parallel(关闭并行编码) |
--device | str | auto | 设备类型,可选auto/cuda/rocm/cpu,auto 自动探测 |
--result-file | str | result.jsonl | 指标汇总结果追加写入的 JSONL 文件 |
--raw-result-file | str | 无 | 可选:逐条(prompt/output/correct)原始结果落盘路径 |
后端选择逻辑见select_sglang_backend(python/sglang/test/test_utils.py 第 303-315 行):srt前缀映射为RuntimeEndpoint,gpt-前缀映射为 OpenAI 兼容后端,其余值直接抛错。这意味着评测并不局限于 SGLang 自部署服务,也可指向任意 OpenAI 兼容 API。
脚本内部机制逐段剖析
1. 数据加载与标签提取
脚本先按--platinum选择数据源并读取为lines列表。随后对每条样本执行标签提取:get_answer_value会先移除答案字符串中的逗号(兼容千分位),再用正则\d+取出全部数字,取最后一个数字经ast.literal_eval转为数值作为标准答案。若找不到任何数字则返回哨兵值INVALID = -9999999。构造完成后脚本还会断言所有标签均有效,确保评测数据可用。
2. few-shot 提示词构造
get_few_shot_examples(lines, k)取测试集前k条样本,每条格式化为Question: ...\nAnswer: <标准答案>,并用空行分隔;评测样本则只含问题部分(不带答案)。最终送入模型的提示词为:
Question: ...(few-shot 示例 1,含答案) Answer: ... Question: ...(few-shot 示例 2,含答案) Answer: ... Question: ...(待评测题目,不含答案) Answer:这样模型被引导按 few-shot 的格式先推理再给出答案。
3. SGL Program 定义与批量执行
评测核心是一个极简的 SGL Program(benchmark/gsm8k/bench_sglang.py 第 105-112 行):
import sglang as sgl @sgl.function def few_shot_gsm8k(s, question): s += question s += sgl.gen( "answer", max_tokens=args.max_new_tokens, stop=["Question", "Assistant:", "<|separator|>"], )它把拼接好的提示词写入状态s,然后调用sgl.gen生成名为answer的字段,并设置三个停止词,防止模型继续生成下一题或产生多余对话轮次。随后通过few_shot_gsm8k.run_batch(...)以num_threads=args.parallel的并发度批量执行所有题目,temperature与top_p直接透传为采样参数。SGL 前端负责自动做批处理与结果收集,这是 SGLang 评测脚本普遍采用的高并发模式。
4. 结果提取与指标计算
生成结束后,脚本对每个状态再次调用get_answer_value提取模型输出中的最后一个数字作为预测答案,随后计算:
- Accuracy:
preds == labels的均值,即数字完全匹配的样本占比; - Invalid:预测无法提取到数字(等于
INVALID)的样本占比,反映模型输出格式的规范性; - Latency:从批量发起(
time.perf_counter()打点)到全部状态返回的总耗时; - Output throughput:通过
state.get_meta_info("answer")["completion_tokens"]累加全部样本的输出 token 数,除以总延迟得到 token/s。
5. 结果落盘
评测结果分三路持久化:
dump_state_text(f"tmp_output_{args.backend}.txt", states)将每个 ProgramState 的完整文本(含提示词与生成内容)写入文本文件,便于人工检查生成质量;dump_bench_raw_result(python/sglang/test/test_utils.py 第 2207-2231 行)在指定--raw-result-file时,逐条写出{"prompt_id", "prompt", "output", "correct"}的 JSONL,用于细粒度分析哪些题答错;- 脚本末段将
task(gsm8k或gsm8k-platinum)、backend、latency、accuracy、num_requests等汇总指标以 JSON 追加写入--result-file(默认result.jsonl),便于多轮实验横向对比。
进阶用法
面向推理模型的思考模式
对 Qwen3、Kimi 等带显式思考开关的模型,可开启--enable-thinking让提示词经 chat 模板包装并附加 generation prompt。启用时必须同时指定--tokenizer-path,且可通过--chat-template-kwargs传入模型相关的思考开关键值,例如 Qwen 系列用{"enable_thinking": true}、Kimi 系列用{"thinking": true}。典型命令:
python3 bench_sglang.py --enable-thinking \ --tokenizer-path Qwen/Qwen3-8B \ --chat-template-kwargs '{"enable_thinking": true}'对应代码分支见 benchmark/gsm8k/bench_sglang.py 第 51-61 行:加载 tokenizer 后,将原始提示词包装为[{"role": "user", "content": raw_question}]消息并调用apply_chat_template展开。
切换后端与全量评测
评测不仅限于 SGLang 服务。将--backend设为gpt-4o之类的值即可把同一套评测逻辑指向 OpenAI 兼容端点;在本地 SGLang 场景下,--parallel可调大以压测服务并发能力。若希望覆盖 GSM8K 全量测试集(1319 题),可将--num-questions调大(原始 GSM8K 测试集规模即为此值附近),或使用--platinum配--num-questions 1209覆盖 Platinum 全量。
与统一评测框架的关系
仓库中 python/sglang/test/few_shot_gsm8k.py 已被标记为 deprecated,官方建议改用sglang.test.run_eval并指定eval_name="gsm8k",后者走统一的 Chat API 评测框架并支持dump_metric。若需要与 CI 或更广泛的评测任务集成,应优先考虑统一框架;单次快速验证与压测则直接使用bench_sglang.py即可。
评测结果解读要点
- Accuracy 是首要质量指标,但 GSM8K 的答案提取只取最后一个数字,因此模型若在答案后追加解释性数字可能被误判,建议同时查看
Invalid与tmp_output_*.txt中的原始输出; - Latency 与 Output throughput 反映服务性能,受并发数(
--parallel)、模型规模、TP 配置与硬件共同影响,横向对比时应固定这些变量; - 使用
--platinum得到的结果相比原始 GSM8K 更少受标签噪声与歧义题干扰,更适合作为模型数学能力对比的稳定基准。
至此,从服务启动、数据集选择、参数调优到指标解读,你已具备在 SGLang 上完整跑通 GSM8K 评测的能力,可以据此开展模型数学推理能力的验证与迭代。
【免费下载链接】sglangSGLang is a high-performance serving framework for large language models and multimodal models.项目地址: https://gitcode.com/GitHub_Trending/sg/sglang
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考