这次我们来看一篇论文,标题很直接:“LLMs Can't Jump”。它不是讲模型跑不起来、显存不够,也不是讲 API 调用报错,而是指一个大模型在某些任务上“跨不过去”的现象——单步问题能做对,一旦需要连续多步推理、在中间状态之间跳跃、或者在长流程里维护一个外部状态,模型就开始掉链子。
这篇论文的核心价值在于:它把“大模型为什么在复杂推理里会失败”这个问题,从玄学变成了可解释、可复现的评估方向。对正在做 RAG、Agent、MCP 编排、批量任务处理和 LLM 应用开发的工程师来说,这里面的结论会直接影响你的架构设计——是先让模型硬推理,还是把步骤拆给外部工具;是加大模型规模,还是换一条调用链;是让 Agent 自己规划,还是给它一个半成品状态机。
这篇文章我会先拆解“LLMs Can't Jump”到底在说什么,再给出一套自己可以复现的实验思路,最后讨论 CoT、Self-Refine、外部工具、MCP 与 Agent 编排这些路线分别能补上哪块短板。全程不堆概念,给的是能直接拿去验证和落地的操作路径。
1. 论文核心观点速览
| 能力项 | 说明 |
|---|---|
| 论文主题 | 大语言模型在多步推理、状态跳跃、组合搜索类任务上的能力边界分析 |
| 核心观点 | LLM 在单步推理上表现优秀,但在需要“跳跃式推理”的任务里,成功率会快速下降 |
| 关键概念 | Jump = 在推理路径中跨越多个中间状态,或从一个求解分支切到另一个分支 |
| 涉及能力 | 多步推理、长程规划、在线搜索、逻辑反推、状态维护、自我纠错 |
| 工程影响 | 对 RAG、Agent、MCP、代码生成、批量任务队列设计都有直接影响 |
| 改进方向 | 思维链、自反思、外部工具、搜索策略、任务分解、状态机编排 |
| 适合读者 | LLM 应用开发、Agent 开发、RAG 调优、算法评估方向的工程师 |
| 硬件要求 | 论文本身不需要本地 GPU;复现实验时用 API 或本地小模型均可 |
这张表里的信息不完全来自论文公开摘要,部分是我从标题方向、社区讨论和通用经验做的推断。更严谨的判断是:这篇论文真正想回答的,是“当我们说一个模型会推理时,它到底是在做真正的组合搜索,还是在做模式匹配”。
2. “Jump” 到底难在哪:从单步推理到多步跳跃
2.1 什么是“跳跃式推理”
普通推理可以理解为一步接一步的路径:A 推出 B,B 推出 C,C 推出答案。这种线性方式对 LLM 来说相对容易,因为 Transformer 本身就在做下一 token 预测,短距离依赖是它的强项。
但很多现实问题不是线性的。比如:
- 解一个约束满足问题,前面选了一个分支,走到一半发现冲突,需要回退并换一个分支。
- 做代码重构,需要同时理解函数 A、函数 B、以及它们共同依赖的数据结构,然后跳到一个新位置完成修改。
- 做一个多轮 Agent 任务,模型调完第一个工具后,需要根据结果重新评估整个计划,而不只是继续执行原计划。
这些任务共同点是:模型必须在推理路径上“跳跃”。跳跃意味着要打破当前局部上下文,重新评估全局目标,然后选择一个新的搜索方向。这不是简单的“多写几步思维链”就能解决的。
2.2 模型失败的原因可能出在哪
从工程角度看,失败通常来自四个层面:
感知窗口有限。模型一次能看到的 token 数量是固定的,长流程跑久了,早期信息会被截断或淡化。即使上下文窗口够长,模型对早期细节的注意力也会下降。
缺少外部状态。模型没有真正“记住”自己已经尝试过哪些分支。对话历史里写的内容,模型未必会当作“不可变事实”来使用,更多时候它是根据当前 token 重新生成,可能在同一个错误分支上反复横跳。
搜索策略缺失。人类遇到走不通的路会回退、会换策略;但模型在普通自回归生成里没有系统性的回溯机制。它更像是在做一个“贪心解码”,每一步都选当前概率最高的 token,然后在错误路径上越走越远。
自我纠错成本高。即使模型发现自己出错了,修正也需要额外的 token 预算和推理轮数。没有外部验证机制时,模型既没有“足够惊讶地发现错误”的能力,也没有“强迫回溯”的手段。
从论文标题的表述方式看,作者更倾向于认为这是一种系统性的能力边界,而不是提示词措辞能简单修复的问题。模型在“无外部支持、仅靠自回归”的条件下,很难完成真正意义上的组合搜索。
3. 典型失败场景:从代码生成到 Agent 规划
如果你觉得上面的分析太抽象,下面看几个实际场景。这些场景不需要论文原文支持,是 LLM 应用开发里普遍存在的高发问题区。
3.1 代码中的跨函数、跨文件修改
让 LLM 改一个函数,通常效果不错。因为它只需要理解局部上下文,把函数体替换掉就行。但如果任务是“跨 5 个文件修改这个接口”,模型需要先建立全局数据结构认知,再同步修改所有调用点,最后还要保证一致性。这时候它经常漏改某一个调用点,或者引入一个全新的、并不存在的依赖。
这类任务失败不是模型不会写某一段代码,而是它在修改路径中“跳”不过去:修改点之间没有直接的 token 连续性,模型需要自己补上中间的推理步骤。
3.2 多步工具调用里的状态维护
在 Agent 场景中,模型先调用搜索 API,拿到结果,再调用数据库 API,再根据数据库结果决定下一步。每一步都依赖上一步的输出。常见问题是:模型在第三步时,不再严格基于第二步的返回值,而是基于自己想象出来的结果继续推理。
这个问题在 MCP(Model Context Protocol)客户端和 LLM 的连接中尤其明显。模型拿到工具返回的结构化内容后,需要把它转换成内部状态,再基于这个状态做下一步决策。如果工具返回内容很复杂,模型很容易“丢掉”关键字段,然后自由发挥。
3.3 长程规划中的早期错误扩散
规划类任务,模型需要先生成一个多步计划,再逐步执行。问题是计划的第一、第二步如果有微小偏差,后面所有步骤都会建立在一个错误的前提上。而且模型在生成计划时,往往没有真正模拟执行,也就无法验证第二步是否能在第一步的结果上成立。
这种错误的特征是:模型全程逻辑通顺,但最终答案是错的。它不是“不会做”,而是“在错误的搜索分支上做得很好”。
3.4 RAG 检索后的逻辑整合
RAG 场景里,检索模块把多篇文章片段拼进上下文,模型需要从这些片段中找到证据链,完成最终回答。当证据分散在不同段落、需要跨两个段落推理时,模型经常只引用其中一段,忽略了另一个关键段落。这本质上也是一个跳跃问题:模型缺少一个“回到检索结果重新组合证据”的机制。
4. 可复现实验:验证你的模型能不能 Jump
论文给的评估任务,自己不一定能完全复现。但我们可以做一个简化版实验,用来验证任意模型在多步跳跃推理上的表现。
4.1 实验设计思路
实验目标:构造一个“单步容易、多步难”的任务,让模型在不调用外部工具的前提下完成。
推荐两类任务:
- 状态追踪任务:给一个初始变量,然后连续做多次赋值/交换操作,最后问某个变量的值。
- 逆向回溯任务:给一个递推关系,要求从终点反推起点,中间有多步不可逆操作。
这两类任务都有一个特点:如果模型在某一步跳错,后面全错;但如果只问单步操作,模型基本都能答对。
4.2 示例 Prompt 与评测脚本
下面给一个状态追踪任务的示例,你可以直接复制到自己的模型环境里测试:
你是一个状态追踪器。请严格按照下面的指令更新变量状态,不能跳过任何一步。 初始状态: x = 1 y = 2 z = 3 操作序列: 1. 将 x 的值赋给 y 2. 将 z 的值加 5 3. 将 y 的值赋给 x 4. 将 x 的值加 z 5. 交换 y 和 z 的值 最终状态: x = ? y = ? z = ?正确答案是:x = 8,y = 3,z = 8。大多数模型在 2-3 步内能答对,超过 5 步后错误率明显上升。
下面是 Python 评测脚本的通用模板:
import json import requests # 评测脚本模板,实际模型和 API 地址需要按你的环境替换 def ask_model(prompt: str, api_url: str, api_key: str = ""): headers = {"Content-Type": "application/json"} if api_key: headers["Authorization"] = f"Bearer {api_key}" payload = { "model": "your-model-name", "messages": [ {"role": "user", "content": prompt} ], "temperature": 0, "max_tokens": 1024, "stream": False } response = requests.post(api_url, json=payload, headers=headers, timeout=120) response.raise_for_status() return response.json()["choices"][0]["message"]["content"] def generate_state_tracking_prompt(steps: int) -> str: lines = [f"v{i} = {i}" for i in range(1, 5)] ops = [] for i in range(steps): # 这里可以换成你自己的操作序列生成逻辑 ops.append(f"将 v{1 + (i % 3)} 的值赋给 v{2 + (i % 2)}") return "你是一个状态追踪器。初始状态:" + ",".join(lines) + "\n操作序列:" + "\n".join(ops) + "\n最终所有变量的值是什么?" # 建议:分别测试 steps = 1, 3, 5, 8, 12 for step in [1, 3, 5, 8, 12]: prompt = generate_state_tracking_prompt(step) result = ask_model(prompt, "http://127.0.0.1:8000/v1/chat/completions") print(f"steps={step}, result={result}")这段代码不是论文官方实现,而是帮你快速建立“模型的跳跃推理能力”基准线。注意替换模型名、API 地址和请求格式。
4.3 结果判断标准
判断时不要只看最终答案对不对,建议记录这几个指标:
- 最终答案正确率。
- 中间状态正确率:让模型把每一步更新后的状态都写出来,看它是从第几步开始错的。
- 错误类型:是“数值替换错”“操作顺序错”还是“回退重算后依然错”。
- Token 消耗:模型是否通过超长输出硬解任务,还是真的做了逻辑维护。
这个实验跑完,你基本就能知道当前模型在你的任务场景里,单靠推理能力能撑住多少步。如果 5 步以上就开始明显出错,那工程上就必须引入外部机制,而不是继续加大提示词。
5. 现有改进路线:CoT、Self-Refine、外部工具与 MCP
论文指出的问题很明确,但工程上我们更关心怎么解决。目前常见的路线有下面几条。
5.1 思维链:能改善,但不能根治
思维链(Chain-of-Thought)的核心是要求模型把中间推理过程显式写出来。这确实有效,因为模型在生成文本的过程中,得到了一次“局部计算外化”的机会,每一步的中间量被写进了上下文,后续生成可以参考它。
但思维链解决的问题是“把隐式的多步计算变成显式的中间变量”,它没有解决“搜索空间太大时需要回溯”的问题。当任务分支多、需要尝试错误分支时,思维链本质上仍然是一条线性路径,模型不会自动分叉再合并。
5.2 Self-Refine:让模型自己检查自己
Self-Refine 的做法是:先生成一个答案,再让模型扮演批评者,指出问题,最后重新生成。这种方案适合“答案有明显缺陷”的任务,比如代码编译报错、回答不完整、格式不对。
但它的边界也很明显:如果模型本身在跳步时缺少批判能力——也就是它根本不知道自己跳错了——那反思环节只是在重复相同的错误。尤其是状态追踪类任务,模型生成的每个中间步骤看起来都很合理,但它无法通过“看自己写的东西”发现自己把一个错误数字传播到了后续所有步骤。
5.3 外部工具:把“跳跃”交给确定性系统
这是工程上最值得投入的方向。既然模型做组合搜索不可靠,那就不要让模型做搜索,让模型负责拆解指令,把搜索、计算、验证工作交给确定性工具。
典型组合:
- 代码生成后交给执行器运行,拿真实运行结果验证。
- 数学计算交给符号求解器或 Python 解释器。
- 多步检索交给搜索引擎或数据库,把结果再喂回模型。
- 状态维护交给结构化存储,而不是让模型在上下文里硬记。
这就是为什么现在 MCP(Model Context Protocol)和各类 Agent 框架越来越流行:它们并不是让模型变得更聪明,而是让模型在不擅长的“跳跃”环节得到外部系统的支撑。
5.4 Agent 编排框架的正确用法
很多人用 Agent 框架时,把全部逻辑塞给模型:让模型自己决定调什么工具、什么时候调、怎么处理结果、什么时候结束。这个思路在简单场景下没问题,但任务一旦变复杂,模型就会在“工具调用序列”上犯和推理任务一样的错误。
更好的编排方式是:把任务流程做半硬化。比如:
# 任务编排配置示例,按实际业务调整 pipeline: - step: extract_inputs type: llm model: your-model prompt: "从用户输入中提取关键参数" - step: call_calculator type: tool name: calculator input_from: extract_inputs - step: format_result type: llm model: your-model input_from: call_calculator这里 LLM 只负责两件事:从输入里提取参数、把工具结果格式化成用户容易读的答案。中间的“计算”交给确定性工具。每一步的输出都是可验证的,即使某一步出错,也能准确知道错在哪个环节。
6. 工程落地影响:RAG、Agent、MCP 与批量任务设计
论文的结论一旦进入工程,会直接影响下面这些决策。
6.1 什么时候该用复杂 Agent
判断标准很简单:如果任务可以被拆成“取数 + 计算 + 格式化”,就不要先上 Agent。先用一个小脚本把流程固定死,只有流程中存在“根据前一步动态决定下一步”的需求时,才引入 Agent 的规划能力。
6.2 任务分解与错误隔离
无论用不用 Agent,任务都要拆。拆分的核心指标是“每一步可验证”。
比如一个批量文档处理任务:
- 第一步:把 PDF 转成文本,用 OCR 或解析库完成,和 LLM 无关。
- 第二步:抽取关键字段,用 LLM,但输出 JSON schema 固定,失败可以重试。
- 第三步:将字段写入数据库,用确定性代码完成。
- 第四步:汇总统计,用 SQL,不用 LLM。
这样做的好处是:如果最终结果错了,你能很快定位是解析问题、字段抽取问题、还是数据库写入问题。而不是对着模型说“再给一次提示词试试”。
6.3 批量任务的重试策略
论文指出模型在多步推理上容易失败,在批量任务里这个问题的表现是“偶发失败”。同一批 100 条输入,可能只有 3 条出错,但出错的位置不固定。
批量任务要把重试当成一等公民。通用建议:
- 每条任务记录完整输入、输出、错误信息。
- 失败后先做确定性重试:换低温度、增加 max_tokens。
- 再失败再换策略:换模型、改提示词、加入工具辅助。
- 连续失败超过 N 次的,进入人工审核队列,不要无限重试。
# 批量任务重试逻辑示意 max_retries = 3 for item in tasks: for attempt in range(max_retries): try: result = get_model_result(item, temperature=0) if validate(result): save_output(item.id, result) break except Exception as e: log_error(item.id, attempt, e) continue else: mark_human_review(item.id)6.4 API 调用与结果校验
论文本身的实验可以不用 API,但如果你要把结论应用到自己的服务里,API 调用是绕不开的。一个标准流程如下:
import requests # 实际项目替换为真实接口地址、模型名和密钥 API_URL = "http://127.0.0.1:8000/v1/chat/completions" API_KEY = "your-api-key" def call_llm(system_prompt, user_prompt, temperature=0): headers = { "Content-Type": "application/json", "Authorization": f"Bearer {API_KEY}", } payload = { "model": "your-model", "messages": [ {"role": "system", "content": system_prompt}, {"role": "user", "content": user_prompt}, ], "temperature": temperature, "max_tokens": 2048, "stream": False, } resp = requests.post(API_URL, json=payload, headers=headers, timeout=180) resp.raise_for_status() return resp.json()["choices"][0]["message"]["content"]调用后必须做结果校验,尤其是生成 JSON 或固定格式字段时。解析失败就重试或降级,不要直接进入下一环。
7. 本地部署 LLM 时的能力观察方法
“LLMs Can’t Jump”这件事,在本地部署小模型和云端大模型上的表现差异很大。如果你在本地跑 7B、13B 模型,单步指令可能没问题,但多步推理的稳定性和开放模型的有明显差距。
7.1 选择合适的模型规模
模型规模越大,多步推理能力通常越强,但本地显存占用也越高。观察指标不应只看“能不能跑通”,还要看:
- 5 步状态追踪任务正确率。
- 10 步以上任务正确率。
- 长上下文中早期信息保持能力。
- 工具调用序列的稳定性。
从实际部署经验看,如果任务只需要 2-3 步推理,7B 模型搭配外部工具完全足够;如果任务需要 8 步以上连续推理,又不想等云端 API,那就需要量化、剪枝、换更大显存卡等方案。这里的每一项都要以本机实测为准,不同模型版本的差异很大。
7.2 显存占用与推理策略的关系
显存占用和“跳跃能力”没有直接关系,但推理策略会影响你能否在有限显存下跑完复杂任务。几个通用做法:
- 长上下文任务优先用支持长窗口的模型,同时开启 KV Cache 量化,降低显存压力。
- 批量任务先跑单条,观察峰值显存,再决定 batch size。
- 如果显存不够,可以降低 max_tokens,强制模型输出更简洁的中间结果,但这可能影响多步推理效果。
- 用 vLLM、LMDeploy 等推理框架,可以更高效管理显存,但需要额外配置。
想观察显存占用,在 Linux 下用nvidia-smi最直接:
nvidia-smi -l 17.3 资源受限环境下的“跳跃”替代方案
如果本地显存小、模型能力弱,不要试图用提示词硬扛,直接绕开“让模型跳跃”这件事。
具体做法:
- 把 10 步任务拆成 5 个 2 步子任务,每个子任务单独调用模型。
- 用外部脚本保存每一步的中间结果,不让模型在上下文里自己维护状态。
- 关键计算步骤全部交给确定性工具。
- 每完成一个子任务,做一次简单的格式校验或断言。
这样做之后,即使模型本身的多步推理能力不强,也能通过流程设计达到较高的整体正确率。这也是“LLMs Can't Jump”给工程侧最重要的启发:不要让模型做它不擅长的事。
8. 常见误区与排查方法
在理解“LLMs Can't Jump”这个问题时,不少团队会走弯路。下面把常见误区整理成表格。
| 误区现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
| 模型单步回答准确,多步任务总是出错 | 模型缺少组合搜索能力,而非单纯提示词问题 | 用状态追踪任务做基准测试 | 拆分任务,引入外部工具,减少推理步数 |
| 加了思维链后效果提升明显,但步骤一长又崩溃 | 思维链解决线性推理,不能解决回溯和分支搜索 | 对比不同步数下的正确率曲线 | 在关键分支点用确定性逻辑辅助判断 |
| Self-Refine 反思后仍输出同样的错误 | 模型没有外部验证,看不到真实错误信号 | 接入代码执行器或校验脚本,把运行结果作为反馈 | 用真实执行结果驱动修改,而不是让模型自我批评 |
| Agent 调用工具时,参数经常传错 | 模型状态维护弱,前一步结果没有被正确传递 | 记录每一步工具输入输出日志 | 用脚本结构化传递中间结果,约束输出格式 |
| 批量任务偶发失败,重试无效 | 模型在特殊输入上稳定出错 | 单独收集失败样本,分析失败模式 | 把失败样本转人工或换更适合的模型 |
| 本地模型多步任务明显弱于 API 模型 | 模型容量和训练数据差距 | 用同一评测集对比 | 拆任务或量化大模型后本地部署 |
| API 调用成功但结果格式频繁报错 | 模型输出不稳定 | 把原始返回保存下来解析错误 | 增加 schema 校验和重试,必要时用函数调用能力 |
这个排查思路的核心只有一个:出现问题后,先确认错误发生在哪一步、是模型能力问题还是流程设计问题。不要盲目换提示词。
9. 最佳实践与工程建议
基于论文给出的问题和上面这些分析,整理几条可以直接落地的建议。
9.1 先建一条能力基线
不管你做 RAG、Agent 还是普通问答,先花半天时间,用 4.2 节里的状态追踪任务跑一遍验证。记录模型在 1、3、5、8、12 步下的正确率。这条基线决定了后续所有架构选择。
9.2 能用外部工具,就不要让模型硬推理
判断一句指令是否需要多步跳跃,如果需要,就考虑拆解。拆解后的每一个子步骤,尽量用确定性的代码去完成。模型只负责“自然语言理解”和“结果包装”。
9.3 每一步都做校验,不要信任模型的自述
模型生成“我已经调用了工具并得到了结果”,不代表它真的这么做了。工程上必须以工具返回内容为准,并校验关键字段是否存在、类型是否正确。
# 一个最小可用的结果校验函数 def validate_result(data: dict, required_keys: list) -> bool: return all(key in data and data[key] is not None for key in required_keys)9.4 批量任务必须设计重试和人工兜底
批量任务不是“调用 N 次 API”那么简单。每一条都要有独立日志,失败要分类统计。连续多次失败的任务要能自动进入人工队列,避免无限循环消耗 token。
9.5 隐私与版权合规
部署 LLM、接入 API、做 RAG 和 Agent 时,注意几个边界:
- 不要将未授权的用户数据、隐私数据直接发送到不可控的外部 API。
- 用内部文档做 RAG 前,确认文档版权和机密等级。
- Agent 调用数据库、接口前,确认查询权限和操作范围,避免越权访问。
- 涉及音频、图像、视频内容处理时,确认素材授权,尤其不要对他人肖像、声音做未经授权的克隆或生成。
- 批量处理任务要记录数据处理方式和保留周期,符合实际业务的安全要求。
10. 总结与下一步
“LLMs Can't Jump”这篇论文的核心不是否定大模型的能力,而是给出一个精确的边界:模型擅长单点推理和线性展开,但在需要跨越多个中间状态、做组合搜索的任务里,失败率会明显上升。这个结论对工程架构的影响远大于对提示词技术的影响——你可以在提示词上花很多功夫,但如果任务本身需要 10 步跳跃,正确率天花板依然很低。
建议你按这样的顺序推进:
- 先跑一遍 4.2 节里的状态追踪实验,给自己的模型建立能力基线。
- 确认 5 步以内的任务用提示词解决,超过 5 步的任务开始引入外部工具。
- 再遇到“模型表现不稳定”的问题时,先检查是流程设计问题还是模型推理问题,不要把锅全甩给提示词。
- 如果做 Agent 或多工具编排,把结果校验、日志、重试机制做扎实,比换更强的模型更优先。
这篇论文真正的价值在于提醒所有 LLM 应用开发者:不要假设模型会在推理时“跳跃”。你要么给它搭好台阶,要么让它每一步都有可验证的外部支撑。建议收藏备用,下次设计 Agent 流程或批量任务时,可以回来对照这些判断标准。