ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

拿走计算器后,50个LLM原生算术能力评测揭秘

拿走计算器后,50个LLM原生算术能力评测揭秘 你有没有遇到过这种场景一个日常对话、写代码、整理文档都很顺手的 LLM却会在“9.11 和 9.8 哪个大”这种问题上翻车或者算不对“23 × 47”很多开发者第一反应是换更强的模型但真正的问题不在模型名字而在“计算方式”。最近开发社区里出现了一个很有意思的实验标题叫“Show HN: I took the calculator away from 50 LLMs and graded the arithmetic”大意是把计算器从 50 个 LLM 手里拿走然后统一给它们的原生算术能力打分。这里说的“计算器”指的是代码解释器、外部工具调用、Python 环境这一类辅助手段。拿走之后模型只能靠自己的参数和注意力机制去算数。这篇文章想借这个实验聊三件事LLM 的算术能力为什么这么不稳定这种“给模型做算术体检”的评测方法怎么设计以及在真实 LLM 应用开发里我们到底该怎么处理数学计算是继续复用工具、还是调提示词、还是干脆换成规则代码。1. 这个实验到底在测评什么先搞清楚实验的核心问题当 LLM 没有外部计算工具时它的原始算术能力到底有多强这里有三个关键词50 个 LLM实验覆盖了主流闭源模型和多个开源模型覆盖面比较广。计算器这是一个很形象的比喻泛指所有能帮模型“算准数”的外部工具。在很多 Agent 架构里LLM 负责推理计算器负责精确计算。打分不是看模型写得对不对而是看最终算术答案本身的标准答案命中率。这个实验的实际背景是很多 LLM 应用开发团队在接入 Agent 时遇到的问题当前端工具链一旦被禁用模型的计算能力就会迅速退化。“能力退化”不是指模型变笨了而是指模型本身就不是一个稳定的计算器。所以这个实验的实践价值是它让我们对“模型自带算术能力”有一个基线认知。它告诉我们模型在纯文本模式下的计算容错率并不高。它提示我们在 LLM 应用落地时是否给模型配计算工具、配到什么程度是会直接影响业务正确率的。2. 为什么 LLM 会算错“简单算术”很多人把 LLM 当计算器用这是对 LLM 工作原理的误解。LLM 不是计算机而是一个概率语言模型。它在生成下一个 Token 时并不是在“执行一段算术程序”而是在根据上下文分布选择最有可能的文本片段。2.1 Token 级别的离散表示数字在转成 Token 时就会被切碎。比如“9.11”可能被切为9、.、11而“9.8”可能被切为9、.、8。模型看到的并不是两个浮点数而是两个文本序列。它需要从训练数据中学到“9.8 9.11”这个结论而不是天然就知道浮点数比较规则。这就像你给一个外国人看中文数字“九点八”和“九点一一”他能读懂字符但很难在潜意识里瞬间完成小数比较只有学过特定换算规则之后才能稳定判断。2.2 概率生成而不是符号运算当模型计算23 × 47时它会根据训练数据里的海量算术题生成一个“看起来合理”的答案。它没有像 CPU 那样执行乘法指令而是模拟了“推导乘法结果”这个文本生成过程。所以当算术步骤越长、进位越多时错误概率就会指数级上升。这不是某一个模型的 bug而是所有自回归语言模型的结构性瓶颈。2.3 注意力窗口与中间错误传播在多步计算中模型需要记住中间结果。比如计算(12 34) × (56 - 23)它需要先算括号再算乘法。每一步的输出都会影响下一步的判断只要中间某一步出现偏差后面就会跟着错。这种错误传播和人类心算很像。人类在多步计算时也会写草稿而 LLM 在纯文本模式下没有“草稿纸”只能把所有中间状态压进上下文注意力中。上下文越长注意力被稀释早期计算结果就越容易被遗忘。3. 评测设计怎么给 50 个模型做同一套算术卷子要评测不同模型的算术能力首先要有一个统一的、可复现的评测方案。这里梳理一个通用的评测流程你在自己项目里也能直接套用。3.1 定义算术题集算术题不能只测加法否则看不出模型的差异。推荐按难度和类型分几个维度题型说明示例整数加法两位数之间或三位数之间123 456整数减法涉及借位1000 - 384整数乘法两位数乘法23 × 47整数除法除不尽和除得尽144 ÷ 12小数运算浮点数加减乘0.1 0.2小数比较容易混淆的比较题9.11 和 9.8 谁大多步混合运算括号与优先级(12 34) × (56 - 23)百分比题实际场景数值800 的 15% 是多少每个类型建议准备 20 到 30 道题题目数量太少无法区分模型差异数量太多会放大低概率抖动。3.2 统一提示模板提示词对 LLM 数学能力影响非常大。评测时最好是所有模型使用完全相同的模板不要给某个模型额外“剧透”。推荐模板请计算下面这道题。只用文字和心算不要调用任何外部工具。 题目{question} 输出格式先给出最终结果再简单说明计算过程但最终结果请单独放在一行答案{{number}}这里要用“心算”这个表述来模拟“拿走计算器”的场景同时要求单独输出答案行方便脚本解析。3.3 采样参数评测算术能力时模型输出的随机性必须压制temperature 0尽量让输出稳定。top_p 1不截断候选分布。max_tokens设为 256 到 512足够输出计算过程。关闭工具调用、代码解释器、函数调用等一切外部能力。如果条件允许每个题目可以跑 3 次用多数投票作为最终答案。但在评测“原生算术”场景中更严格的做法是只跑一次因为这样才能模拟真实用户的使用体验。3.4 评分方式评分不能只看字符串是否完全相等因为模型可能输出23*471081也可能输出1081.0甚至可能输出一千零八十一。推荐统一解析方案从输出里提取答案行。把答案中的中文数字转阿拉伯数字。去除空白和末尾.0。与标准答案做数值比较。同时记录是否回答了“计算过程”用于观察模型的推理结构。4. 评测代码如何用脚本跑一遍“算术体检”下面提供一个可直接使用的 Python 评测脚本遵循的是 OpenAI SDK 的写法。如果你用的是其他模型服务只需要替换base_url和模型名。4.1 基础评测脚本# eval_arithmetic.py import json import re from openai import OpenAI # 不同模型服务只需要改 base_url 和 api_key client OpenAI( base_urlhttps://api.openai.com/v1, api_keyYOUR_API_KEY, ) PROBLEMS [ {id: 1, category: add, question: 123 456 ?, answer: 579}, {id: 2, category: sub, question: 1000 - 384 ?, answer: 616}, {id: 3, category: mul, question: 23 × 47 ?, answer: 1081}, {id: 4, category: div, question: 144 ÷ 12 ?, answer: 12}, {id: 5, category: decimal, question: 0.1 0.2 ?, answer: 0.3}, {id: 6, category: compare, question: 9.11 和 9.8 谁大, answer: 9.8}, {id: 7, category: mixed, question: (12 34) × (56 - 23) ?, answer: 1518}, {id: 8, category: percent, question: 800 的 15% 是多少, answer: 120}, ] def normalize_answer(text: str) - str: 归一化答案去掉逗号、空格、中文数字等。 text text.strip() # 中文数字简单映射只覆盖常见写法 cn_map { 零: 0, 一: 1, 二: 2, 两: 2, 三: 3, 四: 4, 五: 5, 六: 6, 七: 7, 八: 8, 九: 9, } for k, v in cn_map.items(): text text.replace(k, v) text re.sub(r[,\s。], , text) text re.sub(r\.0$, , text) return text def extract_answer(output: str) - str: 优先找 答案 这一行没有就取最后一行数字。 match re.search(r答案([^\n]), output) if match: return normalize_answer(match.group(1)) nums re.findall(r[-]?\d\.?\d*, output) if nums: return normalize_answer(nums[-1]) return def evaluate_model(model_name: str, problems: list, temperature: float 0.0): results [] correct 0 for p in problems: prompt f请计算下面这道题。只用文字和心算不要调用任何外部工具。 题目{p[question]} 输出格式先给出最终结果再简单说明计算过程但最终结果请单独放在一行答案{{number}} try: resp client.chat.completions.create( modelmodel_name, temperaturetemperature, messages[{role: user, content: prompt}], ) output resp.choices[0].message.content or except Exception as e: output fERROR: {e} answer extract_answer(output) is_correct normalize_answer(p[answer]) answer if is_correct: correct 1 results.append({ id: p[id], category: p[category], question: p[question], expected: p[answer], actual: answer, correct: is_correct, output: output, }) return { model: model_name, total: len(problems), correct: correct, accuracy: correct / len(problems), results: results, } if __name__ __main__: report evaluate_model(gpt-4o, PROBLEMS) print(json.dumps(report, ensure_asciiFalse, indent2))4.2 批量评测多个模型如果你要评测多个模型可以写一个简单的批量脚本把模型名放进列表逐个跑。python eval_arithmetic.py --model gpt-4o --model claude-3-5-sonnet --model deepseek-chat如果你的代码还没支持命令行参数可以用下面这种方式包装# run_evals.py from eval_arithmetic import PROBLEMS, evaluate_model import json models [gpt-4o, claude-3-5-sonnet, deepseek-chat] reports [] for model in models: print(fevaluating {model} ...) reports.append(evaluate_model(model, PROBLEMS)) with open(arithmetic_report.json, w, encodingutf-8) as f: json.dump(reports, f, ensure_asciiFalse, indent2) print(done.)4.3 评测时的环境配置为了避免 API 调用中断建议把配置文件单独抽出来# config.yaml eval: temperature: 0 top_p: 1 max_tokens: 512 samples_per_problem: 1 models: - name: gpt-4o base_url: https://api.openai.com/v1 temperature: 0 - name: deepseek-chat base_url: https://api.deepseek.com/v1 temperature: 0 - name: qwen-plus base_url: https://dashscope.aliyuncs.com/compatible-mode/v1 temperature: 0如果你测试的是本地开源模型也可以用 vLLM 或 Ollama 起一个 OpenAI 兼容服务然后把base_url指向本机地址。5. 这类评测中常见的规律虽然这台“50 个模型算术横评”的具体排名和原始得分需要以作者公开的数据为准但如果你按上述方法自己跑一遍会看到很多在其他类似评测中反复出现的规律。5.1 加法减法相对稳定乘除法快速下降大多数模型在两位数的加减法上表现尚可因为训练数据里这类题目太多模型已经形成了比较稳定的模式。但一旦进入两位数乘法、多位数除法错误率会明显上升。位数越多进位越多错误率越高。背后的原因不难理解加法减法可以靠模式记忆兜底乘除法需要真正的逐步运算能力而自回归生成又放大了中间错误。5.2 小数比较是一个“经典陷阱”小数比较题比如9.11 和 9.8 谁大非常容易把模型带偏。因为模型遇到“9.11”和“9.8”时第一反应可能是比较数字字符串的长度或者调用训练数据中的“0.11 vs 0.8”模式而不是把两者统一到同一精度下再比较。这其实涉及一个更深层的问题LLM 在训练时并不会专门针对浮点数比较做符号化处理它的向量空间里“9.11”和“9.8”的表示距离并不等同于它们在实数轴上的距离。5.3 多步混合运算容易中途崩掉(12 34) × (56 - 23)这类题目模型需要先算46 × 33。很多模型会把第一步算错或者把运算优先级搞错。即使模型给出了完整的推导步骤最后一步也可能因为前面某个小错而全盘皆输。所以评测时不能只看最终答案还要看过程。如果一个模型经常在推导过程正确的情况下算错最终结果说明它在算术执行环节有问题如果推导过程就已经错了说明它的步骤分解能力不足。5.4 模型规模不一定等于算术能力开源模型社区里有一个常见误解参数量越大算术越准。实际上算术能力同时受数据分布、训练策略和推理 prompt 影响。有的小模型通过精心构造的指令微调在特定算术题型上反而比大模型更稳但在未见过的新题型上大模型的泛化能力通常更强。因此在选型时不要只看排行要拿你们业务里真实出现的算术题型去测。6. 别把“模型精度”和“算术精度”搞混这个话题正好可以引入一个高频搜索词LLM大模型之精度问题(fp16,fp32,bf16)详解与实践。很多开发者在看到“LLM 算数不准”时第一反应是模型精度不够于是去找 FP16、BF16 的量化参数。这其实混淆了两个精度概念模型权重精度指模型参数用 FP32、FP16 还是 BF16 存储。它影响模型推理时的内存占用和数值稳定性但不会直接决定“9.11 和 9.8 谁大”这种问题。算术正确率指模型输出和标准答案的一致性。它主要取决于模型本身的推理能力、训练数据和提示词。为了理解权重精度可以看这张表类型指数位尾数位典型范围说明FP32823±3.4e38训练时最稳定但显存占用高FP16510±65504推理加速明显但小数值容易损失精度BF1687同 FP32指数范围大尾数精度低训练时常用有些模型在部署时用 INT8 或 INT4 量化推理速度提升明显但算术能力可能略微下降。这是因为量化本质上是对权重做了有损压缩极端情况下会让模型对细微数值模式的记忆变得模糊。但在实际项目中如果一个模型在 FP32 下也算不对9.11 vs 9.8切换成 BF16 并不会修复这个问题。真正的修复手段是给模型配一个计算器也就是外部工具。7. 给 LLM 应用开发的落地建议“拿走计算器”这个实验最大的现实意义是提醒开发者在做 LLM 应用时不要把算数这件事交给模型的“心算”。以下是生产中更稳妥的做法。7.1 能走工具就不走参数在 Agent 架构里计算器应该是独立服务而不是模型能力的一部分。当模型需要精确计算时让它生成一段 Python 代码或调用一个计算函数。输入 - LLM拆分任务- 识别出“需要精确计算” - 调用计算函数/代码解释器 - 拿到结果 - LLM 整理输出这样LLM 负责的是语义理解和流程编排计算器负责的是数值准确性。# calculator_tool.py def calculate(expression: str): import ast import operator as op # 安全计算器只允许白名单运算符 allowed_ops { ast.Add: op.add, ast.Sub: op.sub, ast.Mult: op.mul, ast.Div: op.truediv, ast.Pow: op.pow, ast.USub: op.neg, } def eval_node(node): if isinstance(node, ast.Constant): return node.value if isinstance(node, ast.BinOp) and type(node.op) in allowed_ops: left eval_node(node.left) right eval_node(node.right) return allowed_ops[type(node.op)](left, right) raise ValueError(unsupported expression) return eval_node(ast.parse(expression, modeeval).body)注意这里用了ast解析而不是eval并且只允许白名单运算符可以避免用户输入注入恶意代码。7.2 用提示词鼓励“先列步骤再计算”如果确实没有外部工具可以引导模型把计算过程拆开。请按以下步骤计算 1. 先列出需要用到的数值 2. 写出每一步的中间结果 3. 最后给出最终答案 题目23 × 47这种“思维链提示”能显著提高模型的算术正确率因为它把隐式的计算过程显式化降低了中间错误传播的概率。但要注意思维链不是万能的它只改善推理过程不改变模型对浮点数比较的固有弱点。7.3 加一个校验器在业务系统里最稳妥的方案是加一个后置校验模块。模型输出的最终结果如果是一个数值先被校验器检查一次再返回给用户。7.4 根据题型选择模型如果是聊天、摘要、写作类任务可以追求语言流畅度模型算术能力弱不影响体验。但如果是数据报表、金融计算、数学题解答类任务应该优先选择能稳定调用代码解释器的模型服务。经过数学指令微调的专用模型。自带工具调用能力的 Agent 框架。在实际选型时先跑一遍算术测试再对比价格和延迟比单纯看排行榜更靠谱。8. LLM 算术能力相关常见问题与排查在项目里接入 LLM 做算术经常会遇到一些看起来很“玄学”的问题。下面整理一个排查表按比例覆盖常见场景。问题现象可能原因排查方式解决方案同一个问题有时对有时错temperature 设置过高检查采样参数设置 temperature0或增加多数投票简单加减法都对乘法全崩训练数据中乘法样本分布不足用乘法题集做专项测试引入代码工具或微调专用模型数值比较总是错小数比较的 token 表示异常打印模型的输出 Token换一种表达方式如“9.8 是否大于 9.11回答是或否”多步计算中间步骤出错注意力被长上下文稀释检查模型输出过程分步提示强制作答前先列出中间结果用代码解释器能答对关掉就错模型依赖外部工具做计算对比开关工具时的准确率判断业务是否需要工具兜底需要则保留量化后算术能力下降权重精度损失对比 FP32 与 INT8 输出关键服务保留 FP16 或 BF16不要过度量化模型说“我会算”但结果错误指令跟随与计算执行不一致看最终答案位置和格式使用答案抽取脚本并校验数值格式很多问题的共同点都是开发者默认了“模型输出等于系统输出”。在实际工程里模型输出只是一个中间状态至少要经过解析、校验和格式化才能暴露给用户。9. 从这次实验里我们应该带走什么“把计算器拿走”这个实验真正值得关注的地方不是排行榜上谁第一谁第二而是它用一种很简单的方式把 LLM 的边界暴露在了我们面前。LLM 的算术能力本质上是语言模型在大量文本中“学到”的一种近似能力而不是像计算机那样由 CPU 指令直接执行的结果。它可以在很多日常场景中表现很好但在需要精确数值计算的地方它并不稳定。对开发者来说这个结论直接对应三种工程策略如果算术只是辅助正确性要求不高可以靠 prompt 和思维链提升表现。如果算术是业务核心正确性要求高必须引入外部计算工具而不是指望模型心算。如果模型要在受限环境里运行不能调用工具那就需要提前做算术专项测试而不是上线后再排查。建议你按上面第 4 节的代码把你当前正在用的模型跑一遍保存一份“算术体检报告”。以后每次换模型、换量化精度、改 prompt 模板都重新跑一次你会很早就发现问题而不是等到用户反馈才知道。更长期来看大模型的发展方向一定是“推理 工具”的组合而不是让参数里塞满所有计算能力。Agent 的一个重要价值就是让 LLM 专注于理解任务把精确计算委托给适合的工具。这也是为什么“LLM 应用开发”和“LLM Agent 编排”会成为整个生态里越来越重要的话题。
返回列表