用 Claude 3.5 Sonnet 抬高 SWE-bench Verified 的标杆

举报
yd_298479158 发表于 2026/10/11 12:57:42 2026/10/11
【摘要】 我们最新升级的 Claude 3.5 Sonnet 在软件工程评测 SWE-bench Verified 上取得了 49% 的成绩,超过了此前最先进模型的 45%。本文介绍我们围绕模型构建的 Agent,并希望帮助开发者从 Claude 3.5 Sonnet 中获得尽可能好的表现。SWE-bench 是一项评测 AI 模型真实软件工程能力的 Benchmark。它具体测试模型能否解决流行开源...

我们最新升级的 Claude 3.5 Sonnet 在软件工程评测 SWE-bench Verified 上取得了 49% 的成绩,超过了此前最先进模型的 45%。本文介绍我们围绕模型构建的 Agent,并希望帮助开发者从 Claude 3.5 Sonnet 中获得尽可能好的表现。

SWE-bench 是一项评测 AI 模型真实软件工程能力的 Benchmark。它具体测试模型能否解决流行开源 Python 项目中的真实 GitHub Issue。

对于 Benchmark 中的每个任务,AI 模型都会获得:

  • 一个已经配置好的 Python 环境;
  • 对应 Repository 在原始 Issue 被解决之前的本地 Checkout。

模型需要:

  1. 理解代码;
  2. 修改代码;
  3. 测试代码;
  4. 提交自己的解决方案。

每个解决方案都会使用最初关闭这个 GitHub Issue 的 Pull Request 中的真实单元测试进行评分。

也就是说,这项评测实际测试的是:

AI 模型是否能够实现与原 PR 人类作者相同的功能。

SWE-bench 并不只是孤立地评测模型本身,而是评测一个完整的 Agent 系统。

在这里,Agent 指的是:

AI 模型 + 围绕模型的软件脚手架。

这套脚手架负责:

  • 生成发送给模型的 Prompt;
  • 解析模型输出并执行相应动作;
  • 管理交互循环;
  • 把模型上一步动作产生的结果重新加入下一轮 Prompt。

即使底层使用的是同一个 AI 模型,仅仅改变 Agent Scaffold,SWE-bench 上的表现也可能出现很大差异。

目前有许多用于衡量大语言模型编程能力的 Benchmark,但 SWE-bench 逐渐变得非常流行,主要有几个原因:

  1. 它使用真实项目中的真实工程任务,而不是竞赛题或面试题;
  2. 它还没有饱和,依然存在很大提升空间。在本文写作时,还没有模型在 SWE-bench Verified 上超过 50%,而升级后的 Claude 3.5 Sonnet 已经达到 49%;
  3. 它评测的是完整 Agent,而不是孤立模型。开源开发者和创业公司已经通过优化 Scaffold,在完全相同的模型上获得了显著更好的表现。

需要注意的是,原始 SWE-bench 数据集中有一些任务,如果只有 GitHub Issue 本身的上下文,其实无法完成。

例如:

某些问题要求返回一个非常具体的错误信息,但这个信息并没有出现在 Issue 描述中。

SWE-bench Verified 是 SWE-bench 中一个由人工审查过的 500 题子集,用来确保任务本身确实可以完成,因此它能够提供更清晰的 Coding Agent 能力衡量。

本文后面提到的 SWE-bench,主要都指 SWE-bench Verified。

达到新的 SOTA

使用工具的 Agent

在为升级后的 Claude 3.5 Sonnet 设计 Agent Scaffold 时,我们采用的核心理念是:

尽可能把控制权交给语言模型本身,同时让 Scaffold 保持最简。

Agent 只有:

  • 一个 Prompt;
  • 一个 Bash Tool,用于执行 Bash 命令;
  • 一个 Edit Tool,用于查看和编辑文件与目录。

系统会不断采样,直到:

  • 模型自己判断任务已经完成;
  • 或者超过 200K Context Length。

这种设计让模型能够自行判断:

