← 返回 PaperDaily
大模型与智能体
3B模型苹果芯片连挂5个bug,修复后agent任务完成率0%→30%
这年头能见到一篇"把大模型跑不起来的原因逐条列清楚"的论文,真不容易。研究者把Nanbeige4.2-3B在Apple Silicon上五个独立bug连根拔起,还顺手给出分块预填充方案让上下文扩展2.7倍,干货密度极高。想在Mac上玩agent模型的同学,这份排雷报告必须收藏。
龙哥读论文
阅读 5
查看原文
原论文信息如下:
各位老铁,今天聊一个特别接地气的话题:开源的3B小模型,在Apple Silicon上到底能不能跑起来?
很多同学买了个MacBook Pro或者Mac Studio,内存32GB甚至64GB,寻思着跑个7B、13B甚至70B的量化模型应该没问题吧?结果一搜教程,第一步pip install transformers,第二步from_pretrained,第三步……报错。第四步,上网搜。第五步,搜不到。第六步,放弃。
今天这篇论文讲的正是这种"第六步"的救赎。来自华盛顿大学的研究者John T. Halloran,盯上了近期热度不低的Nanbeige4.2-3B——一个基于Looped Transformer(LT)架构的3B参数agentic小模型,官方宣称在agent和办公工作流基准上比Qwen3.5-4B和Qwen3.5-9B还强。结果拿回来一测,好家伙,五个独立bug排队等着,一个比一个隐蔽,一个比一个致命。
更妙的是,把这五个bug修完之后,你以为就万事大吉了?天真。Looped Transformer架构本身还有一个内存陷阱等着你——参数是省了,但预填充(prefill)阶段注意力内存直接翻倍,32GB统一内存照样顶不住agent任务的长上下文。于是研究者又祭出了分块预填充(chunked prefill),把可用上下文宽度硬生生撑大了2.7倍。然后呢?又挖出了系统提示词被静默替换的坑。今天咱们就一层一层扒开这五个bug和后续的坑。
3B模型在Apple Silicon上"跑不起来"?五个隐藏bug逐一曝光
拿到一个新发布的模型,第一件事是什么?当然是跑起来看看效果。但如果这个模型跑不起来,而且不是报一个错就完事,而是十几个错连环爆,那你大概能体会到华盛顿大学这位研究者内心的崩溃与顽强。
论文作者使用Apple Silicon(MPS后端)加载Nanbeige4.2-3B模型,打算跑agent任务,结果发现模型根本没法用。注意,这不是简单的"报错-修复"流程,而是五个独立bug连环排队,每一个都足以让模型瘫痪。论文把这五个bug逐一列出,还给出了精确定位和修复方案,这份"排雷报告"的细致程度让人佩服。
这五个bug里,最阴险的是第一个:RoPE缓冲区被静默清零。模型的旋转位置编码缓冲区(inv_freq)在加载时被清零,而且再也没有被重新填充。这意味着模型从头到尾都不知道token的顺序——它压根不知道"我爱你"和"你爱我"有什么区别。更可怕的是,这个问题不会崩,不会报错,它只是让模型生成"流畅但位置混乱"的文本。你要是不知道这个bug,可能会误以为模型能力不行,实际是它在"盲猜"位置信息。
第二个bug是RoPE配置分发的KeyError。模型的配置里某些合法参数组合会触发一个KeyError,这个bug在模型构造阶段就炸了,跟什么设备、什么后端完全无关——任何设备上加载都过不去。第三个更离谱,调用forward()时如果直接传默认的past_key_values=None,会调用一个在当前版本transformers中已经被删除的API from_legacy_cache(),直接AttributeError。
第四个bug是位置ID重新裁剪问题,在MPS上会触发一个Metal断言错误,直接崩溃SIGABRT,但在CPU上却复现不了——这种"设备特定"的bug最烦人,因为不容易定位。第五个bug则是权重共享(tied weights)的键名格式不兼容,导致保存模型时直接报错。也就是说,哪怕你把前四个bug都修好了,想重新保存一个可用模型都不行。
作者通过"同目录文件猴子补丁"的方式修复了全部五个bug,而且没有改动任何transformer缓存包内的文件。这个操作的优雅之处在于:补丁文件就在模型checkpoint旁边,加载的时候直接生效,不会污染你系统里的其他模型环境。
Looped Transformer的内存陷阱:参数省了,注意力内存却翻倍
五个bug修完了,总算能跑了吧?别急,更大的坑在后面。Nanbeige4.2-3B采用了一种叫Looped Transformer(LT)的架构,这个架构设计很巧妙:把隐藏状态依次通过全部的L层物理 transformer层,然后把输出再喂给同样的L层走第二遍,最后才产生logits。相当于用L层参数跑出了2L层的效果。
这不就是"一份权重用两次"吗?对,确实省参数。论文里提到,在相同参数预算下,LT模型甚至能超过更大的非循环模型。但天下没有免费的午餐——你省的是参数,代价是计算量和内存需求直接翻倍。原因很简单:自注意力机制的峰值激活内存跟提示词长度的平方成正比(O(prompt_len²)),而LT要跑两遍前向,那这个平方级的内存消耗也跟着翻倍。
对大公司的大算力卡(比如H200)来说,这点内存翻倍不算啥。但在Apple Silicon上,事情就麻烦了。Mac的统一内存是CPU和GPU共用的,操作系统也要吃内存,其他进程也要吃内存,而且还没有像CUDA那样成熟的显存换页机制。模型一旦把内存吃满,直接系统级卡死,不是简单地OOM报错就完了。
32GB统一内存,跑一个3B参数的模型,理论上绰绰有余,但实际用naive prefill(朴素预填充)跑长上下文agent任务,直接把内存吃爆。这就是LT架构的"隐藏成本"——模型卡片上只写着"3B参数",可没人告诉你预填充时的峰值内存相当于6B模型。
这里科普一下什么是预填充(prefill)。在大模型推理时,拿到用户输入的完整提示词后,模型会先做一次前向计算,把每个token对应的Key和Value缓存下来。这个过程叫预填充。预填充阶段要一次性计算整个提示词的注意力矩阵,所以内存消耗是平方级的。如果提示词很长,内存会非常吃紧。
分块预填充:2.7倍上下文长度的关键一招
怎么解决LT架构的内存翻倍问题?作者的思路非常直接:既然一次性处理完整提示词会让注意力张量变得巨大,那就不一次性处理完,切成一块一块地处理。这就是分块预填充(chunked prefill)的核心思想。
具体做法是这样的:把完整提示词按固定大小切块(默认每块256个token),每次只处理一块,处理完就把Key-Value缓存保存起来,然后继续处理下一块,直到全部处理完,再把最终缓存交给generate()函数做解码。这就像你吃饭不用一口吞下整只鸡,而是一块一块地切着吃——虽然慢了,但绝不会被噎死。
这样做的好处是:峰值注意力张量大小被限制在(块大小 × 当前累计长度)以内,不再跟完整提示词长度挂钩。论文验证过,分块预填充和朴素预填充的输出结果完全一致(bit-identical),说明这个优化不会损失任何精度。
效果怎么样?论文在Apple M2 Max 32GB共享内存上做了详细测试,使用LongBench-Pro数据集,选取了50个长样本,测试了8种不同的提示词长度(从1024到12244个token),对比了朴素预填充和分块预填充在不同batch size下的表现。结果非常惊艳:
朴素预填充最大只能支持到4096个token的上下文(batch=1勉强能跑),超过就OOM;而分块预填充直接撑到11231个token,扩展了约2.7倍。这个提升是实打实的,直接决定了agent任务能不能跑起来——因为多轮工具调用很快就会把上下文撑到几千甚至上万token。
但天下没有免费的午餐,分块预填充是有代价的——速度变慢了。在prompt_len=1024时,分块预填充允许的batch size是朴素预填充的2倍(32 vs 16),但吞吐量低了约22.8%;在prompt_len=2048时,batch parallelism提升4倍,但吞吐量低了约40.9%。这种速度损失来自每个分块的固定调用开销。论文也提到,如果用kernel fusion把多个串行子调用合并成更少的大操作,这个开销可以直接降低。
系统提示词"被替换"的坑:一个字节都不能差
内存问题解决了,还有更隐蔽的问题吗?有——这次藏在chat模板里。
Nanbeige4.2-3B的chat模板里有一个if/else逻辑,处理messages[0]的方式有点怪:如果调用者提供了任意系统消息,模板就原样照用,并在末尾追加"\n\n";如果没有提供系统消息,模板会自动注入一个硬编码的默认系统提示词(Nanbeige自己训练好的工具调用提示词,开头是"你是一位工具函数调用专家..."),而且不追加任何额外的换行分隔符。
问题来了:一旦你提供了系统消息,模型自己训练好的默认提示词就被静默丢弃了,而不是被扩展或追加。这就导致一个诡异现象:不传系统消息时,模型能正确输出单次工具调用;一旦传了系统消息——哪怕只是"你是一个有MCP工具的助手"——多工具调用就会碎成乱七八糟的文本。
更离谱的是,你手动把那个默认提示词的内容原封不动地作为显式系统消息传回去,也没用。因为模板会自动追加"\n\n",比自动插入分支多了两个字符。就这两个字符的差异,就会让模型行为彻底改变。万恶的字节级敏感性,一个字都不能差。
论文作者一针见血地指出:这个模型的工具调用可靠性,是被校准到它自己默认渲染路径的精确字节序列上。它的SFT和RL数据只走自动插入分支,从来没跟"调用者提供的系统消息"打过交道。换句话说,模型的训练数据里没有"带系统消息"这个选项,所以一旦出现系统消息,模型就不确定了。
修复方案也很巧妙:把系统消息从chat模板中移除,让模板走它自己默认的零额外空白自动插入路径,然后在渲染完的字符串后面、默认提示词之后,再手动插入调用者的系统内容。这样既保留了模型训练好的默认提示词,又满足了调用者注入系统消息的需求,单工具调用输出也恢复正常。
值得一提的是,还有个类似的bug被llama.cpp社区的PR #26324独立报告过:Nanbeige4.2-3B在约25%的调用里会输出加尾随空格而不是正常换行。这从侧面印证了:这个模型的工具调用可靠性,严重依赖模板和空白字符的确切格式。
修复后效果如何?MCPMark 30% vs BFCL 100%的真相
把所有问题都修复之后,终于可以跑正经benchmark了。论文用了两个测试集:MCPMark和BFCL。
MCPMark(Wu等,2025)是一个专门测试MCP(模型上下文协议)工具使用能力的基准,它的任务是多轮对话式的,要真刀真枪调用工具并检查工具生成的响应。论文选了Filesystem文件系统套件里的10个easy任务(不需要API凭证)来做测试。而BFCL(Berkeley Function-Calling Leaderboard,即伯克利函数调用排行榜,Yan等,2024)则更纯粹,它只测模型能不能选对工具、生成正确的调用格式,不真正执行工具。
MCPMark的结果是3/10,即30%通过率。看起来不高?但这是从原来的0%直接跳到30%。要知道,未修复的原始checkpoint连评估都跑不了(第二个bug在加载时直接KeyError),等于从"完全不可用"变成了"勉强可用"。
分析失败案例可以发现不少有价值的信息。pattern_matching任务超时的原因是:模型成功调用了read_multiple_files工具,但把一个长绝对路径重复了21次——直接把上下文撑爆然后超时。其余几个失败任务也都有一个共同模式:在多轮交互中不断累积上下文,最终超过内存容量。这说明模型在长上下文场景下的工具调用路径选择还有很大问题——不是不会调工具,而是不知道什么时候该停止无效调用。
BFCL测试选取了150个任务,覆盖5个类别,每个类别30个:simple_python(单个正确的函数调用)、multiple(从N个候选函数中选1个)、parallel(对同一函数发出2+次调用)、parallel_multiple(对不同函数发出2+次调用)、irrelevance(正确地发出0个调用,即不该调工具时不调)。
注意,BFCL的"100%",是指irrelevance类别的100%,也就是"不该调用工具时正确保持沉默"。这是模型为数不多的亮点之一:它确实学会了"克制"。而在真正需要工具调用的场景里,simple_python只有63.3%的准确率,multiple只有43.3%,parallel_multiple是30%,parallel则惨到3.3%。
主导性的失败模式非常清晰:模型不会同时输出多个工具调用。在parallel和parallel_multiple这两个需要并行调用多个工具的类别中,模型几乎总是只输出一个调用——它根本没学会"一次性发出多个调用"这个格式。这是一个独立的、格式层面的能力缺陷,跟内存、超时、硬件统统无关——就算给你无限内存、无限快速度,模型在并行工具调用上依然是这个表现。换句话说,这是训练阶段留下的能力边界,不是部署问题能解决的。
另外,论文还发现了一个MPS特有的内存bug:一次捕获的MPS OOM错误会让整个服务进程的可用内存预算永久降低。即使调用torch.mps.empty_cache()和gc.collect()也没用,只有重启进程才能恢复。这个bug的隐蔽性极高——某个任务的OOM会级联污染后续所有无关任务的结果。论文的解法也很务实:每个任务独立开一个进程来跑,相当于用进程隔离来屏蔽这个系统级bug。
龙迷三问
这篇论文到底在解决什么问题?论文定位了Nanbeige4.2-3B在Apple Silicon上无法运行的五个独立bug,修复后结合分块预填充让可用上下文扩展2.7倍,并解决系统提示词被替换问题。
这篇工作最值得看的点是什么?chunked-prefill将最大可处理prompt长度从4096扩展到11231(2.7倍);修复后模型在MCPMark上完成30%真实agentic任务(原始为0%),在BFCL irrelevance类别达100%,simple_python达63.3%,但parallel仅3.3%。
这篇工作的边界或风险在哪里?优点:系统性地识别并修复了5个独立部署bug,提出了有效的chunked-prefill内存优化策略,并发现系统提示词回归和MPS内存bug两个深层问题;实验设计严谨,每个bug都有精确触发条件和修复方案。缺点:chunked-prefill以时间换取内存,吞吐量下降明显;模型在多工具调用场景下表现仍然很差(parallel仅3.3%),实用性受限;评估子集较小(MCPMark仅10任务,BFCL仅150任务)。
如果你还有哪些想要了解的,欢迎在评论区留言或者讨论~
龙哥点评
论文创新性分数:★★★★☆
针对Nanbeige4.2-3B在Apple Silicon上部署的五个独立bug进行修复,并提出chunked-prefill策略降低Looped Transformer的峰值注意力内存开销,同时修复系统提示词回归和MPS内存bug,使模。
实验合理度:★★★★☆
最大批大小、吞吐量(tok/s)、任务通过率、工具调用正确率(AST/exact-match评分)
学术研究价值:★★★★☆
针对Nanbeige4.2-3B在Apple Silicon上部署的五个独立bug进行修复,并提出chunked-prefill策略降低Looped Transformer的峰值注意力内存开销,同时修。
稳定性:★★★☆☆
现有材料未提供充分的极端条件、重复运行或扰动测试,稳定性暂按中性评价。
适应性以及泛化能力:★★★☆☆
现有材料未完整展示跨数据集、跨场景或分布外实验,泛化能力仍需进一步验证。
硬件需求及成本:★★★☆☆
在Apple M2 Max 32GiB共享内存上,chunked-prefill在prompt_len=1024时吞吐量212.5 tok/s(batch=32),较naive prefill慢22.8%;
复现难度:★★★☆☆
https://github.com/johnhalloran/Nanbeige4.2-3B-mps-fix
产品化成熟度:★★★☆☆
论文验证以研究实验为主,真实部署中的时延、成本、维护和异常场景仍需补充验证。
可能的问题:;实验设计严谨,每个bug都有精确触发条件和修复方案。缺点:chunked-prefill以时间换取内存,吞吐量下降明显;模型在多工具调用场景下表现仍然很差(parallel仅3.3%),实用性受限;
主要参考文献
[1] Nanbeige Team. Nanbeige4.2-3b: Unlocking agentic capabilities in a compact model. arXiv preprint arXiv:2607.22083, 2026.
[2] Sangmin Bae, Yujin Kim, Reza Bayat, et al. Mixture-of-recursions: Learning dynamic recursive depths for adaptive token-level computation. NeurIPS, 2026.
[3] Ziyang Chen, Xing Wu, Junlong Jia, et al. Longbench pro: A more realistic and comprehensive bilingual long-context evaluation benchmark. arXiv preprint arXiv:2601.02872, 2026.
[4] Zijian Wu, Xiangyan Liu, Xinyuan Zhang, et al. Mcpmark: A benchmark for stress-testing realistic and comprehensive mcp use. arXiv preprint arXiv:2509.24002, 2025.
[5] Fanjia Yan, Huanzhi Mao, Charlie Cheng-Jie Ji, et al. Berkeley function calling leaderboard (bfcl). UC Berkeley Gorilla Project, 2024.
[6] 原文链接:https://arxiv.org/pdf/2608.13987v1.pdf
[7] 开源代码:https://github.com/johnhalloran/Nanbeige4.2-3B-mps-fix
[8] 修复后模型权重:https://huggingface.co/johnhalloran/Nanbeige4.2-3B-mps-fix
*本文仅代表个人理解及观点,不构成任何论文审核或者项目落地推荐意见,具体以相关组织评审结果为准。欢迎就论文内容交流探讨,理性发言哦~ 想了解更多原文细节的小伙伴,可以点击"阅读原文",查看更多原论文细节哦!
在Mac上跑大模型总踩坑?来龙哥读论文粉丝群,和一群踩坑专家一起排雷!
扫描下方二维码或者添加龙哥助手微信号加群:kangjinlonghelper。
一定要备注:研究方向+地点+学校/公司+昵称(如 agent+上海+清华+龙哥),根据格式备注,可更快被通过且邀请进群。
『龙哥读论文』微信群目前包含:图像处理、大模型及智能体、自动驾驶及机器人、AI医疗及AI金融5个群