16GB MacBook Air 上的 MiniCPM5-2B:中英双语抽取测试与 Ollama 部署

员工的工作请求经常在一句话里混用中英文。为了看看 MiniCPM5-2B 在本地机器上如何处理这种表达,我们在一台 16GB 的 Apple M5 MacBook Air 上跑了一组 12 条结构化抽取测试。本文展示输入与输出、完全匹配的判定规则、实测延迟,以及用来复现其中一条用例的 Ollama 步骤。

MiniCPM5-2B 是我们面向端侧助手的紧凑文本模型。在这组测试中,12 条中英混合请求里有 11 条完全匹配了所有要求的 JSON 键和值。我们同时给出这一结果、独立基准数据和模型已公布的指令遵循与工具调用分数。

为什么中英混合的员工请求是一项苛刻的测试

一条工作请求可能用中文提到工单号,用英文说明优先级,还要求返回固定的 JSON 结构。MiniCPM5-2B 需要把这些细节对应起来,同时保留 ID、数字和缺失值。我们围绕这些具体的抽取检查设计了 12 条用例:常规更新、信息缺失、否定、日期、金额,以及应用要求的准确动作值。

MiniCPM5-2B 是文本输入、文本输出的模型,参数量为 2,516,756,480,原生上下文长度为 131,072 tokens,详见模型卡。它支持推理与工具调用工作流,以 Apache 2.0 协议发布。长上下文是模型能力;设备上实际能舒适运行的上下文,取决于可用内存和服务栈。

独立基准与我们公布的模型评测

2026 年 10 月 8 日,Artificial Analysis 将 MiniCPM5-2B 列在其 Intelligence Index 的 12 分,并在开放权重 Tiny 类别(包含最高 4B 参数的模型)中位列 49 个模型中的第 2 名。MiniCPM5-2B 约有 2.5B 参数;排在它前面的 K2 Horizon 3.7B 体量更大。这是已公布的 Tiny 类别排名,并不是单独的 3B 以下排名。

Artificial Analysis 评测的是开启推理的 MiniCPM5-2B 版本。下面在笔记本上进行的抽取测试关闭了思考模式,并使用了 Q4_K_M 量化,因此 11/12 的结果是不同设置下的另一项测量。Artificial Analysis 没有公布该模型的输出速度数据。

我们的 MiniCPM5-2B 模型卡显示:指令遵循在 Multi-IF 上为 71.8,工具调用在 BFCL v4 上为 66.6。这些是模型卡中公布的结果。本文的中英混合抽取用例则是在下文所述的笔记本上单独运行的。

根据手头的设备选择部署格式

我们的 Ollama 模型页提供了一条直接用于笔记本的路径,使用 Q4_K_M GGUF 构建。我们的 Ollama 指南也记录了手动配置 GGUF 的方法。其他受支持的服务路径包括 llama.cpp、vLLM、SGLang、Transformers 和 LiteRT-LM;本文的步骤与测量均使用 Ollama。模型支持 131,072 tokens 的原生上下文,而本次本地测试配置为 4,096 tokens。

MiniCPM5-2B GGUF 格式

模型文件大小

实际用途

F16

5.04 GB

内存允许时的参考级权重

Q8_0

2.68 GB

更大的量化选项

Q4_K_M

1.56 GB

适合笔记本试用的紧凑选项

上表列出的是部署指南中的 GGUF 文件大小。在我们 16GB MacBook Air 的测试中,Ollama 报告 Q4_K_M 模型加载后占用 1.8GB,上下文为 4,096 tokens。模型文件大小与加载后的模型大小是两回事;下面的配置会写明实际使用的格式和上下文。

用 Ollama 跑同一套 Q4_K_M 配置

OpenBMB Ollama 模型提供了这里使用的 Q4_K_M 构建。安装 Ollama 后,拉取模型并启动本地服务:

ollama pull openbmb/minicpm5-2b

ollama serve

在另一个终端里,向 Ollama 的本地 API 发送一条中英混合的抽取请求。这个示例使用与我们测试相同的推理设置:关闭思考、temperature 0、JSON 模式、4,096 tokens 上下文、最多输出 128 tokens。程序会在执行任何下游动作之前,将解析出的对象与要求的键和值进行校验。

import json

import urllib.request

expected = {"ticket": "INC-204", "priority": "high", "owner": "Maya"}

payload = {

"model": "openbmb/minicpm5-2b:latest",

"messages": [

{"role": "system", "content":

"Extract only facts stated in the request. Return one JSON object, no prose. "

"Keys: ticket, priority, owner"},

{"role": "user", "content":

"请把 ticket INC-204 设为 high priority, owner is Maya. "

"Return JSON with ticket, priority, owner."}

],

"stream": False, "think": False, "format": "json",

"options": {"temperature": 0, "num_ctx": 4096, "num_predict": 128}

}

