论文链接:Feedback That Backfires: Why Small Language Model Agents Repeat the Call They Just Watched Fail 代码仓库:Esmail-ibraheem/feedback-that-backfires(含每个数字的复现脚本、原始分数、种子与环境元数据) 发表时间:2026年8月 机构:University of Passau(帕绍大学,德国,单作者Esmail Gumaan;全程CPU可复现,无GPU) 领域标签:cs.SE / Agent可靠性、执行反馈机制、小模型

一、论文背景

会调工具的agent必然会调错一些工具。出错之后发生什么,不是模型决定的,而是harness(脚手架/框架)决定的。从ReAct开始,几乎所有agent框架的标准做法都是:把失败的调用原封不动追加进transcript,再追加运行时报错,然后让模型继续。这个设计的理由无懈可击——报错是真实信息,来自ground truth而非某个评论家,读了报错的模型理应换个做法。

从业者也熟悉症状:agent卡死在重复调用上,同一个失败调用一遍遍重发,框架只好靠循环检测器和步数上限来兜底。症状通常被归因于模型:它太小了、读不懂报错、换个更强的模型就好了。

本文的测量推翻了这个诊断:把失败记录加进上下文后,模型更可能重复失败的动作——而且这个"反馈倒置"在测的每一个指令微调模型上都成立。更关键的发现是病因定位:损害的83%来自失败调用的表面形式(token序列出现在上下文中触发了复制机制),而非报错语义。这一区别直接决定了哪种修复有效:如果是模型读不懂,该换模型或改报错措辞;如果是字符串本身有害,消息工程就永远够不着病灶,修复必须是结构性的。

类比:老师发现学生抄错题后一错再错,直觉以为是学生不理解批改——但真相是,把错题原文贴在学生眼前这个动作本身就在诱导他再抄一遍。批注写得再清楚也治不了"看着原文抄"的冲动。

二、论文定位和关联工作

论文在四条研究线的交叉口上找到了自己的空位。

执行反馈脉络:ReAct确立了"行动-观察-再试"模板,Reflexion、Self-Refine、self-debugging都在其append-only transcript上叠加显式批评或测试结果,MINT实证了反馈总体有益。共同前提:把失败追加进去是有信息量的;但没有任何工作测量过反事实——单独追加的那个动作字符串本身做了什么。

自我纠正怀疑论:Huang et al.等论证模型没有外部信号时无法可靠自纠。本文不同:它把判断固定为ground truth(环境真实执行),问的是模型的下一token分布是否朝着判决暗示的方向移动——本文记录的失败在"完美反馈"下依然发生。

上下文污染(最近邻):Yang的Context-Contaminated Restart Model形式化了"带污染重试错误率更高"的现象(拟合SWE-bench得级联比7.1,独立重试假设高估pass@3达17.4分),结论是重试前清空上下文。本文与其正交互补:在token级测量污染源、发现真凶是失败动作的表面形式——这直接推翻了"清空重试"的处方(清空把诊断和危害一起扔了,还精确复原了失败现场)。

重复与复制机制:Xu et al.证明句子重复自增强;induction heads实现前缀匹配与复制;负向指令文献证明"命名被禁物反而抬高其概率。agent循环的有趣之处恰恰在于竞争信号按设计存在——问题是哪个赢。

先行工作测量净效应?分离形式与语义?干预手段
重复/退化研究否否解码端
负向指令—否prompt
自我纠正批评是否prompt
上下文污染CCRM是否清空上下文
本文是是上下文+解码端

定位结论:本文的独占贡献是中间那一列——只有分离了"字符串在场"与"被标记为失败"两个效应,才能从机制推出哪个干预有效,而不是靠直觉试错。

三、问题定义

具体场景:agent在上下文C处即将发出动作a×,该动作会失败,运行时返回报错o×。harness把(a×, o×)追加进transcript,让模型继续。