应该如何推进问题。

而不是把它硬编码进某一种固定模式或工作流。

Prompt 会给模型一个建议性流程,但不会写得非常长,也不会对每一步规定得太死。

模型可以自行决定如何在不同阶段之间移动,而不是必须遵守严格、离散的状态转换。

如果你并不特别在意 Token 成本,那么:

明确鼓励模型生成较长、较完整的推理和回答,有时会有所帮助。

下面是我们 Agent Scaffold 中的 Prompt:

<uploaded_files>
{location}
</uploaded_files>

我已经把一个 Python 代码仓库上传到了目录 {location}
(不在 /tmp/inputs 中)。

请考虑下面这份 PR 描述:

<pr_description>
{pr_description}
</pr_description>

你能否帮助我对 Repository 做必要修改,
以满足 <pr_description> 中的要求?

我已经处理好了 <pr_description> 中描述的所有测试文件修改。
这意味着你完全不需要修改测试逻辑,也不需要修改任何测试!

你的任务是:

只对 {location} 目录中的非测试文件进行最小修改,
确保 <pr_description> 中的要求得到满足。

请按照以下步骤解决问题:

1. 第一步,可以先浏览 Repository,熟悉整体结构。
2. 创建一个脚本复现错误,并使用 BashTool 执行:
   python <filename.py>
   以确认错误确实存在。
3. 编辑 Repository 源代码以解决问题。
4. 再次运行复现脚本,确认错误已经修复。
5. 思考边缘情况,确保修复也能正确处理这些情况。

你的思考应该尽可能充分,因此即使非常长也没有关系。

模型的第一个工具负责执行 Bash 命令。

它的 Schema 非常简单,只包含一个需要执行的命令。

不过,更重要的是:

Tool Description。

其中加入了很多模型真正需要知道的细节,包括:

  • 输入是否需要 XML Escape;
  • 当前环境是否可以访问互联网;
  • 如何运行后台命令;
  • 如何查看特定行范围。

下面是 Bash Tool 的规格:

{
  "name": "bash",
  "description": "Run commands in a bash shell\n
* When invoking this tool, the contents of the \"command\" parameter does NOT need to be XML-escaped.\n
* You don't have access to the internet via this tool.\n
* You do have access to a mirror of common linux and python packages via apt and pip.\n
* State is persistent across command calls and discussions with the user.\n
* To inspect a particular line range of a file, e.g. lines 10-25, try 'sed -n 10,25p /path/to/the/file'.\n
* Please avoid commands that may produce a very large amount of output.\n
* Please run long lived commands in the background, e.g. 'sleep 10 &' or start a server in the background.",
  "input_schema": {
    "type": "object",
    "properties": {
      "command": {
        "type": "string",
        "description": "The bash command to run."
      }
    },
    "required": ["command"]
  }
}

模型的第二个工具,也就是 Edit Tool,要复杂得多。

它包含模型:

  • 查看文件;
  • 创建文件;
  • 编辑文件;
  • 查看目录;

所需要的全部能力。

和 Bash Tool 一样,我们在 Tool Description 中加入了非常具体的使用指导。

我们在很多 Agentic Task 上,对这些工具的:

  • 描述;
  • Schema;

投入了大量精力。

我们会主动测试:

  • 模型会怎样误解 Tool Spec;
  • 哪些地方容易误用;
  • 哪些错误最常见。

然后再修改工具描述,提前消除这些问题。

我们认为:

为模型设计工具接口,应该像为人类设计工具接口一样认真。

下面是 Edit Tool 的描述:

{
  "name": "str_replace_editor",
  "description": "Custom editing tool for viewing, creating and editing files\n
* State is persistent across command calls and discussions with the user\n
* If `path` is a file, `view` displays the result of applying `cat -n`. If `path` is a directory, `view` lists non-hidden files and directories up to 2 levels deep\n
* The `create` command cannot be used if the specified `path` already exists as a file\n
* If a `command` generates a long output, it will be truncated and marked with `<response clipped>`\n
* The `undo_edit` command will revert the last edit made to the file at `path`\n

Notes for using the `str_replace` command:
* The `old_str` parameter should match EXACTLY one or more consecutive lines from the original file. Be mindful of whitespaces!\n
* If the `old_str` parameter is not unique in the file, the replacement will not be performed. Make sure to include enough context in `old_str` to make it unique\n
* The `new_str` parameter should contain the edited lines that should replace the `old_str`",
  ...
}

我们提高表现的一种方式,是让工具尽可能:

Error-proof。

例如:

模型有时会在 Agent 已经离开 Repository Root 之后,对相对路径处理错误。

我们的解决方法非常简单:

直接要求 Tool 永远使用绝对路径。

我们还测试过多种修改已有文件的方法。

最终发现,可靠性最高的是:

String Replacement。

也就是:

模型指定:

old_str

然后用:

new_str

替换。

只有当 old_str 在文件中:

恰好出现一次

时,替换才会真正发生。

如果匹配数量:

  • 多于 1;
  • 少于 1;

模型都会收到清晰错误信息,然后自行重试。

下面是 Edit Tool 的输入规格:

{
  "input_schema": {
    "type": "object",
    "properties": {
      "command": {
        "type": "string",
        "enum": [
          "view",
          "create",
          "str_replace",
          "insert",
          "undo_edit"
        ],
        "description": "The commands to run. Allowed options are: `view`, `create`, `str_replace`, `insert`, `undo_edit`."
      },
      "file_text": {
        "description": "Required parameter of `create` command, with the content of the file to be created.",
        "type": "string"
      },
      "insert_line": {
        "description": "Required parameter of `insert` command. The `new_str` will be inserted AFTER the line `insert_line` of `path`.",
        "type": "integer"
      },
      "new_str": {
        "description": "Required parameter of `str_replace` command containing the new string. Required parameter of `insert` command containing the string to insert.",
        "type": "string"
      },
      "old_str": {
        "description": "Required parameter of `str_replace` command containing the string in `path` to replace.",
        "type": "string"
      },
      "path": {
        "description": "Absolute path to file or directory, e.g. `/repo/file.py` or `/repo`.",
        "type": "string"
      },
      "view_range": {
        "description": "Optional parameter of `view` command when `path` points to a file. If none is given, the full file is shown. If provided, the file will be shown in the indicated line number range, e.g. [11, 12] will show lines 11 and 12. Indexing at 1 to start. Setting `[start_line, -1]` shows all lines from `start_line` to the end of the file.",
        "items": {
          "type": "integer"
        },
        "type": "array"
      }
    },
    "required": [
      "command",
      "path"
    ]
  }
}

结果

总体来说,升级后的 Claude 3.5 Sonnet,相比我们此前的模型,在以下能力上都有明显提升:

  • 推理;
  • 编码;
  • 数学。

它也表现出了更强的 Agentic 能力:

好的工具和 Scaffold,能够让模型本身提升后的能力被更充分地发挥出来。

模型 SWE-bench Verified 分数
Claude 3.5 Sonnet(新版) 49%
此前 SOTA 45%
Claude 3.5 Sonnet(旧版) 33%
Claude 3 Opus 22%

以上模型都使用同一套 Agent Scaffold。

Agent 行为示例

运行 Benchmark 时,我们使用 SWE-Agent Framework 作为 Agent 代码的基础。

在下面的 Log 中,我们会把:

  • Agent 文本输出;
  • Tool Call;
  • Tool Response;

分别渲染为:

THOUGHT
ACTION
OBSERVATION

不过,我们实际上并没有强制模型必须按照固定顺序输出。

下面通过一个典型案例,展示 Claude 3.5 Sonnet 如何解决 SWE-bench 任务。

首先,模型收到的初始 Prompt 中,会把真实 SWE-bench 任务内容填入:

{pr_description}

这个任务本身包含了复现步骤,因此给模型提供了非常有价值的调查起点。