request = urllib.request.Request(

"http://127.0.0.1:11434/api/chat",

data=json.dumps(payload, ensure_ascii=False).encode(),

headers={"Content-Type": "application/json"})

with urllib.request.urlopen(request) as response:

reply = json.load(response)

actual = json.loads(reply["message"]["content"])

assert isinstance(actual, dict) and actual == expected

print(actual)

在 16GB MacBook Air 上实测的 MiniCPM5-2B 速度

我们在一台 16GB 统一内存的 Apple M5 MacBook Air 上,用 Ollama 0.33.2 运行 openbmb/minicpm5-2b:latest(Ollama 模型 ID 71a44e98400f,Q4_K_M),系统为 macOS Darwin 25.6,一次只发一个请求,关闭思考,temperature 0,JSON 模式,num_ctx=4096,num_predict=128。在第 2–12 条用例中,请求耗时中位数为 0.321 秒,测量范围从本地 HTTP POST 发出前直到完整 JSON 响应返回。生成速率中位数为 76.5 tokens/秒,按每个请求用 Ollama 报告的生成 token 数除以它报告的生成时长计算,再取中位数。这 11 次热请求包含完全匹配失败的用例 4;只有用例 1 因加载模型(报告的加载时间 1.541 秒)被排除在热启动计时中位数之外。输入长度在 66 到 84 个 prompt tokens 之间,输出为 12 到 37 个生成 tokens。完整的用例日志见下方附录。

这组小型中英双语测试说明了什么

我们测试了 12 条中英混合的合成员工请求。每条请求的系统消息都会列出要求的键;模型在关闭思考、temperature 0、4,096 tokens 上下文的设置下返回 JSON。我们解析响应,只有当它是对象、且键和值完全符合预期、没有多余键时,才计为通过。键的顺序无关紧要;近义词或归一化变体都不算通过。12 条中有 11 条通过。用例 4 未通过完全匹配校验,因为模型返回的动作值是 "cancelled",而要求的是 "cancel"。

测试集中的三条请求

下面每条用例展示原始的中英混合输入、要求的 JSON 对象和模型输出。完整的 12 条用例见附录。

一条常规工单更新(用例 1)。

原始输入: 请把 ticket INC-204 设为 high priority, owner is Maya. Return JSON with ticket, priority, owner.

期望 JSON: {"ticket":"INC-204","priority":"high","owner":"Maya"}

模型输出: {"ticket":"INC-204","priority":"high","owner":"Maya"}

完全匹配结果: 通过

缺失值用 null 表示(用例 9)。

原始输入: 客户要更新 address, but the new address is missing. Return JSON with action, new_address. Use null when missing.

期望 JSON: {"action":"update_address","new_address":null}

模型输出: {"action":"update_address","new_address":null}

完全匹配结果: 通过

一处 schema 不一致(用例 4)。

原始输入: Customer asks to cancel 订单 B-52, but no reason was provided. Return JSON with order, action, reason. Use null for missing reason.

期望 JSON: {"order":"B-52","action":"cancel","reason":null}

模型输出: {"order":"B-52","action":"cancelled","reason":null}

完全匹配结果: 失败

如果应用要求固定的动作枚举,这一差异就很关键。在执行动作之前,请把解析出的对象与函数 schema 做校验,并映射或拒绝超出允许集合的值。上面三个例子分别展示了正常更新、信息缺失的请求,以及完全匹配失败的用例。

如何判断 MiniCPM5-2B 是否适合你的工作流

做工作流试点时,先收集一批有代表性、已获授权的请求,并保留原始的中英文切换。测试前先定义好动作和必填字段,再覆盖常规请求、信息缺失和错误代价高的场景。这里的 12 条用例展示了方法,也提供了一个透明的起始集合。

MiniCPM5-2B 是紧凑型本地文本抽取和结构化输出的有力候选。中英混合请求 11/12 的结果、已公布的基准分数,以及 Ollama 路径,为团队在自己的任务上做匹配试验提供了具体依据。如果需要图像输入或更小的设备预算,可以在 MiniCPM 家族中选择合适的模型。

实际的下一步,是在真正重要的请求和设备上跑同一套 schema 校验。下方完整样本集让这次笔记本上的结果可检查、可复现。

常见问题

MiniCPM5-2B 能在不把员工请求发往云端 API 的情况下运行吗?

可以。上面的 Ollama 配置在本地执行推理,因此员工请求无需发送到云端推理 API。

最低需要什么机器?

