你的AI Agent为什么总在“来回改“?一次真实实验给出的答案 ——融合控制工程PID的Harness实践
文章目录
- 你的AI Agent为什么总在“来回改“?一次真实实验给出的答案 ——融合控制工程PID的Harness实践
- 从真实实验说起
- 结果一览
- 1. 你的Agent迭代系统,其实就是一个反馈控制系统
- 2. 一个实证发现 + 两个理论预测
- 实证发现:无反馈重试会振荡退步(有数据支撑)
- 已验证发现2:激进反馈/强模式更容易退步 ✅ 实验B1数据
- 已验证发现3:间隔反馈省50%评估成本 ✅ 实验B2数据
- 3. PID控制:精确反馈是核心,PID提供系统化框架
- 真实实验中的PID计算
- PID控制信号如何映射到Prompt
- T3中PID增强模式的实际反馈内容
- 4. Lyapunov监控:什么时候该停下来
- 5. 实战Quick-Start:什么时候该用PID增强模式
- 基于真实实验的选择指南
- 判断你的任务是否需要PID增强模式
- 完整PID增强模式实现
- 6. 实验局限性(诚实声明)
- 常见坑
- 坑1: 无脑重试——"再跑一次说不定就好了"
- 坑2: 反馈不精确——"请改进代码"
- 坑3: 过度工程——简单任务上硬套PID
- 总结:精确反馈是核心,PID提供系统化框架
- 参考
你是不是遇到过这些情况?
- 让Agent迭代优化代码,改了4轮反而中间比第2轮更差?
- 无反馈重试时,模型"随机发挥"引入新Bug,分数断崖下跌?
- 想加个"连续N轮没提升就停"的规则,但不知道阈值怎么设?
如果你点头了,这篇文章就是写给你的。
这不是假设,是我们刚刚跑出来的真实数据:
LRU Cache任务(10个测试用例)——简单重试的分数轨迹: Round 1: 7/10 Round 2: 8/10 ← 有改善 Round 3: 4/10 ← 断崖退步!popitem方向改反了 Round 4: 10/10 ← 终于蒙对了第3轮从8/10退步到4/10。模型没有收到任何反馈,独立重新生成了代码,结果引入了更多Bug。这种"振荡退步"不是概率事件——它是无反馈重试系统的结构性缺陷。
而同样的任务,使用PID增强模式(精确反馈+控制信号),轨迹是这样的:
Round 1: 7/10 Round 2: 10/10 ← 一步到位精确反馈告诉模型"T3/T7/T10失败是因为get()未更新访问顺序,同时验证put()的recency更新"——模型一次性修复了所有关联Bug。
本文基于我们2026年5月的真实对比实验,分享一套经过初步验证的方法论:用精确反馈+PID控制让迭代收敛更快,同时诚实说明它的适用边界和局限。
从真实实验说起
我们设计了3个编程任务的对比实验,测试三种迭代策略:
| 策略 | 方法 |
|---|---|
| 简单重试 | 每轮独立重新生成,不提供任何上轮信息 |
| Self-Refine | 给上轮代码+“请改进”,不给具体失败信息 |
| PID增强模式 | 精确失败用例+root cause分析+控制信号调节反馈强度 |
实验环境:Generator和Evaluator均为Claude,测试用例为确定性Python单元测试(pass/fail),PID参数 Kp=0.6, Ki=0.2, Kd=0.15。
结果一览
| 任务 | 难度 | 测试数 | 简单重试 | Self-Refine | PID增强模式 |
|---|---|---|---|---|---|
| T1: 合并有序链表 | 简单 | 5 | 1轮通过 | 1轮通过 | 1轮通过 |
| T2: 螺旋矩阵 | 中等 | 10 | 2轮通过 | 2轮通过 | 2轮通过 |
| T3: LRU缓存 | 困难 | 10 | 4轮(振荡) | 3轮 | 2轮 |
关键发现:简单任务(T1、T2)三种策略完全无差异。只有在复杂多Bug任务(T3)上,PID增强模式的优势才显现出来。
1. 你的Agent迭代系统,其实就是一个反馈控制系统
把你的Generator-Evaluator架构画成框图,和经典控制系统一一对应:
| 控制系统概念 | Agent系统对应 |
|---|---|
| 参考输入 r(t) | 任务目标/评估标准(“通过全部10个测试用例”) |
| 控制器 C(s) | Evaluator的反馈策略(如何组织critique) |
| 被控对象 G(s) | Generator(LLM本身) |
| 输出 y(t) | 生成的代码 |
| 误差 e(t) | (目标通过率 - 当前通过率) / 目标通过率 |
| 反馈通道 H(s) | 测试用例执行结果 |
关键洞察:你的系统是一个离散时间闭环反馈系统。每一轮迭代就是一个采样周期。控制论的工具——增益调节、稳定性分析——可以直接应用。
传统做法(简单重试)相当于没有反馈通道——每轮独立生成,系统是开环的。Self-Refine有反馈但不精确——相当于传感器精度不够。PID增强模式提供精确反馈+增益控制——这才是完整的闭环控制系统。
2. 一个实证发现 + 两个理论预测
实证发现:无反馈重试会振荡退步(有数据支撑)
在T3(LRU缓存)实验中,简单重试策略的轨迹为7→8→4→10。第3轮从8/10暴跌到4/10,原因是:
Round 2: 使用OrderedDict, 修好了get的move_to_end, 但put更新时遗漏 → 8/10 Round 3: 重新独立生成, 用了dict+时间戳方案, popitem(last=True)方向错误 → 4/10没有反馈意味着每轮都是"从零开始赌运气"。模型可能换一个实现方案,而新方案引入的Bug比旧方案更多。这不是模型不够强的问题,是系统设计的问题。
对比之下:
- Self-Refine保留了上轮代码作为参考,轨迹7→8→10,单调递增无振荡
- PID增强模式给出精确失败信息+预防性提示,轨迹7→10,一步到位
已验证发现2:激进反馈/强模式更容易退步 ✅ 实验B1数据
实验B1在LRU缓存任务上对比了两种模式:
普通模式(精确修改指令):40→80→100→100→100 单调收敛,0次退步 激进模式(要求彻底重写):40→50→90→100→90 出现退步,R5从100跌到90激进模式要求"彻底重写所有相关代码",结果模型放弃了已经正确的实现,引入新Bug。这就像方向盘太灵敏——轻轻一动就打满舵,车就蛇形走位。
实践建议:用更强模型或更激进的prompt时,必须降低反馈增益(用更温和的修改指令)。
已验证发现3:间隔反馈省50%评估成本 ✅ 实验B2数据
实验B2在TTLCache任务上对比了每轮反馈(N=1)和隔轮反馈(N=2):
N=1(每轮反馈):8次评估,第3轮收敛到100% N=2(隔轮反馈):4次评估,第3轮收敛到100%同样的收敛速度,但N=2只用了一半的评估调用。Generator在没有新反馈的轮次继续消化上一轮的修改建议,效果不打折。
实践建议:当评估成本高(人工评审或昂贵API调用)时,间隔反馈是有效的成本优化策略。
3. PID控制:精确反馈是核心,PID提供系统化框架
我们的实验表明,PID增强模式的真正优势来自两个层面:
- 精确反馈:告诉模型具体哪些测试失败、为什么失败、关联Bug是什么
- 系统化框架:PID控制信号决定反馈强度级别,避免"每次都全力重写"
真实实验中的PID计算
T3第1轮结束后的PID计算:
# 实际实验参数target=1.0# 目标:100%通过率score=0.7# 当前:70%通过率 (7/10)e=target-score# e = 0.30integral_e=0.30# 首轮,积分等于当前误差delta_e=0.30# 首轮,变化量等于当前误差# PID计算Kp,Ki,Kd=0.6,0.2,0.15u=Kp*e+Ki*integral_e+Kd*delta_e u=0.6*0.30+0.2*0.30+0.15*0.30u=0.18+0.06+0.045u=0.285# light intensity(轻度修改)u=0.285 意味着什么?系统判断只需要"轻度修改"而非重写。这个信号决定了反馈的语气和要求强度。
PID控制信号如何映射到Prompt
defphi_map_to_prompt(u,failed_tests,diagnosis,original_output):""" 将控制信号u映射为不同强度的反馈prompt u < 0.3: 轻度修改——保留主体,修复具体Bug u 0.3~0.6: 中度修改——重构问题部分 u > 0.6: 重度修改——考虑换方案 """ifu<0.3:# light — 实验中T3的情况returnf"""上一版本整体框架正确,只需修复具体Bug: 失败用例:{failed_tests}根因分析:{diagnosis}修复建议:针对性修改,同时检查是否有关联的相似Bug。 保留原有架构,仅修改有问题的方法。"""elifu<0.6:returnf"""上一版本有结构性问题需要修改: 失败用例:{failed_tests}根因分析:{diagnosis}请重构问题部分,但保留正确的逻辑。"""else:returnf"""上一版本问题较多,建议换实现方案: 失败用例:{failed_tests}根因分析:{diagnosis}考虑使用不同的数据结构或算法。"""T3中PID增强模式的实际反馈内容
这是实验中第1轮后发给Generator的精确反馈:
u = 0.285 (light intensity) Failed: T3 (got 2, expected -1), T7 (got 3, expected -1), T10 (got 1, expected -1) Diagnosis: get() does not update access order. - T3: After get(1), key 1 should be most recent, key 2 should be evicted - T7: After get(1),get(2), key 3 is LRU and should be evicted - T10: After get(2), key 1 is LRU and should be evicted Action: Add move_to_end in get(). Also verify put() for existing keys updates recency.注意最后一句"Also verify put() for existing keys updates recency"——这是PID增强模式的预防性提示。它基于root cause分析推断出:如果get()遗漏了move_to_end,put()更新现有key时很可能也遗漏了。
正是这个预防性提示让模型一次性修复了两个关联Bug——而Self-Refine(没有这个提示)花了两轮才分别修复它们。
4. Lyapunov监控:什么时候该停下来
迭代系统还有一个经典问题:什么时候该停?
用T3简单重试的数据来说明问题——轨迹 7→8→4→10:
deflyapunov_monitor(scores,target=10):""" V(i) = 0.5 * (target - score)^2 —— "不满意程度" ΔV = V(i) - V(i-1) ΔV < 0: 系统在改善 ΔV > 0: 系统在恶化 """V=[0.5*(target-s)**2forsinscores]foriinrange(1,len(V)):delta_V=V[i]-V[i-1]status="改善"ifdelta_V<0else"恶化⚠️"print(f"Round{i+1}:{scores[i]}/10, ΔV={delta_V:.1f}({status})")# 简单重试轨迹lyapunov_monitor([7,8,4,10])# Round 2: 8/10, ΔV=-2.5 (改善)# Round 3: 4/10, ΔV=16.0 (恶化⚠️) ← 严重退步!# Round 4: 10/10, ΔV=-18.0 (改善)# Self-Refine轨迹lyapunov_monitor([7,8,10])# Round 2: 8/10, ΔV=-2.5 (改善)# Round 3: 10/10, ΔV=-2.0 (改善) ← 单调收敛如果在Round 3看到ΔV=+16.0这样的剧烈恶化,Lyapunov监控会触发WARNING。配合PID控制,此时应该:
- 降低控制增益(避免过度修改)
- 或切换为带反馈的模式(别再盲目重试了)
5. 实战Quick-Start:什么时候该用PID增强模式
基于真实实验的选择指南
| 场景 | 推荐方案 | 理由(实验支撑) |
|---|---|---|
| 简单任务(首轮>70%通过) | 直接生成或Self-Refine | T1/T2数据:三策略无差异,PID的overhead不值得 |
| 复杂多Bug任务 | PID增强模式 | T3数据:2轮 vs 3轮 vs 4轮(含振荡) |
| 需要避免退步 | PID增强模式或Self-Refine | T3数据:带反馈的策略不会振荡退步 |
| 多Agent系统 | 待验证 | 未测试,已从skill功能中移除 |
| 不知道何时停 | Lyapunov监控 | 比"3轮没提升就停"更精确,能检测退步 |
如果你希望把这套方法直接接到 Codex 的工作流里,我把实验里的判断逻辑整理成了一个可复用的 Skill:harness-design。它做的不是"每个任务都强行上PID",而是先用 Generator-Evaluator 跑出首轮结果:简单任务走普通迭代;复杂多Bug、出现退步或需要控制反馈强度时,再自动升级到PID增强模式。这也正是本文反复强调的工程边界:先评估,再决定反馈力度。
判断你的任务是否需要PID增强模式
defshould_use_harness_pid_mode(first_round_pass_rate,num_distinct_bugs,has_correlated_bugs):""" 基于实验观察的决策函数 """iffirst_round_pass_rate>=0.7:return"不需要 — 简单重试或Self-Refine就够"ifnum_distinct_bugs<=1:return"Self-Refine够用 — 单Bug类型不需要root cause分析"ifhas_correlated_bugs:return"推荐PID增强模式 — 精确反馈+预防性提示能一次修复关联Bug"return"Self-Refine或PID增强模式均可"完整PID增强模式实现
classPIDHarness:def__init__(self,generator,evaluator,target=1.0,Kp=0.6,Ki=0.2,Kd=0.15,max_rounds=8):self.generator=generator self.evaluator=evaluator self.target=target self.Kp,self.Ki,self.Kd=Kp,Ki,Kd self.max_rounds=max_rounds self.scores=[]self.integral_e=0.0defrun(self,task):output=self.generator(task)# 首轮无反馈forround_iinrange(self.max_rounds):score,failed_tests,diagnosis=self.evaluator(output)self.scores.append(score)ifscore>=self.target:print(f"[Round{round_i+1}] 达标:{score:.0%}")break# PID计算e=self.target-score self.integral_e+=e delta_e=eiflen(self.scores)<2else((self.target-self.scores[-1])-(self.target-self.scores[-2]))u=max(0.0,min(1.0,self.Kp*e+self.Ki*self.integral_e+self.Kd*delta_e))# Lyapunov监控iflen(self.scores)>=3:V=[0.5*(self.target-s)**2forsinself.scores]ifV[-1]>V[-2]andV[-2]>V[-3]:print(f"[Round{round_i+1}] Lyapunov STOP: 连续恶化")break# Phi映射 + 生成prompt=phi_map_to_prompt(u,failed_tests,diagnosis,output)output=self.generator(task,feedback=prompt)returnoutput,self.scores6. 实验局限性(诚实声明)
在你决定在生产环境中使用PID增强模式之前,你需要知道这些局限:
| 局限 | 说明 |
|---|---|
| 样本量极小 | 仅3个编程任务,每个只跑1次。无统计显著性。 |
| 仅1个任务显示差异 | T1/T2完全无差异,只有T3(复杂多Bug)看到了优势 |
| Generator和Evaluator是同一模型 | Claude既生成又评估(虽然评估是确定性测试用例) |
| 仅测试了编程任务 | 写作、设计等任务未测试 |
| 多Agent场景未验证 | 未测试,已从harness-design skill功能中移除 |
| PID参数未调优 | 使用"推荐"默认参数,未验证是否最优 |
| k_G估计流程未实测 | Skill中描述的灵敏度估计方法未在实验中使用 |
我们能确信的结论:
- 精确反馈(具体失败用例+root cause)比模糊反馈(“请改进”)有效
- 无反馈重试在复杂任务上会振荡退步
- PID提供了一个系统化的框架来组织反馈,但它的数学公式本身不是魔法
我们不确信的:
- PID是否在所有任务类型上都优于精心设计的Self-Refine
- 最优PID参数是多少(可能因任务而异)
- 强模型是否真的比弱模型更不稳定
常见坑
坑1: 无脑重试——“再跑一次说不定就好了”
症状:代码任务通过了8/10测试,不给任何反馈就再跑一轮,结果变成4/10。
真实数据:T3简单重试策略,Round 3从8/10退步到4/10。原因是模型换了实现方案(从OrderedDict换成dict+时间戳),新方案的popitem方向搞反了。
解法:至少给Self-Refine级别的反馈(保留上轮代码+告知通过率)。如果任务有多个关联Bug,升级到PID增强模式的精确反馈。
坑2: 反馈不精确——“请改进代码”
症状:每轮只修复一个Bug,需要3+轮才能全部修完。
真实数据:T3 Self-Refine策略,Round 2修好了get()的move_to_end但遗漏了put()的相同问题。因为反馈只说"8/10,请改进",没有指出"put更新现有key时也需要move_to_end"。
解法:在反馈中附带root cause分析和预防性提示。PID增强模式的"Also verify put()"就是这种预防性提示的例子。
坑3: 过度工程——简单任务上硬套PID
症状:花了很多时间配置PID参数、设计反馈模板,最后发现直接跑就能一次通过。
真实数据:T1(合并有序链表)和T2(螺旋矩阵),三种策略表现完全相同。LLM首轮就能做对或一轮修复的任务,不需要控制论加持。
解法:先跑一轮看首轮通过率。>70%通过就别折腾了。
总结:精确反馈是核心,PID提供系统化框架
基于真实实验,我们能说三件事:
精确反馈显著优于无反馈或模糊反馈——在复杂多Bug任务上,精确的失败信息+root cause分析+预防性提示让模型一次修复关联Bug(2轮 vs 4轮)。
PID控制信号提供了结构化的"反馈强度"决策框架——u=0.285告诉你"轻度修改就够",避免了每次都"请大幅重写"的冲动。但诚实说,目前实验中PID数学公式的贡献可能不如"精确反馈内容"本身大。
简单任务不需要这些——先评估再决定。首轮通过率>70%的任务,Self-Refine甚至直接重试就够了。
下次你的Agent系统出现振荡时,不要急着换模型、加重试。先问自己:你给了模型精确的反馈吗?它知道具体哪里错了、为什么错、还有哪些关联的坑吗?
这是工程思维,也是实验结论。
参考
- Tsien, H.S. (1954).Engineering Cybernetics. McGraw-Hill.
- Madaan, A. et al. (2023). Self-Refine: Iterative Refinement with Self-Feedback.NeurIPS.
- Shinn, N. et al. (2023). Reflexion: Language Agents with Verbal Reinforcement Learning.NeurIPS.
- An, S. et al. (2018). PID Controller Approach for Stochastic Optimization of Deep Networks.CVPR.
- Zheng, L. et al. (2023). Judging LLM-as-a-Judge with MT-Bench and Chatbot Arena.NeurIPS.
- AICE: AI Control Engineering — 将经典控制理论应用于LLM迭代优化的系统框架.