<uploaded_files>
/repo
</uploaded_files>

我已经把一个 Python 代码仓库上传到了 /repo
(不在 /tmp/inputs)。

请考虑以下 PR 描述:

<pr_description>
linear_model.RidgeClassifierCV 的 store_cv_values 参数问题

#### 描述
sklearn.linear_model.RidgeClassifierCV 的 store_cv_values 参数报错

#### 复现步骤/代码

import numpy as np
from sklearn import linear_model as lm

# 测试数据库
n = 100
x = np.random.randn(n, 30)
y = np.random.normal(size = n)

rr = lm.RidgeClassifierCV(
    alphas = np.arange(0.1, 1000, 0.1),
    normalize = True,
    store_cv_values = True
).fit(x, y)

#### 预期结果

应该正常获得 Ridge Regression 模型输出,
并把交叉验证预测值作为属性保留下来。

#### 实际结果

TypeError:
__init__() got an unexpected keyword argument 'store_cv_values'

lm.RidgeClassifierCV 实际上没有 store_cv_values 参数,
即使它的一些属性又依赖这个参数。
</pr_description>

模型首先回复,并使用 Edit Tool 查看 Repository 结构。

下面可以看到:

  • THOUGHT:模型的文本输出;
  • ACTION:工具调用;
  • OBSERVATION:工具返回的一部分结果。
THOUGHT:
我会帮助你实现满足 PR 描述所需要的修改。
先按照你给出的步骤进行。

1. 首先,让我们浏览 Repository 结构。

ACTION (str_replace_editor):

command:
view

path:
/repo

OBSERVATION:

下面是 /repo 中最多两层深度的文件和目录,
不包含隐藏文件:

/repo
/repo/PULL_REQUEST_TEMPLATE.md
/repo/ISSUE_TEMPLATE.md
/repo/sklearn
/repo/sklearn/decomposition
/repo/sklearn/kernel_ridge.py
/repo/sklearn/model_selection
/repo/sklearn/covariance
/repo/sklearn/cluster
/repo/sklearn/base.py
/repo/sklearn/dummy.py
/repo/sklearn/naive_bayes.py
...

现在模型已经对 Repository 结构有了更好的理解。

接下来,它使用 Edit Tool 创建一个新脚本,用来:

  • 复现错误;
  • 验证之后的修复。
THOUGHT:

根据 Repository 结构,我们需要修改
`sklearn/linear_model` 目录中的 Ridge Classifier。

先创建一个脚本复现错误:

ACTION (str_replace_editor):

command:
create

path:
/repo/reproduce_error.py

file_text:
import numpy as np
from sklearn import linear_model as lm

#test database
n = 100
x = np.random.randn(n, 30)
y = np.random.normal(size = n)

rr = lm.RidgeClassifierCV(
    alphas=np.arange(0.1, 1000, 0.1),
    normalize=True,
    store_cv_values=True
).fit(x, y)

OBSERVATION:

File created successfully at:
/repo/reproduce_error.py

随后,模型用 Bash Tool 执行刚刚创建的脚本,并成功复现任务中的问题:

THOUGHT:

先验证一下我们确实能够复现这个错误:

ACTION (bash):

command:
python3 /repo/reproduce_error.py

OBSERVATION:

Traceback (most recent call last):
  File "/repo/reproduce_error.py", line 10, in <module>
    store_cv_values=True).fit(x, y)

TypeError:
__init__() got an unexpected keyword argument 'store_cv_values'

从这里开始,模型使用 Edit Tool 修改 Repository 中的源代码,然后重新执行自己的复现脚本,确认修改是否真正解决了问题。

THOUGHT:

错误已经成功复现。

查看代码后,我发现问题在于:

虽然 `RidgeClassifierCV` 继承自 `_BaseRidgeCV`,
但它没有把构造函数里的 `store_cv_values` 参数继续传给基类构造函数。

让我们修复它。

ACTION (str_replace_editor):

command:
str_replace

