9 月 23 日早上八点半,我盯着一个进度条发呆。界面写着「均速 0.4 词元/秒」, 第 5 轮已经生成了 3,955 秒——六十六分钟。同一台 M5 Pro,同一个 Qwen3.8-27B-Splash,前一天测出来的解码中位速度是 53.4 词元/秒。差了一百多倍。
后来查明白了:模型早就跑完了。服务端日志写着 08:30:50 Done · output 1,900 · 32.9 tok/s,
五十八秒的事。流在第 51 秒静默,客户端又干等了 64 分钟。那个 0.4,
是拿词元数除以呆滞时间算出来的假速率。
**这就是本地长任务的真实形态:能不能跑完,多数时候不取决于模型有多聪明, 取决于外面那圈循环有没有替它收敛。**而那圈循环,在应用里,不在权重里。
先说清楚「那圈循环」是什么
你让模型做一个能在浏览器里跑的贪吃蛇。它不可能一次吐完:要读环境、想方案、 写文件、跑自检、看报错、改回去。每一次「想 + 动手」是一轮,一个任务是很多轮。
循环的工作就是在每一轮前后做判断:这轮该不该强制它动手?它是不是在原地打转? 额度还够不够?什么时候该停下来交差?这些判断加起来大约十三道,分布在三个位置—— 发请求之前、请求进行中、响应回来之后。上面那张图就是它们的全貌。
打个不太准但好懂的比方:模型是厨师,循环是厨房经理。厨师手艺没问题, 但他可能花四十分钟琢磨摆盘,可能把同一道菜重做五遍,可能菜齐了却不肯端出去。 经理不做菜,只负责在这些时刻插话。
拆开看:三种配置,十二组任务
四道题由简到繁——倒计时钟表、弹跳小球、贪吃蛇、打砖块;三种配置: 现有全部闸门(严格)、只放宽数值阈值(适中)、再关掉两个开关(宽松)。 每格记轮数、墙钟秒、产物字节、最终自检。

十二组全部交付,最终自检十一组通过。看到这张表我第一反应是「适中最优」, 这个判断是错的,我收回——理由下一节讲。
但表里藏着一个干净的自然实验。严格到适中,我只动了数值阈值(连续失误几次算空转, 从 3/5 放宽到 5/8 之类),两个开关一个没关,结果落在噪声内。适中到宽松, 阈值再放宽的同时关掉了两个开关,总轮数从 15 变 64。
数值阈值几乎不起作用,开关起决定作用。
顺带一个对照:这 12 组一共向 Splash 发了 110 次请求,解码速度最低 31.6、中位 53.4、最高 90.3 词元/秒。速度一直很稳,稳到它根本解释不了 17 轮和 64 轮的差别。
那两个开关是:尚无产物时强制调用工具,以及只思考、零产出时中途掐断。
宽松档省下的那点开场时间,账单开在别处:

贪吃蛇那一组,上下文峰值从 38,022 词元涨到 68,407,几乎翻倍。
打砖块从 18,899 涨到 61,640。而十二组里唯一自检没过的,
正是宽松档的弹跳球——unverified,五个错误。「都交付了」和「交付了同样的东西」
是两回事。
最难的地方不是调参,是分辨噪声
这是我想重点说的一节。
同一道题、同一台机器、同一套参数,Ling-3.0-tiny 跑三次:5 / 12 / 39 轮, 88 / 270 / 1,346 秒。什么都没改,轮数差 7.8 倍,耗时差 15.3 倍。

