לפני שישה חודשים, במהלך העבודה על כלי פנימי לשיפור הפרודוקטיביות, הצוות שלנו קיבל החלטה שהייתה אז שנויה במחלוקת: נבנה את המאגר שלנו בלי קוד שנכתב בידי אדם. כל שורה במאגר הפרויקט שלנו הייתה חייבת להיווצר בידי Codex.
כדי שזה יעבוד, תכננו מחדש את תהליך הפיתוח שלנו מהיסוד. בנינו מאגר נוח לעבודה עם סוכנים, השקענו רבות בבדיקות אוטומטיות ובמנגנוני הגנה, והתייחסנו ל-Codex כחבר צוות לכל דבר. תיעדנו את הדרך שעברנו בפוסט הקודם שלנו על הנדסת harness.
וזה עבד, אבל אז נתקלנו בצוואר הבקבוק הבא: מעבר בין הקשרים.
כדי לפתור את הבעיה החדשה הזאת, בנינו מערכת בשם Symphony. Symphony(נפתח בחלון חדש) היא מערכת לתזמור סוכנים, שהופכת לוח לניהול פרויקטים כמו Linear למרכז בקרה לסוכני תכנות. לכל משימה פתוחה מוקצה סוכן, הסוכנים פועלים ברציפות, ואנשים בודקים את התוצאות.
בפוסט הזה נסביר איך יצרנו את Symphony — שהובילה לעלייה של 500% במספר ה-pull requests שמוזגו בחלק מהצוותים — ואיך להשתמש בה כדי להפוך את מערכת מעקב המשימות שלכם למערכת תזמור סוכנים שפועלת ללא הפסקה.
גבולות היכולת של סוכני תכנות אינטראקטיביים
גם כשהשימוש בהם נעשה קל יותר, סוכני תכנות — בין שניגשים אליהם דרך אפליקציות אינטרנט ובין שדרך ממשק שורת פקודה — הם עדיין כלים אינטראקטיביים.
ככל שהיקף העבודה האג'נטית ב-OpenAI גדל, נתקלנו בסוג חדש של עומס. כל מהנדס היה פותח כמה סשנים של Codex, מקצה משימות, בודק את התוצרים, מכוון את הסוכן וחוזר על התהליך. בפועל, רוב האנשים יכלו לנהל בנוחות שלושה עד חמישה סשנים במקביל, לפני שהמעבר בין ההקשרים נעשה מכביד. מעבר לכך, הפרודוקטיביות ירדה. היינו שוכחים איזה סשן עושה מה, מדלגים בין חלונות מסוף כדי להחזיר סוכנים למסלול, ומנסים לאתר תקלות במשימות ממושכות שנתקעו באמצע.
הסוכנים היו מהירים, אבל למערכת היה צוואר בקבוק: הקשב האנושי. למעשה בנינו צוות של מהנדסים זוטרים מוכשרים במיוחד, ואז הטלנו על המהנדסים האנושיים שלנו לנהל אותם עד לפרטים הקטנים. השיטה הזאת לא הייתה יכולה לעבוד בקנה מידה גדול יותר.
שינוי נקודת המבט
הבנו שאנחנו מייעלים את הדבר הלא נכון. ארגנו את המערכת שלנו סביב סשנים של תכנות ו-pull requests שמוזגו, בעוד ש-pull requests וסשנים הם בעצם רק אמצעי להשגת מטרה. תהליכי עבודה בפיתוח תוכנה מאורגנים לרוב סביב תוצרים: סוגיות, משימות, כרטיסים ואבני דרך.
לכן שאלנו את עצמנו מה יקרה אם נפסיק לפקח ישירות על הסוכנים, ובמקום זאת נאפשר להם לקחת עבודה ממערכת מעקב המשימות שלנו.
הרעיון הזה הפך ל-Symphony, מפרט כתוב המשמש כמנגנון פיקוח לתזמור עבודה אג'נטית.
הפיכת מערכת מעקב המשימות שלנו למערכת תזמור סוכנים
Symphony התחילה מרעיון פשוט: כל משימה פתוחה צריכה להילקח לטיפול ולהסתיים בידי סוכן. במקום לנהל סשנים של Codex בכמה כרטיסיות, הפכנו את מערכת מעקב המשימות שלנו למרכז הבקרה.
במבנה הזה, לכל כרטיס פתוח ב-Linear מוקצית סביבת עבודה ייעודית לסוכן. Symphony עוקבת ברציפות אחר לוח המשימות ומוודאת שלכל משימה פעילה יש סוכן שעובד עליה בלולאה עד להשלמתה. אם סוכן קורס או נתקע, Symphony מפעילה אותו מחדש. אם מגיעה עבודה חדשה, Symphony מקבלת אותה ומתחילה לארגן את העבודה.
בנינו את תהליך העבודה שלנו סביב הסטטוסים של הכרטיסים, תוך שימוש בכלי ניהול המשימות Linear כמכונת מצבים.
בפועל, Symphony מנתקת את התלות של העבודה בסשנים וב-pull requests. חלק מהכרטיסים מובילים לכמה pull requests במאגרים שונים; אחרים עוסקים רק בבדיקה או בניתוח, בלי לגעת כלל בבסיס הקוד.
כשמגדירים את העבודה ברמת הפשטה כזאת, כרטיסים יכולים לייצג יחידות עבודה גדולות בהרבה.
אנחנו משתמשים ב-Symphony באופן קבוע כדי לתזמר פיתוח של תכונות מורכבות והסבות תשתית. למשל, אנחנו יכולים לפתוח משימה שמבקשת מהסוכן לנתח את בסיס הקוד, את Slack או את Notion ולהכין תוכנית מימוש. אחרי שהתוכנית מקובלת עלינו, הסוכן יוצר עץ משימות, מחלק את העבודה לשלבים ומגדיר את התלויות בין המשימות.
הסוכנים מתחילים לעבוד רק על משימות שאינן חסומות, כך שהביצוע מתקדם באופן טבעי ובמקביליות מיטבית בהתאם ל-DAG הזה (רצף של שלבי ביצוע). לדוגמה, סימנו את שדרוג React כחסום עד להשלמת המעבר ל-Vite. כצפוי, הסוכנים התחילו לשדרג את React רק אחרי שהמעבר ל-Vite הושלם.
סוכנים יכולים גם ליזום עבודה בעצמם. במהלך המימוש או הסקירה, הם מזהים לעיתים קרובות שיפורים שחורגים מהיקף המשימה הנוכחית: בעיית ביצועים, הזדמנות לשפר את מבנה הקוד או ארכיטקטורה טובה יותר. כשזה קורה, הם פשוט פותחים כרטיס חדש שנוכל להעריך ולתזמן בהמשך — וגם רבות ממשימות ההמשך האלה נלקחות לטיפול בידי סוכנים. בזמן שאנחנו מפקחים על התהליך, הסוכנים שומרים על סדר ומקדמים את העבודה.
צורת העבודה הזאת מפחיתה מאוד את המאמץ המחשבתי שנדרש כדי להתחיל עבודה שעדיין אינה מוגדרת היטב. גם אם הסוכן טועה במשהו, אנחנו עדיין לומדים מכך, והעלות מבחינתנו כמעט אפסית. אנחנו יכולים לפתוח במאמץ מזערי כרטיסים שבהם נבקש מהסוכן לבנות אבות טיפוס ולבחון כיוונים חדשים, ולוותר על כל ניסיון שלא מוצא חן בעינינו.
מכיוון שמערכת התזמור פועלת על מכונות פיתוח ולעולם אינה נחה, אנחנו יכולים להוסיף משימות מכל מקום ולדעת שסוכן ייקח אותן לטיפול. למשל, מהנדס בצוות שלנו ביצע שלושה שינויים משמעותיים דרך אפליקציית Linear בטלפון, מבקתה נעימה עם חיבור Wi-Fi רעוע.
צורת עבודה שמעודדת יותר ניסוי וחקירה
כשבחנו את ההשפעות של העבודה עם Symphony, השינוי הבולט ביותר היה בתפוקה. בחלק מהצוותים ב-OpenAI ראינו עלייה של 500% במספר ה-pull requests שמוזגו בשלושת השבועות הראשונים. מחוץ ל-OpenAI, מייסד Linear, קארי סארינן, ציין זינוק במספר סביבות העבודה שנוצרו(נפתח בחלון חדש) עם פרסום Symphony. אבל השינוי העמוק יותר הוא באופן שבו צוותים חושבים על העבודה.
כשהמהנדסים שלנו כבר לא מקדישים זמן לפיקוח על סשנים של Codex, שיקולי העלות והתועלת של כתיבת קוד משתנים לחלוטין. העלות הנתפסת של כל שינוי יורדת, כי אנחנו כבר לא משקיעים מאמץ אנושי בהובלת המימוש עצמו.
זה שינה את אופן הפעולה שלנו. הפעלת משימות ניסיוניות ב-Symphony הפכה לדבר פשוט ביותר. אפשר לנסות רעיון, לבחון שינוי במבנה הקוד, לבדוק השערה — ולשמור רק את התוצאות שנראות מבטיחות.
כך גם יותר אנשים יכולים ליזום עבודה. מנהל המוצר והמעצב שלנו יכולים עכשיו להזין בקשות לתכונות ישירות ב-Symphony. הם לא צריכים למשוך עותק עבודה של המאגר או לנהל סשן של Codex. הם מתארים את התכונה ומקבלים חבילת חומרים לסקירה, שכוללת סרטון המדגים את התכונה בפעולה בתוך המוצר עצמו.
Symphony מצטיינת גם במאגרי מונורפו גדולים (כמו זה שיש לנו ב-OpenAI), שבהם השלב האחרון של מיזוג pull request הוא איטי ומועד לתקלות. המערכת עוקבת אחר ה-CI, מבצעת rebase כשצריך, פותרת התנגשויות, מריצה מחדש בדיקות שנכשלות לסירוגין, ובאופן כללי מלווה את השינויים לאורך כל תהליך השילוב. עד שכרטיס מגיע לסטטוס במיזוג, אנחנו בטוחים במידה רבה שהשינוי ייכנס לענף הראשי בלי צורך בהשגחה אנושית צמודה.
מאז שהטמענו את Symphony, אנחנו מעבירים יותר עבודה לסוכנים ומתמקדים במשימות קשות יותר, שדורשות יותר חקירה.
ההתקדמות מביאה איתה בעיות חדשות ושונות
לעבודה ברמה הזאת יש גם מחירים. כשעברנו מהכוונה אינטראקטיבית של סוכנים להקצאת עבודה באמצעות כרטיסים, איבדנו את היכולת לכוון אותם באופן שוטף תוך כדי העבודה ולתקן את הכיוון בעת הצורך. לפעמים הסוכן יצר משהו שהחטיא לגמרי את המטרה. זה היה מועיל — הכישלונות האלה חשפו פערים במערכת ועזרו לנו להפוך אותה לחסינה יותר.
במקום לתקן את התוצאה ידנית, הוספנו מנגנוני הגנה ומיומנויות כדי שהסוכנים יצליחו בפעם הבאה. עם הזמן, הוספנו בעקבות זאת יכולות חדשות ל-harness שלנו, כמו הרצת בדיקות מקצה לקצה, הפעלת האפליקציה דרך Chrome DevTools וניהול בדיקות תקינות בסיסיות במסגרת אבטחת האיכות. שיפרנו משמעותית את התיעוד שלנו והבהרנו מה נחשב לתוצאה טובה.
לא כל משימה מתאימה לצורת העבודה של Symphony. חלק מהבעיות עדיין דורשות ממהנדסים לעבוד ישירות בסשנים אינטראקטיביים של Codex, במיוחד בעיות שאינן מוגדרות היטב או עבודה שדורשת שיקול דעת מעמיק ומומחיות. בפועל, אלה בדרך כלל המשימות שהמהנדסים שלנו הכי נהנים לעבוד עליהן ומוצאים בהן הכי הרבה עניין.
ההבדל הוא ש-Symphony יכולה לטפל ברוב עבודת המימוש השגרתית. כך המהנדסים יכולים להתמקד בבעיה קשה אחת בכל פעם, במקום לעבור ללא הרף בין ההקשרים של משימות קטנות יותר.
למדנו גם שההתייחסות לסוכנים כאל צמתים קשיחים במכונת מצבים אינה עובדת היטב. המודלים נעשים חכמים יותר ויכולים לפתור בעיות גדולות יותר ממה שמאפשרת המסגרת שאנחנו מנסים להגביל אותם אליה. בגרסאות המוקדמות של העבודה האג'נטית שלנו, רק ביקשנו מ-Codex לממש את המשימה. הגישה הזאת התבררה כמגבילה מדי. Codex בהחלט מסוגל ליצור כמה pull requests, וגם לקרוא הערות סקירה ולטפל בהן. לכן נתנו לו כלים — ממשק שורת הפקודה gh, מיומנויות לקריאת לוגים של CI ועוד — ועכשיו אנחנו יכולים לבקש מ-Codex לעשות יותר, כמו לסגור pull requests ישנים או להפיק דוחות על עבודה שהושלמה לעומת עבודה שנזנחה. משימות מהסוג הזה חרגו בהרבה מהמסגרת המקורית של מימוש תכונות.
לכן עברנו בסופו של דבר לתת לסוכנים יעדים במקום להכתיב מעברים קשיחים בין מצבים, בדומה למנהל טוב שמגדיר מטרה לעובד הכפוף לו בצוות. הכוח של המודלים נובע מהיכולת שלהם להסיק מסקנות, אז תנו להם כלים והקשר — ותנו להם לעבוד.
בניית Symphony באמצעות Symphony
כשתפתחו את המאגר של Symphony,(נפתח בחלון חדש) הדבר הראשון שתשימו לב אליו הוא שמבחינה טכנית Symphony היא רק קובץ SPEC.md — הגדרה של הבעיה ושל הפתרון המיועד. במקום לבנות מערכת פיקוח מורכבת, הגדרנו את הבעיה ואת הפתרונות המיועדים, ונתנו לסוכנים הכוונה כללית.
מימוש הייחוס נכתב ב-Elixir — כי כשכתיבת קוד כמעט אינה עולה דבר, סוף סוף אפשר לבחור שפות לפי היתרונות שלהן, כמו יכולות המקביליות של Elixir — אבל את הרעיון המרכזי אפשר לבטא במסמך Markdown פשוט. אנחנו מזמינים אתכם להפנות את סוכן התכנות המועדף עליכם למפרט ולבקש ממנו ליצור מימוש משלו.
הגרסה הראשונה של Symphony הייתה בסך הכול סשן של Codex שרץ בתוך tmux, בדק את Linear במחזוריות והפעיל סוכני משנה למשימות חדשות. זה עבד, אבל לא היה אמין במיוחד. הגרסה השנייה פעלה בתוך מאגר הפרויקט הראשי שלנו, שנבנה מראש לעבודה עם סוכנים. כבר בנינו את ה-harness לסוכנים כדי לתת להם את המיומנויות וההקשר הדרושים לעבודה איכותית במאגר הזה, כך ש-Symphony פשוט מחברת הכול יחד.
ברגע שהיכולות הבסיסיות היו מוכנות, השתמשנו ב-Symphony כדי לבנות את Symphony.
כשהדגמנו בתוך החברה איך המערכת מנהלת משימות ומצרפת סרטון שמציג את העבודה שביצעה, התגובות היו חיוביות מאוד: ערוץ הפרויקט של Symphony התרחב, וצוותים ברחבי הארגון החלו להשתמש בה מיוזמתם. ב-OpenAI, התאמת מוצר לצורכי המשתמשים בתוך החברה היא תנאי מוקדם להשקה מחוצה לה. לאור השימוש שראינו ב-OpenAI, התברר שכדאי לשתף את Symphony גם מחוץ לחברה.
לכן ניסחנו את הרעיון בקובץ SPEC.md עצמאי וביקשנו מ-Codex לממש אותו. למימוש הייחוס בחרנו ב-Elixir, שפה נישתית יחסית עם אבני בניין מצוינות לתזמור ולפיקוח על תהליכים מקביליים. Codex בנה את המימוש ב-Elixir בניסיון אחד, ומשם המשכנו לשפר גם את המפרט וגם את המימוש. כדי ללטש את המפרט, אפילו ביקשנו מ-Codex לממש אותו בכמה שפות נוספות — TypeScript, Go, Rust, Java, Python — ולהשתמש בתוצאות כדי לזהות אי-בהירויות ולפשט את המערכת. הוא הצליח בכל השפות.
בתהליך הבנייה של Symphony הסרנו הרבה מורכבות לא הכרחית, כמו תלות במאגרים מסוימים או ב-Linear MCP. Symphony כבר אינה תלויה במאגרים הפנימיים או בתהליכי העבודה שלנו. הגישה הבסיסית הפכה לפשוטה:
לכל משימה פתוחה, יש לוודא שפועל סוכן בסביבת עבודה משלו.
מעבר לסיוע בעבודה השוטפת, הסוכנים מכירים כעת גם את תהליך הפיתוח ופועלים לפיו. תהליך הפיתוח — עבודה על כרטיס, משיכת עותק עבודה של המאגר, סימון הכרטיס כמשימה בתהליך כדי שמנהל המוצר ידע שמטפלים בה, הוספת ה-pull request, העברה לסטטוס בסקירה, צירוף סרטונים וכן הלאה — מתועד כעת בקובץ WORKFLOW.md פשוט. כל זה הוא תהליך שאנשים פעלו לפיו, אבל מעולם לא תועד. במקום להסתמך על רצף השלבים הלא-כתוב הזה, אנחנו מתעדים אותו כעת, ו-Symphony מוודאת שהסוכנים פועלים לפיו. כך אנחנו יכולים לבנות סוכנים שעובדים לצדנו. אם נחליט שסוכנים צריכים לצרף גם הערכה עצמית לעבודה שהושלמה, נוסיף זאת ל-WORKFLOW.md, ו-Symphony תנחה את הסוכנים לבצע את השלב הזה.
השתמשנו גם ב-Codex במצב שרת אפליקציה(נפתח בחלון חדש), מצב מובנה להפעלת Codex ללא ממשק משתמש. המצב הזה אפשר לנו להפעיל את Codex ולתקשר איתו באמצעות קוד דרך API מסוג JSON-RPC עם תיעוד מפורט, למשל כדי להתחיל שרשור או להגיב לתורות בשיחה. זה נוח יותר ומתאים יותר להרחבת היקף הפעילות מאשר ניסיון לתקשר עם Codex דרך ממשק שורת פקודה או סשנים פעילים של tmux.
Codex App Server התאים בדיוק לצרכים שלנו: אנחנו מנצלים את ה-harness ש-Codex מספק, ובמקביל מקבלים אפשרויות שליטה ונקודות חיבור למערכת. למשל, כדי לא לחשוף את אסימון הגישה של Linear לסוכני משנה, אנחנו משתמשים בקריאות דינמיות לכלים(נפתח בחלון חדש) כדי להנגיש ישירות את הפונקציה linear_graphql, שמבצעת בקשות מכל סוג מול Linear, בלי להסתמך על MCP ובלי לחשוף את אסימון הגישה לקונטיינרים.
מה הלאה
Symphony היא שכבת תזמור מינימלית במכוון. אנחנו מפרסמים אותה בקוד פתוח כדי להדגים את העוצמה של Codex App Server בשילוב עם כלים שונים לניהול תהליכי עבודה, כמו Linear. בהתאם לכך, איננו מתכננים לתחזק את Symphony כמוצר עצמאי. אפשר לראות בה מימוש ייחוס. מפתחים רבים הפנו את סוכני התכנות שלהם לפוסט על הנדסת harness כדי להקים את המבנה הראשוני של המאגרים שלהם. באופן דומה, אנחנו מקווים שתפנו את סוכן התכנות המועדף עליכם למפרט(נפתח בחלון חדש) ולמאגר(נפתח בחלון חדש) של Symphony כדי לבנות גרסאות משלכם, המותאמות לסביבות שלכם.
העוצמה מגיעה מ-Codex ומשרת האפליקציה שלו. Symphony הייתה דרך לחבר בין Codex ל-Linear, שני כלים שכבר השתמשנו בהם, כדי לפתור את בעיית ניהול העבודה. ככל שסוכני תכנות משתפרים ב-reasoning ובמילוי הוראות, אנחנו מעריכים שגם בחברות אחרות צוואר הבקבוק יעבור מכתיבת קוד לניהול עבודה אג'נטית. הדבר המרגש הוא שסף הכניסה להתנסות במערכות האלה של סוכני תכנות נמוך כעת באופן מפתיע. אפשר פשוט לבנות דברים עם Codex.
פרגון לקהילה
אנחנו שמחים לראות את קהילת הפיתוח משתמשת ב-Symphony בשבועות שחלפו מאז פרסומה. נכון ל-23 באפריל, הפרויקט צבר יותר מ-15 אלף כוכבים ב-GitHub(נפתח בחלון חדש).