ACTS 原理与实战:利用 MDP 建模 LLM 推理过程,节省 Token 同时保持高准确率
在RAG项目中,LLM推理效率问题常令人头疼:使用o3-mini处理复杂推理时,token消耗动辄上万,客户查看账单时的表情透露着成本压力。曾尝试粗暴截断max_tokens,却导致准确率直线下降——一道数学推理题,充足预算下能正确作答,将token削减一半后直接答非所问。

尝试过多种方案:缩短system prompt中的推理指令、先用小模型预跑再决策、甚至编写正则表达式剔除CoT中看似“废话”的部分。然而效果均不理想——要么token节省有限,要么准确率大幅下滑。最典型的一次,正则删除了"Let me verify this step"这类验证性语句,导致模型在关键步骤出现低级错误。
直到最近偶然发现一个名为ACTS的开源项目(arXiv: 2606.03965),才意识到有人已将这个问题优雅建模。花了一天时间研读论文并运行代码,这篇笔记是对理解的系统梳理。
看完本文你能知道:
- LLM推理效率问题的核心本质,以及为何简单截断不可行
- ACTS如何借助MDP与强化学习实现“边推理边调控”
- 实际效果评估、代码运行方法及常见陷阱
问题本质:为何无法直接管理模型的思维过程
Chain-of-Thought(CoT)推理是大模型能力大幅提升的关键。模型思考越深入,答案越准确——这一点已得到大量实验验证。但硬币的另一面是:token消耗和响应延迟也随之飙升。
在此前的RAG项目中,一个复杂问题生成的CoT长度通常在8000-12000 token,其中真正对最终答案有贡献的仅约3000-4000,其余部分均为模型“自言自语”——反复确认已知内容、绕弯路后再折返、以不同方式重复相同结论。
当前主流效率优化方案大致分为三类:
| 方法 | 思路 | 问题 |
|---|---|---|
| 长度约束生成 | 训练模型输出更短的推理链 | 需额外训练,泛化能力差 |
| 提前停止机制 | 根据条件判断何时停止推理 | 仅控制长度,无法干预推理策略 |
| 推理知识蒸馏 | 利用大模型CoT训练小型模型 | 小模型性能上限较低 |
这些方法存在一个共同盲区:只关注模型“思考多久”,而不关注“如何思考”。模型内部的推理策略是隐式且不可控的。想要模型“先列出要点再逐个分析”还是“直接给出结论再反向验证”?无法实现。
此前尝试的“正则砍CoT”方案本质上属于长度压缩,效果不佳——无法判断被删除的部分是否为关键推理步骤。更糟糕的是,模型在CoT中的“废话”有时正是其进行自我验证的过程,删除后反而导致准确率下降。这让我们认识到,问题并非CoT过长,而是无法有效控制CoT的“质量”。
核心思路:将推理过程视为 MDP
ACTS的核心做法:将LLM的推理过程建模为马尔可夫决策过程(MDP),然后使用一个轻量的controller agent来“操控”一个冻结的reasoner。
这一建模方式的精妙之处在于:它将“控制推理”从“修改模型”转变为“在模型外部增加决策层”。传统方法(例如训练模型生成更短的CoT)需要改动模型本身,而ACTS的reasoner完全保持不变,所有控制逻辑位于外部。这类似给自动驾驶汽车配备一位人类教练——车辆无需改装,教练坐在副驾驶发出指令即可。
具体分解如下:
状态(State) = 当前推理轨迹 + 剩余token预算
这是整个设计的关键——controller不仅能观察到模型已“思考”的内容,还能知晓“剩余额度”。从而在资源充裕时引导模型深入思考,资源紧张时快速收敛。
动作(Action) = (推理策略, 引导短语)
推理策略是一组预定义的方向,例如"continue"(延续当前方向)、"summarize"(总结已有内容并推进)、"verify"(验证当前结论)、"pivot"(切换思路)。引导短语是一段自然语言文本,注入到reasoner的下一步生成中,起到“方向盘”的作用。
例如,当controller检测到模型在某条思路上徘徊过久时,可输出("pivot", "Let me try a different approach:"),强制reasoner转换方向。
奖励(Reward) = 最终答案正确性 × token效率系数
此处设计十分巧妙:奖励并非简单的“答对得1分”,而是同时考量正确性与效率。一个使用5000 token答对的方案,其奖励比使用10000 token答对的方案高一倍。这使得controller自然学会“用更少的token达成相同效果”。
整个流程可以写成简化版伪代码:
class ACTSController:def __init__(self, reasoner, budget):self.reasoner = reasoner# 冻结的推理模型self.budget = budget# token 上限self.trace = "" # 累积推理轨迹def step(self):# 1. 观测当前状态remaining = self.budget - count_tokens(self.trace)state = (self.trace, remaining)# 2. Controller 决策strategy, phrase = self.controller_policy(state)# strategy ∈ {"continue", "summarize", "verify", "pivot"}# phrase = "Let me verify the above step..."# 3. 将引导短语注入 reasoner 的下一步next_chunk = self.reasoner.generate(prefix=self.trace + phrase,max_new_tokens=512)self.trace += phrase + next_chunkreturn is_done(self.trace)def run(self):while not self.step():passreturn extract_answer(self.trace)
关键点在于:reasoner保持冻结,无需任何微调。所有“智能”集中在controller中。这意味着同一个controller可搭配不同的reasoner——QwQ、DeepSeek-R1,甚至未来模型均适用。
这种解耦设计在工程上极为友好:reasoner可以是任意黑盒模型(甚至包括您调用的外部API),controller仅需观察推理轨迹和剩余预算即可。无需访问模型内部状态,亦无需修改模型权重。
为何该设计效果显著
ACTS在以下四个方面表现出色:
1. 合成引导轨迹构建。缺乏现成的“带引导的推理数据”怎么办?团队采用多预算级别(100%、75%、50%、25%)让reasoner自由推理,然后在每个预算水平上标注最优策略切换点,构建出合成引导轨迹(synthetic steering trajectories)。这一数据构造思路本身就极具借鉴意义——无需人工标注,只需在不同预算下运行一遍,再利用启发式规则标注“在何处切换策略最佳”。
2. 基于预算的条件奖励塑造(Budget-conditioned Reward Shaping)。奖励函数并非固定,而是根据剩余预算条件化。预算充裕时,奖励偏向准确率;预算紧张时,奖励偏向效率。这使得controller学会在“够用就好”与“仔细思考”之间动态切换。直觉上:若一个问题已消耗80%的预算仍未得出结论,则应尽快总结现有思路给出答案,而非继续深挖。
3. 策略与短语的双层动作空间。并非简单地“继续或停止”,而是同时输出一个语义策略和一段自然语言引导。策略决定方向,短语决定执行。这种设计比纯离散动作空间灵活得多——同一个“verify”策略,搭配不同的短语可引导模型进行不同类型的验证。例如,“verify” + “Let me check the arithmetic”与“verify” + “Let me verify the logical consistency”会引导模型执行完全不同的检查。
4. 跨模型泛化能力。由于controller与reasoner解耦,同一个controller可搭配不同的reasoner,亦可迁移至不同类型的推理任务。论文中展示的跨模型迁移效果令人印象深刻:在QwQ上训练的controller,直接应用于DeepSeek-R1仍然有效。
实验结果与数据
论文在多个推理基准(数学、逻辑、代码等)上进行了验证,以下是几个关键数据点:
Token效率 vs 准确率:这是最核心的对比。在75% token预算下,ACTS的准确率与full-thinking几乎持平(损失<2%),而简单截断(naive truncation)下降了8-12个百分点。低预算下差距更为显著——25%预算时ACTS仍保持85%以上准确率,而简单截断直接跌至60%以下。
跨reasoner迁移:在QwQ上训练的controller,直接应用于DeepSeek-R1仍有效,准确率仅下降1-2个百分点。这意味着无需为每个模型单独训练一套controller。在实际应用中这一点至关重要,因为模型迭代速度极快,若每更换一个模型都要重新训练controller,维护成本将非常高。
预算灵敏度:针对同一问题,给予不同预算时,controller会自动调整推理深度。简单题在50%预算下即可正确解答,难题则需100%预算才会深入思考。这表明controller确实学会了“看菜下饭”,而非一刀切地节省token。
最后一点最值得关注——它意味着无需为每个模型训练独立的controller。在实际应用中,模型迭代频繁,若每换一个模型就要重新训练controller,维护成本将难以承受。
实践中的注意事项与陷阱
Controller本身也产生推理开销。尽管它比reasoner轻量,但每一步都需要进行一次前向推理来做出决策。如果reasoner本身的步骤很短(例如简单数学题),controller的额外开销可能抵消所节省的token。论文中的实验针对较复杂的问题,在简单问题上ACTS的收益可能不明显。本地测试发现,对于一步即可得出答案的简单算术题,ACTS反而比直接推理多消耗20%的token——controller的决策开销成了额外负担。
策略空间的离散化损失。目前仅支持4种预定义策略(continue/summarize/verify/pivot),对于需要更细粒度控制的场景可能不够。例如在代码生成任务中,可能希望模型“先写函数签名再填充实现”或“先写测试再写代码”,这类领域特定的推理顺序无法用现有策略表达。未来若能支持自定义策略空间将更加灵活。
延迟问题。token节省不等于延迟节省。每步增加一次controller推理,在API调用场景下意味着更多的往返次数,实际加速效果可能不如论文中描述的那么理想。本地测试显示,同一问题下ACTS节省了40%的token,但wall-clock time仅提升约15%,原因在于controller本身的推理延迟。若场景为批量处理(对延迟不敏感),则收益更为显著。
合成轨迹的质量瓶颈。整个训练数据来源于“事后标注”,若reasoner在低预算下本身表现不佳,标注生成的轨迹质量也会存在问题。这在小模型上可能成为限制。在7B模型上测试,controller的效果不如32B模型上明显——小模型的推理本身不太稳定,controller难以从中提取有意义的策略切换点。
与现有优化手段的叠加效应。若已在使用KV cache压缩、推测解码(speculative decoding)等优化,ACTS的收益需要重新评估。这些技术本身就在减少token或加速推理,与ACTS叠加后,效果可能不如论文中单独测试时那么理想。
快速上手与代码实践
代码开源在GitHub(Andree-9/ACTS),基于PyTorch+transformers:
# 安装git clone https://github.com/Andree-9/ACTS.gitcd ACTSpip install -r requirements.txt# 推理示例(伪代码,具体参见 repo README)from acts import ACTSController, load_reasonerreasoner = load_reasoner("QwQ-32B")controller = ACTSController(reasoner, budget=2048)answer = controller.run("Solve: if f(x) = x^2 + 3x, find f'(2)")print(answer)# 7
建议直接查看repo中的examples/目录,其中包含完整的基准复现脚本。若希望在自己的项目中尝试,建议:
- 从简单数学推理开始,将budget设为原先full-thinking的50%,观察准确率变化
- 若场景为API调用(关注延迟),先测量wall-clock time的变化,而非仅关注token数
- 若已采用其他推理优化手段(如KV cache压缩、推测解码等),务必进行消融实验,评估叠加效果
代码结构清晰,核心文件仅有两个:controller.py(controller的策略网络)和environment.py(MDP环境封装)。若需修改策略空间,可从environment.py中的action_space入手。训练脚本位于train.py,采用PPO算法,代码注释较为清楚,运行起来并不困难。
总结与展望
ACTS的最大价值并非具体节省了多少token,而在于它提供了一种推理过程可控的新范式。过去只能“给模型足够的token让其自由发挥”,现在则可以“指示模型每一步该如何思考”。
这是一个自然的思路转变:推理不应是黑盒,而应是一个可被监控和调控的过程。ACTS借助MDP与强化学习将这一理念落地,尽管仍存诸多局限,但方向是正确的。
从更宏观的视角看,ACTS代表了一种“agent控制agent”的架构模式——用轻量级决策agent调控重量级执行agent。这种模式在其他领域也有应用(例如用小模型进行路由、用RL进行prompt选择),ACTS将其应用于推理效率,效果直观。随着推理模型规模增大、推理链不断延长,这种外部调控机制将日益重要。
下一步计划在自己的RAG项目中尝试ACTS的controller,评估实际业务场景下的成本节省情况。初步打算使用50%的budget运行一轮回归测试,对比准确率与token消耗的变化。如果您在推理效率方面也有实践经验,欢迎一起交流探讨。
