המודל העדכני ביותר של אנתרופיק, הלא הוא Claude 3.5 Sonnet המשודרג, הגיע לציון מרשים של 49% במדד SWE-bench Verified – מדד ביצועים להנדסת תוכנה. בכך הוא גבר על המודל שהחזיק בשיא הקודם, שעמד על 45%. פוסט זה נועד להסביר את מבנה ה"סוכן" שבנינו סביב המודל, במטרה לסייע למפתחים להפיק את הביצועים המרביים מ-Claude 3.5 Sonnet החדש.

SWE-bench הוא מדד ביצועים להערכת AI, הבוחן את יכולתו של מודל להשלים משימות הנדסת תוכנה בעולם האמיתי. באופן ספציפי, המדד בודק כיצד המודל יכול לפתור בעיות (issues) מתוך GitHub ממאגרי קוד פתוח פופולריים ב-Python. עבור כל משימה במדד, מודל ה-AI מקבל סביבת Python מוכנה ועותק עבודה מקומי (checkout) של המאגר, כפי שהיה רגע לפני פתרון הבעיה. לאחר מכן, המודל נדרש להבין, לשנות ולבדוק את הקוד לפני שיגיש את הפתרון המוצע על ידו.

כל פתרון נבחן מול בדיקות היחידה (unit tests) האמיתיות מתוך ה-pull request שסגר את בעיית ה-GitHub המקורית. בדיקה זו בוחנת האם מודל ה-AI הצליח להשיג את אותה פונקציונליות כמו המפתח האנושי המקורי שיצר את ה-PR.

חשוב להבין ש-SWE-bench לא מעריך רק את מודל ה-AI עצמו בבידוד, אלא מערכת "סוכן" שלמה. בהקשר זה, "סוכן" מתייחס לשילוב של מודל AI עם תשתית התוכנה העוטפת אותו. תשתית זו אחראית על יצירת הפרומפטים שנכנסים למודל, ניתוח פלט המודל לצורך ביצוע פעולות, וניהול לולאת האינטראקציה שבה תוצאת הפעולה הקודמת של המודל משולבת בפרומפט הבא שלו. ביצועי סוכן ב-SWE-bench יכולים להשתנות באופן משמעותי בהתאם לתשתית זו, גם בעת שימוש באותו מודל AI בסיסי.

קיימים מדדי ביצועים רבים נוספים ליכולות הקידוד של מודלי שפה גדולים (LLMs), אך SWE-bench צבר פופולריות מכמה סיבות מרכזיות:

  1. הוא משתמש במשימות הנדסיות אמיתיות מתוך פרויקטים קיימים, ולא בשאלות בסגנון תחרותי או ראיונות עבודה.
  2. הוא עדיין אינו רווי – יש עדיין מקום רב לשיפור. אף מודל עדיין לא חצה את רף ה-50% במדד SWE-bench Verified (אף ש-Claude 3.5 Sonnet המשודרג עומד, נכון לכתיבת שורות אלה, על 49%).
  3. הוא מודד מערכת "סוכן" שלמה, ולא רק מודל בבידוד. מפתחי קוד פתוח וסטארט-אפים הצליחו מאוד באופטימיזציה של תשתיות סוכנים כדי לשפר דרמטית את הביצועים סביב אותו מודל.

יש לציין כי מאגר הנתונים המקורי של SWE-bench מכיל כמה משימות שלא ניתן לפתור ללא הקשר נוסף מחוץ לבעיית ה-GitHub (לדוגמה, לגבי הודעות שגיאה ספציפיות שיש להחזיר). SWE-bench-Verified הוא תת-קבוצה של 500 בעיות מתוך SWE-bench, שנבדקו על ידי בני אדם כדי לוודא שהן ניתנות לפתרון. לכן, הוא מספק את המדד הברור ביותר לביצועי סוכני קידוד. זהו מדד הביצועים אליו נתייחס בפוסט זה.

השגת ביצועי חזית טכנולוגית

סוכן המשתמש בכלים

