087|SWE-agent:模型不会稳定修代码,问题可能也在工具接口
论文:John Yang、Carlos E. Jimenez 等,SWE-agent: Agent-Computer Interfaces Enable Automated Software Engineering,2024。采用原文 v3;代码及配置见官方项目。实验对应文中模型快照和当时 API 价格,不能作为当前产品性能或报价。
图表来源:John Yang、Carlos E. Jimenez 等,2024,原文;CC BY 4.0。本篇展示做了PNG格式转换,图中数据与标签未改动。
先接住前作的问题
SWE-bench给出仓库修复任务,ReAct提供观察与动作交替的方式。问题是原始终端输出和编辑操作对模型并不友好;本篇把接口本身变成可消融对象,检验固定权重下如何少犯操作错误。
五个前置概念
五个前置概念:ACI定义代理可做什么与能看到什么;ReAct交替生成推理、行动与观察;补丁表示仓库前后差异;回归测试检查既有行为未受破坏;Pass@K统计 K 次尝试中至少一次成功,区别于自动选出正确结果。
一、问题设定:模型懂代码却操作失败时,接口怎样影响修复轨迹
输入历史仓库和问题描述,输出补丁,最终由独立测试判定。代理要自行定位、理解、修改与验证;它是交互软件环境中的单代理推理,没有在线RL更新,接口改变的是有限预算内可能走到的轨迹。
可以借用强化学习语言描述:仓库和执行环境构成状态,代理看到的只是部分文件及命令反馈,动作包括搜索、编辑和执行,终止来自主动提交或预算耗尽。但终局测试得分是评估指标,不是这篇论文用于训练策略的奖励信号。
与 SWE-bench 原始 RAG 基线相比,代理能够主动改变工作目录里的代码并得到执行反馈。与 Shell-only 相比,关键差异是怎么表达操作,以及操作后返回什么。它保留普通 shell 作为底层能力,新增的动作不是把计算机功能重新实现一遍,而是提供更易组合的语义操作。
二、把动作解析、观察窗口和历史管理写入固定策略条件
搜索:先给全局摘要,再局部阅读
find_file 搜索文件名,search_dir 与 search_file 搜索内容。结果控制在 50 条以内,超过时要求缩小查询,而不是截取最前面的若干条假装已经全面呈现。
这个细节改变代理行为:如果只提供“下一条匹配”,模型可能不断翻页,直到预算耗尽。摘要式结果让它先比较候选位置,再决定读哪个文件。它仍可能遗漏正确结果,但减少了机械遍历的交互成本。
阅读与编辑:共享行号和即时状态
文件查看器一次呈现最多 100 行,并附路径、总行数、上下文省略范围和每行行号。goto 与滚动命令改变窗口;edit 接收起止行和替换文本,与查看器共享坐标。
编辑完成后自动显示新内容。对选定的严重 lint 错误,系统拒绝变更,展示错误及前后片段,要求重试。这里检查的是语法等局部约束,不能证明业务逻辑正确。成功通过 lint 只是允许后续执行测试的最低门槛。
一次拒绝编辑,怎样改变后续整个状态空间?
把编辑前仓库记为 ,候选替换记为 ,暂时应用后的仓库记为 ,检查器 返回接受或拒绝。接口执行的事务可抽象为
失败反馈仍会进入模型上下文,但实际文件保持 。这使下一次修订是在已知旧状态上重试,避免“模型以为改了一半、文件实际坏了一半”的不一致。这是教学形式化,不是论文训练的转移模型。检查器只覆盖指定lint错误,接受并不代表补丁满足issue。
原创教学轨迹。 第一次替换第40–43行时漏写冒号,工具拒绝并显示原文件与错误。第二次应仍针对原40–43行,而不能把未提交的新增两行算进去,改成40–45行。若第二次语法通过却把空列表返回值写成字符串,文件会提交,但后续类型相关测试仍可失败。因此“自动反馈”至少包含事务反馈、语法反馈和行为反馈三个不同层次。
原文表3的“有编辑无lint”15.0%与完整18.0%是对这一接口组件的经验检验;它并未分别隔离回滚、错误消息措辞和自动回显的贡献。另一方面,合法重构的中间态若暂时触发检查器,严格拒绝也可能增加操作难度,所以接口约束既能防错,也能限制可达路径。
历史:保留决策轨迹,压缩陈旧观察
模型每轮输出思考和命令。格式错误会收到明确反馈;命令成功但没有标准输出时也给出说明。超过最近五条的环境观察被折叠,避免旧版本代码持续占据上下文。
这不等于删除所有历史。代理仍需要知道做过哪些操作及为什么做。压缩观察可能丢掉后续有用信息,因此设计必须在陈旧内容与可追溯性之间取舍。
用一个公式说明:优化对象不是模型权重
下面是教学形式化,不是论文提出的新损失函数。令接口 负责生成观察、动作解析与历史表示,固定模型策略为 :
是仓库和运行环境, 是面向模型的上下文整理, 是包括编辑校验在内的操作执行。即使 不变,改变 也会改变轨迹分布。
系统设计追求的是预算 下的成功率:
论文通过开发集观察和配置搜索改进接口,没有对上式求梯度。数学目标、系统机制和指标由此分开:目标是预算内成功,机制是工具与反馈设计,实测指标是 Resolved 和费用。
流程是 §3 与附录 A 的教学改写。独立评估测试不能偷偷作为无限次可查询的验证器,否则问题设定已经改变。
把编辑拒绝视为一次明确的状态转移
编辑校验失败后,下一观察应指向仍保留的旧文件,而不是模型原本打算提交的新内容。可在执行前后对文件求摘要:被拒操作应保持原内容,被接受操作才改变。否则代理会基于不存在的修改继续测试,无法判断失败来自补丁语义、工具执行还是上下文记录。
教法联系:Lilian Weng的LLM Powered Autonomous Agents。算例为本文自构。
三、执行搜索、编辑校验和独立测试的工作循环
假设问题是空列表输入导致统计函数异常。代理先搜索函数名,在 100 行窗口内看到 total / len(values),添加空列表分支,随后自动看到新代码。若缩进错误,编辑被拒绝并指出行号,原文件保持可执行;若缩进正确但返回类型错误,lint 不会解决问题,需要运行正常输入和空输入测试。
输入:问题描述、仓库历史版本、固定语言模型、费用上限
初始化:容器环境、工具文档、示范、空交互历史
while 未提交且费用未耗尽:
组织系统说明、问题、行动历史及最近观察
模型生成思考和一个动作
若格式错误:反馈错误并要求重新生成
若搜索:输出简洁匹配摘要;过多则提示缩小范围
若查看:显示带行号与省略范围的文件窗口
若编辑:执行检查,严重错误则撤销,否则显示新窗口
若运行命令:返回执行结果或明确的无输出说明
压缩过旧的环境观察
预算耗尽或 submit:从仓库变更生成补丁
独立评估:应用补丁,运行基准指定测试
四、在相同后端下比较ACI组件与反馈预算
差异为 7 个百分点,约 63.6% 相对提升。
先比较同后端与相同示范,再看编辑和信息量消融;Pass@K扩大覆盖不等于系统已经知道该交付哪个补丁。
| 项目 | 原文设置 | 解释与边界 |
|---|---|---|
| 仓库任务 | SWE-bench 全集 2294 题、12 个 Python 仓库;Lite 300 题 | Lite 侧重较独立的功能修复,不能代替全部真实开发 |
| 底层模型 | GPT-4 Turbo gpt-4-1106-preview;Claude 3 Opus claude-3-opus-20240229 |
不重新训练;模型版本属于复现条件 |
| 对照 | BM25 RAG 一次生成补丁;Shell-only 交互代理 | RAG 对照同时少了反馈与多轮计算;Shell 对照更接近接口消融 |
| 预算 | 每实例 API 费用上限 4 美元,超过后自动提交已有编辑 | 历史价格下的限制;不是固定 token 数或固定墙钟时间 |
| 配置选择 | 开发集行为检查;窗口、历史处理、温度搜索 | 需要计入系统开发与调参,不能把最后配置称为免调参 |
| 重复性 | Lite 额外运行 6 次;表10 报均值和离散程度 | 全集主结果与各消融不能假定都做了相同次数重复 |
| 短代码修复 | HumanEvalFix,每语言 164 题,提供单文件及可用示例测试 | Python、JS、Java 的高分不等同于仓库导航能力 |
依据 §4、附录 B.1、B.5、B.7。论文的 $ Avg. Cost 按成功解决的实例平均推理费用,而非所有成功失败尝试的总费用除以成功数。部署时真正的“获得一个成功修复需要多少钱”还要把失败尝试计算进去。
测试通过不等于补丁覆盖所有需求。代理自己编写的复现脚本可能过窄,独立测试也可能遗漏边界。闭源预训练数据不可见,按问题年份做分析只能寻找污染线索,不能证明不存在泄漏。
证据一:表1,交互及 ACI 均有增益。 GPT-4 Turbo 的全 SWE-bench 成绩为 286/2294,即 12.47%;其 RAG 基线为 1.31%。但两者计算和反馈不同。Lite 上 ACI 18% 对带示范 Shell-only 11% 才更直接体现接口改进。若与不带示范的 Shell 7.33% 比,会得到 10.67 个百分点,必须注明示范也发生了变化。
证据二:表3,编辑与即时校验降低无效操作。 完整系统 18%,保留编辑但移除 lint 为 15%,移除专用编辑为 10.3%。这支持整合式编辑与错误拦截有价值。它不能证明 lint 会发现语义错误,也不意味着所有编程语言都具有同样的检查器收益。
证据三:表3,更多信息和更多操作并非总是更好。 100 行窗口为 18%,30 行为 14.3%,整文件为 12.7%;摘要式搜索为 18%,逐条搜索为 12%,不提供专用搜索为 15.7%。机制解释是信息粒度影响定位和预算,但这些数字仅验证被测模型与任务,并非“100 行永远最优”的定律。
证据四:表10 与图4,多次尝试扩大覆盖。 六次独立运行的单次成功率均值为 17.94%,表中离散量为 0.49;Pass@6 达 32.67%。这表示六条轨迹中存在成功补丁的比例上升,不代表系统已有一个无成本、准确选择成功补丁的方法。 横轴 k 表示允许的尝试数,纵轴是至少一次通过的覆盖率;该图不包含现实中自动选出正确补丁的保证。

