适用机器:fnOS-Ser8。脚本版本:quant_eval.py v2.2。 目标:在同一套题、同一组参数下,让 LFM2.5(Q5_K_M / Q6_K)和你机器上的 Qwen3.6-35B 各跑一遍,然后并排对比。
0. 先看这里
0.1 能不能比?
能。脚本只做一件事:往一个 OpenAI 兼容的 /v1/chat/completions 端点发题、收答案、判分。只要模型是 llama-server 提供的,换端口就能比,不用改代码。
0.2 但要知道这几点,否则结论会失真
比的是"你机器上实际在跑的那个 qwen36",不是抽象的"Qwen3.6-35B"。它具体是官方权重还是社区改版、是什么量化档位,会影响结果。第 2.3 步会教你看模型文件名,对比结论要带上这个前提
一次只能开一个模型。内存不允许两个同时加载(你之前把 swap 打满就是这么来的)。流程是:跑完一个,停掉,再起下一个
所有模型必须用完全相同的条件:同一个脚本版本、同样的
--repeats、--temperature、--max-tokens。脚本在compare时会检查这些,不一致会打警告同一温度不等于各自的最佳设置。默认温度 0.1 是 LFM2.5 官方推荐值,Qwen3.6 的推荐值我没核实过,可能更高。想更公平,可以去 Qwen3.6 的模型卡查推荐温度,用
--temperature再单独跑一轮,当作补充参考题目偏简单,两个模型都可能接近满分,主要用来发现明显的退化。想分出细微差别,要加你自己的真实任务(第 7 节)
每题只重复几次,样本小。相差一两题属于正常波动,别据此下结论
脚本版本变了,旧结果就不能混着比。v2.1 修正了判分规则(模型把城市名写成 Tokyo、Shanghai 也算对)、把日历题改成了绝对日期、默认
--max-tokens提到 6000,并且会自动清理混在回答里的思考标签。你之前用旧版跑出的结果文件,都要重跑。例外:v2.1 → v2.2 只新增了题目,旧题一字未改,所以已有的 v2.1 结果可以用
--resume续跑,只补新增的题(见 2.4A)。续跑要求--repeats、--temperature、--max-tokens与之前完全一致
0.3 这套对比能告诉你什么,不能告诉你什么
能:工具调用是否规范、遇到缺参数时是追问还是编造、基础数学逻辑和指令遵循、平均输出 token 数和平均耗时(后两项直接关系到你用 Hermes 时的等待感)
不能:长文本理解、复杂代码、深度推理这类更难的能力。这些要靠你自己加的真实任务和人工对比题
1. 准备工作
1.1 放好脚本 v2
把下载的 quant_eval.py 放到 SER8 的这个目录(scp 或 fnOS 文件管理器都行):
mkdir -p /vol3/1000/docker/lfm25-24b/eval
cd /vol3/1000/docker/lfm25-24b/eval
ls -l
如果这个目录里已经有旧版脚本和旧结果,先收起来,避免混淆:
mkdir -p old-v1
mv results-*.json old-v1/ 2>/dev/null
mv run-*.log old-v1/ 2>/dev/null
然后覆盖新版脚本。确认是 v2:
head -2 quant_eval.py
python3 --version
第一条第二行应显示
quant_eval.py v2.2,不是的话重新放文件第二条能显示版本号,说明 python3 可用
1.2 确认磁盘和内存
df -h /vol3
free -h
评测本身占用很少,主要是模型加载的内存,参考之前的数据:LFM2.5 Q5_K_M 加载后 available 约 11Gi,Q6_K 约 8.8Gi。
每次评测前再确认一次 ollama 没有常驻模型,否则会悄悄吃掉约 8GB:
docker exec ollama ollama ps
输出空表才算干净,有模型就用 docker exec ollama ollama stop <模型名> 卸载。
1.3 评测期间别用 Hermes
评测期间不要在飞书里和 Hermes 对话。Hermes 的请求会和评测抢同一个服务,既干扰耗时数据,也可能触发 503。
2. 阶段 A:给 LFM2.5 评分
如果你想在 Q5_K_M 和 Q6_K 两个版本都评一遍,每个版本各做一轮(切换方法见《LFM2.5 Q5/Q6 保姆级教程》第 6 节)。下面以当前正在运行的版本为例。
2.1 确认现在加载的是哪个文件
curl -s http://localhost:8088/v1/models | grep -o 'LFM2.5-24B-A2B-[A-Za-z0-9_]*' | head -1
输出 LFM2.5-24B-A2B-Q5_K_M 或 LFM2.5-24B-A2B-Q6_K。下面命令里的 --label 要和它对应,不要贴错标签。
2.2 先自测工具调用能正常返回
这一步是为了排除"启动参数不对导致工具调用整类失败"的情况,对每个模型都要做一次:
curl -s http://localhost:8088/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"messages":[{"role":"user","content":"现在北京天气怎么样"}],
"tools":[{"type":"function","function":{"name":"get_weather","description":"查询城市天气","parameters":{"type":"object","properties":{"city":{"type":"string"}},"required":["city"]}}}]
}'
返回里应有 "finish_reason":"tool_calls" 和 {"city":"北京"} 这样的参数。如果没有,先别评测,工具调用类题目会整类失败,那是配置问题,不代表模型能力。
2.3 先试跑一轮,估算耗时
这个模型的思考过程很长,所以先用 --repeats 1 看看一轮要多久。参考:LFM2.5 Q5_K_M 在你机器上实测,28 题平均每题约 11 秒,全程约 5 分钟,所以 --repeats 3 大约 15 分钟(Qwen3.6 要多久取决于它自己的速度,先试跑再说):
cd /vol3/1000/docker/lfm25-24b/eval
pgrep -af quant_eval
必须没有输出再继续(防止重复启动,互相覆盖结果):
nohup python3 quant_eval.py run --url http://localhost:8088 --label LFM_Q5_K_M --repeats 1 > run-LFM_Q5_K_M.log 2>&1 &
tail -f run-LFM_Q5_K_M.log
日志每行形如
[3/28] tool_weather #1 PASS 49tok 1.4s,前面是进度,后面是输出 token 数和耗时失败的题会多打印一行
->,告诉你模型实际返回了什么,方便判断是模型答错还是格式问题Ctrl+C 只是退出查看,评测不会停
跑完会自动打印汇总,并保存 results-LFM_Q5_K_M.json。
2.4A 你已经有 LFM_Q5_K_M 的 v2.1 结果:只补跑新增的题(推荐)
v2.2 新增了 4 类、共 16 道更难的题(多步推理 5、多约束指令 4、难工具调用 5、长文本检索 2),一共 48 次请求。已有的 84 次结果(75 次自动判分加 9 次人工题)不用重跑:
cd /vol3/1000/docker/lfm25-24b/eval
cp results-LFM_Q5_K_M.json results-LFM_Q5_K_M.v21.bak
pgrep -af quant_eval
nohup python3 quant_eval.py run --url http://localhost:8088 --label LFM_Q5_K_M --repeats 3 --resume > run-LFM_Q5_K_M-resume.log 2>&1 &
tail -f run-LFM_Q5_K_M-resume.log
第一行
cp先留一份备份开头会打印
续跑:已有 84 条有效结果,只补跑缺少的题,进度显示[1/48]参数必须和上次一致(
--repeats 3,温度和--max-tokens用默认值,上次也是默认值)。不一致会直接报错退出,不会写坏结果上次出过请求失败的题会自动重跑
这一步我没有在你的真实模型上测过耗时。新增题里,长文本检索每题要先处理约 4000 字的提示,多步推理和多约束写作会思考得久一些,我粗估要 15~25 分钟,实际以你的日志为准
跑完汇总里会多出 4 类题的得分,这几类才是用来拉开差距的。
2.4 从头完整跑(--repeats 3)
没有旧结果,或者要给其他模型(Q6_K、Qwen3.6)跑的时候用这个。试跑的耗时可以接受的话,正式跑一遍,同样的标签会覆盖试跑结果。完整 44 题 × 3 次大约需要 30 分钟以上(旧的 28 题实测约 14 分钟,新增部分按上面的粗估,不是实测):
pgrep -af quant_eval
nohup python3 quant_eval.py run --url http://localhost:8088 --label LFM_Q5_K_M --repeats 3 > run-LFM_Q5_K_M.log 2>&1 &
tail -f run-LFM_Q5_K_M.log
之后所有模型都用同样的 --repeats 3。
2.5 看汇总里这几项
因达到 max_tokens 被截断: N 次:默认上限是 6000 token。N 很大说明思考没写完就被截断了,自动题会被判失败,人工对比题则会拿到空回答。需要用更大的值(如--max-tokens 10000)把所有模型都重跑一遍content 里混入思考标签(已自动清理后再判分):只是提示,脚本已经处理了请求失败(已排除,不计入):服务偶发 503 或断连的次数,脚本已自动重试 6 次,这些不算模型成绩
3. 阶段 B:给 Qwen3.6-35B 评分
3.1 停掉 LFM2.5,腾出内存
docker stop lfm25-24b
docker ps --filter "name=llama" --filter "name=lfm25"
确认没有 llama.cpp 模型容器处于 Up。ollama 虽然不是 llama.cpp 容器,但它自己也会常驻模型占内存(你实际遇到过 gemma4:12b 占了约 8GB、默认保留 3 天),所以要再查一次:
docker exec ollama ollama ps
输出空表才算干净。列出了模型就卸载(模型名按 NAME 列填写,卸载只释放内存,不删模型):
docker exec ollama ollama stop gemma4:12b
3.2 启动 qwen36
用你平时切换到 qwen36 的方式启动(切换面板,或你的切换脚本都行)。如果直接起容器也可以:
docker start llama-qwen36
3.3 找到它的端口,确认模型名
docker ps --filter "name=llama-qwen36" --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}'
PORTS 列形如 0.0.0.0:8083->8080/tcp,左边的数字就是宿主机端口。下面命令里的 8083 只是示例,换成你实际看到的。
等它加载完。注意 docker start 会沿用旧日志,看日志时只看最新的几行,别被旧的 listening on 迷惑:
docker logs --tail 20 -f llama-qwen36
最新几行出现 listening on 后 Ctrl+C 退出。然后看模型文件名:
curl -s http://localhost:8083/v1/models | head -c 600
记下返回里的模型文件名,这就是对比结论里 qwen36 的真实身份(官方权重还是社区改版、Q 几)。
3.4 自测工具调用
用 2.2 同样的命令,把端口换成 qwen36 的:
curl -s http://localhost:8083/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"messages":[{"role":"user","content":"现在北京天气怎么样"}],
"tools":[{"type":"function","function":{"name":"get_weather","description":"查询城市天气","parameters":{"type":"object","properties":{"city":{"type":"string"}},"required":["city"]}}}]
}'
同样要看到 tool_calls。
3.5 评分(参数必须和阶段 A 一模一样)
cd /vol3/1000/docker/lfm25-24b/eval
pgrep -af quant_eval
nohup python3 quant_eval.py run --url http://localhost:8083 --label Qwen3.6-35B --repeats 3 > run-Qwen3.6-35B.log 2>&1 &
tail -f run-Qwen3.6-35B.log
注意:--url 只写到端口,不要加 /v1,脚本会自己拼。
Qwen3.6 如果也有长思考,同样关注汇总里的"被截断"次数,处理方法同 2.5。
4. 对比
cd /vol3/1000/docker/lfm25-24b/eval
python3 quant_eval.py compare results-LFM_Q5_K_M.json results-Qwen3.6-35B.json
可以同时对比 2 个以上,比如 LFM 的两个量化加 Qwen3.6:
python3 quant_eval.py compare results-LFM_Q5_K_M.json results-LFM_Q6_K.json results-Qwen3.6-35B.json
输出分几块:
怎么解读:
旧的四类题(工具调用、数学逻辑、指令遵循、中文知识)LFM2.5 Q5_K_M 已经拿了满分,很可能所有模型都接近满分,参考价值有限。重点看新增的四类:多步推理、多约束指令、难工具调用、长文本检索
先看"通过率不完全相同的题",列表很短就说明两边基本打平
重点看
tool_flight_missing:缺必填参数时,是追问(通过),还是编造参数去调用(失败)。这类行为在实际使用中比答对一道算术题更重要看"平均输出token"和"平均耗时":同样答对,谁更啰嗦、谁让你等得更久,直接影响 Hermes 的体验
人工题三道,你自己读完再下结论。想让我帮你盲评,把两份输出去掉标签贴给我,不过那只是参考
别做的事:
差一两题就断言谁更强
只看合计分数,不看失败的原因(失败行里有
->线索,区分"模型真的答错"和"格式没对上")工具调用类整类失败时直接归因于模型,先回头检查 2.2、3.4 的自测
5. 收尾:恢复服务
评测结束,把现场还原。同一时刻只留一个模型:
docker stop llama-qwen36
docker start lfm25-24b
docker logs --tail 20 -f lfm25-24b
看最新几行出现 listening on 后 Ctrl+C 退出(docker start 沿用旧日志,别看旧行)。再确认:
curl -s http://localhost:8088/v1/models | grep -o 'LFM2.5-24B-A2B-[A-Za-z0-9_]*' | head -1
free -h
如果你平时是用切换面板管理 qwen36,也可以用面板停掉它,效果一样。
6. 想追加测另一个版本
比如还想补测 LFM2.5 的 Q6_K:
停掉当前模型容器
按《LFM2.5 Q5/Q6 保姆级教程》第 6.3 步切到 Q6_K,等
listening on用 2.1 确认文件名,用
--label LFM_Q6_K、同样的--repeats 3跑最后用
compare带上所有结果文件
7. 加你自己的真实任务(强烈建议)
默认题目偏简单,要分出差别,需要加你日常觉得"模型答得不好"的真实任务。
7.1 编辑脚本
cd /vol3/1000/docker/lfm25-24b/eval
nano quant_eval.py
在 nano 里搜索(Ctrl+W)man_rewrite,找到 CASES 列表里最后一道题,在它后面、列表结尾的 ] 之前,加上你的题。这里 nano 保存是 Ctrl+O 回车,退出是 Ctrl+X(注意和终端里中断命令用的 Ctrl+C 不同)。
7.2 两种格式
能自动判分的题(答案可以用关键词判断):
dict(id="my_extract_date", cat="我的任务",
prompt="从下面这句话里提取日期,只输出 YYYY-MM-DD:会议定在2026年11月3日下午三点。",
check=has_any("2026-11-03")),
只做人工对比的题(长文本、写作、总结之类):
dict(id="my_summary", cat="人工对比", manual=True,
prompt="这里放你日常真实使用的任务原文……"),
规则:
id不能和已有的重复自动判分题的
check可以用现有的has_any(...)、num_is(...),也可以自己写函数加完后保存,所有要对比的模型必须用同一份题集,不能新题只跑了其中一个
只在列表末尾追加新题,不要改已有题的内容,这样已有结果还能用
--resume补跑新题,不用全部重来。已有题一旦改动,对应的结果就必须重跑
7.3 语法检查
python3 -m py_compile quant_eval.py && echo 语法OK
输出 语法OK 再去跑评测,写错了会直接报错,不会误跑。
8. 常见问题
附:命令速查
# 评测(每次先 pgrep 确认没有残留)
pgrep -af quant_eval
nohup python3 quant_eval.py run --url http://localhost:<端口> --label <标签> --repeats 3 > run-<标签>.log 2>&1 &
tail -f run-<标签>.log
# 对比(2 个或更多)
python3 quant_eval.py compare results-A.json results-B.json [results-C.json]
# 切换模型前
docker stop <当前模型容器>
docker ps --filter "name=llama" --filter "name=lfm25"
# 确认当前加载的模型
curl -s http://localhost:<端口>/v1/models | head -c 600
评论区