פילוסופיית העיצוב שלנו בעת יצירת תשתית הסוכן, שאופיינה עבור Claude 3.5 Sonnet המשודרג, הייתה להעניק כמה שיותר שליטה למודל השפה עצמו, ולשמור על תשתית מינימלית. הסוכן מצויד בפרומפט, בכלי Bash (Bash Tool) לביצוע פקודות Bash, ובכלי עריכה (Edit Tool) לצפייה ועריכת קבצים וספריות. אנו ממשיכים לדגום עד שהמודל מחליט שסיים את משימתו, או חורג מאורך חלון ההקשר (context window) של 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. הסכמה פשוטה, ומקבלת רק את הפקודה שיש להריץ בסביבה. עם זאת, תיאור הכלי נושא משקל רב יותר. הוא כולל הוראות מפורטות יותר למודל, כולל שימוש ב-escaping לקלטים, היעדר גישה לאינטרנט, וכיצד להריץ פקודות ברקע.

{
   "name": "bash",
   "description": "Run commands in a bash shell\n\n* When invoking this tool, the contents of the \"command\" parameter does NOT need to be XML-escaped.\n\n* You don't have access to the internet via this tool.\n\n* You do have access to a mirror of common linux and python packages via apt and pip.\n\n* State is persistent across command calls and discussions with the user.\n\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\n* Please avoid commands that may produce a very large amount of output.\n\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) מורכב הרבה יותר, ומכיל את כל מה שהמודל צריך לצפייה, יצירה ועריכה של קבצים. גם כאן, תיאור הכלי שלנו מכיל מידע מפורט למודל על אופן השימוש בו.

השקענו מאמץ רב בתיאורים ובמפרטים של כלים אלה עבור מגוון רחב של משימות סוכני. בדקנו אותם כדי לחשוף כל דרך שבה המודל עלול להבין לא נכון את המפרט, או מלכודות אפשריות בשימוש בכלים, ולאחר מכן ערכנו את התיאורים כדי למנוע בעיות אלו. אנו מאמינים שיש להשקיע הרבה יותר תשומת לב בעיצוב ממשקי כלים למודלים, באותו אופן שבו מושקעת תשומת לב רבה בעיצוב ממשקי כלים לבני אדם.
{
   "name": "str_replace_editor",
   "description": "Custom editing tool for viewing, creating and editing files\n\n* State is persistent across command calls and discussions with the user\n\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\n* The `create` command cannot be used if the specified `path` already exists as a file\n\n* If a `command` generates a long output, it will be truncated and marked with `<response clipped>` \n\n* The `undo_edit` command will revert the last edit made to the file at `path`\n\n\nNotes for using the `str_replace` command:\n\n* The `old_str` parameter should match EXACTLY one or more consecutive lines from the original file. Be mindful of whitespaces!\n\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\n* The `new_str` parameter should contain the edited lines that should replace the `old_str`",
...

דרך אחת שבה שיפרנו את הביצועים הייתה "אטימת שגיאות" של הכלים שלנו. לדוגמה, לעיתים מודלים עלולים לבלבל נתיבי קבצים יחסיים לאחר שהסוכן עבר מחוץ לספריית הבסיס. כדי למנוע זאת, פשוט חייבנו את הכלי תמיד לדרוש נתיב מוחלט.

ערכנו ניסויים עם מספר אסטרטגיות שונות לציון עריכות בקבצים קיימים, והשגנו את האמינות הגבוהה ביותר באמצעות החלפת מחרוזות. בשיטה זו, המודל מציין את המחרוזת old_str שאותה יש להחליף ב-new_str בקובץ הנתון. ההחלפה תתבצע רק אם יש התאמה בודדת ומדויקת של old_str. אם יש יותר או פחות התאמות, המודל מקבל הודעת שגיאה מתאימה כדי שיוכל לנסות שוב.

...
   "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 המשודרג מפגין יכולות חשיבה, קידוד ומתמטיקה גבוהות יותר ממודלים קודמים שלנו, וכן מהמודל המוביל הקודם. הוא גם מציג יכולות סוכני משופרות: הכלים והתשתית מסייעים לרתום את היכולות המשופרות הללו לשימוש מיטבי.

דוגמאות להתנהגות הסוכן

להרצת מדד הביצועים, השתמשנו בפריימוורק 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.
</pr_description>

המודל מגיב ומשתמש תחילה בכלי העריכה (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 (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 הוא מדד ביצועים רב עוצמה, אך הוא גם מורכב יותר להרצה ממדדי הערכה פשוטים וחד-פעמיים. אלו כמה מהאתגרים שאיתם התמודדנו בשימוש בו – אתגרים שגם מפתחי AI אחרים עלולים להיתקל בהם:

  1. משך זמן ועלויות טוקנים גבוהות. הדוגמאות לעיל הן ממקרה שהושלם בהצלחה ב-12 צעדים. עם זאת, הרצות מוצלחות רבות דרשו מאות תורות מהמודל כדי לפתור את הבעיה, ולמעלה מ-100 אלף טוקנים. Claude 3.5 Sonnet המשודרג עקשן: הוא יכול לעיתים קרובות למצוא דרך לפתור בעיה בהינתן מספיק זמן, אך הדבר יכול להיות יקר.
  2. דירוג. בעת בדיקת משימות שנכשלו, מצאנו מקרים שבהם המודל פעל נכון, אך היו בעיות בהגדרת הסביבה, או בעיות של יישום טלאי התקנה פעמיים. פתרון בעיות מערכתיות אלו חיוני לקבלת תמונה מדויקת של ביצועי סוכן AI.
  3. בדיקות נסתרות. מכיוון שהמודל אינו יכול לראות את הבדיקות שלפיהן הוא מדורג, הוא לעיתים קרובות "חושב" שהצליח כאשר המשימה למעשה נכשלה. חלק מהכישלונות הללו נובעים מכך שהמודל פתר את הבעיה ברמת הפשטה שגויה (יישום פלסטר במקום ריפקטור עמוק יותר). כישלונות אחרים מרגישים פחות הוגנים: הם פותרים את הבעיה, אך אינם תואמים את בדיקות היחידה מהמשימה המקורית.
  4. רב-מודאליות. למרות של-Claude 3.5 Sonnet המשודרג יש יכולות ראייה ורב-מודאליות מצוינות, לא יישמנו דרך עבורו לצפות בקבצים שנשמרו למערכת הקבצים או הוזכרו ככתובות URL. עובדה זו הפכה את הניפוי (debugging) של משימות מסוימות (במיוחד אלו מ-Matplotlib) לקשה במיוחד, וגם הפכה אותן לנוטות ל"הזיות" של המודל. בהחלט יש כאן "פירות נמוכים" למפתחים לשפר – ו-SWE-bench השיקה מדד ביצועים חדש המתמקד במשימות רב-מודאליות. אנו מצפים לראות מפתחים משיגים ציונים גבוהים יותר במדד הערכה זה עם Claude בעתיד הקרוב.

Claude 3.5 Sonnet המשודרג הגיע ל-49% במדד SWE-bench Verified, ובכך עקף את המודל המוביל הקודם (45%), תוך שימוש בפרומפט פשוט ושני כלים לשימוש כללי. אנו בטוחים שמפתחים שיבנו עם Claude 3.5 Sonnet החדש ימצאו במהרה דרכים חדשות וטובות יותר לשפר את ציוני SWE-bench מעבר למה שהצגנו כאן לראשונה.

תודות

אריק שלונץ (Erik Schluntz) אופטימיזציה של סוכן SWE-bench וכתב פוסט זה בבלוג. סיימון ביגס (Simon Biggs), דון דריין (Dawn Drain) ואריק כריסטיאנסן (Eric Christiansen) סייעו ביישום מדד הביצועים. שאונה קרבק (Shauna Kravec), דון דריין, פליפה רוסו (Felipe Rosso), נובה דסארמה (Nova DasSarma), ון צ'נדרסקארן (Ven Chandrasekaran) ורבים אחרים תרמו לאימון Claude 3.5 Sonnet כדי שיהיה מצוין בקידוד סוכני.