核心洞察:追加(a×, o×)其实同时做了两件事——(1)把a×的token序列放进上下文,模型的复制机制够得着它;(2)断言a×失败了。两者方向相反,净效应才是观测到的行为。要定位病因,必须把两者拆开测量。

定义核心测量——corrective gain(矫正增益):

$$G(a_\times) = \log\pi(a_\times|C) - \log\pi(a_\times|C \oplus (a_\times, o_\times))$$

即失败记录前后,重新发出失败动作的对数概率变化。G>0是harness期望的行为(失败后更不可能重复);G<0称为反馈倒置(feedback inversion)——记录反而让重复更可能。两个可读的衍生读数:固定候选集{a×, 正确动作, 两个干扰项}上的归一化重复概率;贪心解码逐token复现率(打分时argmax已免费算出,零额外成本)。

分解设计——反事实观察:构造一个"无价态"观察o∅(承认调用发生但不说成败),与真实的o×(报失败)、反事实的o✓(报成功)形成对照:

  • Δcopy = 加入(a×, o∅)的效果 = 表面形式项(字符串在场本身)
  • Δsem = (a×, o×)相对(a×, o∅)的效果 = 语义项(被标记为失败的额外作用)
  • 恒等式:−G = Δcopy + Δsem

形式化的问题定义:给定决策点(C, a×, o×),测量G的符号;分解−G中Δcopy与Δsem的占比;进而回答——修复应在消息层(改报错措辞/加指令)还是结构层(改上下文构成/解码约束)?

这个抽象的精妙之处:把"harness工程问题"变成可分解、可反事实验证的测量问题,且所有条件共享同一成功前缀、仅在失败如何书写上逐字节可控地不同。

四、问题解法

4.1 探针物品构造:控制到字节级

每个probe item冻结一个决策点:系统提示+目标+成功的执行前缀+失败动作a×+运行时报错+本可成功的参考动作a✓。两个关键设计:

  • 失败动作固定而非采样:a×由a✓经固定扰动算子生成(丢必填参数、工具名复数化、参数改名、类型混淆、日期人写格式、幻觉实体……都是小模型真实犯的错)。若让各模型自己犯错,大模型的错更罕见更难,规模曲线会把模型大小与题目难度混在一起。固定算子保证每个模型被 probing 在逐字节相同的题目上。
  • 条件只差一件事:pre(无尝试,基线)/ fail(标准harness)/ succ(假报成功)/ neut(无价态确认)/ abstract(运行时生成的失败描述,调用本身缺席)。反事实成功观察由失败调用自己的参数生成,保证连贯性——防模型利用"不连贯线索"作弊。

4.2 两个环境:控制与真实的两端

  • ToolShed(自建模拟工具调用):12个类型化工具(文件/联系人/日历/消息/单位转换)+6任务模板;8种扰动算子→12类错误族。自建的理由:反事实分解需要同一动作配失败/成功/无价态三种观察,公开基准(BFCL、SWE-bench等)都只为打分设计、不为暴露反事实观察设计——手工改造恰恰会让实验者的预期泄漏进数据。
  • CodeRepair(MBPP程序修复):动作为整个Python函数,运行时在子进程中真实执行返回解释器输出。失败程序是参考解的单元编辑突变。此环境补上ToolShed够不着的体制:真实traceback会引用出错源码行——一种没人决定加、却自然出现在agent transcript里的表面形式回声。

4.3 干预家族:由分解推出的处方

  • verbatim:标准ReAct transcript
  • +instruction:verbatim+系统提示"别重复已失败的调用"(消息层处方代表)
  • abstract:失败调用替换为运行时从错误元数据生成的描述(如[attempt 1 failed: create_event, an argument was badly formatted; that call is not repeatable])——诊断保留,token序列消失,无额外模型调用
  • +ban:解码时把已失败字符串设为不可达(经典bad-words构造:仅当已生成前缀匹配被禁序列前缀时mask掉末token——mask首token会误杀修正后的调用,因为修正版通常与失败版共享长前缀)
  • drop:删除失败步骤、干净上下文重试(即上下文污染文献的标准处方,作为对照纳入)

