Recursion-of-Thought
Recursion-of-Thought(RoT,Lee & Kim, 2023)可以理解为“递归版的 CoT”:在一条思维链中,一旦遇到中间的复杂子问题,就把它单独拎出来交给另一次模型调用/另一个提示词去解决;等子问题解完,再把结果回填到原来的推理链里继续往下走。这样就像程序里的“递归函数调用”。
它的价值主要在两点:
- 把复杂问题分治:降低一次推理的复杂度,减少走偏。
- 突破上下文/步骤过长:把长推理拆成多次短推理,避免一次输出太长或超出上下文限制。
论文中报告它在算术与算法类任务上更稳定。
论文实现里用微调让模型输出“特殊 token”来触发子调用;但工程上完全可以**只用提示词 + 多轮调用(或函数调用)**实现同样模式。
1) RoT 和 ToT / DECOMP 的区别(避免混淆)
- RoT(递归):遇到“难点”就把该难点当成新的子问题,再调用一次模型解它;解完回填继续。更像“深度优先 + 递归分治”。
- ToT(树搜索):每一步生成多个候选分支并评估选择,更像“广度/束搜索”。
- DECOMP(函数分解):把子问题派发给不同“函数/工具/模块”(可能是不同 prompt 或外部工具)。
RoT 的典型触发条件不是“要不要多分支”,而是:推理链中出现一个局部很难/很长的子任务。
2) RoT 的提示词写法:关键是“子问题触发格式 + 回填规则”
要让模型可递归地工作,提示词通常要规定:
- 什么时候算复杂子问题(例如:需要多步计算、需要做长列表处理、需要证明/推导等)
- 如何把子问题写成独立请求(标准化格式,方便你在工程上拦截)
- 子问题返回后如何回填(回填到哪一行/哪个变量)
模板:纯提示词可实现的 RoT(建议格式)
你将用“递归思考(Recursion-of-Thought)”解题。
规则:
1) 你在推理过程中如果遇到“复杂子问题”(需要≥5步推理/长计算/长列表处理),不要在原地硬算;
2) 请输出一个【子问题请求】块,格式如下:
【子问题请求】
目标:...
输入:...
输出要求:...
【/子问题请求】
3) 我会把子问题的答案返回给你,格式为:
【子问题答案】...【/子问题答案】
4) 你必须将子问题答案“回填”到原推理中继续,直到得到最终答案。
工程上:你可以写一个简单编排器,检测到“子问题请求”就新开一次 LLM 调用;返回后再把“子问题答案”插回去继续对话。这就是 RoT。
3) 实际例子 1:长算术/分段计算(展示“递归回填”)
问题:
“计算:((12345 \times 6789) + (98765 \times 4321)) 的结果。”
如果直接让模型一步算,容易错;RoT 会把它拆成两个大乘法子问题。
主提示词(RoT 风格)
请用递归思考(RoT)解题:遇到复杂运算就发起子问题请求,子问题算完后回填继续。
题目:计算(12345×6789) + (98765×4321)。
模型可能先输出
我将把两个大乘法作为子问题分别计算,然后再相加。
【子问题请求】
目标:计算 P1 = 12345×6789
输入:12345, 6789
输出要求:给出精确整数结果
【/子问题请求】
【子问题请求】
目标:计算 P2 = 98765×4321
输入:98765, 4321
输出要求:给出精确整数结果
【/子问题请求】
然后你(或系统)分别调用“子模型/子提示词”去算 P1、P2,把结果返回:
【子问题答案】P1 = ...【/子问题答案】
【子问题答案】P2 = ...【/子问题答案】
主模型收到后回填并完成:
- 总和 = P1 + P2
- 输出最终值
这种模式在工程里非常实用:你甚至可以把子问题交给计算器工具而不是另一个 LLM,从而更可靠。
4) 实际例子 2:算法题(把“子过程”递归出去)
问题:
“给定数组 [7, 2, 9, 4, 3, 8],请用归并排序说明排序过程,并给出最终结果。”
归并排序天然递归,RoT 很贴合:把“对左半部分排序”“对右半部分排序”作为子问题,再回填合并步骤。
主提示词
请用递归思考(RoT)讲解归并排序。遇到对子数组的排序过程,请发起子问题请求,
等子问题答案返回后再继续合并步骤。输出要用中文,包含每次拆分与合并的结果。
数组:[7, 2, 9, 4, 3, 8]
主模型会先拆成:
- 子问题1:对 [7,2,9] 做归并排序过程
- 子问题2:对 [4,3,8] 做归并排序过程 回填两边的排序结果后,再讲最后一次 merge。
5) 为什么它能缓解“上下文长度/推理过长”
当一个问题需要非常长的中间过程(大量步骤、长表格、长推导),一次性写完会:
- 输出很长,容易丢步骤、前后不一致
- 可能超出上下文或导致后半段质量下降
RoT 通过“子调用”把长任务拆短:每次只解决一个局部子问题,并把结果作为摘要回填,从而让主链保持紧凑。
6) 只用提示词也能做,但要配合“流程编排”
你注意到原文说论文用微调输出特殊 token 触发子调用;但仅靠提示词也能做,前提是你(或你的应用)要做一件事:
- 检测模型输出中的“子问题请求块”
- 把块内内容作为新的 prompt 去调用模型/工具
- 把答案包装成“子问题答案块”发回主对话
这就是 RoT 的工程落地方式(类似“手写函数调用协议”)。
7) 给初学者的落地建议(最常见的 3 个技巧)
- 明确触发阈值:比如“需要≥5步计算/需要处理≥10行数据就递归”。
- 子问题要小且可验证:子问题越可验证(算术、抽取、排序、局部证明),收益越大。
- 回填用变量名:让子结果以
P1=...、子数组已排序=...这种形式回填,主链更不易乱。
如果你给我一个你正在做的具体任务(例如:一道复杂算术题、一个需要多段推导的题、或一段要递归处理的文本/代码),我可以帮你设计一套“RoT 主提示词 + 子提示词 + 回填格式”,让它可以直接用于多轮调用的应用里。你想用 RoT 解决哪类问题?