SWE-agent论文浅读
最近读了一篇关于 Agent Harness 的综述,对 Agent 应用开发产生了兴趣,于是打算从 SWE-agent 这篇论文入手,了解一个具体的 Agent 系统是如何设计和实现的。
这篇博客更像是一份个人阅读笔记,主要记录阅读过程中的理解与思考,而非对论文的系统性解读。如有理解不当或疏漏之处,欢迎交流指正。
Harness 综述:《From Question Answering to Task Completion: A Survey on Agent System and Harness Design》
1. 背景与问题
1.1 这篇论文要解决什么问题?
人类开发者在完成软件工程任务时,可以借助 VS Code 等开发工具提供的代码浏览、搜索、编辑与错误检查功能,提高工作效率。那么,基于LLM的 Agent 是否也能从专门设计的交互工具中受益?这是作者的出发点。
相比直接让 Agent 使用现成的 Shell,作者希望探索是否能够在不改变底层语言模型权重的情况下,通过改进 Agent 与计算机的交互方式,来提高他完成软件工程任务的能力?

构建并开源了 SWE-agent,并在 SWE-bench 等基准上评估了它的表现。
链接:https://www.swebench.com/
1.2 提出了哪些思路
为此,作者提出了 Agent-Computer Interface(ACI,智能体—计算机接口)的概念。它可以理解为 Agent 与计算机之间的一层交互抽象:不仅提供 Agent 可以执行的操作,也设计执行结果的反馈方式,使 Agent 更容易查看、搜索、修改和运行代码。
可以把Agent当作一个特殊的"人",和真正的人类在能力上的局限不同,因此需要为他专门设计一类交互接口。
论文中提出,在以GPT-4 Turbo为基础模型,使用ACI之后解决SWE-bench等基准中的真实软件工程问题的成功率提高了7%。在基础能力不变的情况下,为什么ACI能够显著提升Agent任务完成的能力?就单纯改变交互接口?这点使我非常疑惑。
2. 方法
2.1 如何设计ACI?
作者提出了两个方法:
第一,人工观察Agent执行任务中的表现,观察Agent的使用行为判断这个接口是否适配Agent,从而改进这个接口。
第二,网格搜索,网格搜索是在预先设定的参数候选值中,枚举不同组合,比较它们的评测结果,并选择其中表现较好的配置,比如read读取多少行,工具反馈保留多少行。然后找到最优的配置。
在使用这两种方法进行实验的过程中,作者也总结了几个设计原则:
- 操作应该简单易于理解
- 操作应该紧凑和高效
- 环境反馈要充分和精炼
- 内置校验可以阻止错误传播,帮助agent快速恢复
我感觉ACI可以提升任务完成率,主要是在于三点:
1.上下文:模型的上下文有限的,接口设计的简洁明了可以减少不必要的上下文
2.信息干扰:即使没有超过上下文上限,冗余内容和已经过时的代码也可能增加模型筛选有效信息的负担。这里是我对实验现象的理解,论文并未直接证明提升来自模型内部注意力机制的变化。
3.操作负担:把修改、局部检查和结果展示等固定步骤整合到工具中,可以减少模型每次临时组织这些操作的负担,并及时发现部分错误,降低错误继续传播的可能性。
2.2 SWE-agent的ACI设计
WE-agent 采用交互式执行方式:模型根据问题描述、工具说明和已有执行记录,生成下一步操作;系统执行操作,将结果反馈给模型,模型再据此决定下一步。搜索、查看、编辑和运行代码的顺序由模型在任务中动态选择,而不是固定为一条预设流程。专用命令之外,模型也可以使用普通 Shell 命令。
ACI 设计的是模型可以怎样行动、会收到什么反馈,而实际任务路径是在交互过程中形成的。
文件查看器:Agent通过open打开文件,一次最多展示100行代码。如果还需要查看其他部分,可以通过scroll_up和scroll_down上下翻动,或者使用goto跳转到指定行。返回的内容除了代码本身,还包括文件路径、总行数、每行的行号,以及当前窗口前后还有多少行没有展示。
作者并没有直接把整个文件交给Agent,而是给它提供了一个可以移动的阅读窗口。这样既可以控制每次返回的信息量,也能让Agent知道自己正在看哪个文件、哪个位置。
文件编辑器:提供了edit命令,让Agent通过起始行、结束行和替换文本,修改当前打开的文件。修改后,文件查看器会自动展示更新后的内容,不需要Agent再额外调用一次查看命令。
编辑操作中还内置了代码检查。如果修改引入了检查器能够识别的特定错误,系统就会丢弃这次无效修改,并返回错误信息,让Agent重新尝试。但这里的检查并不代表功能已经正确,只是在编辑阶段拦截一部分错误。
这里把“修改—检查—反馈”这些固定操作整合到了一起。底层要做的事情并没有减少,但是模型不需要每次都自己组织这一串操作。
上下文管理:
这部分管理的是每次调用模型时,应该把哪些信息交给模型,而不是让模型主动调用的一个工具。系统会先整理历史记录,再将处理后的内容送入模型。SWE-Agent
论文中的做法是:完整保留最近5次观察结果,更早的观察各自压缩成一行。这里不是整个对话只保留最近5轮,而是主要处理历史中的环境反馈。另外,系统会提供工具说明和操作示例;模型输出格式不正确时,会返回提示,要求重新生成。
对于执行成功但没有输出的命令,系统也会明确告诉Agent“命令执行成功,但没有产生输出”,而不是直接返回空白。SWE-Agent
我感觉这部分关注的不只是上下文长度,还包括信息是否明确。比如,一个文件已经修改了多次,如果旧版本的代码一直完整保留在上下文中,模型还需要判断哪些内容已经过时。
3. 实验与结果
3.1 实验设置
这部分到了实验环节,下面是实验设置:
数据集:主要使用SWE-bench。论文使用的完整测试集包含2294个任务,来自12个Python项目;另外使用包含300个任务的SWE-bench Lite,进行消融实验和行为分析。作者还使用了HumanEvalFix,它更侧重短代码的错误修复,不需要像SWE-bench一样在较大的代码仓库中定位问题。
基线模型:基础模型主要是GPT-4 Turbo和Claude 3 Opus,具体版本分别为gpt-4-1106-preview和claude-3-opus-20240229。
在此基础上,作者比较了两种基线方案。第一种是非交互式RAG:根据issue描述,使用BM25检索相关代码文件,再让模型直接生成修复补丁。
第二种是Shell-only:让模型通过Linux Shell操作代码仓库,可以执行命令、观察结果并继续操作,但没有SWE-agent提供的这套专用接口。
指标:主要指标是任务解决率。将Agent生成的补丁应用到代码仓库后,根据评测要求的测试是否通过,判断任务是否解决。这里的一次尝试可以包含多轮模型调用和工具执行,并不是只调用一次模型。
配置搜索:
作者从SWE-bench开发集中随机抽取了37个任务,比较下面几类参数的组合:
| 参数 | 候选配置 |
|---|---|
| 文件查看窗口大小 | 100行、200行 |
| 历史处理方式 | 完整历史、仅完整保留最近5次观察 |
| 模型生成温度 | 0.0、0.2 |
3.2 结果分析
| 方案 | SWE-bench解决率 | SWE-bench Lite解决率 |
|---|---|---|
| RAG | 1.31% | 2.67% |
| Shell-only,带操作示例 | — | 11.00% |
| SWE-agent | 12.47% | 18.00% |
在SWE-bench Lite上,SWE-agent相比Shell-only提高了7个百分点。成功任务的平均推理费用也从1.46美元增加到了1.67美元,所以这里的提升也随着一定的成本增加。
使用Claude 3 Opus时,SWE-agent在完整SWE-bench上的解决率为10.46%。在HumanEvalFix上使用GPT-4 Turbo的SWE-agent在Python、JavaScript和Java任务上的解决率分别为87.7%、89.7%和87.9%。
到底是哪些设计起了作用?之后作者又做了消融实验,以完整配置为参照,分别改变其中的某项设计。下面是GPT-4 Turbo在SWE-bench Lite上的部分结果:
| 配置 | 任务解决率 |
|---|---|
| 完整配置 | 18.0% |
| 去掉专用编辑接口,仍可使用Shell修改文件 | 10.3% |
| 保留编辑接口,但去掉内置检查 | 15.0% |
| 文件窗口改为30行 | 14.3% |
| 文件查看器一次展示整个文件 | 12.7% |
| 保留完整历史观察,不做原来的压缩处理 | 15.0% |
可以看到文件窗口不是越小越好,也不是越大越好。编辑工具的作用也不只是修改文件,修改后如何检查、怎样反馈,同样会影响最终结果。
4. 理解与疑问
本文最重要的贡献是提出一个问题:改变提供给智能体的接口是否可以提升任务的完成率?这对后面的harness设计提供了基本指导。先让系统运行起来,再观察实际执行轨迹。对于模型反复承担的固定操作,以及冗余、含糊或过时的反馈,可以考虑专门封装,原生接口已经足够好用的地方,则保留原生能力,并通过评测判断修改是否有效。

浙公网安备 33010602011771号