4.4 免费rollout与统计

探针打分是teacher-forced、确定性的——不采样,无解码噪声,比特级可复现。自由rollout(Qwen2.5-0.5B在24个ToolShed任务贪心跑)检验结论能否存活。统计全部用按任务聚类的cluster bootstrap(10,000重采样),headline检验做Holm校正。KV cache前缀复用砍掉87%的重复编码。

五、评估指标与实验证据

指标体系:主指标G(corrective gain,nats);辅助读数为归一化重复概率(固定四动作候选集)与贪心逐token复现率;消融指标为Δcopy/Δsem分解、误差族分层、rollout的精确/规范化重复率与任务成功率。

测量1:反馈倒置普遍存在。ToolShed上6/6模型G为负且置信区间排除零:

模型G (nats)G/tokenΔcopyΔsem归一化重复率 前→后贪心复现 前→后
SmolLM2-135M−23.92−1.21+21.69+2.230.142→0.8750%→43%
SmolLM2-360M−18.62−0.93+16.08+2.540.117→0.7530%→41%
Qwen2.5-0.5B−13.91−0.94+9.91+4.000.013→0.6020%→3%
Qwen3-0.6B−21.50−1.47+18.25+2.780.006→0.2960%→0%
Llama-3.2-1B−12.41−0.92+9.42+3.260.009→0.2460%→0%
SmolLM2-1.7B−13.91−0.71+11.67+2.240.050→0.4760%→27%

汇总口径:平均−17.38 nats ≈ −1.03 nats/token(每token odds×2.8);90-100%的单个item为负;固定候选集重复概率0.06→0.54;贪心复现0%→19%。

测量2:是字符串,不是消息。Δcopy占损害的83%;copy:sem中位比7:1(工具调用)、61:1(程序修复,极端106:1)。语义项符号甚至跨环境不一致——ToolShed上略正(解释错误需重提工具名与参数),CodeRepair上略负(traceback确有推离作用但被淹没)。CodeRepair上G/token同为约−1.1~−1.2——同一量级从受控模拟和真实解释器两个方向汇聚,是"效应属于transcript组装方式而非特定环境"的最好证据。

测量3:消息工程几乎惰性,出现次数不惰性。

操纵(相对标准harness的配对变化,nats)SmolLM2-135MQwen2.5-0.5B
terse报错−0.32−0.23
verbose报错(显式给出正确参数名)−0.09−0.31
报错里引用失败调用+1.31+0.10
同一调用失败两次+3.06+3.61
失败三次+3.29+4.78
+“不要重复"指令+0.16(方向反了)−0.02
abstract化(去掉verbatim调用)−21.68−11.05

关键对照:verbose报错把该用的参数名都告诉模型了——信息量拉满,重复概率纹丝不动;而报错多引用一次失败调用(字符串第二次出现),重复概率显著上升。加信息没用,加第二份字符串有用——这是形式vs内容最锋利的分界证据。abstract化移除76%倒置并把贪心复现清零;连只留[attempt 1 failed]无任何诊断的极简版都恢复−18.62 nats——起作用的是字符串缺席,不是措辞精妙。

测量4:free rollout验证处方排序(Qwen2.5-0.5B,24任务):

harness成功率精确重复率死循环率
verbatim(标准)42%31%29%
+instruction58%24%17%
abstract33%16%8%
drop(清空重试)33%80%67%
verbatim+ban42%8%12%
abstract+ban33%7%4%