path:
/repo/sklearn/linear_model/ridge.py

old_str:
    def __init__(self, alphas=(0.1, 1.0, 10.0), fit_intercept=True,
                 normalize=False, scoring=None, cv=None, class_weight=None):
        super(RidgeClassifierCV, self).__init__(
            alphas=alphas, fit_intercept=fit_intercept, normalize=normalize,
            scoring=scoring, cv=cv)
        self.class_weight = class_weight

new_str:
    def __init__(self, alphas=(0.1, 1.0, 10.0), fit_intercept=True,
                 normalize=False, scoring=None, cv=None, class_weight=None,
                 store_cv_values=False):
        super(RidgeClassifierCV, self).__init__(
            alphas=alphas, fit_intercept=fit_intercept, normalize=normalize,
            scoring=scoring, cv=cv, store_cv_values=store_cv_values)
        self.class_weight = class_weight

在这个具体案例中,模型总共工作了:

12 个步骤

然后判断自己已经可以提交答案。

随后任务测试成功通过,证明模型的修改确实解决了问题。

但有些任务并没有这么快。

一些任务需要:

超过 100 轮

模型才会提交解决方案。

另一些任务里,模型会一直不断尝试,直到:

Context 被完全耗尽。

对比升级后的 Claude 3.5 Sonnet 与旧模型的运行轨迹,我们发现:

新版 3.5 Sonnet 更经常:

主动自我纠错。

它也更擅长:

尝试多个不同方案,

而不是反复犯同一个错误,并卡在原地。

挑战

SWE-bench Verified 是一项非常强的评测,但相比简单的单轮 Eval,它运行起来也明显更加复杂。

下面是我们实际遇到的一些问题。

这些问题,其他 AI 开发者也很可能会遇到。

1. 运行时间长,Token 成本高

前面的示例只用了 12 步就成功完成任务。

但很多成功案例需要:

  • 数百轮交互;
  • 超过 100K Token。

升级后的 Claude 3.5 Sonnet 非常“执着”。

只要给它足够时间,它往往能够想办法绕过问题,最终找到解决方案。

但这种方式也可能:

非常昂贵。

2. Grading 本身也会出问题

在检查失败任务时,我们发现:

有些情况下,模型其实做对了。

真正的问题来自:

  • 环境配置错误;
  • Install Patch 被重复应用;
  • 其他系统问题。

要准确评估 AI Agent 的真实性能,

就必须先把这些基础设施问题解决掉。

3. Hidden Test

模型看不到:

最终给自己评分的测试。

所以它经常会认为:

“我已经成功了。”

但真正执行隐藏测试后,任务其实仍然失败。

有些失败是合理的。

例如:

模型在错误的抽象层级解决了问题。

它可能只是做了一个:

临时补丁

而真正需要的是:

更深层的重构。

但也有一些失败显得没那么公平。

例如:

模型实际上解决了真实问题,

只是它的实现没有恰好匹配:

原始任务中的单元测试预期。

4. 多模态能力没有被真正利用

升级后的 Claude 3.5 Sonnet 本身拥有很强的:

  • Vision;
  • Multimodal;

能力。

但我们的 Agent Scaffold 并没有实现让它查看:

  • 保存到 Filesystem 的图像文件;
  • URL 引用的图像。

这让某些任务的 Debugging 变得非常困难。

尤其是:

Matplotlib 相关任务。

同时也更容易让模型产生幻觉。

这里显然还有大量容易拿到的性能提升空间。

结论

升级后的 Claude 3.5 Sonnet,在一个非常简单的配置下:

  • 一个简单 Prompt;
  • 两个通用工具;

就在 SWE-bench Verified 上取得了:

49%

超过此前 SOTA 的:

45%。

我们相信:

围绕新的 Claude 3.5 Sonnet 构建 Agent 的开发者,

很快就会找到:

比本文这套初始方案更好的 Scaffold 和 Tool Design,

并继续把 SWE-bench 分数推得更高。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。