把这张图左边第一组(纯噪声)和右边第三组(真实效果)放在一起看,结论很刺眼: 在这个噪声水平上,跑一次就说「这个参数更好」,说的其实是运气。
9 月 23 日我重跑了严格档四格,想验证一处修复有没有让它变好。结果是 17 轮 997 秒 → 18 轮 1,182 秒。看着像退步了 19%,其实什么也说明不了—— 它落在噪声里。这次重跑的真实价值是回归检查:确认修复没有破坏已经能走通的路。
代价是实打实的。要在 15 倍跨度里分辨一个真实差异,需要的重复次数不是个位数; 而每一次重复在本机是几分钟到几十分钟的墙钟——这 12 组本身就跑了 4,207 秒, 接近七十分钟,还只是每格一次。「调一调参数」听起来像十分钟的事,实际是一整天。
这也是为什么我最后没有把数值阈值做成可调项。不是因为它不重要, 而是因为让用户在 15 倍噪声里自己试出一个值,是把不可能的任务转嫁给他。
当年 -O2 和 -O3 之争持续了很多年,很大一部分原因是基准测试的噪声接近两者的差距,
而每个人只跑一次。噪声吃掉效果,结论就会变成信仰。
关键选项:各自管什么,关掉会怎样
下面这张表按「你在界面上能改到什么」来排。有利与不利都是本机实测,不是推演。
| 选项 | 默认 | 作用 | 调高/打开的好处 | 调高/打开的代价 |
|---|---|---|---|---|
| 单次输出上限 | 自动 | 一轮最多生成多少词元(含思考与工具参数) | 复杂产物能一次写完,少几轮往返 | 思考也在这个额度里,越大越容易被思考吃光 |
| 单轮时长上限 | 180 秒 | 单轮墙钟兜底,上限 3,600 秒 | 慢机器不会被提前掐断 | 放太宽时,跑飞的一轮要等很久才停 |
| 工具代理轮数 | 自动 | 一个任务最多几轮 | 复杂任务有空间反复修 | 不收敛时把时间拖满才收场 |
| 思考强度 | 自动 | 给模型的思考预算份额 | 难题规划更稳 | 本地模板常把预算当建议,档位≠硬约束 |
| 该动手时不许只写字 | 开 | 连着两轮没产物就强制调用工具,并关掉这轮思考 | 避免一直描述计划不落盘 | 关掉后实测:弹跳球连做 8 轮重复自检,400 秒 |
| 只思考零产出时中途掐断 | 开 | 一轮只有思考、越过额度安全线时提前结束请求 | 不让一轮把整个额度烧在思考里 | 关掉后实测:一轮烧满 32,768 词元、11 分钟、零产出 |
| 上下文历史上限 | 24 条 / 12,288 词元 | 带多少历史进下一轮 | 模型记得住更早的决定 | 峰值直接推高,越长越慢越贵 |
| 截断自动接续 | 开 | 撞上限时带着已生成内容自动续写 | 长回答不会半截断掉 | 最多续 4 段,续不完仍是截断 |
**两个开关默认都开,就是加开关之前的行为。**数值阈值我没有暴露给用户—— 实测证明调它没有可观测效果,而一个调了没用的旋钮只会让人以为自己在控制什么。
这套剧本早在数据库的查询计划器身上演过一遍:调参手册厚得像砖头, 真正起作用的往往是少数几个开关,其余旋钮的存在更多是让人安心。 区别在于计划器手里有统计信息可依据,而这里没有——生成过程每次都不一样。
我不确定的部分
这套闸门是我一道道加出来的,加的时候每一道都觉得理所当然。9 月 23 日逐项核对, 发现其中三处是同一个病的不同变体:客户端自己掐断的请求,在消费端与「真失败」 长得一模一样。
文字守卫、思考熔断、墙钟兜底,三者中止后合成的终止原因都是「length」, 与真撞额度不可区分。代码里当初还专门写了理由:「不值得分出第三种状态让每个消费者 各判一次」。今天这句话被实测推翻——四种成因的处置相反:撞额度该提高上限; 墙钟到点提高上限毫无作用;流静默两者都不是;守卫掐断该下一轮强制动手。 抹平成因不是少判一次,是逼每个消费者从更弱的旁证各判一次,已经判错两回。
更难堪的是第三处:客户端拿不到服务端用量时会按文本长度估一个数填进去, 把「有没有拿到用量」这个信号抹掉了——而前两处的修复恰恰靠这个信号工作。 第三处会把前两处一起废掉。
至于开头那 64 分钟:读流的那行代码可以永远不返回。当时以为有兜底, 注释写着「由 undici 的 bodyTimeout 兜」。两点都不成立——这个选项在项目里 从没配置过,而且这条请求跑在 WKWebView 里,用的根本不是 undici。 静默的流当时零约束。
这些现在都修了:成因改成显式带回,读流加了总时限和首字节之后 120 秒的静默时限。 为这两处加的回归测试我都做了证伪——把时限逻辑短路掉,测试立刻挂死到超时; 还原后全绿。但我不敢说没有第四处。
当年做网页兼容也是这个局面:页面跑不通不是浏览器不够强,是缺一层抹平差异的东西。 不同的是那时候的差异可以穷举成一张表,而模型的失败形态写不出完整清单—— 今天这三处,每一处都是先在真实任务里翻车,才被我看见的。
谁在这件事上赚,谁在赔
谁受益:卖硬件的。「换更大的模型」这句话可以直接翻译成内存需求。 还有按调用量计费的云端服务——本地跑不顺,用户自然回到云上。
谁受损:用户的时间。同一道贪吃蛇,关掉两个开关多花 16 分钟; 而调参本身的时间成本更大,大部分花在分辨噪声上。这笔钱不进任何人的账,纯蒸发。
谁在沉默:模型发布方没有动机告诉你「这个模型需要一层外部收敛机制才好用」, 那听起来像是模型不够好。所以公开榜单上全是单轮能力分,几乎没有「多轮任务完成率」 和「完成一个任务平均要几轮」。沉默方的立场就是结论:榜单的形状决定了大家优化什么。
这也解释了为什么厂商愿意公布解码速度而不公布完成率。9 月 20 日我撞过一次: 三值量化的 27B 解码快 2~3 倍、原子探针四项全过,真实长任务却超时交不出; 同题的 Q8 27B 用 31 分钟交付了。速度好测,完成率难测,于是只有速度被测。
回到那 64 分钟
开头那个进度条,现在会在静默 120 秒后停下,并明确说出「是这条连接不再出数据, 既不是额度也不是时间」。这是这轮改动里我最满意的一处——不是因为它复杂, 而是因为它把一个「看起来像模型慢」的现象还原成了它本来的样子。
给想上手的人三条路径:
只想跑通:两个开关保持默认打开,别动数值阈值,单轮时长留 180 秒。 Qwen3.8-27B-Splash 在 32GB 以上的 Apple Silicon 上,四道构建题都能交付。
想调参:先量你自己机器的噪声。同一道题同一套参数跑三次,把跨度记下来。 比这个跨度小的差异,别当结论。
想排障:卡住时先看是不是流静默——服务端日志说 Done 而界面还在转, 就是这个病,跟模型没关系。
我自己也在那份沉默里。写这篇之前,我一直以为这套闸门的问题是「阈值定得不够好」。 逐项核对之后才明白,真正的问题一次都不在阈值上。
我做的工具
这些工具都由我持续维护。预览版会明确标注,下载、更新和已知边界以发行页为准。
- 黑粉剪辑 HyphenCut — Rust 写的本地专业视频剪辑:达芬奇键位、AI 助理直接改真实工程,免费(初步构建 · 预览版) https://github.com/HackerChi-Hub/HyphenCut-Releases/releases
- 黑粉盒子 HyphenBox — 免费大模型 API 雷达:持续复测可用性,本地统一接口,Key 只存本机(初步构建 · 预览版) https://github.com/HackerChi-Hub/hyphenbox-release/releases
- 方寸智匣 LocalBrain — 本地模型的多模态 MCP 工具箱:TTS / Whisper / 视频生成一站接入(正式迭代) https://github.com/HackerChi-Hub/localbrain-releases/releases
- ScreenLex 光影词库 — 看美剧顺手把生词背了,Mac/Windows 双平台,免费(正式迭代) https://github.com/HackerChi-Hub/screenlex-download/releases
- 黑粉录屏 HyphenScreen — 录屏 + 智能剪辑一体:达芬奇式时间线、自动打码、导出前成片体检,免费(初步构建 · 预览版) https://github.com/HackerChi-Hub/HyphenScreen-Releases/releases
🧰 我做的工具
这些工具都由我持续维护。预览版会明确标注,下载、更新和已知边界以发行页为准。
信息:黑粉剪辑 HyphenCut 状态: 初步构建 · 预览版
Rust 写的本地专业视频剪辑:达芬奇键位、AI 助理直接改真实工程,免费
信息:黑粉盒子 HyphenBox 状态: 初步构建 · 预览版
免费大模型 API 雷达:持续复测可用性,本地统一接口,Key 只存本机
信息:方寸智匣 LocalBrain 状态: 正式迭代
本地模型的多模态 MCP 工具箱:TTS / Whisper / 视频生成一站接入
信息:ScreenLex 光影词库 状态: 正式迭代
看美剧顺手把生词背了,Mac/Windows 双平台,免费
信息:黑粉录屏 HyphenScreen 状态: 初步构建 · 预览版
录屏 + 智能剪辑一体:达芬奇式时间线、自动打码、导出前成片体检,免费
引用:黑粉科技 让AI成为你的超能力 本地部署 · 免费白嫖 · 自制软件 https://hyphentech.top

留言
正在加载留言…