模型部署与推理
本地模型不是下载成功就算部署:Qwen3 8B 的流式推理与任务正确性实测
在 Apple M4 16 GiB 上固定 qwen3:8b 的完整 digest、Q4_K_M 量化和采样参数,运行 14 次 Ollama 流式请求,同时记录 TTFT、总耗时、输出吞吐、原始 JSON 与失败样本。
时间与证据
这项实验在 2026 年 7 月 13 日直接调用本机 Ollama 完成。执行前 ollama list 显示 qwen3:8b,API /api/tags 返回完整 digest:
500a1f067a9f782620b40bee6f7b0c89e17ae61f686b92c24933e4ca4b2b8b41
模型元数据记录为 Qwen3、8.2B、GGUF、Q4_K_M,文件大小 5,225,388,164 bytes。运行机器是 Apple M4、10 个逻辑 CPU、16 GiB 统一内存,系统 darwin arm64。这些条件都写入 labs/local-inference-benchmark/results/2026-07-13-qwen3-8b.json,不能只保留一个容易变化的模型别名。
代码与证据分别位于:
labs/local-inference-benchmark/src/benchmark.mjs:流式 NDJSON 解析、计时、任务断言和汇总。labs/local-inference-benchmark/test/benchmark.test.mjs:流解析、token/s、nearest-rank 百分位,以及历史工件 digest、设置、两轮任务覆盖、失败样本和汇总一致性测试。labs/local-inference-benchmark/results/2026-07-13-qwen3-8b.json:14 条逐请求结果、响应原文、环境、设置和模型 digest,SHA-256 为1f8ba8056d8978adf6f01d100e62805d223afcad92f97fc04d6a543fe03d863f。
证据等级为 reproduced。这里确实运行了本地模型,不是显存公式或厂商速度;但只有一台机器、一个模型、一个量化、短输入、串行请求和 14 个样本,所以不能写成“Qwen3 8B 的通用速度”,更不能写成生产 SLA。
实验设计
同时测速度与任务结果
本地部署常见的错误验收是:模型能输出文字,任务就算完成;或者只记录 token/s,不检查输出是否符合业务契约。实验把一次请求拆成四项:
TTFT:发起 HTTP 请求到收到第一个非空输出片段的本地墙钟时间。totalMs:发起请求到 Ollama 终态事件完成的墙钟时间。outputTokensPerSecond:使用 Ollama 终态的eval_count / eval_duration,不拿字符数冒充 token。correct:解析完整 JSON 后按任务固定断言,格式不合法同样算失败。
Ollama 自报的 load_duration、prompt_eval_count 与 eval_count也进入逐请求记录。TTFT 使用客户端 performance.now(),包含本地 HTTP、排队、prompt evaluation 和首段生成;它与服务端单独的 eval duration不是同一指标。
固定设置
脚本先做一次不计入结果的 warm-up,再运行 7 个任务、每个两轮,共 14 次串行请求:
| 设置 | 值 |
|---|---|
| 模型 | qwen3:8b + 完整 digest |
temperature |
0 |
seed |
42 |
num_ctx |
4096 |
num_predict |
96 |
think |
false |
| 输出 | Ollama JSON mode,stream=true |
| 并发 | 1 |
任务覆盖事故等级分类、发票税号抽取、代码赋值错误识别、策略查找、Agent 工具审批判断和算术。事故分类故意保留两种提示:
- 含糊版给出
{"severity":"P1 或 P2"}作为输出形状。 - 约束版明确字段只能取
P1或P2,并给出一个合法枚举例子。
两者业务事实完全相同,只改变输出合同,用来检查模型是否把示例文本原样复制。
复现需要本机已有完全相同 digest:
ollama list
node --test labs/local-inference-benchmark/test/benchmark.test.mjs
node labs/local-inference-benchmark/src/benchmark.mjs \
--out /tmp/younis-ai-lab-qwen3-8b.json
shasum -a 256 labs/local-inference-benchmark/results/2026-07-13-qwen3-8b.json
重新运行会改变计时和 capturedAt,因此复核文章时应保留旧工件或在修订记录中说明,不要静默覆盖历史数字。
结果
最终捕获时间为 2026-07-13T15:14:33.920Z。14 次 HTTP 请求全部完成,没有 transport 或 JSON 解析失败。汇总结果为:
| 指标 | 结果 | 边界 |
|---|---|---|
| 请求完成 | 14 / 14 | 只代表本地串行短任务 |
| 任务正确 | 12 / 14,85.71% | 两次失败来自同一个含糊提示 |
| TTFT P50 | 178.995 ms | warm 模型、本机 loopback |
| TTFT P95 | 184.003 ms | 只有 14 个样本,nearest-rank |
| 总耗时 P50 | 636.774 ms | 输出长度不同 |
| 总耗时 P95 | 1869.235 ms | 税号抽取输出 23 tokens |
| 输出 token/s P50 | 14.98 | Ollama eval_count / eval_duration |
| 输出 token/s P95 | 15.828 | 不是并发吞吐 |
两轮含糊事故提示都返回:
{"severity":"P1 或 P2"}
它是合法 JSON,却没有作出分类,因此断言失败。收紧字段契约后,两轮都返回:
{"severity":"P1"}
这项差异比一个“模型回答看起来合理”的截图更有工程价值。JSON mode 只能约束语法,不会自动把自然语言中的“P1 或 P2”理解为枚举定义。生产系统还需要 JSON Schema、业务枚举校验和失败处理;模型输出通过解析不等于通过业务合同。
税号抽取的总耗时约 1.87 秒,是这组请求中最慢的一类,主要因为输出 token 数为 23;代码审查和工具审批只有 6 个输出 token,总耗时约 0.56 秒。仅报告 token/s 会掩盖用户实际等待时间,仅报告 total 又会把任务输出长度混在一起。
失败与边界
第一,任务集太小而且简单。85.71% 不是通用模型准确率;同一个失败任务运行两轮,也不能当作两个独立语义样本。真正评测应扩大到时间隔离数据集,并按任务类别报告置信区间。
第二,warm-up 排除了模型首次装载成本。这适合观察常驻服务,但不适合 serverless 冷启动。原始工件仍保存每次 loadMs,后续应单独测量 cold start、模型换入换出和长时间空闲。
第三,没有并发。单请求约 15 token/s 不代表 5 个用户同时请求仍有 15 token/s,也不代表 TTFT 保持 180 ms。并发容量必须增加固定到达率、队列长度、取消和内存压力。
第四,输入很短,num_ctx=4096 不等于实际填满 4096 tokens。长上下文会改变 prompt evaluation、KV cache 内存和 TTFT,本文没有测。
第五,只有 Q4_K_M 一个量化,不能回答 Q8、Q6、Q4 的质量和性能取舍,也没有同 API 模型比较。模型 digest、Ollama 版本和系统后台负载变化都可能让结果改变。
第六,流式第一个片段不一定是对用户有意义的首 token。如果 UI 在 JSON 闭合后才展示内容,真实首可用响应接近 totalMs;产品指标必须按呈现方式定义。
商业价值
本地推理的潜在购买者包括有数据驻留要求、稳定高频任务、边缘网络约束或需要控制模型版本的团队。价值不来自“免 API 费”一句话,而要核算:
本地路线月度净价值
= 避免的外部调用费用 + 数据与可用性收益
- 硬件折旧 - 电力 - 运维 - 评测 - 容量冗余 - 升级成本
本次机器在短 JSON 任务上获得约 15 token/s 和约 179 ms warm TTFT,说明它可以进入单用户内部工具的候选验证;它没有证明能承载团队并发,更没有证明质量优于云模型。若任务输出很短、调用稳定且模型质量达标,本地常驻可能降低边际成本;若任务稀疏、峰值高或需要更强模型,购买弹性 API 可能更便宜。
未来 90 天的可证伪门槛是:用至少 300 条盲测任务比较本地 Q4 与一个固定 API 基线,记录任务正确率、P95 TTFT、P95 total、每小时稳定吞吐、峰值内存、能耗和人工失败处理。只有本地路线在目标质量下的单次成功成本更低,才能进入商用建议。
复盘
这次实验把“本地能跑”升级成了可复核的四层证据:模型身份、运行参数、系统延迟、任务断言。最有价值的发现不是 15 token/s,而是同一个模型在含糊和严格输出合同下呈现稳定差异。部署优化与接口设计必须一起做。
下一版将加入 Ollama 版本、进程 RSS/峰值统一内存、长上下文、并发阶梯和固定 API 对照。届时才能讨论量化、batching、KV cache 和路由,不会用这 14 条串行结果提前宣称生产容量。
方法披露
本文使用 AI 工具协助设计任务、审查流解析和绘制 SVG;所有 14 次模型调用在作者本机真实执行,模型 digest、响应原文、计时、代码和判断由作者复核。任务没有包含个人数据或客户资料。
修订记录
2026-07-13:初版发布并完成工件审计;固定 qwen3:8b digest 与 Q4_K_M 环境,记录 14 次流式请求、4 个自动测试和含糊提示失败样本。
Reusable projects
关联可复用项目
本文已经进入以下工程项目;项目页提供固定版本、运行命令和结果工件。
- 实验验证已独立复现
本地推理容量规划工具
本文公开 qwen3:8b 的 14 次串行流式请求、固定模型身份、逐任务输出和含糊提示失败样本。
Source ledger
来源账本
以下来源用于核对事实、日期与当时可用范围。厂商自报性能不视为本站独立复现。
讨论