一、三个数字,先把话说清楚
一台没有独立显卡的办公笔记本。模型文件 812MB。一次判断,中位 78 毫秒。
这组数字来自一份笔记本 CPU 上的实测记录。同一份记录里还有两个数:p95 是 153 毫秒,第一次调用约 4 秒——那 4 秒不是算得慢,是在把权重读进内存。
拿它跟云端比,必须先把对照物写清楚。这里说的"快 3 倍",对照的是 Jev 托管 API 单次调用 236 到 276 毫秒的 P50,而且这个数字含网络往返。它不等于"比所有云端 API 都快":微软 10 月 9 日放出的 Decision-1,官方报的 p50 是 85 毫秒,比这台笔记本还快。
所以真正值得聊的,不是"本地赢了云",而是另一件事:为什么一个 0.8B 的小东西,能在没有显卡的机器上把一次判断压进一百毫秒。
答案有点反直觉——它不是算得更快,是把嘴闭上了。
二、它不写字,所以不用等一个前向就出结果
常说的那类大模型,回答"这封邮件该转给哪个部门",流程是:先想,再一个字一个字往外吐,"建议转给——售后——部门——",每个字都要跑一次前向、再采样一次。你等的那一秒多,大部分花在吐字上。
决策模型把这一段整个删掉。你给它一段状态,加一道题,加几个固定选项;它跑一次前向,直接去看选项字母那个位置的输出值,做一次 softmax,得到每个选项的概率。整条链路里没有解码循环,也没有"生成"这个动作。
这就是它的全部秘密。省下的不是算力,是"逐字生成"那一段。
题型只有三种,够用:
• choice:从固定选项里选一个,返回每个选项的概率
• noul:是或否,返回一个是/否的概率
• score:在你定义的刻度上打分,返回一个位置
一次请求里可以并排问好几个独立问题,共用同一段状态。这一点对做业务的人很重要:一张工单进来,"转哪个部门""客户是否生气""紧急程度几分"三件事,一次调用就都回来了。
它到底有多小
项目
数值
量化文件 Q8_0
812MB,原版 safetensors 是 1.50GB
同档其他实现
775MB(Q8_0)、505MB(Q4_K_M,快 25% 到 30%)
CPU 推理进程峰值内存
2.19 GiB,同机 Transformers FP32 是 7.44 GiB
上下文长度
8192 tokens,部分实现支持 16384
单次选项上限
最多 255 个,部分实现是 2 到 26 个
一个 812MB 的文件,意味着它能塞进几乎任何一台在用的电脑,也能跟着 U 盘走。内存那栏更值得看:2.19 GiB 对 7.44 GiB,差了三倍多。在一台还在开浏览器、开着会议软件的办公本上,这两个数字决定的是"能不能跑"和"跑起来会不会被系统杀掉"。
延迟这张表,口径得写全
场景
中位
其他
无独显笔记本,Q8_0,短输入,权重已加载
78 ms
p95 153 ms
首次调用,含加载权重
约 4 s
同一模型换 PyTorch,CPU 32 线程
463 ms
i7-9700 八线程,Q8_0 短输入
524 ms
Jev 托管 API
236 到 276 ms
含网络往返
微软 Decision-1 托管 API
85 ms
官方 p50
这张表想说的不是"78 毫秒最好看",而是同一档模型,换机器、换后端、换输入长度,数字能差出一个数量级。463 毫秒和 78 毫秒之间没有矛盾,它们是两条不同的路:一条是 PyTorch 直接跑,一条是 GGUF 加 llama.cpp 的 CPU 路径。
跑起来只有几行
模型的 GitHub 在 github.com/yanqiangmiffy/chinese-decision,GGUF 版本在 github.com/kouhxp/gutsy,两个都是 Apache 2.0。
启动服务之后,一次请求长这样:
curl -s http://127.0.0.1:8765/v1/systemone \-H 'Content-Type: application/json' -d '{"state": "订单 1182 周一发出。客户说周四到货,盒子被压扁了。","questions": {"next": {"type": "choice","instructions": "客服下一步该做什么?","criteria": {"refund": "退款", "replace": "补发", "escalate": "转主管 24 小时内处理"}}}要自己量延迟,别信任何人的数字,包括这篇文章里的。下面这段可以直接跑,量的是"从发出请求到收完响应",冷启动单独算:
import json, statistics, time, urllib.requestURL = "http://127.0.0.1:8765/v1/systemone"payload = {"state": "订单 1182 周一发出。客户说周四到货,盒子被压扁了。","questions": {"next": {"type": "choice", "instructions": "客服下一步该做什么?","criteria": {"refund": "退款", "replace": "补发", "escalate": "转主管"}}},def call():req = urllib.request.Request(URL, data=json.dumps(payload).encode("utf-8"),headers={"Content-Type": "application/json"})t0 = time.perf_counter()with urllib.request.urlopen(req) as r:r.read()return (time.perf_counter() - t0) * 1000first = call() # 冷启动,只算一次samples = sorted(call() for _ in range(200)) # 预热后的 200 次p50 = statistics.median(samples)p95 = samples[int(len(samples) * 0.95) - 1]print(f"首次 {first:.0f} ms | p50 {p50:.0f} ms | p95 {p95:.0f} ms")准不准,分两栏看测试
0.8B 本地
Jev
金融情绪 Financial PhraseBank
RAG 真实性 RAGTruth
BoolQ 是/否阅读
SNLI 蕴含判断
常识 CommonsenseQA
评判 JudgeBench
WinoGrande
推理 BBH
前两行是它训练分布内的活儿,赢了云端的大家伙;从第五行开始,差距是按倍算的。同一批题目里,JevBench 公开集 231 条,本地这个 0.8B 对 169 条,Jev 对外公布的是 0.866。
这不是"小模型打赢大模型"的爽文,这是一张能力地图:它擅长"归类",不擅长"想"。
三、78 毫秒的边界,比 78 毫秒本身重要
先承认它的价值:把一次判断从"一秒多"压到"几十毫秒",改变的不是体验,是架构。原来你不敢在游戏循环里、在语音交互的每一帧里、在 Agent 每一步里调模型,因为那一秒会毁掉整个交互;现在你敢了。这个门槛的跨越是真实的。
但 78 毫秒这个数字有四个前提,缺一个就不成立。
第一,输入得短。同一份模型卡写得很清楚:长输入在 CPU 上,中位 4.3 秒,p95 27 秒。78 毫秒属于短文本。你要拿它去啃一份三十页的合同,那就不是这个量级的故事了。
第二,机器和编译选项都算数。前面那张表已经写了,同一档模型在 CPU 上可以是 78 毫秒,也可以是 463 毫秒、524 毫秒。谁拿一个数字说"这就是本地推理的水平",这话是不成立的。
第三,单条请求的延迟不等于吞吐。一个人问一次是 78 毫秒;二十个人同时问,排队之后每个人的等待都会变长。做服务的人必须自己压一遍,看的是 p95,不是 p50。
第四,它不会推理。日期和数字算术接近随机,多步规则手册看不懂,需要世界知识的题直接掉到 0.577,难档的 JevBench 里 111 条只对了 56 条。它能做的是"在你说清楚的选项之间快速、稳定地挑一个",不是"帮你想清楚该怎么办"。这两件事经常被混为一谈。
反过来,有个东西比"快"更稀缺,却很少有人提——校准。
它的验证集校准误差是 0.022。翻成人话:当它说 0.8,大约就是 80% 会是对的。所以你的代码可以写 if p > 0.9: 自动放行,这个阈值是有意义的。而生成式模型那句"我有 95% 的信心",本质上是它吐出来的一个 token,看着像概率,不是概率。
再加上两条工程属性:选项顺序打乱之后,96% 到 97% 的答案不变;它还有一个"这些选项都不合适"的拒答概率。这三样东西凑在一起,才让"把判断交给模型"这件事从演示变成可以上线。
四、它该待在哪里
该用的地方,都是"高频、短、有明确选项"的判断:工单分派、评论和内容审核、Agent 循环里选工具、检索完之后判断"这段材料够不够回答问题"、模型路由里决定这句话该走便宜的还是贵的模型。
不该用的地方也很清楚:需要解释为什么、需要多步推理、需要读长文、需要世界知识。硬要用,就是拿一把很快的刀去拧螺丝。
真正的工程答案不是二选一,是分层。高置信度的本地判断直接过,低置信度的、高风险的、需要说明理由的,转给大模型或者人。AWS 对自家开源的 Decider 2B 给的也是这个建议。
还有一层价值经常被忽略:数据不出机器。在合规要求严格的单位里,把工单正文、合同片段、日志发给外部接口这件事本身就要走流程;跑在一台不上网的笔记本上,这一整段流程就消失了。对很多团队来说,这个理由比 78 毫秒更硬。
成本那笔账也算得清。Jev 的输入价是每百万 token 0.042 美元,按今天的汇率约 0.28 元,输出不计费。一次判断的输入按 200 token 算,一百万次判断大约 56 元。这个价格不贵——所以"省钱"不是本地推理的主要理由,"没有网络、没有计量、版本可以定格"才是。
最后一条实操建议:别直接信零样本。先拿你自己的两百条标注量一遍,看它在你的分类体系上错在哪,再决定要不要微调。有一份公开记录是这么做的:约 1.1 万条业务样本,一块 GPU 上半小时,留出集准确率从 31.7% 拉到 95.8%。0.8B 的零样本只是起点,微调才是它真正的工作状态。
顺带提醒一个坑:那 4 秒的冷启动,如果你把它做成命令行工具,每调一次就要付一次;要做成常驻服务,让它一直待在内存里。
五、你项目里有多少次调用,其实只是在"选一个"
云端不是敌人,本地也不是信仰。这次真正被撬动的,是一个被默认了很久的习惯:只要涉及"让模型判断一下",就去调一个大模型,然后写正则去抠它吐出来的那半句话。
现在这条路有了便宜的替代:一次前向,一个概率,一行 if。
那么问题留给你——你手上那个项目里,有多少次大模型调用,其实只是在给定的几个选项里挑一个?如果把它们挪到本地,你的账单和延迟会变成什么样?
热门跟贴