要说这两年大模型领域最热的路线,肯定绕不开“AI for Math”这个方向。从早期拿ChatGPT硬解奥数题,到后来大家发现单纯对话根本不够用,再到今天的Agent体系——这个演进过程,几乎就是大模型应用落地的一部缩影。我自己从纯LLM调用做起,一路踩坑踩到今天能跑通一套数学解题Agent,中间有不少经验值得沉淀下来。
这篇是“AI for Math速成”系列的第四篇,重点聊一个核心转变:为什么要从单一大语言模型(LLM)走向智能体(Agent)。很多朋友现在依然停留在“prompt调一调、答案刷一刷”的阶段,遇到复杂数学问题就发现,模型的推理链看着头头是道,但结果一验就是错的。问题不出在模型智商,而是出在架构。用Agent的方式做数学推理,本质上把“死记硬背的答题者”升级成“会查资料、会打草稿、会验算的工作流”。这篇文章会把这个转变的逻辑拆透,并给出一个可以直接照着搭的最小实现。适合正在做数学AI产品、竞赛解题助手、科研辅助工具,或者自己折腾大模型应用的朋友参考。
1. LLM在数学推理上的能力边界
1.1 数学推理不是“生成下一句话”
先别急着上Agent,你得先明白纯LLM在数学问题上到底靠什么工作。大语言模型的核心机制是自回归生成,它每吐出一个token,依据是前文内容和训练中学到的概率分布。说白了,它是在“续写”,不是在“计算”。你给它一段“设x为实数,满足x²+2x+1=0”,它大概率会接出“则(x+1)²=0,解得x=-1”,因为这串内容在训练语料里出现过太多次,续写路径非常成熟。
但对稍复杂的题,比如多步不等式证明、带参数讨论的方程组、需要分类讨论的排列组合,模型的“续写”就会变味。它不是真的在做逻辑推导,而是在编织一条看起来连贯的路径。这句话不是我危言耸听,你让模型解一个需要分三种情况讨论的绝对值方程,它经常写着写着丢掉一种情况;让它做需要代两次换元的不定积分,它敢在第三步直接写出错误原函数。
我做个比喻。LLM像一位口才极好的考生,知识面广、表达流畅,但考试时不打草稿、不验算、不回头检查。它更擅长“把答案描写得漂亮”,而不是“把答案算得正确”。所以当我们谈AI for Math,第一步必须认清这个现实:语言模型的强项是“模式识别+表达”,弱项是“精确计算+可靠推理”。
1.2 三个绕不开的痛点:幻觉、误差传播、路径依赖
在实战中,我总结了三个纯LLM解数学题最要命的痛点。
第一个是幻觉。模型会一本正经地引用不存在的定理,编一个看似严密的推导过程,甚至把“显然可得”用在完全错误的步骤上。我之前拿某道数论题测试,模型先假设“所有奇数是素数”这种离谱前提,然后一路推导出结论。这种幻觉在纯文本生成领域影响不大,但在数学里是致命伤。
第二个是误差传播。代数变形只要错一步,后面全错,而且错得越来越离谱。LLM是逐token生成的,一旦第5步少了个负号,第6步基于错误结果继续“推理”,到第15步整个式子已经面目全非。它没有“回退到错误点重算”的机制。人类做题错了会划线重来,LLM做不到,它只会顺着错误往下编。
第三个是路径依赖。模型往往只会走训练语料里最高频的解法路径,一旦题目需要换个角度切入,它就卡住。比如有些几何题需要辅助线,模型很少主动尝试多条辅助线;有些代数题需要构造向量或复数表示,模型通常想不到。它像一个只会背标准答案的学生,遇到底层逻辑相同但外表不同的题目就直接翻车。
这三个痛点决定了:要解决数学问题,不能只靠把LLM当做一个“超级答题机”。我们需要给它装上“外部计算器”“验证器”“规划器”和“记忆模块”——这就是Agent化的核心动机。
2. Agent介入后会发生什么变化
2.1 从“一口气答完”到“分步干活”
纯LLM的工作方式是一次性完成的:输入题目,输出答案,中间没有中断,没有工具调用,没有状态回溯。Agent的思路则完全不同:把解题过程拆成“感知-规划-行动-观察-反思”的循环。
用ReAct模式来说,LLM在每一轮先观察当前状态,然后决定下一步行动(比如调用计算器、搜索某个公式、写一段Python做符号计算),拿到工具返回结果后,再决定下一步。这个过程像极了人类做题:先审题,再找思路,算一步,核对一步,发现不对就换方法。
这里面的关键变化是:LLM不再需要独立完成所有计算,它只需要负责“规划”和“组织”,把精确计算交给外部工具。这就像你写一份行业研究报告,不需要自己背诵所有数据,可以随时打开Excel、查数据库、用计算器。LLM的角色从一个“什么都会但什么都不精”的全能选手,变成了一个“懂得找谁帮忙”的项目经理。
2.2 数学Agent里的四大角色拆解
我搭建的数学Agent参考了业内常见的工具调用范式,架构上可以拆成四个核心角色:
规划器(Planner):负责拆解题目的逻辑链条。它看一遍题目,把问题分解为“条件转化-公式选择-中间计算-结果验证”四步,并决定每一步用什么工具。
计算器(Calculator):这里不建议直接用自然语言让LLM做算术,而是让它生成表达式或代码,交给Python、SymPy等精确计算工具执行。误差直接降为零。
验证器(Validator):验证器负责检查解题结果。它可以是另一个LLM(给出完整推导让M验证),也可以是比较器(将模型答案与数值计算结果对照),还可以是符号验证工具(把解代回原方程看左右是否恒等)。
反思器(Reflector):当验证失败,反思器会分析错因,比如“第三步去绝对值时没有讨论x<0的情况”,然后指导规划器重新规划。这就是Agent比纯LLM多出的关键闭环。
这四者协同,才解决了我前面说的三个痛点。幻觉由验证器拦截,误差由计算器规避,路径依赖由反思器带来的多轮迭代化解。
3. 从零搭建一个面向数学推理的最小Agent
3.1 架构选型:单Agent多工具,别一上来就整多Agent
很多同行一听到Agent就想着搞一堆角色互相聊天,多Agent框架一套接一套,最后发现数学问题根本不需要那么复杂。做数学推理,先做单Agent多工具,把循环跑通再说。
我推荐的架构非常简单:一个主循环,挂三件工具——符号计算引擎(SymPy或同类库)、Python执行环境、一个校验公式库。主循环内部由LLM驱动的Agent做决策,工具负责执行决策并回传结果。
为什么这么选?数学问题最核心的动作是“算”和“证”,不是“讨论”。多Agent的通信开销大、上下文消耗快,用在发散性的创意任务上可能合适,用在精确推理上反而容易越聊越偏。单Agent多工具的优势是决策链短、可追踪性强,每一步干了什么一目了然,出了问题也好排查。
3.2 核心流程实现:工具注册与思考循环
我按下面的伪代码逻辑开发了一个最小实现,核心流程是ReAct循环的变体,只是把“工具”换成了数学专用工具集。
# -*- coding: utf-8 -*- import json from sympy import symbols, solve, simplify, Eq, latex TOOLS = { "solve_equation": { "description": "求解方程或方程组,返回精确解", "func": solve_equation, }, "simplify_expr": { "description": "化简表达式", "func": simplify_expression, }, "verify_solution": { "description": "把候选解代回原方程,返回验证结果", "func": verify_solution, }, "python_exec": { "description": "执行一段Python代码,用于数值计算或枚举", "func": exec_python, }, } def agent_solve(question, max_steps=8): state = {"question": question, "answer": None, "trace": [], "history": []} for step in range(max_steps): # 1. LLM根据当前状态生成下一步动作 action = llm_decide_action(state) # 2. 调用对应工具 result = call_tool(action, state) # 3. 把结果加入状态 state["trace"].append({"step": step, "action": action, "result": result}) # 4. 验证是否已经得到最终答案 if action["type"] == "final_answer": verified = verify_final_answer(action["candidate"], state) if verified: state["answer"] = action["candidate"] break else: state["history"].append({"candidate": action["candidate"], "verified": False}) return state这一段代码是整个Agent的核心骨架。注意几个关键设计:
工具函数的输入不是自然语言,而是结构化参数。比如“求解方程x^2-5x+6=0”,LLM输出的action必须是JSON格式,包含工具名和参数,而不是“请帮我算一下这个方程”。这能极大减少LLM在工具调用中的自由发挥,降低出错率。
每轮行动后必须把观测结果拼接进状态。工具返回的结果会成为下一轮LLM决策的参考依据,形成连续的上下文。如果计算器算出x=2或x=3,LLM下一步自然可以考虑写答案或验证。
验证器独立于LLM生成流程。最终答案不是LLM说“我算完了”就算数,必须通过符号代回验证。这保证了即使LLM推理链有幻觉,最终输出也经过了数学层面的确认。
3.3 实测中的关键参数与策略
在实际跑通这个Agent后,我沉淀了几个关键策略,直接影响解题成功率。
温度参数调低。这个Agent的LLM决策模块,我把temperature调到0到0.2之间。数学推理不是创意写作,不需要随机性,低温度能让模型更稳定地选择工具和编写表达式。
输出格式强制为JSON。我在prompt里明确要求LLM只能输出合法JSON,不输出任何多余解释。然后程序侧做JSON解析,解析失败就自动重试。这招能有效拦截一大波格式漂移问题。
步数限制与成本控制。我设了8步的上限,超过直接返回“无法解决”。数学问题不需要无限探索,几步之内找不到思路基本就是题目太难或者模型理解偏了。浪费更多token只会增加成本,收益却极为有限。
工具返回结果要简洁。SymPy的表达式输出有时一长串,直接塞进上下文会冲淡注意力。我先对结果做了简化,只保留解的数值或化简后的核心表达式,再喂回给LLM。这一条看着不起眼,实测效果提升非常明显。
4. 常见问题与排查技巧实录
4.1 四个高频率翻车现场
我在这套Agent上跑了数百道题,从初中代数到竞赛入门题都试过,归纳出四个最容易碰到的问题,附上我的处理办法。
问题一:LLM生成的动作不是合法JSON。这种概率并不低,尤其用了一些微调过的模型后更严重。处理方式有两种:一种是在解析失败时自动重发,让模型“生成一个合法的JSON,不要输出任何其他内容”;另一种是使用语法约束生成框架,从解码层面强制JSON格式。对生产环境,第二种更稳,能彻底消灭格式类问题。我在实验里先用了第一种,后期切到约束生成。
问题二:计算工具报错,LLM陷入死循环。SymPy对某些复杂方程会返回异常,比如解不出来或者耗时过长。LLM看到报错信息后,有时会反复用同一个工具尝试同一条路径,一点不懂变通。我的解决方法是给工具执行加了超时限制(比如5秒),超时返回“计算超时,建议换一种解法”。同时在反思模块里告诉LLM:如果上一次工具报错,必须换工具或者换解法,不能重复尝试。
问题三:代回验证时,表达式判断过于死板。比如解方程得到x=2.0000000001这种数值解,代入原方程左右两边差0.000001,符号判断equality会直接返回False。实际上这是浮点误差。我的做法是在验证模块里加了容差判断,数值结果差值小于1e-6判定为验证通过;符号解则优先用SymPy的simplify判断是否恒等。
问题四:模型给出“伪证明”。证明题是重灾区。模型有时会写出“假设结论成立,则...,因此结论成立”这种循环论证,或者偷换条件。我把验证器做成了独立的检查环节,把模型的推导过程交给另一个模型做“检查员”,专门找逻辑漏洞。如果检查员认为有漏洞,整条路径打回重做。这一步额外增加了一些成本,但对证明类题目几乎是必须的。
4.2 防止Agent“偷懒”的三个调教技巧
Agent用多了你会发现一个有趣的现象:它会偷懒。明明该调用计算器的场景,它试图心算;明明需要枚举的情况,它直接拍脑袋给答案;明明验证失败,它换个说法把同样的答案再报一遍。
技巧一:在系统提示词里埋“严格要求”。我加了一条明确指令:只要涉及数值运算,必须调用计算器;只要方程含有根式,必须先化简再判断。这相当于给Agent立了一条工作规范,能显著减少“懒得动手”的情况。
技巧二:设计“反馈回路”。当候选答案验证失败时,我不能只告诉LLM“答案错误”,而是要把验证器的具体反馈接回去:“你把x=2代入方程得到4≠0,请检查你的推导步骤。”这个反馈越具体,LLM修正的成功率越高。
技巧三:给Agent呈现“人类草稿纸”。我让状态树保留每一步的中间表达式,Agent可以随时调取前面的草稿,而不是只看到最终的生成文本。这样它更容易定位到出错的那一步,而不是从头来一遍。实测这种“草稿纸机制”对多步代数题提升很大。
4.3 工具箱扩展方向
如果想让这个Agent的解题能力再上一层楼,可以考虑扩展工具集。我自己试验过加进几何画板接口和数论计算库,效果不错。你还可以加“公式查询器”——输入关键词返回相关公式,减少模型凭记忆编公式的概率。
工具集大了以后,要注意一个平衡:工具越多,LLM选择负担越重,反而容易选错。一个有效的做法是给每个工具打标签,并在prompt里描述“何时用、不要何时用”,而不是只写功能。比如我要写清楚“solve_equation:仅用于显式方程,不能用于不等式或含参数的恒等式”。这样能大幅降低误调用概率。
5. 总结之外的几句真心话
整套流程跑下来,我最深的感受是:AI for Math这件事,工程架构的权重一点不比模型能力低。同样的底座模型,裸调用的解题成功率可能只有30%,但加上工具调用、验证闭环和反思机制后,成功率能拉到80%以上。这不是玄学,而是把“语言模型的概率输出”约束到了“数学逻辑的硬核轨道”上的必然结果。
我也遇到过一个意外收获。某次Agent在解一道组合计数题时,先自己枚举了前几项,然后调Python做了递推验证,最后返回了一个我不敢说一定正确的答案——但验算结果显示它对了。这个过程已经接近人类做题的思维模式了:先猜后证。这一类“涌现行为”出现了好几次,让我确信LLM走Agent化这条路是走对了。
如果你正准备入局AI数学方向,我的建议是从最小Agent方案开始,不要一上来就堆多智能体,也不要做太重的定制。先把“主循环+工具+验证”跑通,再逐步扩展工具集和场景。数学问题是最适合验证Agent方法论效果的试验田,因为它有明确的对错边界,出了问题一眼就能发现。等你把这一整套逻辑吃透了,再把它迁移到其他领域,复杂度会低很多。这套路我已经试过好几遍,值得你花时间搭一次。