排序与分解预测完全一致:作用于表面形式的干预占好的一端,删掉失败的drop占最差端,标准harness居中。drop把重复率从31%炸到80%——确定性策略在相同上下文发出相同动作,清空不是修复而是保证复读。论文诚实报告的边界:表面形式干预均未提升任务成功率(0.5B模型18%的失败是"该调工具却输出散文"的能力瓶颈,harness治不了);instruction提成功率+17pp但不降重复(作用于别的东西,作者拒绝过度解释)。

六、效果优势的根源解释

为什么标准harness必然倒置、为什么处方按机理分层有效?因果链如下。

标准harness的机制病灶:transcript追加(a×, o×)后,induction heads等复制机制(为in-context learning而生、无法关闭)对a×的token序列产生强拉力;而"断言失败"只是文本层面的弱信号。两者在每一token的对数几率上竞争,竞争结果由分解给出——7:1到61:1,复制完胜。这不是模型"不理解”:语义项在程序修复场景确实为负(读是读了的),只是被表面项碾压。注意"复制 indiscriminately抬高一切"的反对意见不成立:正确动作概率也升(+4.30 nats),但gold−failed的margin缩小−13.12 nats——复制专占优势的错误动作,因为被写下来的恰恰是它。

处方的因果匹配:

abstract有效:从上下文移除a×的token序列 → 复制机制失去目标 → Δcopy项消失(76%倒置移除、贪心复现清零)→ 诊断信息保留,模型知道该换什么而非只是换个字符串

decoder ban有效:即使上下文仍有a×,解码时其末token被mask → 复制拉力再强也无法兑现 → rollout精确重复31%→8%、死循环29%→12%,canonical率同步下降(不是换措辞绕开)

两者互补而非冗余:abstract去掉的是复制机会,去不掉重新推导——goal、schema、成功前缀都还在,它们当初就是这么推出错误调用的;ban则挡住重新推导的兑现。实测abstract下ban仍在约一半数量的解码步上触发;叠加后重复率7%、死循环4%,全表最优

instruction无效:负向指令要求模型对"就在眼前的字符串"维持一个否定表示——恰是负向指令已知最失效的条件(命名被禁物抬高其概率)。probe +0.07 nats(方向反),rollout重复率24%对31%区间含零

drop最糟:删除失败步骤 → 上下文回到失败前的逐字节状态 → 确定性策略在同一上下文发出同一动作 → 重复率80%。它违反了修复的必要条件:失败后的上下文必须不同于失败前,且差异不能是失败动作本身——verbatim用失败动作改变上下文(拉回),drop不改变上下文(原地),abstract/ban用非失败字符串或解码约束改变行为(有效)

规模趋势的正确读法:家族内更大checkpoint的G更温和(SmolLM2从−23.9到−13.9),且随规模减弱的是Δcopy而非Δsem——“更大的模型复制更少,不是读错误更好”。作者明确拒绝外推零点(留一法重拟合让交点在20B-79B间晃,因子3.8全由恰好买得起哪6个checkpoint决定),把"8B上是否消失"标记为几百次前向就能回答的便宜问题。

七、必要知识反推

领域知识层:

  • agent循环的transcript组装方式(式(1):C_{t+1}=C_t⊕(a_t,o_t))——识别出这是"本文要研究的设计决定"而非自然律,需要读过ReAct以来的框架实现
  • LLM的复制机制(induction heads、重复自增强)与负向指令文献——它们分别预测了Δcopy的主导地位和instruction的失效,是分解设计的理论先验

方法论知识层:

  • 反事实分解:构造无价态观察o∅切断"在场"与"断言失败"的混淆——这是全文的方法论支点
  • teacher-forced测量:不采样直接打分,无解码噪声、可复现,且贪心argmax免费获得
  • 固定扰动算子保证跨模型题目逐字节一致——规模声明的前提
  • 配对比较(同item同条件族内对比)消掉题目难度这个最大方差源
  • cluster bootstrap、Holm校正等统计卫生
  • 控制实验的对照设计:安慰剂(别的调用失败)、中性参考的长度匹配、极简abstract(排除"措辞好"的解释)