本文测试在一台 16GB Apple M5 MacBook Air 上运行 Q4_K_M 构建,上下文 4,096 tokens,一次一个请求。我们的 GGUF 指南列出 Q4_K_M 模型文件为 1.56GB;实际容量取决于运行时、上下文长度和并发负载。

指数分数高就能保证中英双语任务成功吗?

指数和笔记本测试衡量的是不同的事情。Artificial Analysis 报告的是开启推理模型的一般性能。这里的本地运行衡量的是关闭思考、Q4_K_M 量化下的精确 schema 抽取:12 条请求中 11 条通过,失败的那个值已在上文展示。

*来源与测试设置:*基准信息于 2026 年 10 月 8 日对照 Artificial Analysis 和我们的模型卡核对。部署信息来自我们的 Ollama 模型页和 Ollama 指南。本地结果来自 12 条用例脚本;完整用例集见下方附录。

附录:完整的 12 条中英双语抽取用例

下面保留每条原始输入、期望对象、实际对象和完全匹配结论。只有用例 4 不一致。

用例 1 — 通过

原始输入:请把 ticket INC-204 设为 high priority, owner is Maya. Return JSON with ticket, priority, owner.

期望 JSON:{"ticket":"INC-204","priority":"high","owner":"Maya"}

模型输出:{"ticket":"INC-204","priority":"high","owner":"Maya"}

用例 2 — 通过

原始输入:For ticket INC-205, 负责人是 Leo,优先级 low。Return JSON with ticket, priority, owner.

期望 JSON:{"ticket":"INC-205","priority":"low","owner":"Leo"}

模型输出:{"ticket":"INC-205","priority":"low","owner":"Leo"}

用例 3 — 通过

原始输入:请将 order A-17 的 delivery date 改为 2026-10-03, status pending. Return JSON with order, date, status.

期望 JSON:{"order":"A-17","date":"2026-10-03","status":"pending"}

模型输出:{"order":"A-17","date":"2026-10-03","status":"pending"}

用例 4 — 失败

原始输入:Customer asks to cancel 订单 B-52, but no reason was provided. Return JSON with order, action, reason. Use null for missing reason.

期望 JSON:{"order":"B-52","action":"cancel","reason":null}

模型输出:{"order":"B-52","action":"cancelled","reason":null}

用例 5 — 通过

原始输入:请为客户 Ava 写英文回复。The package is delayed by two days. Return JSON with language and delay_days only.

期望 JSON:{"language":"English","delay_days":2}

模型输出:{"language":"English","delay_days":2}

用例 6 — 通过

原始输入:Ticket INC-210 已解决, but customer needs an English summary. Return JSON with ticket, status, output_language.

期望 JSON:{"ticket":"INC-210","status":"resolved","output_language":"English"}

模型输出:{"ticket":"INC-210","status":"resolved","output_language":"English"}

用例 7 — 通过

原始输入:把 invoice INV-88 标为 unpaid; due date 是 2026-10-15. Return JSON with invoice, payment_status, due_date.

期望 JSON:{"invoice":"INV-88","payment_status":"unpaid","due_date":"2026-10-15"}

模型输出:{"invoice":"INV-88","payment_status":"unpaid","due_date":"2026-10-15"}

用例 8 — 通过

原始输入:Route request R-71 to sales, not support; 优先级为 medium。Return JSON with request, team, priority.

期望 JSON:{"request":"R-71","team":"sales","priority":"medium"}

模型输出:{"request":"R-71","team":"sales","priority":"medium"}

用例 9 — 通过

原始输入:客户要更新 address, but the new address is missing. Return JSON with action, new_address. Use null when missing.

期望 JSON:{"action":"update_address","new_address":null}

模型输出:{"action":"update_address","new_address":null}

用例 10 — 通过

原始输入:Please schedule meeting M-12 on 2026-10-08 at 14:30, 时区是 Asia/Shanghai. Return JSON with meeting, date, time, timezone.

期望 JSON:{"meeting":"M-12","date":"2026-10-08","time":"14:30","timezone":"Asia/Shanghai"}

模型输出:{"meeting":"M-12","date":"2026-10-08","time":"14:30","timezone":"Asia/Shanghai"}

用例 11 — 通过

原始输入:订单 C-90 要 refund 25 USD, not 52 USD. Return JSON with order, action, amount, currency.

期望 JSON:{"order":"C-90","action":"refund","amount":25,"currency":"USD"}

模型输出:{"order":"C-90","action":"refund","amount":25,"currency":"USD"}

用例 12 — 通过

原始输入:For task T-6, 输出中文还是英文? User says: reply in English. Return JSON with task and reply_language.

期望 JSON:{"task":"T-6","reply_language":"English"}

模型输出:{"task":"T-6","reply_language":"English"}