证据五:§5.2 与附录 B.4,错误恢复仍是瓶颈。 全集 51.7% 轨迹至少经历一次失败编辑。未解决实例中,自动分类约 52% 属于实现错误或过于特定的实现,23.4% 属于编辑恢复失败。这些类别由模型自动标注,应当作为行为分析线索,而非人工核验的精确因果分解。
表2 的 HumanEvalFix 成绩分别是 Python 87.7%、JS 89.7%、Java 87.9%;其约 88.3% 的跨语言平均值与 Python 单项要分开。单文件中无需大规模定位,所以高分不抵消仓库级任务的低成功率。
五、局部检查与多次覆盖仍不能替代最终选择
这个例子说明三层不同责任:接口保证编辑可表达,检查器拦截局部错误,测试检验行为。任何一层都无法代替完整需求理解。
它没有提出新的 Transformer,也没有以更大训练集解释全部差异。贡献在于固定模型条件下,接口可以成为可实验、可消融的能力来源。
费用是实质代价。Lite 成功实例的平均费用为 1.67 美元,而同模型 RAG 为 0.13 美元;不能只展示成功率倍数而隐藏交互成本。预算受价格影响,不同模型用相同美元并不表示拥有相同 token 或思考轮数。
作者观察到成功任务往往较快结束,失败任务拖得更久。这是相关关系:困难任务导致更长轨迹,不能据此推断“强制早停会提升成功率”。安全地利用这个规律需要验证可在线识别的失败信号及重新开始策略。
接口还有适用边界。基于行号的编辑在并行变更和陈旧观察下会错位;严格 lint 有时会阻止合理的多步重构中间状态;只保留最近观察可能丢失跨文件依赖。以上是从机制推得的工程边界,原文没有完整测试所有这些场景。
六、沿可靠工具反馈比较其它验证代理
可靠操作接口之外,最终答案与证据也可能需要核查。DeepVerifier是跨任务的反馈设计对照;它不继承本篇编辑器,比较重点应是反馈如何改变后续动作和错误恢复。
自测:能否从系统结果推回实验结论
1. 不更新模型参数,为什么解决率仍会改变?
模型根据上下文选择动作。接口改变可选操作、动作执行可靠性和返回的信息,因此改变下一步输入和整条轨迹。例如一次可靠的多行编辑替代五次易错 shell 操作,能让相同模型在相同预算下更早得到测试反馈。这里提升的是闭环系统能力,不是模型权重中的知识量。
2. 18% 与 7.33% 能否直接作为纯 ACI 增益?
不能完全这样解释。7.33% 是没有示范的 Shell-only;带示范版本为 11%。更接近接口效应的直接比较是 18% 对 11%,同时还要核对预算与配置选择。若引用 10.67 个百分点,应承认示范条件也不同。
3. Pass@6 为 32.67%,是否表示给用户运行六次就能可靠得到同样成功率?
它表示六次中至少存在一个通过基准评估的补丁。实际系统还需决定选择哪个补丁,且不能访问泄漏答案的测试;六次费用和延迟也必须计入。只有配套可靠验证与选择机制,候选覆盖才能转化为可交付成功率。