工程知识层:

  • KV cache前缀复用(省87%编码)、float32 CPU推理的可行边界(17GB RAM卡住1.7B以上)
  • 解码级约束实现(bad-words mask仅作用于完成token的细节)
  • 可复现性工程:单一基种子派生命名子流、原始分数落盘、正文数字由记录生成而非手打、NaN数值故障的断言防护(这个"多线程PyTorch静默返回全NaN"的教训本身就有通用价值)

知识融合的关键节点:最关键的化学反应是把"复制机制+负向指令"这两条纯生成领域知识,翻译成agent场景的可测量分解——前者预测了哪个项会赢,分解验证了预测,预测又规定了干预的靶点。其次是把harness当成实验对象而非实验环境:同一模型、同一环境、同一任务,只拧"失败如何被书写"这一个旋钮。最后是诚实的负面结果报告:干预不提成功率就直说(18%散文失败是模型瓶颈),指令提成功率但不降重复也直说并拒绝解释——这种克制恰恰让机制结论更可信。

八、论文中可以提取的通用性灵感

灵感1:净效应分解——任何"默认设计"都应做反事实归因

  • 核心思想:一个操作的净效果往往是两个反向机制的加和;不拆开测量就会把处方开错。
  • 论文证据:失败记录=复制拉力(83%)+语义推力(17%),净效应为负但病因在复制;清空上下文的处方只看了净效应,结果成为最差干预。
  • 推广场景:警示标签是否反而提升风险行为的显著性;代码评审评论对后续行为的净效应分解;推荐"撤回"按钮对流传播的分解;医学副作用通报的服从性分析。

灵感2:结构修复优先于语义劝说——当载体本身是病灶

  • 核心思想:若危害由信息的物理存在(字符串/信号/刺激)携带,则任何关于它的措辞工程都无效,必须改结构(移除载体或使其不可达)。
  • 论文证据:verbose报错(信息最全)与terse报错均区间含零;报错引用原调用(多一份字符串)+0.71 nats;abstract与ban(结构手段)立竿见影。
  • 推广场景:戒瘾环境设计(移除触发物优于告诫);防错设计(物理互锁优于警示语);敏感信息脱敏而非加密提示词。

灵感3:确定性系统里"清空重试"=保证复读——差异必须被制造

  • 核心思想:确定性策略在同一上下文产生同一输出;重试要有意义,上下文必须与产生失败的上下文不同,且差异不能是失败物本身。
  • 论文证据:drop harness重复率80%(标准31%),因为精确复原了失败现场;这条必要条件(上下文须变且变得不是失败动作)统一解释了全部六种harness的排序。
  • 推广场景:搜索算法的tabu列表设计;调试时"再跑一遍"前的环境扰动注入;自动化流水线重试的任务变形策略。

灵感4:把测量做到"每token一nat"的可迁移单位

  • 核心思想:跨环境/跨系统的比较需要找到与规模无关的归一化单位,两个独立环境汇聚到同一数值是最强的普适性证据。
  • 论文证据:工具调用与程序修复的G/token都落在约−1.03~−1.2 nats——同一效应从受控模拟与真实解释器两端汇聚。
  • 推广场景:UI设计的错误率按"每交互步"归一;教育干预按"每学习小时"标准化;跨语言系统的性能按每token/每事务规范化。

灵感5:便宜的诊断先于昂贵的评估

  • 核心思想:把昂贵的行为评估压缩成几百次前向就能算的分布级探针指标,让机制研究平民化(本文全程一台CPU笔记本完成)。
  • 论文证据:probe(teacher-forced打分)比rollout便宜三个数量级,且与rollout在所有共同比较上一致;作者明确把"probe能否跨模型预测loop倾向"列为第一个后续实验。
  • 推广场景:用小规模A/B探针代替全量上线;编译器fuzzing先于端到端测试;单元测试级的回归检测代替集成级。