核验日期:2026-07-08
内容来源:Anthropic Engineering 官方技术博客。本文先作为 Claude Code 专区后台草稿入库,发布前应由内容人员复核标题、摘要、图片、来源链接与是否需要补充本站实践说明。
用 Claude 3.5 Sonnet 提高 SWE-bench Verified 的标杆
SWE-bench 是一个 AI 评估基准,用于评估模型完成真实软件工程任务的能力。
来源:https://www.anthropic.com/engineering/swe-bench-sonnet
发布日期:2025-01-06
我们的最新模型、升级版 Claude 3.5 Sonnet,在软件工程评估 SWE-bench Verified 上取得了 49% 的成绩,超过了此前最先进模型的 45%。本文解释了我们围绕该模型构建的「智能体」,旨在帮助开发者尽可能发挥 Claude 3.5 Sonnet 的最佳性能。
SWE-bench 是一个 AI 评估基准,用于评估模型完成真实软件工程任务的能力。具体来说,它测试模型如何解决来自热门开源 Python 仓库的 GitHub issue。对于基准中的每个任务,AI 模型都会获得一个已设置好的 Python 环境,以及该 issue 被解决前的仓库 checkout(本地工作副本)。模型随后需要理解、修改并测试代码,然后提交它提出的解决方案。
每个解决方案都会用关闭原始 GitHub issue 的 pull request 中真实的单元测试来评分。这会测试 AI 模型是否实现了与原 PR 人类作者相同的功能。
SWE-bench 评估的并不只是孤立的 AI 模型,而是整个「智能体」系统。在这个语境中,「智能体」指的是 AI 模型及其周围软件脚手架的组合。这个脚手架负责生成输入模型的提示词、解析模型输出以采取行动,并管理交互循环:模型上一次行动的结果会被纳入下一次提示词中。即便使用相同的底层 AI 模型,一个智能体在 SWE-bench 上的表现也会因脚手架不同而显著变化。
还有许多其他评估大型语言模型编码能力的基准,但 SWE-bench 因以下几个原因越来越受欢迎:
- 它使用真实项目中的真实工程任务,而不是竞赛或面试风格的问题;
- 它还没有饱和,仍有很大的改进空间。还没有模型在 SWE-bench Verified 上超过 50% 完成率(尽管更新版 Claude 3.5 Sonnet 在本文写作时达到了 49%);
- 它衡量的是整个「智能体」,而不是孤立模型。开源开发者和创业公司已经通过优化脚手架,在同一个模型周围大幅提升了表现。
请注意,原始 SWE-bench 数据集中包含一些如果没有 GitHub issue 之外的额外上下文就无法解决的任务(例如,需要知道应返回的具体错误消息)。SWE-bench-Verified 是 SWE-bench 的一个 500 题子集,经过人工审核以确保题目可以解决,因此为编码智能体表现提供了最清晰的衡量方式。本文将引用的就是这个基准。
达到最先进水平
使用工具的智能体
在为更新版 Claude 3.5 Sonnet 创建优化后的智能体脚手架时,我们的设计理念是尽可能把控制权交给语言模型本身,并让脚手架保持最小化。这个智能体有一个提示词、一个用于执行 bash 命令的 Bash Tool,以及一个用于查看和编辑文件与目录的 Edit Tool。我们会持续采样,直到模型决定自己已经完成,或超过其 200k 上下文长度。这个脚手架允许模型自行判断如何推进问题,而不是被硬编码到某种特定模式或工作流中。
提示词为模型概述了建议方法,但对这个任务来说,它并不过长,也不过于详细。模型可以自由选择如何从一个步骤移动到下一个步骤,而不是遵循严格、离散的转换。如果你对 token 不敏感,明确鼓励模型产出较长回复会有所帮助。
下面的代码展示了我们智能体脚手架中的提示词:
<uploaded_files>
{location}
</uploaded_files>
I've uploaded a python code repository in the directory {location} (not in /tmp/inputs). Consider the following PR description:
<pr_description>
{pr_description}
</pr_description>
Can you help me implement the necessary changes to the repository so that the requirements specified in the <pr_description> are met?
I've already taken care of all changes to any of the test files described in the <pr_description>. This means you DON'T have to modify the testing logic or any of the tests in any way!
Your task is to make the minimal changes to non-tests files in the {location} directory to ensure the <pr_description> is satisfied.
Follow these steps to resolve the issue:
1. As a first step, it might be a good idea to explore the repo to familiarize yourself with its structure.
2. Create a script to reproduce the error and execute it with `python <filename.py>` using the BashTool, to confirm the error
3. Edit the sourcecode of the repo to resolve the issue
4. Rerun your reproduce script and confirm that the error is fixed!
5. Think about edgecases and make sure your fix handles them as well
Your thinking should be thorough and so it's fine if it's very long.
复制
模型的第一个工具用于执行 Bash 命令。它的 schema 很简单,只接收要在环境中运行的命令。不过,工具描述承担了更重要的作用。它为模型提供了更详细的指令,包括输入转义、无法访问互联网,以及如何在后台运行命令。
接下来,我们展示 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)复杂得多,包含模型查看、创建和编辑文件所需的一切。同样,我们的工具描述中包含了模型如何使用该工具的详细信息。
我们在许多不同智能体式任务中,为这些工具的描述和规格投入了大量精力。我们测试它们,以发现模型可能误解规格的方式,或使用工具时可能遇到的陷阱,然后编辑描述来提前规避这些问题。我们认为,应该像为人类设计工具接口时投入大量注意力一样,在为模型设计工具接口时投入更多注意力。
下面的代码展示了我们 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
\n
Notes for using the `str_replace` command:\n
* 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`",
...
复制
我们提升性能的一种方式是对工具做「防错」设计。例如,当智能体离开根目录后,模型有时可能会搞错相对文件路径。为避免这种情况,我们简单地让工具始终要求绝对路径。
我们尝试过几种不同策略来指定对现有文件的编辑,可靠性最高的是字符串替换:模型指定要用 new_str 替换的 old_str。只有当 old_str 恰好匹配一次时,替换才会发生。如果匹配次数多于或少于一次,模型会看到相应错误消息,以便重试。
下面是我们 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 相比我们之前的模型以及此前最先进的模型,展现出更高的推理、编码和数学能力。它也展现出更强的智能体能力:工具和脚手架有助于充分发挥这些改进能力。
| Model | Claude 3.5 Sonnet (new) | Previous SOTA | Claude 3.5 Sonnet (old) | Claude 3 Opus |
|---|---|---|---|---|
| SWE-bench Verified score | 49% | 45% | 33% | 22% |
我们部分模型在 SWE-bench Verified 上的得分,均使用这个智能体脚手架。
智能体行为示例
为了运行该基准,我们使用 SWE-Agent 框架作为智能体代码的基础。在下面的日志中,我们把智能体的文本输出、工具调用和工具响应分别渲染为 THOUGHT、ACTION 和 OBSERVATION,尽管我们并没有约束模型遵循固定顺序。
下面的代码块会展示 Sonnet 3.5 解决一个 SWE-bench 问题的典型过程。
在第一个代码块中,你可以看到给模型的初始提示词的一部分,其中 {pr_description} 被填入了来自 SWE-bench 任务的真实值。重要的是,这个任务包含复现问题的步骤,这会为模型提供有价值的调查起点。
<uploaded_files>
/repo
</uploaded_files>
I've uploaded a python code repository in the directory /repo (not in /tmp/inputs). Consider the following PR description:
<pr_description>
linear_model.RidgeClassifierCV's Parameter store_cv_values issue
#### Description
Parameter store_cv_values error on sklearn.linear_model.RidgeClassifierCV
#### Steps/Code to Reproduce
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)
#### Expected Results
Expected to get the usual ridge regression model output, keeping the cross validation predictions as attribute.
#### Actual Results
TypeError: __init__() got an unexpected keyword argument 'store_cv_values'
lm.RidgeClassifierCV actually has no parameter store_cv_values, even though some attributes depends on it.
复制
模型随后响应,并首先使用 Edit Tool 查看仓库结构。你可以在 THOUGHT 和 ACTION 下看到模型的文本输出和工具调用参数,在 OBSERVATION 下看到工具输出的一部分:
THOUGHT:
I'll help you implement the changes to satisfy the PR description. Let's follow the steps you outlined.
1. First, let's explore the repo structure:
ACTION (str_replace_editor):
command:
view
path:
/repo
OBSERVATION:
Here's the files and directories up to 2 levels deep in /repo, excluding hidden items:
/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
...
复制
现在模型对仓库结构有了更好的理解,它会使用 Edit Tool 创建一个新脚本,用于复现问题并测试修复:
THOUGHT:
Based on the repository structure, we'll need to modify the Ridge Classifier in the `sklearn/linear_model` directory.
Let's create a script to reproduce the error:
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:
Let's verify that we can reproduce the error:
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 修改仓库中的源代码,并重新运行它的脚本,以验证更改是否解决了问题:
THOUGHT:
The error is reproducible. Looking at the code, I can see that the issue is that while the `RidgeClassifierCV` class inherits from `_BaseRidgeCV`, it fails to pass the `store_cv_values` parameter from its constructor through to the base class constructor.
Let's fix this:
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 轮;另一些任务中,模型会一直尝试,直到上下文耗尽。
通过比较更新版 Claude 3.5 Sonnet 与旧模型的尝试,我们发现更新版 3.5 Sonnet 更常自我纠正。它还展现出尝试多种不同解决方案的能力,而不是反复陷在同一个错误里。
挑战
SWE-bench Verified 是一个强大的评估,但它也比简单的单轮 eval 更复杂。下面是我们在使用它时遇到的一些挑战,也是其他 AI 开发者可能会遇到的挑战。
- **持续时间和高 token 成本。**上面的示例来自一个在 12 个步骤内成功完成的案例。然而,许多成功运行需要模型花费数百轮、超过 100k token 才能解决。更新版 Claude 3.5 Sonnet 很有韧性:只要给它足够时间,它往往能绕开问题找到路径,但这可能很昂贵;
- **评分。**检查失败任务时,我们发现一些案例中模型行为正确,但存在环境设置问题,或安装补丁被应用两次的问题。解决这些系统问题,对于准确了解 AI 智能体表现至关重要。
- **隐藏测试。**因为模型看不到评分所依据的测试,所以它经常「以为」自己成功了,而任务实际失败。其中一些失败是因为模型在错误的抽象层级解决问题(打了补丁,而不是做更深层重构)。另一些失败则显得没那么公平:它们确实解决了问题,但不匹配原始任务中的单元测试。
- **多模态。**尽管更新版 Claude 3.5 Sonnet 具备出色的视觉和多模态能力,我们并没有实现让它查看保存到文件系统中的文件或 URL 引用文件的方法。这使得调试某些任务(尤其是来自 Matplotlib 的任务)特别困难,也更容易导致模型幻觉。开发者显然有一些容易改进的空间,而且 SWE-bench 已经推出了一个专注多模态任务的新评估。我们期待看到开发者在不久的将来用 Claude 在这个 eval 上取得更高分数。
升级版 Claude 3.5 Sonnet 在 SWE-bench Verified 上取得了 49% 的成绩,凭借简单提示词和两个通用工具超过了此前最先进水平(45%)。我们相信,使用新版 Claude 3.5 Sonnet 构建的开发者会很快找到新的、更好的方法,进一步提升 SWE-bench 得分,超过我们在这里最初展示的结果。
致谢
Erik Schluntz 优化了 SWE-bench 智能体并撰写了这篇博客文章。Simon Biggs、Dawn Drain 和 Eric Christiansen 帮助实现了该基准。Shauna Kravec、Dawn Drain、Felipe Rosso、Nova DasSarma、Ven Chandrasekaran 以及许多其他人参与训练 Claude 3.5 Sonnet,使其在智能体式编码方面表现出色。