SWE-Bench에서 Claude가 달성한 획기적인 성과를 살펴봅니다. 고도화된 소프트웨어 엔지니어링 역량과 코드 생성 정확도를 확인하고, 기술 평가 방법론까지 함께 알아보세요.
Anthropic의 최신 모델인 업그레이드된 Claude 3.5 Sonnet은 소프트웨어 엔지니어링 평가 벤치마크인 SWE-bench Verified에서 49%를 달성하며, 기존 최고 성능 모델의 45%를 넘어섰습니다. 이 글에서는 모델을 감싸는 "에이전트(agent)" 구조를 어떻게 설계했는지 설명하며, 개발자들이 Claude 3.5 Sonnet에서 최상의 성능을 끌어내는 데 도움이 되고자 합니다.
SWE-bench는 실제 소프트웨어 엔지니어링 작업을 수행하는 모델의 능력을 측정하는 AI 평가 벤치마크입니다. 구체적으로는, 인기 있는 오픈소스 Python 저장소의 GitHub 이슈를 모델이 얼마나 잘 해결하는지를 테스트합니다. 각 과제에서 AI 모델은 사전 구성된 Python 환경과 해당 이슈가 해결되기 직전 시점의 저장소 체크아웃(로컬 작업 사본)을 제공받습니다. 모델은 코드를 분석하고 수정한 뒤 테스트를 거쳐 솔루션을 제출해야 합니다.
각 솔루션은 원래 GitHub 이슈를 종료한 풀 리퀘스트(Pull Request)의 실제 유닛 테스트를 기준으로 채점됩니다. 즉, AI 모델이 해당 PR을 작성한 실제 개발자와 동일한 기능을 구현할 수 있는지를 검증하는 것입니다.
SWE-bench는 AI 모델 단독이 아니라 전체 "에이전트" 시스템을 평가합니다. 여기서 "에이전트"란 AI 모델과 이를 둘러싼 소프트웨어 스캐폴딩(scaffolding)의 조합을 의미합니다. 스캐폴딩은 모델에 전달할 프롬프트를 생성하고, 모델의 출력을 파싱하여 실행하며, 이전 행동의 결과를 다음 프롬프트에 반영하는 상호작용 루프를 관리합니다. 동일한 AI 모델을 사용하더라도 스캐폴딩 구성에 따라 SWE-bench 성능이 크게 달라질 수 있습니다.
대규모 언어 모델의 코딩 능력을 측정하는 벤치마크는 다양하지만, SWE-bench가 특히 주목받는 이유는 다음과 같습니다:
참고로, 원래의 SWE-bench 데이터셋에는 GitHub 이슈 외의 추가 맥락(예: 반환해야 할 특정 에러 메시지 등)이 없으면 풀 수 없는 과제가 포함되어 있습니다. SWE-bench-Verified는 SWE-bench에서 사람이 직접 검토하여 풀 수 있는 문제인지 확인한 500개 문제 서브셋으로, 코딩 에이전트의 성능을 가장 명확하게 측정할 수 있는 벤치마크입니다. 이 글에서 언급하는 벤치마크는 모두 이 버전을 기준으로 합니다.
업데이트된 Claude 3.5 Sonnet에 최적화된 에이전트 스캐폴드를 설계할 때 핵심 철학은 언어 모델 자체에 최대한 많은 제어권을 부여하고, 스캐폴딩은 최소한으로 유지하는 것이었습니다. 에이전트는 프롬프트, bash 명령어를 실행하는 Bash Tool, 파일과 디렉토리를 조회·편집하는 Edit Tool로 구성됩니다. 모델이 스스로 작업 완료를 판단하거나 200k 컨텍스트 길이를 초과할 때까지 계속 샘플링합니다. 이 구조 덕분에 모델은 특정 패턴이나 워크플로에 고정되지 않고, 자체 판단에 따라 문제를 풀어나갈 수 있습니다.
프롬프트에는 모델에게 권장하는 접근 방식이 제시되어 있지만, 이 과제에 비해 지나치게 길거나 상세하지는 않습니다. 모델은 엄격하고 불연속적인 전환 없이 각 단계를 자유롭게 진행할 수 있습니다. 토큰 사용량에 민감하지 않다면 모델에게 긴 응답을 생성하도록 명시적으로 권장하는 것이 성능 향상에 도움이 됩니다.
다음은 에이전트 스캐폴드에서 사용한 프롬프트 코드입니다:
<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 명령어를 실행하는 도구입니다. 스키마는 간단하며, 환경에서 실행할 명령어만 입력받습니다. 하지만 도구 설명(description)이 더 중요한 역할을 합니다. 입력값 이스케이프 처리, 인터넷 접속 불가 안내, 백그라운드 명령어 실행 방법 등 모델을 위한 상세한 지침이 포함되어 있습니다.
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`",
...성능을 개선한 방법 중 하나는 도구를 "오류 방지(error-proof)" 처리한 것입니다. 예를 들어, 에이전트가 루트 디렉토리에서 벗어난 후 상대 경로를 잘못 지정하는 경우가 있었습니다. 이를 방지하기 위해 도구에서 항상 절대 경로만 입력받도록 강제했습니다.
기존 파일 편집 방식을 여러 가지 실험한 결과, 문자열 치환(string replacement) 방식이 가장 안정적이었습니다. 모델이 지정한 파일에서 `old_str`을 `new_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은 기존 모델은 물론 이전 최고 성능(SOTA) 모델보다도 뛰어난 추론, 코딩, 수학 능력을 보여줍니다. 에이전트 역량 역시 크게 향상되었으며, 도구와 스캐폴딩을 활용해 이러한 성능 개선을 최대한 끌어낼 수 있습니다.
| 모델 | Claude 3.5 Sonnet (신규) | 이전 SOTA | Claude 3.5 Sonnet (기존) | Claude 3 Opus |
|---|---|---|---|---|
| SWE-bench Verified 점수 | 49% | 45% | 33% | 22% |
벤치마크 실행에는 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은 자기 수정(self-correction) 빈도가 눈에 띄게 높았습니다. 또한 같은 실수를 반복하며 막히는 대신, 여러 가지 다른 솔루션을 시도하는 능력도 보여주었습니다.
SWE-bench Verified는 강력한 평가 도구이지만, 단순한 단일 턴 평가에 비해 실행이 훨씬 복잡합니다. 아래는 저희가 이 벤치마크를 활용하면서 직면한 과제들로, 다른 AI 개발자들도 충분히 마주할 수 있는 문제입니다.
업그레이드된 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의 에이전틱 코딩 성능 향상을 위한 학습에 기여했습니다.