דלג לתוכן

פוסט זה עוסק בגבולות הלקוח והפלטפורמה העומדים בבסיס חוויית המשתמש והאינטראקציות עם Ask DoorDash: כיצד עברנו מקרוסלות של האקתון למודל הנוכחי, כיצד אובייקט אחד משרת שלושה קוראים, וכיצד ההקשר והמצב נשמרים עקביים ככל שהצרכנים מתקדמים בתוך DoorDash. הפוסט ממשיך "בניית DoorDash Assistant: סקירה הנדסית" ולסקירות המעמיקות שלנו בניית Ask DoorDash (חלק 2): בינה, בניית Ask DoorDash (חלק 3): הערכה, ו בניית Ask DoorDash (חלק 4): פלטפורמה לבניית והתפתחות סוכנים.


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

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

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

לדברים גדולים יש התחלות קטנות

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

מבחינה פונקציונלית, זה היה דומה למה שאנו משווקים כיום. מבחינת חוויית המשתמש, זה היה פחות מלוטש, וכדאי לעבור על הפרטים.

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

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

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

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

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

חפץ אחד, שלוש עדשות

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

הפורמט המאוחסן הוא מערכת התיעוד: בלוק JSON המוחזק כאובייקט ב-Managed Agent Services, כפי שתואר בפוסט על הפלטפורמה. הוא חייב להיות שלם, והוא העותק המוסמך היחיד.

הסוכן אינו קורא את ה"בלוב" הזה באופן ישיר. רשימת קניות אינטראקטיבית מכילה פרטים רבים יותר ממה שהמודל זקוק לו ברוב פעולות ההמשך. חזרה על כל שם מוצר, מחיר, כמות, תחליף ופרט מטא-נתונים של התצוגה בכל תור תתחרה במה שהצרכן ביקש בפועל. לכן, כאשר סוכן מוציא "ווידג'ט", מה שנשאר בהקשר השיחה הוא סיכום תמציתי: החנות, ותוכן הרשימה. כאשר תור בשיחה דורש מצב מדויק, הסוכן קורא את האובייקט ומקבל בחזרה תצוגה מצומצמת, שממנה הוסרו נתוני המטא-נתונים של התצוגה. תצוגה זו חד-משמעית וקטנה מספיק כדי לעבד אותה ביעילות. רשימה ממוצעת תופסת בין 40 ל-60 KB בפורמט JSON. מה שנשאר בהקשר השיחה הוא שורה אחת של כ-240 תווים, קטנה פי 250 בערך.

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

פרט אחד ממחיש עד כמה הדעות הללו שונות זו מזו. כאשר הסוכן בוחר מוצר עבור פריט ברשימה, הוא שומר את שאר המוצרים שהתאימו לאותו חיפוש, והצרכן יכול לעבור ביניהם בלחיצה אחת. הוא שומר עשרה מועמדים לכל פריט, ול-99.7% מהפריטים יש מספיק תוצאות תואמות כדי למלא את הרשימה הזו, כך שכמעט כל שורה בתצוגה של הצרכן כוללת בחירה אחת ותשע חלופות מאחוריה. תצוגת הצרכן מציגה את כל החלופות הללו. תצוגת הסוכן אינה מציגה אף אחת מהן, מכיוון שהבחירה ביניהן היא תפקידו של הצרכן (אלא אם כן מתבקש העוזר במפורש לעשות זאת).

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

להישאר עם הרגליים על הקרקע

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

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

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

החלוקה הזו היא הבסיס לנתונים עצמם. ערכי המסחר בווידג'ט אינם נלקחים מהמודל. מחירים, מלאי, שעות פתיחה של החנות ותכולת עגלת הקניות נקראים מאותן מערכות רישום שהאפליקציה כולה משתמשת בהן, ולכן מחיר המוצג ב-Ask תואם למחיר המופיע בדף החנות באותו הרגע. תוכן מסוג מסוים (typed) מספק גם לשרת וללקוח הסכם יציב. תמיכה בווידג'ט חדש דורשת יותר משינוי מיידי. הסוכן צריך לדעת מתי להשתמש בו ומה להכניס לתוכו, והלקוח זקוק לסכימה שמית בנוסף לקוד הדרוש לפיענוח ולרינדור שלה. מעבר לכך, ווידג'ט חדש מגיע לצרכן באמצעות אותו מנגנון שיחה וסטרימינג כמו כל ווידג'ט אחר.

איור 3: שני סוגים של הצעות לגבי אותה עגלה. רק באחת מהן מוסבר מדוע.

ווידג'טים כערוצי קלט/פלט

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

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

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

שאלות הבהרה מובנות הן הדוגמה הברורה ביותר, והדפוס לקוח מתחום תכנות הסוכנים: הכלי AskUserQuestion של Claude Code מבצע את אותה המשימה עבור מפתחים. אנו מספקים ווידג'ט שמפריע לצרכן עם סדרה קצרה של שאלות (בחירה מרובה ובחירה מרובת אפשרויות), ומאפשר לו לכוון את השיחה בנקודות פתוחות באמת. זה הפך לעמוד תווך מרכזי במודל האינטראקציה בסוכן המכולת, וכעת הוא מיושם גם בסוכן המסעדות כדי לפשט את אותו סוג של אינטראקציה. אנו משלבים את הכלי בפלטפורמת הזיכרון הצרכנית שלנו, שמצמצמת את האפשרויות באופן משמעותי, אך עדיין נותרים פערי ידע הדורשים קלט מצד הצרכן. אין מנוס משאלות. אך אנו יכולים לשאול באופן שקל ויעיל לצרכן לענות עליו.

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

שינוי החנות הוא היוצא מן הכלל, והיוצא מן הכלל הוא החלק המעניין. זה אינו שינוי של הרשימה הקיימת. זה מתפתח לבקשה מהעוזר, שבונה מחדש את הרשימה בחנות החלופית. אינטראקציה זו נדירה גם היא: היא הייתה הפעולה הראשונה ב-0.1% מהפעמים שבהן המשתמשים היו מעורבים, וזה בערך מה שהיינו מצפים לו אם הקו היה נמתח במקום הנכון בערך. אם מציבים את הקו במקום הלא נכון, הצרכן או שמחכה שהעוזר יבצע פעולה שהוא היה יכול לבצע בלחיצה אחת, או שמקליד את דרכו דרך פעולה שהייתה יכולה להרוויח מהשיקול הדעת של העוזר.

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

התוצאה היא שעריכה ישירה היא הקובעת. לפני שתור מסוים משנה את הרשימה, הסוכן קורא את הרשימה הנוכחית במקום לעבוד על סמך התמליל; לפיכך, אם הצרכן מסיר את חלב השיבולת-שועל, התור הבא מתחיל מרשימה שבה אין חלב שיבולת-שועל.

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

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

כל גרסת עריכה של עוזר נשארת פעילה

כאשר העוזר מתקן רשימת קניות, הגרסה שהוא מחליף נשארת על המסך וניתן להמשיך להשתמש בה.

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

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

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

כאשר רשימה הופכת לעגלת קניות

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

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

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

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

העברת הקשר ברחבי DoorDash

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

מערכת ה-scope שתכננו למטרה זו משתרעת על פני הלקוח והשער. הלקוח מצרף לכל בקשה מרכיבים מרכזיים של הקשר הכניסה: הנושא שתחתו נכנס הצרכן (מכולת, מסעדה), החנות שהוא בוחן וכמה מזהים קשורים. השער משתמש בנושא כדי להחליט לאיזה סוכן להפנות את התור, ובשאר הפרטים כדי לספק לכלים את המזהים הדרושים להם.

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

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

במקרים מסוימים, תחומים (scopes) יכולים גם לאפשר לנו לדלג על המודל לחלוטין. קחו לדוגמה את נקודת הכניסה "להזמין מחדש את העגלה האחרונה שלי". אפשר פשוט לשלוח את הביטוי הזה לעוזר כהודעה, ואף על פי שזה יעבוד, צירוף תחום מאפשר לנו להיות מדויקים יותר. המקרה של "הזמנה מחדש" הוא למעשה דטרמיניסטי, ולכן אנו יכולים לעקוף את ה-LLM ולהחזיר רשימת קניות כמעט באופן מיידי. התוצאה היא ווידג'ט רגיל של רשימת קניות: הצרכן יכול לשנות כמויות, להחליף מוצרים או לבקש מהעוזר לערוך אותה בצ'אט, בדיוק כפי שהיה עושה עם כל רשימה אחרת. שימו לב שהעקיפה תקפה רק אם החנות עדיין מחזיקה את כל הפריטים שהיו בעגלת הקניות הקודמת; אם פריט כלשהו אינו זמין, הבקשה מועברת לסוכן המכולת, אשר בונה מחדש את הרשימה באותו אופן שבו היה עושה זאת על סמך בקשה שהוקלדה.

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

איור 5: צ'אט אחד, שהוזן משני מקומות. ההיקף משתנה בהתאם לכל בקשה, ולכן בקשה בתוך Safeway מוסיפה לרשימה ב-Safeway.

מַסְקָנָה

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

פלטפורמת הניסויים של DoorDash מנהלת למעלה מ-60,000 דגלי תכונות בכ-623 מאגרי קוד. זיהינו למעלה מאלף דגלי תכונות מיושנים; במילים אחרות, התכונה שהדגל שימש בעבר לשליטה עליה כבר הושקה במלואה, אך הדגל והלוגיקה של הענפים שלו עדיין נמצאים בבסיס הקוד כמשקל מת. ניקוי ידני של דגל אחד בלבד לוקח למהנדס בין שעה לשעתיים. עם כ-2,300 דגלים חדשים שנוצרים מדי חודש, הצבר רק הולך וגדל.

לכן בנינו מערכת LLM רב-סוכנתית שמנקה דגלים מיושנים מקצה לקצה, החל מכרטיס Jira ועד לבקשת משיכה (PR) המוכנה למיזוג, ללא מעורבות אנושית למעט מהנדס המאשר את הערך היעד ואת השלמת ה-PR. מתוך 50 הדגלים המיושנים האחרונים שעיבדה, המערכת יצרה בקשות משיכה שמישות עבור 45 מהם, בעלות ממוצעת של 4.79 דולר ו-13.8 דקות לכל דגל, ובכך חסכה אינספור שעות עבודה של מהנדסים. המערכת שבנינו לא רק הייתה צריכה להיות יעילה, אלא שגבולות האמינות שלה היו צריכים להיות של שלמות, ולא של נכונות; אם הסוכן נכשל, הוא היה צריך לעשות זאת בבטחה, מבלי לבצע שינויים בקוד שעלולים לגרום לתקלות.

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

מדוע כדאי לבטל באמצעות אוטומציה דגלי תכונות מיושנים

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

הלוגיקה המותנית שלו כבר אינה משרתת שום מטרה, אך היא לא סתם שוכנת שם ללא כל השפעה:

  • דגלים מיושנים עלולים להישאר בבסיס הקוד במשך שנים. מחקרים קודמים מצאו שכ-25% מדגלי התכונות נשארים פעילים במשך יותר משמונה שנים בפרויקטים בקוד פתוח; אנשי המקצוע מדווחים באופן עקבי כי תהליך הניקוי הוא משימה מכבידה, והוא נדחה שוב ושוב.
  • דגל מיושן הוא חוב טכני. כל דגל מיושן מוסיף ענף, מקרה קיצון, ועוד קצת חומר לקריאה ולהבנה, מה שעלול להיות מכביד במיוחד בעת התרחשות אירוע.
  • דגלים מיושנים עלולים להוות סיכון תפעולי. דגל מיושן משמר מסלול קוד רדום שעלול להיות מופעל מחדש בטעות. במקרה אחד שתועד היטב, חברת מסחר השתמשה בדגל מיושן למטרה אחרת במהלך פריסה, מה שגרם לעסקאות לא מכוונות בהיקף של 460 מיליון דולר תוך 45 דקות בלבד.

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

ערכים דינמיים

דגלי תכונות ב-DoorDash מכונים "ערכים דינמיים" (DV). הם מופעלים באמצעות פלטפורמת הניסויים שלנו. לאורך פוסט זה, המונח DV משמש כשם נרדף ל"דגל תכונה".

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

  1. הוא לא עבר שינויים ב-90 הימים האחרונים.
  2. עדיין יש אליו הפניה בקוד.
  3. הוא עדיין לא נמצא במצב של סיום מחזור חיים (בארכיון או שהוצא משימוש).
  4. זה לא מופיע ברשימת ההחרגות.

משימת cron יומית פותחת כרטיס Jira מסוג STALEDV עבור כל DV מיושן שזוהה, ומקצה אותו ליוצר ה-DV. פעולה זו מסמנת את תחילת התור שממנו פועלת מערכת הניקוי שלנו.

זרימת עבודה סוכנתית לעומת כלי ניקוי מבוססי AST

הגישה האוטומטית הידועה ביותר לניקוי דגלים היא Piranha ויורשתה התומכת במספר שפות, אשר מפשטות תנאים המותנים בדגלים באמצעות התאמת תבניות בעץ התחביר המופשט (AST). גישה זו פועלת היטב כאשר דגל נקרא באמצעות קריאה ישירה ל-API, שאותה כלל כתיבה מחדש יכול להתאים לתבנית.

אבל ב-DoorDash לא כך ניגשים ל-DVs. השירותים שלנו משתמשים בתבנית עטיפה בת שלוש שכבות עם הזרקת תלות:

// Layer 1: RuntimeKeys.kt – the DV name as a string constant
object RuntimeKeys {
  const val ENABLE_X = “enable_feature_x”
}

// Layer 2: FeatureFlags.kt – a DI wrapper that calls the DV client
@Singleton
class FeatureFlags @Inject constructor(
    private val dvClient: DynamicValuesClient
) {
  fun shouldEnableX(userId: String): Boolean =
    dvClient.getBoolean(ENABLE_X, withContext(“user_id” to userId), false)
}

// Layer 3: business logic – uses the flag via dependency injection
class MyService @Inject constructor(
    private val featureFlags: FeatureFlags
) {
  fun process(userId: String) {
    if (featureFlags.shouldEnableX(userId)) handleNewPath()
    else handleOldPath()
  }
}

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

קביעת ערך היעד

ישנה בעיה נוספת שכלי המתבסס על קוד מקור בלבד אינו יכול לפתור: קביעת ערך היעד ובדיקת מצב הפריסה בזמן אמת. כלי שקורא רק את קוד המקור עלול לקבוע בביטחון ערך שגוי בקוד ולשנות את ההתנהגות בשקט. כדי להבטיח שהכלי יבצע את ניקוי הקוד הנכון, יש לדעת את מצב הפריסה בזמן אמת של הדגל, הנמצא בפלטפורמת הניסויים ולא במאגר הקוד. לדוגמה, פלטפורמת הניסויים של DoorDash תומכת בשימוש בדגלי תכונה מסוג מספר שלם, מחרוזת ו-JSON. קריאה בזמן אמת של ערך היעד מבטיחה שהכלי משנה את הקוד עם הערך הנכון של דגל התכונה, המייצג את המצב הנוכחי של המערכת. באופן דומה, מידע על הפריסה הוא גם חלק חשוב במשוואה. ייתכן שניסוי הושק ב-60% מהמערכת ואז ננטש. הכלי צריך להיות חכם מספיק כדי לקבוע שמדובר בהשקה חלקית ולבקש מהמשתמש אישור לפני ביצוע כל ניקוי. הדבר יכול לגרום למשתמש להשלים את ההשקה או את החזרה לאחור לפני השימוש בכלי לביצוע הניקוי, או להנחות את המשתמש לדלג על הניקוי בשלב זה.

היקף ומורכבות

לבסוף, אפילו DV בוליאני פשוט עשוי להשפיע על חמישה עד 20 קבצים, לאחר התחשבות בקבוע, בעטיפה, בכל אתר קריאה, ובעדכון או מחיקה של בדיקות רלוונטיות. זו משימה שדורשת הבנה של הקוד, ולא רק התאמה לתחביר. זו בדיוק הסיבה שבחרנו להשתמש בסוכני LLM. אך המשימה לא הייתה פשוטה כמו כתיבת פקודה וביקוש מהסוכן לבצע את הניקוי; גישה כזו לא הייתה מאפשרת ניקוי יעיל מבחינת עלות וזמן, עם מנגנוני הגנה בקנה מידה גדול.

תהליך דו-שלבי הכולל מעורבות אנושית

המערכת מבוססת על ערכת הפיתוח לסוכנים (ADK) של גוגל ופועלת בשני שלבים, עם נקודת בקרה אנושית אחת ביניהם, כפי שמוצג באיור 1.

איור 1: ארכיטקטורת המערכת. סוכן תזמור מבצע את הניתוח של שלב 1, שולף DVs מיושנים מ-Jira, שואל את פלטפורמת הניסויים לגבי מצב הפריסה באמצעות פרוטוקול הקשר המודל (MCP), ומחפש בבסיס הקוד; מהנדס מאמת את הדוח. לאחר מכן, שלב 2 מפעיל סוכני ניקוי מקבילים בעצי עבודה מבודדים של Git, אשר עורכים, בודקים, מאמתים את הכיסוי ומבצעים בדיקת לינט לפני פתיחת בקשת משיכה (PR).

שלב 1: ניתוח ודוח

סוכן מתאם, ובמקרה זה קלוד סונט, מעבד בקשות ל-DV מיושן. עבור כל DV, הוא:

  1. מביא את כרטיסי ה-DV Jira שהתיישנו באמצעות כלי ממשק שורת הפקודה של Atlassian.
  2. מבקש מפלטפורמת הניסויים של DoorDash, באמצעות פרוטוקול הקשר המודל (MCP), את המטא-נתונים של ה-DV — ה-UUID שלו, אחוז הפריסה וערך היעד.
  3. מאתר את המאגר המקומי ומחפש כל אזכור בקוד של ה-DV.
  4. מייצר דוח מובנה המציע ערך יעד ומפרט את הקבצים המושפעים עבור כל DV.

שילוב ה-MCP הזה הוא הגיבור השקט של העיצוב. באמצעות קריאת מצב הפריסה בפועל בסביבת הייצור, הסוכן קובע את הערך היעד הנכון במקום לנחש על סמך הקוד. לדוגמה, DV שהוכנס עבור תכונה שבסופו של דבר נזנחה מציג פריסה של 0% בפלטפורמה, ולכן הסוכן יודע להסיר אותו באמצעות ערך הבסיס במקום להניח שהתכונה פעילה.

נקודת ביקורת אנושית

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

שלב 2: ניקוי מקביל

עבור כל DV שאושר, ה-Orchestrator מפעיל סוכן הסרה ייעודי — Claude Opus — כאשר כל אחד מהם פועל בסביבת עבודה git מבודדת משלו. עד ארבעה סוכנים פועלים במקביל לכל מאגר, והדבר ניתן להגדרה. כל אחד מהם מבצע ניקוי מלא ופותח בקשת משיכה (pull request) המוקצית לבעל ה-DV.

בתוך חומר להסרת כתמים

כל סוכן הסרה מבצע תהליך עבודה איטרטיבי כדלקמן:

  1. חפש את כל ההפניות ל-DV, כולל הקבוע, פונקציית העטיפה וכל אתר קריאה.
  2. קבעו אסטרטגיית ניקוי בהתאם לסוג ה-DV — בוליאני, מספר שלם או מחרוזת — ולשימושו.
  3. החל את השינויים; החלף את קריאות ה-wrapper בערך היעד ופשט את התנאים שהפכו כעת לקבועים.
  4. הסר את פונקציית העטיפה, את ההגדרה ואת הקבוע.
  5. יש לעדכן או להסיר את הבדיקות המושפעות, כגון מחיקת ענפי בדיקה המסומנים כ"מושבתים".
  6. ודא שהבנייה עברה בהצלחה.
  7. יש לוודא שהבדיקות עברו בהצלחה.
  8. יש לוודא כי שיעור הכיסוי של התיקונים הוא 95% לפחות בשורות ששונו.
  9. הפעל את כלי הבדיקה Detekt.
  10. אם אימות כלשהו נכשל, יש לאתר את התקלה, לתקן אותה ולנסות שוב.

אוטונומיה על בסיס קוד פועלת רק אם מערכי ההגנה הם אמיתיים. ארבעה מנגנונים שומרים על בטיחות הסוכנים:

  • בידוד עץ העבודה ב-Git: כל סוכן פועל בתוך עץ עבודה ייעודי, כך שסוכנים הפועלים במקביל לעולם אינם מפריעים זה לזה, וניקוי שנכשל נמחק בפשטות על ידי הסרת עץ העבודה.
  • פסק זמן קשיח של שעה לכל סוכן: כך מובטח שמפגש שנתקע לא יוכל להימשך ללא הגבלה.
  • אימות כיסוי התיקונים של JaCoCo: תכונה זו אוכפת כיסוי בדיקות של לפחות 95% על השורות שהסוכן שינה.
  • ניתוח סטטי של Detekt: כלי זה אוכף את כללי הסגנון ומאתר בעיות נפוצות.

כמו כן, אנו מריצים את Gradle עם האופציה –no-daemon כדי למנוע זיהום מצב בין עצי עבודה במהלך ריצות מקבילות. חשוב לציין כי אסור לסוכן לפתוח בקשת משיכה (PR) עד שהבדיקות והניתוח הסטטי יעברו בהצלחה באופן מקומי.

תוצאות

בניית מערכת היא דבר אחד, אך כאשר היא פועלת בקנה מידה של DoorDash, רק שאלה אחת חשובה: עד כמה היא פועלת היטב? במקרה זה, אכן היטב מאוד.  מתוך 50 הדגלים ה"מיושנים" האחרונים שהמערכת עיבדה, היא יצרה PR מוכן למיזוג עבור 45 מהם, בעלות ממוצעת של 4.79 דולר ו-13.8 דקות לכל ניקוי, במקום שעה עד שעתיים שהיו נדרשות לניקוי ידני. המערכת לא גרמה לשום באגים או רגרסיות בתהליך.

כיצד הערכנו את המוצר

בדקנו את המערכת על 50 ה-DV-ים ה"מיושנים" האחרונים שהיא עיבדה במספר מאגרי Kotlin. סיווגנו כל אחד מהם לפי רמת המורכבות: 

  • פשוט — בדיקה בוליאנית אחת בקובץ אחד או שניים; n=6
  • בינוני — שימושים מרובים בשלושה עד חמישה קבצים, עם כמה שינויים לצורך בדיקה; n=18
  • מורכב — תנאים מקוננים, תלות בין קבצים, סוגי נתונים שאינם בוליאניים או עדכונים משמעותיים בבדיקות; n=26 

לפי סוג, 41 היו מסוג בוליאני, 6 היו מסוג מחרוזת ו-3 היו מסוג מספר שלם/ארוך. כל בקשת משיכה (PR) נבחנה על פי שלושה קריטריונים: עמידה ב-CI — כולל רף כיסוי התיקונים של 95% — נכונות הקוד, ובדיקת מפתחים. 

תוצאות לפי רמת המורכבות

איור 2: תוצאות הניקוי לפי רמת המורכבות. משתנים תלויים פשוטים מתקבלים ב-100% בניסיון הראשון; משתנים תלויים בינוניים מגיעים לשיעור ניקוי של 94%; משתנים תלויים מורכבים מצריכים יותר תיקונים וכישלונות, אך עדיין מגיעים לשיעור של 85%.

כפי שמוצג באיור 2, 31 מתוך 50 תהליכי הניקוי אוחדו בניסיון הראשון, 14 הצריכו תיקון קל אחד, וחמישה הצריכו התערבות של מהנדס. פירוט המורכבות מתאר את גבול האמינות של המערכת:

  • קובצי DV פשוטים: 100% נוקו במעבר אחד.
  • ערכי DV בינוניים: 94% (17/18) – 14 הושלמו בניסיון אחד, שלושה לאחר תיקון אחד, ואחד שהצריך התערבות של מהנדס.
  • DV-ים מורכבים: 85% (22/26), אפילו עם הסרת פרמטרים בשרשרת דרך יותר מחמש שכבות שיטות, תנאים מקוננים ושינויים נרחבים בקוד הבדיקה.

14 התיקונים היו מינוריים וניתנים לתיקון עצמי; בששה מקרים כיסוי התיקון לא היה מספיק, ונדרשה איטרציה נוספת כדי להוסיף בדיקות, ובשמונה מקרים הסרת הקוד המת הייתה חלקית, עם משתנה או הפניה שנותרו בעומק שרשרת הקריאות. עם זאת, כולם תוקנו בהנחיה חוזרת אחת של ה-LLM.

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

עלות וזמן

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

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

מורכבותnזמן ממוצעזמן חציוניעלות ממוצעתעלות חציונית
פשוט67.5 דקות8.2 דקות$2.69$2.50
בינוני1810.4 דקות9.9 דקות$3.46$3.42
מורכב2617.7 דקות14.4 דקות$6.20$4.50

טבלה 1: מדדי ביצועים לפי רמת מורכבות ב-50 דגלי תכונות שנבדקו.

איור 3: עלות ה-API לעומת זמן השעון עבור כל DV, מסודרים לפי צבע בהתאם לרמת המורכבות. ה-DV-ים הפשוטים והבינוניים מתרכזים באזור בעל העלות הנמוכה והזמן הקצר. ה-DV-ים המורכבים פזורים, עם כמה ערכים חריגים המתקרבים ל-40 דקות ו-19 דולר. ה-DV-ים שנכשלו (×) נוטים לזמני ריצה ארוכים יותר.

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

מה שלמדנו

  • התמחות במודלים לפי תפקיד משתלמת. אנו משתמשים ב-Claude Sonnet לצורך תזמור, כולל הקשר רחב, איסוף ותכנון מטא-נתונים קלים, וב-Claude Opus עבור סוכני ההסרה, כולל חשיבה מעמיקה על סמנטיקה של קוד, שרשראות קריאות ותלותי בדיקה. השמירת המודל היקר יותר לשלב העריכה, התובעני מבחינה קוגניטיבית, הובילה להפחתת העלות הכוללת של ה-API מבלי לפגוע באיכות הניקוי.
  • בידוד עץ העבודה הוא תנאי הכרחי עבור סוכנים הפועלים במקביל. הניסויים המוקדמים שלנו, שבהם לא נעשה שימוש בבידוד עץ העבודה, הובילו למצבי תחרות שבהם סוכנים הפועלים במקביל ערכו את אותם קבצים ויצרו דפים של הבדלים פגומים. עץ עבודה ייעודי לכל סוכן, בשילוב עם Gradle במצב –no-daemon, הפך את הניקוי המקביל לבטוח ואיפשר התמודדות קלה עם כשלים.
  • שילוב הניסויים בזמן אמת היה ההחלטה שהניבה את התועלת הגדולה ביותר. ללא מצב הפריסה הנוכחי, כל גישה אוטומטית — בין אם מבוססת כללים ובין אם מבוססת LLM — עלולה להוביל לקידוד קשיח של ערך שגוי ולשימור סמוי של ההתנהגות השגויה. קריאת הנתונים באמצעות MCP הוסיפה חביון זניח וחיסלה סוג שלם של שגיאות בערכי היעד.

כל צוות השוקל יישום אוטומציה דומה צריך לשים לב שתוצאותינו מצביעות על שלושה תנאים מוקדמים מעשיים: 

  • מקור אמין של מדינת הדגל שבה הוצב הספינה
  • בידוד עץ העבודה לצורך עריכות מקבילות, ו- 
  • תהליכי אימות דטרמיניסטיים מתבצעים עוד לפני פתיחת בקשת משיכה (PR).

מה הלאה

אנו מרחיבים את המערכת בשני מישורים:

  1. ציון אמינות של שלב 1 לאישור אוטומטי של ניקויים בעלי סיכון נמוך. לדוגמה, משתנה תלוי בוליאני (DV) שנמצא ב-100% פריסה, שקוד ברירת המחדל שלו כבר תואם לסביבת הייצור, מה שמאפשר לשמור את נקודת הבדיקה האנושית למקרים מעורפלים באמת.
  2. בדיקה של איכות הקוד לאחר הניקוי. בדיקה זו תאתר בעיות סמנטיות, כגון שמות משתנים שאינם משקפים עוד את ייעודם לאחר הסרת דגל מסוים.

ניקוי דגלי תכונות הוא סוג של עבודה שכל משימה בנפרד היא קטנה, אך במצטבר היא עצומה, במיוחד בקנה המידה של DoorDash, והיא נדחית ללא הרף. באמצעות שילוב של מתאם, סוכני הסרה מקבילים בעצי עבודה מבודדים, חיפושים בפלטפורמת ניסויים בזמן אמת ושערי אימות קפדניים, מערכת ניקוי דגלי התכונות שלנו הופכת צבר עבודה של אלפי שעות לתהליך רקע זול ואמין, המייצר בקשות למשיכה (PR) מוכנות למיזוג עבור 90% מהדגלים שהיא מטפלת בהם, בעלות של כ-4.79 דולר ו-14 דקות לכל אחד, ללא רגרסיות. האתגר שנותר הוא השלמת שרשראות הקריאות העמוקות ביותר, וזה בדיוק המקום שבו נתמקד בשלב הבא.

מעוניינים לבנות מערכות מסוג זה? מחלקת ההנדסה של DoorDash מחפשת עובדים – בואו לעזור לנו לבנות בקנה מידה גדול.

Flux היא פלטפורמת הסוכנים מבוססת הענן של DoorDash המיועדת למהנדסים. בחודש אחד בשנת 2026, השתמשנו ב-Flux כדי לבצע אוטומציה של 130,000 משימות הנדסיות. Flux, שהתרחבה במהירות לאחר השקתה ברבעון הראשון של 2026, כבר מפעילה תהליכי עבודה ברקע בהיקפים גדולים ברחבי DoorDash, כולל יותר מ-25,000 ביקורות קוד אוטומטיות בכל שבוע, וכן יותר מ-300 מדריכים ייחודיים ויותר מ-10,000 קריאות המשמשות מדי שבוע. תהליכי עבודה אלה יכולים לפעול ללא השגחה, במקביל, מסביב לשעון.

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

דוגמאות לשימוש בתהליך העבודה של Flux Background

טבלה 1: תמונת מצב של השימוש ב-Flux ברחבי DoorDash במהלך חודש אחד, הכוללת ביקורות קוד אוטומטיות, הרצות של מדריכי פעולה והשלמת משימות ברקע

מאיפה התחלנו

במהלך השנה האחרונה, משתמשים שהריצו עומסי עבודה מבוססי סוכנים במחשבים הניידים שלהם נתקלו במהרה במגבלות:

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

הגישה שלנו לטיפול בסוגיות אלה היא פשוטה: 

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

מדוע פיתחנו את Flux באופן פנימי

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

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

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

אלמנטים בסיסיים, לא תהליכי עבודה

כפי שמוצג באיור 1, Flux בנוי סביב ארבעה מרכיבים בסיסיים של הפלטפורמה: סביבות בדיקה (sandboxes), שער פרוטוקול הקשר המודל (MCP), מדריכי פעולה (playbooks) ומשטחי הפעלה (invocation surfaces). יחד, הם מאפשרים לבצע האצלת משימות לסוכנים באופן חוזר. מדריך הפעולה מגדיר את העבודה. סביבת בדיקה בענן מספקת לסוכן סביבה אמיתית לביצועה. שער הסוכן שולט באילו מערכות הסוכן יכול לגשת. ומשטחי ההפעלה מאפשרים למהנדסים להתחיל ולקבל משימות מהמקומות שבהם הם כבר משתמשים.

איור 1: ארבעת המרכיבים הבסיסיים של הפלטפורמה המרכיבים את Flux — סביבות בדיקה, שער ה-MCP, מדריכי פעולה ומשטחי הפעלה — והאופן שבו הם מתחברים כדי להפוך משימה לעבודה שסוכן יכול לבצע בבטחה

סביבות בדיקה מספקות את סביבת ההרצה

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

Flux מעבירה את הביצוע לסביבות בדיקה מבודדות בענן, הנתמכות על ידי מיקרו-מכונות וירטואליות (microVMs) של Firecracker, לצורך בידוד ברמת החומרה. כל סביבת בדיקה מצוידת במאגרי הקוד, בכלי הפיתוח, בסודות ובתלות הריצה הנדרשים למשימה, מה שמספק לסוכנים סביבת עבודה הנדסית מלאה, תוך מתן מודל עקבי של ביצוע, אבטחה וניטור ל-DoorDash.

השליטה בשכבה זו מאפשרת לנו לתמוך בתהליכי עבודה הנדסיים אמיתיים, כולל ביצוע שינויים במספר מאגרים ובמספר בקשות משיכה (pull requests) מתוך הפעלה אחת. ל-Flux יש יעד רמת שירות (SLA) של פחות מחמש שניות באחוזון ה-95 עבור ההתקנה המלאה מקצה לקצה — החל מהפעלת ה-microVM ועד לשכפול המאגרים הנדרשים, התקנת כלי הבנייה והגדרת מערכי הסוכנים הנתמכים לכתיבת קוד.

שער ה-MCP מספק גישה מבוקרת

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

Flux מחבר את הסוכנים למערכות הפנימיות באמצעות שער MCP פנימי המכונה Agent Gateway. כל תסריט פעולה מציין את הכלים הנדרשים לו, ו-Flux מעניק רק את ההרשאות המוגבלות הנחוצות לביצוע משימה זו. כל פעולה נרשמת, וכך נוצר תיעוד ביקורת ברור.

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

המדריכים מגדירים את העבודה

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

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

משטחי Invocation מתאימים את עצמם לצרכים של המפתחים

ניתן להפעיל את אותו תסריט עבודה מ-Slack, GitHub, cron, ממשק השורה (CLI) או מיומנות שיחתית. משמעות הדבר היא שצוותים יכולים להגדיר זרימת עבודה פעם אחת ולהפעיל אותה מהממשק המתאים ביותר לאותו הרגע:

  • Slack לצורך חלוקת משימות בשיתוף פעולה
  • GitHub לאוטומציה של בקשות למשיכה (PR) ו-CI
  • Cron לצורך תחזוקה שוטפת
  • CLI לשליטה ישירה של המפתח, או הפעלה באמצעות סקיל

זה מה שהופך את Flux לקל לאימוץ.

לקחים שנלמדו

הקמת Flux לימדה אותנו לא פחות על אימוץ המוצר מאשר על התשתית, ובכלל זה:

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

מה הלאה

בפוסטים הבאים נעמיק בנושא הרכיבים הבסיסיים של הפלטפורמה שמאפשרים את פעולת Flux, וכן בחוויית המפתחים בבניית זרימות עבודה חדשות. כמו כן, נדון ביישומים שבנינו על בסיס הפלטפורמה, כולל Flux Responder, הסוכן הפנימי שלנו ב-Slack.

תודות

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

הישארו מעודכנים עם עדכונים שבועיים

הירשמו לבלוג ההנדסה שלנו כדי לקבל עדכונים שוטפים על כל הפרויקטים הכי מגניבים שהצוות שלנו עובד עליהם

סוכני בינה מלאכותית הופכים לשימושיים כאשר הם יכולים לפעול במערכות אמיתיות. ב-DoorDash, משמעות הדבר היא גישה ל-API פנימיים, למערכות הנדסיות, לפלטפורמות ניטור, למערכות ניהול תקלות, למאגרי ידע ולמוצרי SaaS של צד שלישי. פרוטוקול הקשר המודל (MCP) הקל על חשיפת הכלים הללו בכך שהעניק לסוכנים ולשרתים דרך משותפת לתאר, לאתר ולהפעיל יכולות.

כשהסוכנים עברו מניסויים לתהליכי עבודה אמיתיים, נתקלנו בבעיה אחרת. אמנם ה-MCP קבע תקן לצורת קריאת הכלי, אך הוא לא סיפק מענה לשאלות מרכזיות הקשורות לייצור סביב אותה קריאה:

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

השאלות הללו הולכות ומתרבות במהירות. סוכן תכנות עשוי להזדקק ל-GitHub, Jira, חיפוש קוד, אינטגרציה רציפה (CI), יכולת ניטור ותיעוד. שרת MCP של צד שלישי עשוי לחשוף מאות כלים, בעוד שתהליך העבודה זקוק לחמישה בלבד. סוכן הפונה למשתמשים עשוי להזדקק לאישור OAuth של המשתמש, בעוד שאוטומציה צוותית צריכה להשתמש בגוף שירות לא אישי. אם כל צוות פותר את הבעיות הללו באופן עצמאי, כל צמד של סוכן-כלי מסתיים עם קוד אימות, זרימת OAuth, טיפול בסודות, קטלוג כלים, מגבלות קצב ויומנים משלו.

לכן הקמנו את "Agent Gateway" כדי להפוך את הגישה לכלי הסוכנים ליכולת מובנית בפלטפורמה. זוהי נקודת כניסה יחידה ומפוקחת, שבה הסוכנים מאתרים ומפעילים כלים. השער מאמת את זהות המתקשר, בודק את ההרשאות, חושף רק את ממשק הכלים המאושר, מזין את פרטי ההזדהות הנכונים, מנתב את השיחה לשרת ה-MCP במורד הזרם, ומקליט אירוע שימוש מובנה עבור כל שיחה.

השער אינו רק פרוקסי. הוא מהווה את מישור הבקרה של מערכת הסוכנים. הוא קובע מי רשאי להפעיל כלים, בוחר אילו כלים יוכלו הסוכנים לראות, מאגד את הכלים לממשקים המותאמים למשימות, ומספק ל-DoorDash נקודת גישה אחת לניטור, להגבלת קצב השימוש, לביטול ולשיפור הגישה של הסוכנים לכלים.

הבעיה: הגישה לכלי מורכבת משלושה חלקים

בעוד ש-MCP מסייע לסוכנים להפעיל כלים, הבעיה המורכבת יותר בסביבת הייצור כוללת שלושה ממדים:

  1. הנושא הראשון הוא הגישה. הפלטפורמה צריכה לדעת מי מתקשר, האם הוא מורשה לכך, ואיזה מודל אימות חל: זהות פנימית, אסימון המוחזק בשער, OAuth לכל משתמש, או גישה באמצעות ישות שירות.
  2. השני הוא ניהול משטח הכלים. הסוכנים לא צריכים לקבל קובץ גולמי המכיל את כל הכלים שנחשפים על ידי שרתי MCP במורד הזרם. קטלוגים קטנים יותר, הרלוונטיים למשימה, משפרים את הבטיחות, מפחיתים את הבלבול במודל ומקלים על תפעול הסוכנים.
  3. הנושא השלישי הוא התפעול. קריאות לכלים דורשות הגבלות קצב, מעקב, מדדים, אירועי שימוש, ייחוס עלויות, מטא-נתונים על בעלות ושקיפות בסביבת הייצור.

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

ארכיטקטורת שער

לשער יש שני מרכיבים מרכזיים: פרוקסי ומרשם, כפי שמוצג באיור 1 להלן. הפרוקסי הוא מישור הנתונים; הוא מקבל כל בקשת MCP, מאמת את זהות המתקשר, מאשר את הפעולה, מפעיל מגבלות קצב, מזין אישורים, מעביר את הבקשה ומשדר נתוני ניטור. הרישום הוא מקור האמת של מישור הבקרה; הוא מאחסן סוכנים, שרתים MCP, בעלים, תצורות העברה, מצבי אימות, מדיניות, קטלוגים של כלים שזוהו ותצורות ממשק הכלים.

איור 1: ארכיטקטורה כללית של שער הסוכנים

חלוקה זו מעניקה לשער מספר תכונות שקשה להשיג באמצעות אינטגרציות מסוג "נקודה לנקודה":

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

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

זהות, הרשאות וסודות מרכזיים

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

שער הגישה בודק את ההרשאה באופן מרכזי. שאלות המדיניות אינן מסתכמות בשאלה האם המתקשר יכול לגשת לשרת זה. הן עשויות לכלול גם:

  • האם הסוכן הזה יכול לגשת לשרת הזה?
  • האם המשתמש הזה יכול להפעיל את הכלי הזה באמצעות הסוכן הזה?
  • האם ניתן לחשוף את הכלי הזה בסביבה זו?
  • האם המתקשר הזה יכול להשתמש בגרסה התומכת בכתיבה, או רק בגרסה לקריאה בלבד?
  • האם תהליך עבודה זה יכול להשתמש בגוף שירות צוותי, או שהוא מחייב שימוש ב-OAuth לכל משתמש בנפרד?

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

הטיפול בתעודות עוקב אחר אותו דפוס, כפי שמוצג בטבלה 1:

מצב אימותמי מחזיק בתעודהמה תפקידו של השער
זהות שירות פנימיתהתשתית של DoorDashמעביר את הקשר של המתקשר המאומת לשירותים פנימיים
אסימון המוחזק על ידי Gatewayאחסון סודי של שער הגישהמזריק אסימון ספק או שירות מבלי לחשוף אותו לסוכן
OAuth לכל משתמשמאגר הרשאות מוצפן לכל משתמשמזריק ומרענן את האסימון של המשתמש עבור פעולות בהיקף המשתמש
גורם שירות ראשימנהל הקבוצה מטעם גייטווייגופים מנפיקים או מתווכים של אישורים לא אישיים בעלי תוקף קצר

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

OAuth לכל משתמש מבלי לשבש את תור הסוכנים

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

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

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

איור 2: לחיצת יד לצורך איסוף מידע

משטחי כלים מאורגנים: חבילות וסינון

סוכנים אינם חושבים באופן טבעי במונחים של שרתים מסוג MCP. הם חושבים במונחים של משימות. סוכן תכנות אינו מעוניין ב-GitHub, ב-Jira, ביכולת ניטור ובתיעוד כשלבים נפרדים בתהליך ההתקנה; הוא מעוניין בממשק הכלים הדרוש לו כדי לחקור בעיה, לשנות קוד, לפתוח בקשת משיכה (pull request), לבדוק את ה-CI ולהבין את התנהגות המערכת בסביבת הייצור.

במקביל, מרבית שרתי ה-MCP במורד הזרם חושפים הרבה יותר כלים מכפי שסוכן בודד אמור להשתמש בהם. שרתים של צד שלישי עשויים לפרסם מאות פעולות, לרבות פעולות ניהול, פעולות הרסניות, ממשקי API לחיוב ותכונות ייחודיות לספקים ספציפיים. מרבית תהליכי העבודה של DoorDash זקוקים רק לתת-קבוצה קטנה ומאושרת מתוכן.

השער פותר את שתי הבעיות באמצעות ממשקי כלים שנבחרו בקפידה, כפי שמוצג באיור 3. החבילות משלבות כלים ממספר שרתים של MCP לנקודת קצה לוגית אחת של MCP. המסננים קובעים אילו כלים מכל שרת ייחשפו עבור חבילה, סוכן, קבוצת משתמשים, סביבה או קהל יעד נתונים.

לדוגמה, חבילת כלי מפתחים עשויה לכלול:

  • כלים נבחרים של GitHub לתהליכי עבודה של מאגרים ובקשות משיכה;
  • כלי Jira נבחרים לחיפוש בעיות ולעדכונים;
  • כלי ניטור נבחרים עבור יומנים, מדדים ועקבות;
  • כלי חיפוש קוד ותיעוד נבחרים; וכן
  • כלי פריסה או כלי סימון תכונות נבחרים.

איור 3: חוויית המשתמש עם חבילת MCP המצורפת

הסוכן מתחבר לכתובת URL אחת של השער, כגון נקודת קצה של כלי מפתחים. מאחורי כתובת ה-URL הזו, השער מפזר את tools/list בין השרתים בחבילה, מיישם סינון הרשאות וכלים, מגדיר מרחבי שמות או כינויים לשמות הכלים לפי הצורך, ומחזיר קטלוג אחיד אחד. כאשר הסוכן קורא ל-tools/call, השער אוכף את המדיניות שוב, מנתב את הקריאה לשרת הנכון במורד הזרם, ומיישם את מודל האישורים של אותו שרת.

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

היתרונות הם מעשיים:

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

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

נראות, ייחוס עלויות והגנה על שלבים הבאים בתהליך

מכיוון שכל שיחה עוברת דרך השער, כל בקשה יכולה לשדר אירוע מובנה הכולל:

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

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

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

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

השער הופך את הניהול לנתונים, במקום להסתמך על כל צוות שימלא את השדות הנכונים ויאכוף את המגבלות הנכונות.

תהליך קליטה בשירות עצמי

שער גישה פועל רק אם הצוותים מעדיפים להשתמש בו במקום לעקוף אותו. הרישום, האיתור, הסינון וניהול החבילות – כולם חייבים להתבצע באופן עצמאי.

באמצעות ממשק המשתמש (UI) וממשק ה-API של מישור הבקרה, הצוותים יכולים לרשום שרתים וסוכנים של MCP, להגדיר אימות, לאתר כלים, להקצות בעלות, להגדיר מסננים, להוסיף כלים לחבילות ולבדוק את השימוש בסביבת הייצור.

תהליך ההטמעה של השער כולל את השלבים הבאים:

  1. רשום את שרת ה-MCP.
  2. גלו את קטלוג הכלים הגולמי שלו דרך tools/list.
  3. בחר ואשר את הכלים ש-DoorDash מעוניינת לחשוף.
  4. הגדר את מצב האימות, הבעלות והמדיניות.
  5. הוסף את הכלים שאושרו לחבילה אחת או יותר.
  6. עקבו אחר התעבורה, זמן ההשהיה, השגיאות, החלטות האישור והעלות.

ממשל הדורש כרטיסים אינו ניתן להרחבה. הדרך הסלולה חייבת להיות קלה יותר מאשר העתקת סוד לסוכן והתחברות ישירה לשרת.

מה השתנה

השער מעניק לכל קבוצה יתרון שונה:

  • מפתחי סוכנים מקבלים אינטגרציה אחת, קטלוג אחד שנבחר בקפידה, וללא אימות במורד הזרם, OAuth, טיפול בסודות או ניתוב לפי כלי.
  • בעלי הכלים זוכים למסלול הפצה מנוהל הכולל בקרת גישה, חשיפה מאושרת של הכלים ונתוני שימוש בסביבת הייצור.
  • צוותי האבטחה מקבלים גישה למדיניות מרכזית, לסודות, להרשאות OAuth, לביטול הרשאות ולרישומי ביקורת.
  • צוותי הפלטפורמה זוכים ליתרון; זהות, הגבלת קצב, יכולת ניטור, איכות הכלים, ייחוס עלויות וחווית המפתחים – כל אלה משתפרים במקום אחד.
  • הסוכנים זוכים לקטלוגים מצומצמים יותר, לשמות כלים ברורים יותר, לחבילות המותאמות למשימות, למספר מצומצם יותר של אפשרויות לא רלוונטיות ולתהליכי חיבור הניתנים לשחזור.

אימוץ

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

  • מאחורי השער רשומים יותר מ-200 שרתים מסוג MCP, אשר יחד חושפים אלפי כלים שנבחרו בקפידה והוכנסו לתתי-קבוצות מאושרות המותאמות למשימות ספציפיות, במקום קטלוגים גולמיים.
  • יותר מ-30 סוכנים ושירותים, שבהם משתמשים אלפי עובדים, ניגשים לכלים אלה דרך השער, ואף אחד מהם אינו מטפל בנתוני הזדהות גולמיים. 
  • מיליוני קריאות לכלי עבודה בכל שבוע מועברות דרך שער הסוכנים (Agent Gateway), כאשר כל אחת מהן עוברת אימות, אישור והקלטה כאירוע שימוש מובנה.
  • תהליך ההטמעה הוא עצמאי ומהיר. רישום שרת MCP חדש והכלים הנלווים אליו אורך דקות ספורות, והצבת סוכן על כלי שכבר נרשם היא מהירה עוד יותר.

לקחים שנלמדו

הקמת השער והרחבתו שינו את האופן שבו אנו תופסים את הגישה של הסוכנים לכלים. ניתן להפיק מכך מספר תובנות בולטות, ולא רק ב-DoorDash:

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

מה הלאה

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

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

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

מַסְקָנָה

שער הסוכנים (Agent Gateway) הופך את הגישה לכלי הסוכנים מעבודה חוזרת ונשנית של אינטגרציה ליכולת משותפת של הפלטפורמה. MCP הקל על תיאור הכלים והפעלתם; השער הופך את הגישה הזו למפוקחת, מאורגנת, ניתנת לניטור וניתנת להרחבה.

תודות

מבוא

פיתחנו את Ask DoorDash על גבי פלטפורמה משותפת המאפשרת לצוותי התחומים לבנות ולשכלל את הסוכנים שלהם מבלי לבנות מחדש את המערכות העומדות בבסיסם. הערכנו את הפלטפורמה על פי שני מדדים מעשיים: מהירות הוספת התכונות והתחומים על ידי הצוותים, ומהירות הערכתם ושחרורם של שיפורים בתחומי העלות, האיכות וזמן ההשהיה.

השקנו את "Ask DoorDash" עם תמיכה במסעדות ובמרכולים תוך כחודשיים, ומאז היא טיפלה ביותר משני מיליון שיחות. הוספת "Reservations", הסוכן התחומי השלישי שלנו, ארכה שבוע אחד – מהירות גבוהה פי 10 בערך בהשוואה לפיתוח הסוכנים התחומיים הראשונים.

מערכת ההערכה המשותפת שלנו ובקרות הפריסה מספקות לצוותים אינדיקציות ברורות לגבי איכות התוצאות, תוך כדי העברת השינויים לסביבת הייצור. תוך שבוע מרגע שחרורו של מודל LLM חדש, הערכנו אותו ופרשנו אותו, ובכך צמצמנו את זמן ההשהיה ב-p50 ב-35% ללא ירידה בציוני האיכות. שדרוג מודל שבוצע לאחר מכן צמצם את זמן ההשהיה ב-p50 בעוד 40%.

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

כיצד בחרנו מה לתקנן

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

במקרים שבהם היה קיים תקן תעשייתי מתאים, אימצנו אותו. Agent2Agent (A2A) הגדיר את אופן התקשורת בין הסוכנים, ואילו Google Agent Development Kit (ADK) סיפק את המסגרת לבנייתם ולהפעלתם. תקנים אלה הגבילו לעתים את אפשרויות העיצוב שלנו, אך הם סיפקו לצוותים חוזים משותפים וחסכו לנו את הצורך לפתח מקבילים קנייניים.

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

שאל את צוות הארכיטקטורה של DoorDash

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

כפי שמוצג באיור 1, כל בקשה נכנסת דרך השער (Gateway). השער מאמת את זהות המשתמש, מרכיב את הקשר של נקודת הכניסה, ומבצע תרגום בין ממשקי ה-HTTP והסטרימינג של הלקוח לבין פרוטוקול ה-A2A של הפלטפורמה. לאחר מכן, הוא מעביר את הבקשה למנצח, אשר בוחר את הסוכן התחומי עבור כל תור, תוך שמירה על רציפות ככל שהשיחה עוברת בין תחומים. הסוכן הנבחר טוען את הכישורים המתאימים ומשתמש בכלים של פרוטוקול הקשר המודל (MCP) כדי לתקשר עם שירותי DoorDash הקיימים.

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

איור 1: Ask DoorDash מבדיל בין התנהגות הסוכנים הספציפית לתחום לבין יכולות הביצוע וההפקה המשותפות המשמשות בכל רחבי המערכת.

שער לחוויות מותאמות ומולטי-מודאליות

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

ה-Gateway מטפל בתרגום זה. הוא מאמת את המשתמש, מוסיף הקשר לגבי המקום שבו החלה השיחה, וממיר בקשות HTTP של הלקוח לבקשות A2A. במסלול החזרה, הוא משתמש ב-Vercel AI SDK כדי לשלוח עדכוני טקסט ותכנים של ווידג'טים ללקוחות באמצעות Server-Sent Events (SSE). הלקוחות מציגים את העדכונים עם הגעתם, כך שהמשתמשים יכולים לראות את ההתקדמות בזמן שהסוכן משלים את תורו.

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

עוזר אחד, סוכנים המתמחים בתחום מסוים

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

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

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

איור 2: "פינינג" מונע קריאה ל-Orchestrator בתורות הבאות, תוך שמירה על האפשרות שהשיחה תעבור בין תחומים.

המיומנויות מגבילות את ההקשר ואת העלות

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

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

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

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

סוכןהוראות בסיסיות והוראות מיומנות עם כל המיומנויות הטעונותהמספר החציוני של הוראות המותאמות לרמת המיומנות בכל תורהפחתה
מסעדהכ-42,000 אסימונים

כ-20,000 אסימונים50% ומעלה
מכולתכ-25,000 אסימוניםכ-10,000 אסימונים60%

גישה בטוחה וניתנת לשימוש חוזר לשירות באמצעות MCP

האפליקציה "Ask DoorDash" זקוקה לגישה לשירותי DoorDash כדי לחפש חנויות ומוצרים, לקרוא תפריטים, לנהל עגלות קניות ולפעול בשם המשתמש. ממשקי ה-API העומדים בבסיס פעולות אלה מבוססים על קוד יישום דטרמיניסטי. מודל שפה גדול (LLM) הבוחר פעולות בזמן ריצה זקוק לממשק מצומצם יותר. חשיפת ממשקי ה-API באופן ישיר תאלץ את המודל לפרש ממשקים ברמה נמוכה. קידוד ההרשאות וכללי העסק רק בפרומפט יוסיף הקשר, אך לא יבטיח את אכיפתם.

בנינו שכבת Model Context Protocol (MCP) משותפת בין הסוכנים לממשקי ה-API של DoorDash. כל כלי MCP חושף פעולה ספציפית הכוללת את הקלטים והפלטים הדרושים למודל. המודל בוחר לאיזה כלי לפנות. קוד דטרמיניסטי מאמת כל בקשה ומאכף הרשאות וכללים עסקיים לפני שהבקשה מגיעה לשירות הבסיסי.

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

תכנון כלים דורש איזון. כלי רחב מדי עלול להציב בפני המודל אפשרויות רבות מדי, בעוד שכלי צר מדי עלול להפוך משימה לשרשרת ארוכה של קריאות. שרת ה-MCP המשותף שלנו מספק כעת יותר מ-60 כלים עבור זרימות עבודה של סוכנים, הן ציבוריות והן פנימיות. סוכן חדש בוחר את הכלים הדרושים לו מתוך הספרייה הזו, והשיפורים בתחומי האימות, הטלמטריה או שילוב השירותים מטיבים עם כל סוכן המשתמש בהם.

איור 3: ההנחיות משפיעות על מה שהמודל מבקש; קוד הכלי MCP קובע מה ניתן לבצע.

מוכנות לייצור כברירת מחדל

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

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

מעקב הוא דוגמה אחת לכך. צוות מאפשר זאת באמצעות תצורה, ו-SDK המשותף מעביר מזהה מעקב דרך שיחות A2A, כלי MCP ושירותי DoorDash במורד הזרם. מהנדסים יכולים לעקוב אחר בקשה אחת לאורך ה-Orchestrator, סוכני התחום ושיחות הכלים, במקום להרכיב יומנים ממערכות נפרדות. אותם נתוני מעקב תומכים באיתור באגים ובהערכה. מתן יכולת מעקב דרך הפלטפורמה חוסך כ-חודש של עבודת נראות עבור כל השקה של סוכן חדש.

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

מצב משותף לשיחות אמינות

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

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

בפרויקטים קודמים של סוכני DoorDash יושמו יכולות אלה באופן עצמאי. הדבר גרם לכפילות בעבודת השמירה על נתונים והפך את האמינות לתלויה בבחירות של כל צוות. ריכזנו אותן בשירותי הסוכנים המנוהלים (Managed Agent Services), המספקים ממשקי API תואמי ADK עבור הפעלות, זיכרון וארטפקטים. סוכני התחום משתמשים באותם ממשקים מבלי להפעיל מערכות מצב משלהם.

ריכוזיות עדיין מחייבת כללים נפרדים לאחסון ולמחזור החיים של נתוני הפעלה, זיכרון לטווח ארוך ואובייקטים. שירותי הסוכן המנוהלים (Managed Agent Services) מאגדים את הגבולות הללו במקום אחד. כל תחום עדיין מחליט איזה מידע יש לשמור ולאחזר במסגרת החוויה שלו.

שירותי הסוכנים המנוהלים וארכיטקטורת הזיכרון מוסברים בפירוט רב יותר בחלק השני.

הישארו מעודכנים עם עדכונים שבועיים

הירשמו לבלוג ההנדסה שלנו כדי לקבל עדכונים שוטפים על כל הפרויקטים הכי מגניבים שהצוות שלנו עובד עליהם

מה השתנה בפלטפורמה

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

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

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

הצטרפו אלינו

אם פיתוח פלטפורמות לסוכנים ו-AI הפונה למשתמשים בקנה מידה גדול נשמע לכם מעניין, אתם מוזמנים לבדוק את משרות ההנדסה הפנויות שלנו באתר careersatdoordash.com.

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

בקיצור

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

התוצאה הבולטת: בדו"ח הכולל 105 מקרים, בודק קוד הייצור של DoorDash (Claude Sonnet 4.6 בתפקיד "סקאוט" ברמה גבוהה + Claude Opus 4.8 בתפקיד "בודק" ברמה גבוהה) מצא 504 ממצאים אמיתיים עם שיעור זיהוי משוקלל של 53.6%, בהשוואה ל-164 ממצאים אמיתיים ושיעור זיהוי משוקלל של 30.7% עבור קו בסיס של GPT 5.5 ברמה גבוהה ללא "סקאוט". התמונה הרחבה יותר של שילוב המודלים מעניינת יותר מאשר מנצח בודד: השילוב של Kimi K2.6 כ-scout ו-Claude Fable 5 כ-reviewer הוביל בשיעור הזיכרון המשוקלל וב-F1, השילוב של Composer 2.5 כ-scout ו-GPT 5.5 medium כ-reviewer הוביל בדיוק המשוקלל, ובסיסי ההשוואה של מעבר יחיד נותרו זולים בהרבה.

איור 1: פשרה בין דיוק לאחזור משוקללים
איור 2: פשרה בין F1 משוקלל לעלות.

הערה: מדדים משוקללים מעניקים משקל רב יותר לבעיות בעלות רמת חומרה גבוהה יותר (קריטית = 4, גבוהה = 2, בינונית = 1, נמוכה = 0.5).

מדוע האותות הברורים מטעים

הדרך המפתה למדוד את ביצועיו של בודק קוד – והמדד העיקרי שבו משתמשים כיום רוב כלי בדיקת הקוד הגדולים – היא לעקוב אחר המתרחש בסביבת הייצור: האם הכותבים מקבלים את הערותיו, והאם הם פועלים לפיהן? האות הזה הוא אמיתי. אבל הוא מבוסס על הנחות רעועות ומידע חלקי. בשפת מטריצות הבלבול, קבלה ממלאת תמיד רק שתיים מתוך ארבע התאים: הערה שהכותב מקבל נרשמת כ"חיובי אמיתי" (TP), והערה שהוא דוחה נרשמת כ"חיובי כוזב" (FP). שני הרישומים הללו מניחים שההחלטה האנושית היא "האמת המוחלטת" – שהמהנדסים אינם טועים, או לפחות שהם טועים לעיתים רחוקות ובאופן אקראי מספיק, כך שהטעויות אינן משפיעות באופן מצטבר. כפי שנראה, זו הנחה שגויה. 

שתי התאים האחרים נשארים ריקים, וזה המחיר האמיתי. קבלת הקוד אינה יכולה לתעד תוצאות שליליות כוזבות (באגים שהבוחן פספס) או תוצאות שליליות אמיתיות (קוד נקי שבו השתיקה הייתה התשובה הנכונה). היא מודיעה לכם שמשהו קרה; היא לא מודיעה לכם אם הבדיקה הייתה נכונה, אם השתיקה הייתה מוצדקת, או מה פספסו. DashBench מטפל בכך באופן שונה: לאחר ההכרעה, אשכולות של בעיות אמיתיות שפספסו נחשבים כתוצאות שליליות כוזבות לצורך דירוג הביצועים, אף על פי שתלמטריית קבלת הקוד בסביבת הייצור אינה יכולה לזהות אותם.

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

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

מארכיטקטורת ייצור למקום מסודר שבו ניתן לבצע מדידות

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

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

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

כיצד בנינו את מדד ההשוואה

איור 3: תהליך הבדיקה של DashBench

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

המקרים.

DashBench התחיל מכ-1,000 מועמדים גולמיים ל-PR ועבר תהליך בחירה כדי להתמקד במקרים המדגישים דפוסי התנהגות שונים של סקירה, כגון שינויים מורכבים, היסטוריית סקירות רועשת ותוצאות חומרה מגוונות. הפוסט משתמש בדוח התקף הכולל 105 מקרים כדי לנתח מערכות רב-שלביות לעומת מערכות חד-שלביות, בחירות מודל של סקאוט/סקורר, ואיכות משוקללת לפי חומרה, על בסיס חתך הערכה אחיד אחד.

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

התוויות. 

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

התוצאה היא מדד ביצועים שהאמת המוחלטת שלו אינה נשענת על מקור יחיד ונתון לטעות. שיקול הדעת האנושי, המשוב מההפקה וההערכה הסוכנתית תורמים כולם; אף אחד מהם אינו נחשב כבלתי טועה. 

סביבת ההרצה. 

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

הדו"ח: מה שמציג DashBench בפועל

אנו משתמשים ב-DashBench כדי לענות על ארבע שאלות שטלמטריית הייצור לבדה אינה יכולה לענות עליהן. ראשית, האם חלוקה לשלבים אכן מגדילה את הכיסוי? שנית, אילו בחירות במודל הסקאוט/הבוחן משנות את קו הגבול של העלות, הדיוק וההחזרה? שלישית, האם הדירוגים הכלליים נשמרים כאשר אנו מחלקים את הממצאים לפי חומרה? רביעית, מתי תצורות של סקאוט/בוחן בשלבים עולות על בוחנים חזקים יותר הפועלים במעבר אחד, ומה הן מוותרות כדי לעשות זאת?

יתרונות ההעמדה

הבדיקה בשלבים מספקת כיסוי, והמחיר ניכר לעין. בדו"ח הכולל 105 מקרים, בודק קוד הייצור של DoorDash (Claude Sonnet 4.6 high scout + Claude Opus 4.8 high reviewer) מצא 504 ממצאים אמיתיים עם שיעור זיהוי משוקלל של 53.6%, בהשוואה ל-164 ממצאים אמיתיים ושיעור זיהוי משוקלל של 30.7% עבור קו הבסיס של GPT 5.5 high ללא scout. הדיוק המשוקלל נותר באותו טווח, 87.0% לעומת 84.1%, אך בודק הייצור עלה יותר לכל PR ולקח יותר זמן. זהו בדיוק סוג התוצאה שאנו רוצים ש-DashBench יחשוף: לא גביע, אלא פשרה מדודה.

מערכתממצאים אמיתייםדיוק משוקללשיעור איתור משוקללעלות / יחסי ציבור
בוחן קוד ייצור ב-DoorDash50487.0%53.6%$3.91
ללא סקאוט + מבקר בכיר ב-GPT 5.516484.1%30.7%$0.75
ללא סקאוט + קלוד אופוס 4.8 – מבקר בעל דירוג גבוה11589.8%20.2%$0.65

בחירת דגם על ידי סקאוט/מבקר

השוואת שילובי המודלים היא המקום שבו מדד הביצועים הופך לשימושי ביותר: אנו מחליפים בין המודלים המשמשים כ"סקאוט" לאלה המשמשים כ"בוחן", תוך שמירה על מדד הביצועים קבוע. אף תצורה אינה שולטת בכל הצירים. השילוב של Kimi K2.6 כ"סקאוט" ו-Claude Fable 5 כ"בוחן" השיג את שיעור ההחזרה המשוקלל ואת ה-F1 המשוקלל הגבוהים ביותר בתת-קבוצה תקפה של 105 מקרים, עם שיעור החזרה משוקלל של 65.2% ו-F1 משוקלל של 75.3%. השילוב של Composer 2.5 כמודל סקאוט + GPT 5.5 כמודל סקירה בינוני הציג את הדיוק המשוקלל החזק ביותר, 92.2%, אך עם ריקול נמוך משמעותית. קווי הבסיס ללא מודל סקאוט היו זולים יותר, בעוד שהשילוב של Kimi K2.6 כמודל סקאוט + Claude Opus 4.8 כמודל סקירה גבוה היווה חלופה מדורגת בעלות נמוכה יותר, אך עם ריקול נמוך משמעותית.

תצורהממצאים אמיתייםדיוק משוקללשיעור איתור משוקללF1 משוקללעלות / יחסי ציבור
קימי K2.6 סקאוט + קלוד פייבל 5 מבקר53789.2%65.2%75.3%$3.81
קלוד סונט 4.6 – צופה בכיר + קלוד אופוס 4.8 – מבקר בכיר50487.0%53.6%66.3%$3.91
Kimi K2.6 scout + Claude Opus 4.8 מבקר בכיר39682.3%45.8%58.9%$2.35
קלוד סונט 5 – צופה בכיר + קלוד סונט 5 – מבקר בכיר32177.3%40.1%52.8%$6.55
קלוד סונט 5 – צופה בכיר + קלוד אופוס 4.8 – מבקר בכיר22680.8%32.9%46.8%$5.06
GPT 5.5 – סקאוט ברמה בינונית + GPT 5.5 – מבקר ברמה גבוהה27691.5%19.9%32.6%$5.95
Composer 2.5 (סקאוט) + GPT 5.5 (מדרג בכיר)26791.1%19.6%32.2%$4.68
Composer 2.5 (סקאוט) + GPT 5.5 (מבקר ברמה בינונית)24692.2%18.0%30.1%$3.53
ללא סקאוט + מבקר בכיר ב-GPT 5.516484.1%30.7%45.0%$0.75
ללא סקאוט + קלוד אופוס 4.8 – מבקר בעל דירוג גבוה11589.8%20.2%33.0%$0.65

השפעת חומרת הממצאים על ההערכה

רמת החומרה משנה את התמונה שוב. בכל תת-הקבוצה התקפה של 105 מקרים, איחוד הממצאים האמיתיים שנפסקו מכיל 40 אשכולות קריטיים, 136 אשכולות ברמת חומרה גבוהה, 271 אשכולות ברמת חומרה בינונית ו-385 אשכולות ברמת חומרה נמוכה. הצמד Kimi K2.6 כסקאוט + Claude Fable 5 כבוחן היה החזק ביותר בכיסוי של מקרים קריטיים, ברמת חומרה גבוהה ובינונית, בעוד שהצמד Claude Sonnet 4.6 כסקאוט ברמת חומרה גבוהה + Claude Opus 4.8 כבוחן ברמת חומרה גבוהה כיסה מעט יותר את הזנב של מקרים ברמת חומרה נמוכה. השורה של GPT 5.5 high ללא scout הייתה זולה ועדיין שימושית בבעיות בחומרה גבוהה, אך חלשה יותר בכיסוי הכולל. זו הסיבה לקיומו של הציון המשוקלל: הוא מעניק לחסרים בחומרה קריטית וגבוהה משקל רב יותר מאשר לחסרים בחומרה נמוכה, תוך שהוא עדיין מאפשר לנו לבחון את החלוקה המלאה לפי חומרה.

איור 4: שיעור הזיכרון לפי רמת חומרה.

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

השפעת איכות המודל וגודלו על תוצאות מבחני הביצועים

נתוני שילוב המודלים מאששים זאת גם במספרים: השילוב של Kimi K2.6 כ-scout ו-Claude Fable 5 כ-reviewer מוביל במדדי ה-recall וה-F1 המשוקללים; השילוב של Composer 2.5 כ-scout ו-GPT 5.5 כ-reviewer בינוני מוביל במדד הדיוק המשוקלל; ואילו קווי הבסיס של מעבר יחיד ללא scout נשארים זולים יותר, אך במחיר של ויתור על כיסוי. שלבי ביניים שתוכננו למטרה ספציפית אינם הופכים מודל חלש יותר למוביל בכל התחומים כבמטה קסם; הם משנים את אופי הפשרה. מודלי הסקאוט משפרים את רוחב הכיסוי כאשר מודל הסקירה יכול לאמת באופן אגרסיבי. תצורות מודל סקירה מחמירות יותר משפרות את הדיוק כאשר המטרה העסקית היא להפחית רעש. קווי הבסיס של מעבר יחיד ללא סקאוט מהווים בסיס שימושי ובעלות נמוכה יותר, אך הם מותירים כיסוי על השולחן. התוצאה אינה שמודל אחד מנצח. התוצאה היא שאף תצורה אחת אינה שולטת, והיכולת לומר זאת במדויק היא העיקר.

לקחים מניתוח השוואתי של סקירת יחסי ציבור

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

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

השונות היא תכונה, לא תקלה. מודלים לשוניים גדולים (LLM) אינם דטרמיניסטיים, ולכן ריצות מרובות של אותו סוכן חושפות ממצאים תקפים נוספים; כלומר, ריצה בודדת ממעיטה בערכו של הכיסוי האמיתי של הסוכן, ויש לבצע ריצות חוזרות ולבצע צבירה כדי לדרג אותו באופן הוגן. אותה אקראיות חלה גם על השופט: התאמה דטרמיניסטית היא יציבה אך מתעלמת משוויון סמנטי, בעוד ששופטי LLM מספקים נימוקים עשירים יותר אך זקוקים לכיול, מערכי ביקורת וקריטריונים יציבים כדי להישאר אמינים. כל מערך המדידה הוא אקראי; המשימה היא לתכנן בהתאם לכך, במקום להתעלם מכך.

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

הישארו מעודכנים עם עדכונים שבועיים

הירשמו לבלוג ההנדסה שלנו כדי לקבל עדכונים שוטפים על כל הפרויקטים הכי מגניבים שהצוות שלנו עובד עליהם

מה הלאה

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

השלב הבא הוא ביצוע השוואות ביצועים רציפות:

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

ואנחנו מתחילים לבצע השוואות ביצועים של סוכני קידוד — ולא רק של בודקים — על בסיס קוד ארגוני אמיתי, עם משימות ותכונות אמיתיות. עוד על כך בהמשך.

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


נספח

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

א. סביבת ביצוע (מפרט מלא). במסגרת ההשוואה, כל תצורה פועלת על אותו חתך של מערך הנתונים ומניבה את אותו חוזה ממצאים מובנה: חומרה, ראיות ונקודות עוגן בקובץ. ה-harness עצמו הוא חלק ממה ש-DashBench מודד, ולכן הפרופילים עשויים להשתנות בסוג הרץ, בחלוקה בין סקאוט/בוחן, בבחירת המודל, בממשק הכלי, במכניקת ההקשר ובמגבלות הספק. לאחר מכן, הניקוד משתמש באותו נתיב התאמה עבור אותה השוואה, עם התאמה דטרמיניסטית במידת האפשר ושיפוט סוכני כאשר נדרשת התאמה סמנטית. המטרה היא לא למחוק את ההבדלים בין המערכות; המטרה היא להפוך את ההבדלים הללו למפורשים מספיק, כך שהעלות, זמן ההשהיה והאיכות ישתנו מסיבות שניתן לפרש.

ב. גודל מערך הנתונים ומערכת ההערכה. DashBench התחיל מכ-1,000 מועמדים גולמיים ל-PR, ולאחר מכן צמצם את הרשימה למקרים שניתן היה לשחזר ולפסוק לגביהם. הפוסט משתמש בדוח התקף של 105 מקרים לצורך ניתוח שילוב המודלים העיקרי וניתוח ההשוואה בין שלבים לעומת מעבר חד-פעמי. המכנה של חומרת הממצאים במדגם המצומצם של 105 המקרים הוא איחוד של אשכולות ממצאים אמיתיים: 40 קריטיים, 136 גבוהים, 271 בינוניים ו-385 נמוכים. מדובר באשכולות ממצאים, ולא במספר ה-PR; PR אחד יכול לתרום ליותר מאשכול אחד.

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

מֶטרִיבוחן קוד ייצור ב-DoorDashללא סקאוט + מבקר בכיר ב-GPT 5.5
הגדרהקלוד סונט 4.6 – צופה בכיר + קלוד אופוס 4.8 – מבקר בכירמבקר יחיד
ממצאים גולמיים611200
ממצאים אמיתיים504164
דיוק משוקלל87.0%84.1%
שיעור איתור משוקלל53.6%30.7%
F1 משוקלל66.3%45.0%
שיעור זיכרון גבוה/קריטי52.8%51.7%
עלות / יחסי ציבור$3.91$0.75
עלות / ממצא בפועל$0.82$0.48
בדיקת זמן ההשהיה / PR725.0s170.3s
אזהרהעלות גבוהה יותר וזמן השהיה ארוך יותר, אך כיסוי נרחב יותרעלות וזמן השהיה נמוכים יותר, אך שיעור הזיכרון הכולל נמוך בהרבה

תצורהממצאיםאיכותעלות / זמן השהיה
קימי K2.6 סקאוט + קלוד פייבל 5 מבקר669 גולמי
537 אמיתי
132 לא אמיתי
89.2% דיוק
65.2% כיסוי
75.3% F1
3.81 $ / PR
0.75 $ / ריאל
589.3 שניות / PR
התוצאות הטובות ביותר במדד recall/F1 משוקלל
קלוד סונט 4.6 – צופה בכיר + קלוד אופוס 4.8 – מבקר בכיר611 גולמי
504 אמיתי
107 לא אמיתי
87.0% דיוק
53.6% כיסוי
66.3% F1
3.91 $ / PR
0.82 $ / ריאל
725.0 שניות / PR
Kimi K2.6 scout + Claude Opus 4.8 מבקר בכיר574 גולמי
396 אמיתי
178 לא אמיתי
82.3% דיוק
45.8% כיסוי
58.9% F1
2.35 $ / PR
0.62 $ / ריאל
263.9 שניות / PR
ההכנה המהירה ביותר שנמדדה
קלוד סונט 5 – צופה בכיר + קלוד סונט 5 – מבקר בכיר509 גולמי
321 אמיתי
187 לא אמיתי
1 לא ברור
77.3% דיוק
40.1% כיסוי
52.8% F1
6.55 $ / PR
2.14 $ / real
657.9s / PR
קלוד סונט 5 – צופה בכיר + קלוד אופוס 4.8 – מבקר בכיר327 גולמי
226 אמיתי
100 לא אמיתי
1 לא ברור
80.8% דיוק
32.9% כיסוי
46.8% F1
5.06 $ / שיא כל הזמנים
2.35 $ / מחיר נוכחי
565.3 שניות / שיא כל הזמנים
GPT 5.5 – סקאוט ברמה בינונית + GPT 5.5 – מבקר ברמה גבוהה332 גולמי
276 אמיתי
56 לא אמיתי
דיוק של 91.5%
, שיעור איתור של 19.9%
, F1 של 32.6%
5.95 $ / PR
2.26 $ / real
619.5s / PR
Composer 2.5 (סקאוט) + GPT 5.5 (מדרג בכיר)324 גולמי
267 אמיתי
57 לא אמיתי
91.1% דיוק
19.6% כיסוי
32.2% F1
4.68 $ / PR
1.84 $ / ריאל
539.2 שניות / PR
Composer 2.5 (סקאוט) + GPT 5.5 (מבקר ברמה בינונית)285 גולמי
246 אמיתי
39 לא אמיתי
92.2% דיוק
18.0% כיסוי
30.1% F1
3.53 $ / PR
1.50 $ / אמיתי
429.4s / PR
הדיוק המשוקלל הטוב ביותר
ללא סקאוט + מבקר בכיר ב-GPT 5.5200 גולמיים
164 אמיתיים
36 לא אמיתיים
84.1% דיוק
30.7% כיסוי
45.0% F1
0.75 $ / PR
0.48 $ / ריאל
170.3 שניות / PR
ללא סקאוט + קלוד אופוס 4.8 – מבקר בעל דירוג גבוה134 גולמי
115 אמיתי
19 לא אמיתי
89.8% דיוק
20.2% שיעור זיהוי
33.0% F1
0.65 דולר / PR
0.60 דולר / ריאל
112.8 שניות / PR

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

סיכום לפי רמת חומרה

חומרהאשכולות אמיתיים של UnionKimi K2.6 + Fable 5Sonnet 4.6 high + Opus 4.8 highKimi K2.6 + Opus 4.8 highGPT 5.5 ברמה גבוהה
קריטי4080.0%62.5%72.5%37.5%
גבוה13677.9%50.0%46.3%55.9%
בינוני27156.8%53.5%43.2%20.3%
נמוך38546.8%51.4%26.8%4.2%

דיוק לפי רמת החומרה

חומרהKimi K2.6 + Fable 5Sonnet 4.6 high + Opus 4.8 highKimi K2.6+ Opus 4.8 גבוהGPT 5.5 ברמה גבוהה
קריטי100.0%100.0%100.0%לא רלוונטי
גבוה96.0%95.6%94.9%86.9%
בינוני94.2%87.8%86.8%80.9%
נמוך65.3%76.8%49.7%70.4%

כוונות המשימות הן בעלות תוויות מרובות, ולכן סך המספרים עולה על 105.

כוונות משימה

מטרת המשימהספירהאחוז המקרים
מבחנים9085.7%
config_build8581.0%
תכונה4139.0%
api_schema3331.4%
docs_kb2019.0%
כלי תלות1918.1%
תיקון באג1817.1%
data_model1514.3%
refactor_cleanup1514.3%
ui109.5%
rollout_guard98.6%
אבטחה_פרטיות87.6%
יכולת ניטור76.7%
ביצועים65.7%
שינוי_התנהגות11.0%

שינוי גודל יחסי הציבור

קטגוריית גודל PRספירהאחוז המקרים
גדול3634.3%
בינוני3634.3%
קטן3331.4%

אפשרות לאימות

אפשרות לאימותספירהאחוז המקרים
בינוני5451.4%
strong3836.2%
חלש1312.4%

תחומי מוצרים

מוצגים 20 הדומיינים המובילים.

תחום המוצרספירהאחוז המקרים
עדכוני צרכנים1817.1%
ציוד לקמפיין65.7%
logistics_labor54.8%
עגלת ההזמנות54.8%
מסלול_תמיכה_תמיכה43.8%
סיכון_להונאה_בסיסי32.9%
לוגיסטיקה_ביצוע הזמנות32.9%
money_payin32.9%
תוכן לגילוי צרכנים21.9%
הליוס21.9%
merchant_mdh21.9%
הזמנות_סוחרים21.9%
תמיכה_בסוחרים21.9%
שירות_ניהול_משתמשים_סוחרים21.9%
platform_pretzel21.9%
ציבורי21.9%
repo_config21.9%
תמיכה_אוטומציה_סוכן_בינה_מלאכותית21.9%
קול_תמיכה21.9%
כלים21.9%

פְּגִיעָה

תוויות ה-Impact הן תוויות מרובות, ולכן סך כל התוויות עולה על 105.

פְּגִיעָהספירהאחוז המקרים
הפונה ללקוח3432.4%
פעילות_מסחרית3331.4%
אמינות התשתית3028.6%
לוגיסטיקה2221.0%
שלמות הנתונים1817.1%
ידע_מפתחים1615.2%
לא ידוע1615.2%
איכות הבדיקה98.6%
אבטחה_פרטיות87.6%
כסף76.7%

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

כדי להתמודד עם בעיה זו, הקמנו פלטפורמת מטא-נתונים למסעדות המונעת על ידי בינה מלאכותית. הפלטפורמה שלנו מסיקה תכונות ברמת המנה וברמת המסעדה — למשל, האם מנה מסוימת חריפה, או שמא המטבח של המסעדה הוא סיני — באמצעות אותות רב-מודאליים שמקורם בטקסט, בתמונות ובחיפושים נרחבים באינטרנט. כדי לבנות מטא-נתונים אמינים ומדויקים בקנה מידה גדול, פיתחנו מספר חידושים מרכזיים בתוך המערכת המורכבת של DoorDash, ביניהם: 

  • מערכת שיפוט המבוססת על מודל שפה גדול (LLM) לצורך הערכה באיכות גבוהה, שהגדילה את דיוק התיוג בכ-20% בהשוואה לבודקים אנושיים רגילים.
  • סוכני אופטימיזציה לפי הקשר, המשמשים לשיפור איטרטיבי של הפקודות בתוך דקות ספורות, מגדילים את דיוק המודל ביותר מ-20% ובמקביל נמנעים מחוסר היעילות של פקודות שנכתבו ידנית ואינן מיטביות. תהליך זה האץ את פיתוח הפקודות פי עשרה.
  • מחשוב מבוזר מאפשר ביצוע הסקת מודלים לשוניים גדולים (LLM) בהיקפים נרחבים, מקצר את זמן השלמת הנתונים מיותר מחודש לכמה ימים בלבד, ובכך הופך את הייצור של מיליוני פריטים לבר-ביצוע מבחינה תפעולית.
  • תיוג מונחה בינה מלאכותית ליצירת נתוני אימון, אשר איפשר כיוונון עדין כדי להגיע לאיכות של מודלים לשוניים גדולים (LLM) מתקדמים ביותר, בעלות של 10% מעלות ההסקת מסקנות, וללא כל מאמץ אנושי בתיוג.

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

סקירה כללית ברמה גבוהה של התהליך

כפי שמוצג באיור 1, התהליך שלנו מתחיל בקליטת עדכוני תפריטים ובביטול כפילויות כדי למזער את עלויות ההסקת המסקנות. אנו מזינים פריטים אלה למחוללי בינה מלאכותית כדי לייצר מטא-נתונים, אשר עוברים אימות מבני מיידי לצורך זיהוי שגיאות וניסיונות חוזרים. אנו עוקבים באופן רציף אחר איכות התחזיות שנוצרו באמצעות "חבר מושבעים" של מודלים לשוניים גדולים (LLM); תוצאות ההערכה משמשות גם להנדסת הקשר כדי לשפר את איכות היצירה. בנוסף, אנו מספקים מנגנון עקיפה לסוחרים, המאפשר לבעלי עסקים לאמת או לתקן תכונות.

איור 1: סקירה כללית זו של תהליך יצירת המטא-נתונים של DoorDash בתחום המזון כוללת עדכוני תפריטים והסרת כפילויות באמצעות יצירה באמצעות בינה מלאכותית, הערכה והתאמות מצד הסוחרים.

חידושים טכנולוגיים

איסוף נתונים, תיוג, אימון והערכה בשיטות המסורתיות הם תהליכים איטיים ויקרים להחריד, מה שמקשה על יצירת וחילוץ מטא-נתונים באיכות גבוהה בהיקף הנדרש על ידי DoorDash. כדי להתמודד עם אתגר זה, פיתחנו מערכת המשתמשת הן במודלים לשוניים רב-מודאליים והן במודלים לשוניים קטנים ומאומנים (SLM) כדי להשיג יצירה באיכות גבוהה ובעיכוב נמוך, בעלות סבירה. מערכת ה-LLM Jury שתוכננה בקפידה מאפשרת הערכה אמינה בקנה מידה גדול, אופטימיזציה רציפה של ההקשר על סמך אותות כשל אמיתיים, ויצירה אוטומטית של נתונים מתויגים באיכות גבוהה, כדי להאיץ את שיפור המודל ואת האימון הפנימי.

הערכות יעילות ואיכותיות באמצעות ועדות שופטים של מודלים לשוניים גדולים (LLM)

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

מערכת הערכת הקונצנזוס האוטומטית שלנו, המבוססת על מודלים לשוניים גדולים (LLM) — "חבר מושבעים של LLM" — מחליפה את תהליך האימות האנושי, שהוא איטי, יקר וחסר עקביות. כפי שמוצג באיור 2, היא כוללת את השלבים הבאים:

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

איור 2: מערכת ההערכה של LLM מבוססת על צוות שופטים המורכב ממספר מעריכים חזקים של LLM, אשר שופטים את התגים המוצעים באופן עצמאי. אנו מסכמים את הקולות ומאמתים את התגים באופן פרטני.

גילינו כי תגי ה-LLM שהוסכמו היו מדויקים בכ-20% יותר מאשר תוויות טיפוסיות שסומנו על ידי בני אדם. הצלחתה של מסגרת ההערכה האוטומטית שלנו היוותה את הבסיס לאוטומציה של מערכת יצירת המטא-נתונים כולה.

אופטימיזציה אוטומטית של ההקשר בהשראת למידה חיזוקית 

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

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

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

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

כמה לקחים חשובים שהיינו רוצים לחלוק:

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

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

תיוג נתונים מונחה בינה מלאכותית להאצת איסוף נתוני האימון

יצירת מטא-נתונים בקנה המידה של DoorDash דורשת הן דיוק והן יעילות. מודלים לשוניים גדולים (LLM) מוכנים לשימוש הם לרוב לא מדויקים או יקרים מדי; כתוצאה מכך, חלק ממערכת ה-AI שלנו מסתמך על מודלים מכוונים ומותאמים במיוחד. עם זאת, אימון מודלים כאלה דורש תיוג של אלפי תגיות על פני מיליארדי ישויות בקטלוג, מה שהופך את תיוג הנתונים לאחד המגבלות הגדולות ביותר במחזור הפיתוח. בתהליך עבודה מסורתי, הפקת נפח כזה של נתוני אימון והערכה תלויה במידה רבה בתיוג אנושי, מה שהופך את תהליך האיטרציה של המודלים לאיטי, יקר וקשה להרחבה.

איור 4: מערכת התיוג המונעת על ידי בינה מלאכותית שלנו משתמשת בסוכני יצירה והערכה ייעודיים כדי ליצור ולאמת ביעילות תוויות באיכות גבוהה, לצורך אימון מודלים מיוחדים ומכוונים היטב.

כדי להתמודד עם בעיה זו, פיתחנו מערכת לתיוג נתונים המונעת על ידי בינה מלאכותית, המוצגת באיור 4, המייצרת ומאמתת תוויות באיכות גבוהה. פיתחנו מערך דומה של סוכנים לאופטימיזציה, יצירה והערכה אוטומטית של הקשר, במיוחד למשימות תיוג. המודלים הקטנים והמותאמים שלנו צמצמו את עלויות ההסקת מסקנות בכ-90% בהשוואה למודלים לשוניים גדולים (LLMs), תוך השגת ביצועים דומים.

אופטימיזציה של הסקת מסקנות בקנה מידה גדול באמצעות LLM

בהיקף הפעילות של DoorDash, מיליוני פריטי תפריט ייחודיים, מיליארדי אפשרויות תפריט ומאות אלפי עדכונים יומיים מחייבים רענון מתמשך של המטא-נתונים. הסתמכות על קריאות API סינכרוניות לכל פריט לצורך השלמת נתונים באופן מלא הייתה אורכת שבועות, מה שהופך את העדכונים היומיים לבלתי מעשיים, ובמקביל מעלה את עלויות התשתית והמודלים. 

איור 5: צינור ההסקת המסקנות של מודל השפה הגדול (LLM) המבוזר שלנו עושה שימוש בהסרת כפילויות, הפצה באמצעות Spark, עיבוד אצווה ומיפוי מחדש של התוצאות, כדי להפוך את היצירה בקנה מידה גדול מ"צוואר בקבוק" איטי לתהליך יעיל בעל תפוקה גבוהה.

כדי להתמודד עם אתגרים אלה, תכננו צינור עיבוד מבוזר למודלים לשוניים גדולים (LLM), המוצג באיור 5, במטרה למנוע חישובים מיותרים ולמקסם את התפוקה. הגישה שלנו מתבססת על ארבעה מנגנונים מרכזיים:

  • ביטול כפילויות: סוחרים רבים משתמשים בשמות ותיאורים זהים למוצרים; עיבוד לא מתוחכם היה שולח שוב ושוב נתונים זהים למודל. אנו מבטלים כפילויות באמצעות התאמות מדויקות של תכונות, ובכך נמנעים מקריאות מיותרות למודל.
  • חלוקת נתונים ב-Spark: אנו מחלקים את הנתונים הייחודיים הנותרים לחלקים ומפיצים אותם על פני אשכול של עובדי Spark לצורך עיבוד מקביל.
  • עיבוד אצווה: אנו מנצלים ממשקי API של מודלים לשוניים גדולים (LLM) לעיבוד אצווה כדי לשלוח נתונים מקובצים למודל, ובכך למקסם את התפוקה ואת היעילות הכלכלית. עבור מודלים שעברו אימון, אנו מחלקים את הנתונים למקטעים, מה שמאפשר לנו להריץ את העיבוד מחדש על פני מספר רב של מעבדי GPU.
  • מיפוי מחדש של התוצאות: לאחר העיבוד, אנו ממפים את תוצאות המודל חזרה לישויות המקוריות כדי לשמור על שלמות הנתונים.

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

יצירת חווית לקוח טובה יותר 

המטא-נתונים שלנו משמשים כשכבת בסיס ליישומים רבים בהמשך הדרך בפלטפורמת DoorDash. באמצעות הפיכת טקסט תפריט לא מובנה לתכונות מדויקות ומובנות, אנו פותחים אפשרויות חדשות רבות, כולל שיפור יכולות החיפוש והגילוי של הלקוחות, מתן אפשרות לסינון מנות רלוונטיות, התאמה אישית ויצירת מדדים לצורכי ניתוח, כפי שמוצג באיור 6:

איור 6: מטא-נתונים מובנים משמשים כשכבת הבסיס ליישומים של DoorDash בהמשך התהליך, ומאפשרים התאמה אישית ללקוח, סינון וחיפוש משופר.

מַסְקָנָה

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

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


מבוא

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

בנינו מערך הערכה כדי לאפשר מעקב אחר איכות הנציגים בקנה מידה נרחב. מדד האיכות התרחב מממוצע של משוב אחד שהוגש על ידי עובד ל-2,000 מפגשים שזכו לציון אוטומטי מדי יום. מדד רחב יותר זה סייע לנו לאתר מוקדם יותר תקלות של נציגים הפוגעות באמון הלקוחות, ולתת עדיפות לדפוסי כשל חוזרים; בעקבות זאת, השגנו שיפור של 8 נקודות בציוני איכות הנציגים עוד לפני ההשקה הארצית – צמצמנו את שיעורי השגיאות כמעט בחצי ועמדנו ביעד ההשקה הסופי שלנו. מערכת ההערכה גם האצה משמעותית את תהליך האימות לפני ההשקה: בדיקת רגרסיה מקיפה, שבעבר ארכה יותר מ-6 שעות לביצוע ידני, מתבצעת כעת תוך כ-20 דקות, מה שמאפשר להעריך שינויים נרחבים כגון מעבר למודל בסיסי, שהפחית את זמן ההשהיה ב-35% תוך שמירה על האיכות.

פוסט זה מסביר כיצד פיתחנו את מערך ההערכה הזה: מדדי ההערכה המגדירים הצלחה, בונה התמלילים המשחזר את המפגשים, הסימולטור שיוצר ריצות לא מקוונות הניתנות לשחזור, והשופט המכויל המבוסס על מודל שפה גדול (LLM) שמאפשר הערכה ברמת המפגש בקנה מידה גדול.

האתגרים המרכזיים

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

איור 1: ההערכה צריכה לקחת בחשבון הן את השיחה הגלויה והן את מסלול הפעולה הנסתר של הכלי.

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

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

מה אנו מעריכים, ואיפה

Ask DoorDash משתמשת בארכיטקטורת ריבוי סוכנים. הודעת המשתמש מגיעה תחילה לסוכן ה-Orchestrator, אשר מנתב את הבקשה לסוכן תחום ייעודי (למשל, סוכן איתור המסעדות). לאחר מכן, סוכן התחום הנבחר מטפל בשיחה באופן ישיר, או מחזיר את השליטה ל-Orchestrator כאשר יש צורך לנתב את הבקשה מחדש. 

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

איור 2: ההערכה משקפת את ארכיטקטורת זמן הריצה של הסוכן.

בתוך מערך החיבורים של Eval

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

טבלת הערכה

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

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

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

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

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

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

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

בונה תמלילים

אנו עוקבים אחר כל הפעלה של הסוכן באמצעות OpenTelemetry. כל הפעלה הופכת ל"עקבות" (trace), אותן אנו מאחסנים במופע פנימי של ClickHouse. ה-"spans" שלה מתעדים את השלבים שביצע הסוכן, כולל הקלט של המשתמש, הפלט של המודל, קריאות לתוכניות ותגובותיהן, וכן הווידג'טים שהוצגו למשתמש. תיעוד מלא זה מהווה את חומר הגלם שממנו מתחיל כל תהליך הערכה.

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

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

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

איור 3: כלי בניית התמלילים הופך את העקבות הגולמיות לתצוגות המותאמות לקריטריונים ספציפיים, כדי לאפשר שיפוט ממוקד ועקבי יותר.

סימולטור שיחה

סימולטור השיחה מאפשר לנו להעריך סוכן מועמד לפני שהוא מגיע למשתמשים אמיתיים, באמצעות יצירת מפגשים מציאותיים עם משתמש מדומה – מודל שפה גדול (LLM) המגלם את תפקיד הקונה. כל ריצה מתחילה מתרחיש המגדיר את הבקשה הפותחת, את מטרת המשתמש ואת האופן שבו עליו להגיב לשאלות או לתוצאות, ובכך מייצרת שיחות רב-סיבוביות הניתנות להשוואה. כאשר תרחיש תלוי במצב חיצוני, כגון הזמנות קודמות ב-Safeway, עגלת קניות בתהליך או מלאי החנות, המערכת משתמשת ב"פיקסצ'רים": נתוני תגובה מוקלטים המוחזרים במקום שיחות בזמן אמת. כך כל ריצה נשמרת באותו מצב, מה שמבטל סטיות הנובעות משינויים בקטלוג, זמינות בחנות או היסטוריית חשבונות הבדיקה. לדוגמה, תרחיש ההזמנה החוזרת נפתח ב"הזמן מחדש את המוצרים הרגילים שלי" וקובע את get_reorder_items להיסטוריית הזמנות מוקלטת.

// simulating reorder scenario
{
  "evalId": "mt-reorder",
  "sessionInput": {
    "state": {
      "__tool_fixture_pack_names": [
        "reorder_history_v1"
      ],
      "max_turns": 3
    }
  },
  "conversationScenario": {
    "startingPrompt": "Reorder my usuals",
    "conversationPlan": "You want to reorder your usual groceries.."
  }
// ...
}// reorder_history_v1 — returned in place of the live get_reorder_items call
{
  "success": true,
  "orders": [
    { "store_name": "Albertsons", "order_date": "2026-04-22T18:30:00Z",
      "items": [
        {"name": "Meadow Gold Whole Milk Jug (1 gal)",     "quantity": 2},
        {"name": "Oroweat 100% Whole Wheat Bread (24 oz)", "quantity": 1},
        {"name": "Signature Select Hass Avocados (5 ct)",  "quantity": 1},
        {"name": "Ben & Jerry's Half Baked Ice Cream",     "quantity": 1}
        // ... more items
      ] }
    // ... more historical orders
  ]
}

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

סימולציית השיחות הפכה את שלב הקלט בהערכה במצב לא מקוון לבר-ביצוע. עבור Ask DoorDash, סבב בדיקה מקיף טיפוסי מכסה 50 תרחישים עם 8 ניסיונות בכל אחד, מה שמניב 400 שיחות שנוצרו. ללא סימולציה, יצירת מערך בדיקות זה מחייבת את המפתח לשוחח עם הסוכן באופן מקומי, שיחה אחת בכל פעם. בהנחה שכל שיחה אורכת כ-1 דקה, הדבר היה אורך יותר מ-6 שעות. הסימולטור מקצר את שלב היצירה לכ-20 דקות.

תואר שני במשפטים (LLM) בתפקיד שופט

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

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

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

שופט LLM מועיל רק אם הוא מסכים עם הבודקים האנושיים.

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

השופט מעניק ציון לכל קריטריון בנפרד. הוא מקבל את הקריטריון ואת הראיות שעליהן הוא מבוסס, ולאחר מכן מגיש פסק דין הכולל נימוק קצר. באמצעות מבנה זה, הרחבנו את בקרת האיכות מכ-1 משוב שהוגש על ידי עובד לכ-2,000 מפגשים המדורגים באופן אוטומטי מדי יום.

שירות הערכה

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

מעגל המשוב

מערכת הבדיקה מספקת לנו דרך הניתנת להרחבה למדידת איכות הסוכנים. השאלה הבאה היא כיצד מדידה זו משנה את מחזור הפיתוח.

קיבוץ תקלות לפי נושאים

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

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

מהאיתור ועד לפתרון

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

כישורי סוכן

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

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

איור 4: מעגל המשוב הופך את תהליך ההערכה למסלול רציף, המוביל מכישלונות שזוהו לשיפורים שאושרו.

מהערכת האות ועד להשפעה על הייצור

צמצום דליפת ההנמקה

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

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

איור 5: Eval איפשר זיהוי וצמצום של דליפת היסק בהודעות המופנות למשתמשים.

הפחתת הסיכונים במעבר למודל בסיסי

כאשר Gemini 3.5 Flash הושק באמצע מאי, הסוכנים שלנו פעלו על Claude Sonnet 4.6. תוצאות מבחן הביצועים של Flash הצביעו על הזדמנות: לצמצם את זמן ההשהיה של Ask DoorDash, כך שהסוכן ירגיש שהמערכת מגיבה במהירות ולא נתקעת. אך החלפת מודל הבסיס כרוכה בסיכון, מכיוון שהיא עלולה לשנות את התנהגות הסוכנים בכל המערכת. היינו צריכים לוודא שהאיכות תישמר לפני שנחשוף את המשתמשים לשינוי זה.

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

That diagnosis pointed to a set of small, targeted fixes. Some were deterministic guards on tool inputs – Flash would occasionally pass a search query as a JSON object like {“dishes”: […]} where the tool’s signature declared a plain string, so we coerced these back into the expected shape instead of dropping the call. Others were prompt updates that stated explicitly what Sonnet had inferred on its own, such as using the exact store name from the data and not embellishing beyond what the tool results support. We were not changing the model; we were correcting the environment around it.

ביצוע חוזר של ההערכה החזיר את Flash לרמת איכות זהה לזו של Sonnet, במסגרת טווח השגיאה של מערכת הבדיקה. העברנו את הסוכנים לסביבת הייצור ועקבנו אחר האיכות והמעורבות בתעבורה החיה. התוצאה החיובית נשמרה – הפחתה של 35% בחביון ללא פגיעה במדדי האיכות.

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

לקחים שנלמדו

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

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

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

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

מַסְקָנָה

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

מערכת ה-Harness מגשרת על הפער בין מדידה לשיפור. היא הרחיבה את הניטור היומי של האיכות מכ-1 משוב שהוגש על ידי עובד לכ-2,000 מפגשים שזכו לציון אוטומטי, וקיצרה את משך בדיקות הרגרסיה המקיפות מיותר מ-6 שעות של עבודה ידנית לכ-20 דקות. השיפורים הללו אפשרו לנו לאתר בעיות בייצור בשלב מוקדם יותר, לתעדף מצבי כשל חוזרים ולאמת שינויים נרחבים לפני שהגיעו למשתמשים. התוצאה הייתה השפעה מדידה על הייצור, כולל שיפור של 8 נקודות בציוני האיכות של הנציגים לקראת ההשקה הארצית, ומעבר מאומת למודל הבסיסי שהפחית את זמן ההשהיה ב-35% תוך שמירה על האיכות.

מערכת הערכה הניתנת להרחבה דורשת תשתית פלטפורמה איתנה. שיתוף פעולה הדוק עם צוות הפלטפורמה האץ את פיתוח מערכת ההערכה של הסוכנים עבור Ask DoorDash. העבודה הבסיסית הזו מהווה כעת את הבסיס לשירות הערכה משותף.

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

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

בפרקים הבאים אסקור את הדרך שעברתי: החל מ"Cursor" כשותף המוביל שלי לתכנות בינה מלאכותית, דרך הניסיונות הראשונים והמבולבלים שלי להשתמש ב-"Claude Code", ועד לניסויים עם צוותי סוכנים שהניבו בעיקר תוצאות גרועות ויקרות, וכלה בלולאה של "מחקר → תכנון → יישום" שהפכה לבסוף את העבודה עם סוכנים הפועלים לאורך זמן למשהו מעשי.

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

איור 1: לוח המחוונים הראשי של Agentic Orchestrator, המציג מעקב אחר מספר תכונות הנמצאות בשלבי פיתוח שונים.

אבל בואו נתחיל מההתחלה.

לפני הלולאה: שלב הסמן שלי

Cursor הוא כלי מדהים להגברת הפריון, המשלב את הנוחות של סביבת פיתוח משולבת ומלאה עם העוצמה של בינה מלאכותית סוכנתית (agentic AI) כדי להתמודד עם משימות ברמות מורכבות שונות. הוא הולך ומשתפר עם הזמן, ככל שהמודלים והכלים נעשים מתקדמים יותר. זה הפך לכלי העבודה העיקרי שלי בשנת 2025 ובמהלך 2026. אני לא זוכר שכתבתי הרבה שורות קוד באופן ידני, אלא אם כן לחיצות בלתי פוסקות על מקש ה-Tab נחשבות.

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

בזכות התכונות פורצות הדרך שהציג Opus של Anthropic, כבר דיברו בתעשייה על סוכנים הפועלים לאורך זמן ועל יכולתם לזהות תכונות במכה אחת, ללא התערבות אנושית. רציתי לחוות את כל זה בעצמי! לכן הגיע הזמן שאעבור לדבר החם החדש שכולם דיברו עליו: Claude Code.

היחסים המורכבים שלי עם קלוד קוד

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

אנשים שונים מחברות שונות ובעלי רקע טכני מגוון ניסו לשכנע אותי שהגענו כעת ל"סינגולריות". לדבריהם, כבר אין צורך בבני אדם בתהליך; הבינה המלאכותית תגלם כל משאלה שלך ותהפוך אותה למציאות, כולל התחזות אליך ב-Slack, השתתפות בשיחות זום, הכנת אספרסו משובח, וכמובן, כתיבת קוד. כל מה שהייתי צריך לעשות, אמרו לי, זה לעבור ל-Claude Code עם Opus 4.6 כדי לראות את עולמי מתערער. וכך עשיתי! אבל מבחינתי, התברר שזה היה גרוע יותר מאשר להשתמש במודלים מקבילים עם Cursor.

כמו כל מתכנת אחר, גם אני אוהב כלי נחמד שמבוסס על מסוף, אבל עם Claude Code איבדתי את היכולת שלי לקיים אינטראקציה ישירה כדי לבדוק כל שינוי בנפרד. בתיאוריה, זה היה אמור לבוא בתמורה לתיאום טוב יותר ולכלים שמספקת מערכת ה-harness, אבל בסופו של דבר, המודל נותר זהה. וזה לא ש-Cursor לא הציע כלים או מצב תכנון. אז מה העניין?

מתברר ש-Claude Code מביא עמו שינוי תפיסתי: כבר אין צורך לקיים אינטראקציה עם הקוד. עליכם לשנות את תהליך הפיתוח שלכם, לסמוך על הסוכן ולבצע את כל תהליך האיטרציה באמצעות פקודות. 

הגיע הזמן להתחיל להתנסות ולשאוף לאותו אספרסו חלומי המופעל על ידי Opus.

התחלת הניסויים: סוכנים, סוכנים, סוכנים!

זכרו את המטרה העיקרית שלי: לגרום לבינה המלאכותית לבנות מאפיין מורכב באופן עצמאי.

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

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

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

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

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

גישה חדשה זו היא זו שהובילה אותי בסופו של דבר לנתיב שונה לחלוטין.

הפריצה שלי: מחקר, ראיונות, תכנון, חזרה על התהליך, ומבקרים עוינים

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

התובנה הראשונה הגיעה מהרצאה מעוררת השראה של Humanlayer על מה שהם מכנים מסגרת ה-RPI — מחקר, תכנון, יישום. הרעיון פשוט למראה אך מתעתע: במקום לדחוף מפרט שלם לסוכן ולקוות לטוב, מחלקים את העבודה לשלבים קוגניטיביים נפרדים. ראשית, הסוכן חוקר את בסיס הקוד על ידי קריאת הקבצים הרלוונטיים, הבנת הדפוסים ומיפוי התלות. לאחר מכן הוא מפיק תוכנית — מסמך יישום מפורט ומדורג הכולל נתיבי קבצים ספציפיים, קטעי קוד וקריטריוני הצלחה. רק לאחר השלמת שלב זה הוא מבצע את היישום, תוך שהוא פועל על פי התוכנית שלו עצמו ולא על סמך הבנה מעורפלת של מפרט שכבר שכח למחצה לפני 30,000 טוקנים.

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

התובנה השנייה הייתה פשוטה עוד יותר, באדיבות המיומנות "grill-me" של מאט פוקוק: תנו לסוכן לראיין אתכם. במקום לבזבז שעות בכתיבת הפקודה המושלמת, שמצפה לכל מקרה קיצון ומבהירה כל עמימות, תנו לסוכן לשאול אתכם שאלות! מתברר ששיחה של שאלות ותשובות עם סוכן שרק סיים לחקור את בסיס הקוד שלכם שווה יותר משעות של תכנון פקודות מראש. הסוכן יודע מה הוא צריך; אתה רק צריך לתת לו אישור לשאול. תתפלא עד כמה השאלות האלה רלוונטיות לפעמים. בסופו של דבר, זה הגיוני לחלוטין; אחד הדברים שאתה לומד ככל שאתה מתקדם בקריירה הוא להאציל סמכויות. כשאתה עושה זאת, לרוב המהנדסים שאליהם האצלת את העבודה יחזרו אליך עם שאלות. הם לא רוצים להניח הנחות שגויות לגבי מה שהיה לך בראש. למה שסוכנים יהיו שונים?

אבל הלקח השלישי והחשוב ביותר שלמדתי היה על מה שהתעשייה מכנה בדרך כלל "הלולאה".

אתם רואים, גם אם אתם מיישמים RPI, עדיין יש לכם שתי בעיות. הראשונה היא בעיית חלון ההקשר: יישום מורכב עלול לדרוש יותר טוקנים ממה שמסוגלת להחזיק פגישה אחת. הסוכן עלול להגיע ל-80% מהדרך בתוכנית ואז להתחיל לאבד את הקוהרנטיות. או שהוא עלול להיתקל בשגיאת קומפילציה בלתי צפויה שתשלח אותו לסחרור. הבעיה השנייה עדינה יותר: ביקורת עצמית היא כמעט חסרת ערך. סוכן שבדיוק השקיע חצי שעה ביישום תכונה לא צריך להחליט לאחר מכן אם היישום הזה הוא באמת טוב.

ה-loop פותר את הבעיה הראשונה. מבקר אנטגוניסטי פותר את השנייה. והחלק היפה? כל העניין פשוט עד כדי מבוכה. בבסיסו, זה עדיין בעצם לולאת while ב-Bash, רק עם שער ביקורת, כפי שמוצג כאן:

while [ iteration < max_iterations ]; do
      run the implementation agent with the objective and current progress
      check if the agent reported SUCCESS or RETRY
      if RETRY → feed the progress back in and go again
      if SUCCESS → run an antagonistic reviewer in a fresh context window
          if APPROVED → done
          if CHANGES_REQUESTED → feed the review back in and go again
  done

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

כשאני אומר "מבקר ביקורתי", אני לא מתכוון לסוכן שהוא גס או מתנגד לשם ההנאה (אם כי זה באמת כיף לצפות בזה; כדאי לכם לנסות את זה!). אני מתכוון לסוכן נפרד שתפקידו להיות ספקן באופן מקצועי. הוא קורא את התוכנית, בוחן את ההבדלים, בודק את הבדיקות, מחפש דרישות שפספסו, מצביע על הנחות שבירות, ושואל את השאלה שלסוכן המיישם יש הכי פחות תמריץ לשאול: "האם זה באמת הושלם?"

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

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

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

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

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

סביבת עבודה מבולגנת

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

איור 2: סביבת העבודה הישנה שלי: מספר הפעלות של Claude וחלוניות מסוף, שכל אחת מהן עוקבת אחר שלב אחר בלולאת ה-RPI.

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

התגובה האינסטינקטיבית הראשונה שלי הייתה לחזור לשימוש בסוכנים. הנחיתי סוכן-מנהל ליישם את מסגרת ה-RPI-plus-loop באמצעות סוכנים-משנה, כדי שאוכל לנהל את הכל מתוך מופע יחיד של Claude. אך, מכיוון שכבר הייתי טראומטי מהניסיון הקודם שלי עם צוותי הסוכנים, החלטתי במקום זאת לבנות כלי. אני שמח לבשר כי הכלי הזה זמין כעת כקוד פתוח, כך שכולם יוכלו ליהנות ממנו.

הכירו את Agentic Orchestrator

וכך נולד Agentic Orchestrator. מדובר בממשק משתמש מסופי (TUI) שלוקח את המסגרת "מחקר → תכנון → יישום", משפר אותה ומטמיע אותה בהנדסה של ממש.

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

מלולאות Bash ועד מכונת מצבים אמיתית

זוכרים את לולאת ה-`while` ב-Bash שהזכרנו קודם? זו שבה מריצים את הסוכן, בודקים את המצב ומעדכנים את ההתקדמות. Agentic Orchestrator לוקח את אותו הרעיון ומעניק לו מבנה ממשי. כל תכונה עוברת דרך מכונת מצבים מוגדרת היטב, כפי שמוצג באיור 3: מאגר ידע → בירור → מחקר → תכנון → תכנון → יישום → בדיקה → פרסום → הושלם.

איור 3: מעגל הפיתוח החדש והמשופר.

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

שלבתְפוּקָהמדוע הוא קיים
מאגר הידעמפה הניתנת לשימוש חוזר של ארכיטקטורה, מוסכמות, ממשקי API, תלות ופקודות אימותמאפשר לכל שלב מאוחר יותר להתחיל מנקודת התחלה אמיתית, במקום לגלות מחדש את המאגר מאפס.
בקשההבהרת שאלות ותשובות המשתמשים באמצעות תבנית "grill-me"מאלץ את הגורמים הבלתי ידועים לצאת לאור לפני שסוכן כלשהו יתחיל לשער השערות.
מֶחקָרמחקר מסמכים הכולל הפניות קונקרטיות לקבצים ותיאור ההתנהגות במצב הנוכחימתאר את המציאות, ולא את הפתרון, שעליה תתבסס תכנית התשתית העובדתית. 
לְעַצֵבמסמך תכנון: תיאור הבעיה, הפתרון, סיפורי משתמשים, החלטות, הגדרות מפורשות של מה שאינו נכלל בהיקף הפרויקטמהווה את מקור האמת של התכונה, שנוצר באמצעות סקירת תכנון ממוקדת עם הסוכן.
מפת דרכיםרשימה מסודרת של פרוסות אנכיות דקות מקצה לקצהמאפשר לסוכנים לבצע פעולות מוגבלות וניתנות לאימות, במקום תוכניות נרחבות הנוגעות בכל השכבות בבת אחת.
תכנון שלביםתוכנית שלבים מאושרת הכוללת משימות, קריטריוני קבלה וציפיות לאימותהופך את העבודה למוחשית מספיק כדי שניתן יהיה לבצע אותה; ביקורת אופציונלית בשלב התכנון מאפשרת לאתר תוכניות לקויות לפני שהקוד הופך ליקר.
יישוםקוד, בדיקות, קובץ התקדמות, דוח אימותמאפשר לחלון הקשר חדש להמשיך מהמקום שבו הסתיימה ההפעלה הקודמת; קובץ ההתקדמות הזה אוכף את הלולאה בקפדנות.
סקירה סופיתאישור או בקשות לשינויים מפורטותמאפשר למבקר, שאין לו את המומנטום של היישום, להחליט אם "מוכן" אכן פירושו "מוכן".

טבלה 1: הסבר על כל שלב במחזור הפיתוח החדש.

התשתית המשעממת

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

  • עצי עבודה: כל תכונה פועלת בעץ עבודה נפרד ב-Git, מה שאומר שתכונות שונות יכולות לעבור את תהליך הפיתוח על בסיס אותו מאגר מבלי להפריע זו לזו.
  • ה-TUI: ממשק זה מספק לוח מחוונים העוקב אחר כל מה שנמצא בתהליך — מה נמצא בשלב המחקר, מה נחסם, מה דורש בדיקה ומה מוכן לפרסום.
  • התאוששות מקרי קריסה וניהול הפעלה: מכיוון שמכונת המצבים נשמרת, לא תאבד את ההתקדמות שלך עקב אירועים כגון סגירת מסוף, הפעלה שתקועה או קריסה חמורה.
  • פעולות לאחר הפרסום: גם לאחר פרסום ה-PR, ה-Orchestrator ממשיך לתמוך בך. תוכל לבצע ריבייז מול ה-main, לבקש שינויים מבניים ממוקדים, לחזור למצב קודם, לשפר את היישום או לטפל בהערות ביקורת נכנסות מבלי לצאת מה-TUI.
  • מעברי פאזה דטרמיניסטיים: הקוד מחליט מה יבוצע בשלב הבא, שומר את התוצרים ומאכף את שלבי הבדיקה, בעוד שהסוכן הוא זה שחושב; הוא אינו יכול להמציא את זרימת העבודה תוך כדי תנועה.

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

זה עובד?

התוצאות עשויות להשתנות. 

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

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

ניסיתי לעשות את אותו הדבר עם Agentic Orchestrator במצב האוטונומי המלא — כלומר, ללא צורך בתגובות מצד בני אדם. לאחר 12 שעות, 250 דולר וללא כל התאמות נוספות, זו הייתה התוצאה:

נכון, כאן נעשה שימוש ב-Opus 4.7 בכל השלבים, בניגוד לגרסה 4.5 שבה השתמשה חברת Anthropic בהדגמה שלה. 

זה מתחיל להיראות ממש כמו אספרסו המופעל על ידי Opus.

אז, האם פתרנו את בעיית הנדסת התוכנה?

עדיין לא, אבל בשלב זה אנחנו כבר די קרובים לפתרון בעיית הקוד.

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

אבל אפילו בעולם שבו הדגמים יהיו בעלי יכולות גבוהות פי עשרה ממה שהם כיום, יש דבר אחד שאני משוכנע יותר ויותר שלא ישתנה — הידע האנושי בתחום וההבנה הבסיסית שלנו לגבי מערכות אינם ניתנים להחלפה.

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

תפקידו של מהנדס התוכנה משתנה, אך אינו נעלם.

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

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

הערה בנושא עומס בעבודה, התמכרות ובריאות הנפש

אני רוצה לשנות את הטון כאן, כי החלק הזה חשוב.

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

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

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

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

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

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

לכו לבנות משהו!

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

הנה מה שהייתי אומר למי שמתחיל מאפס היום: אל תנסה לעשות את הבלתי אפשרי. התחל במשימה קטנה ב-Cursor או ב-Claude Code. התרגל לקצב של מתן הנחיות, בדיקה ושיפור. לאחר מכן, נסה את מסגרת ה-RPI על תכונה אחת — תחילה מחקר, אחר כך תכנון, ולבסוף יישום. אתה לא צריך שום דבר מתוחכם. פשוט פתח שלוש הפעלות של Claude, אחת לכל שלב, והעבר את התוצרים באופן ידני. תחושו עד כמה זה שונה כאשר הסוכן מקבל הקשר מהמחקר שלו עצמו, במקום מההנחיה שכתבתם בחופזה.

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

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

עכשיו צאו להתנסות. וכשתמצאו משהו שעובד, שתפו אותו, כי אני מבטיח לכם שיש מישהו אחר שתקוע בדיוק באותו המקום שבו הייתם בחודש שעבר.

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

אפילו כאשר הנתונים לא השתנו, כל בקשה עדיין גרמה לקריאות gRPC, לחישובים חוזרים ולפעמים לקריאות ממסד הנתונים האחורי. בהיקף הפעילות של DoorDash, הדבר גרם לשימוש מיותר במשאבי השירות, לעומס גבוה יותר על מסד הנתונים ולהידרדרות בחביון P90/P99.

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

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

זה מה שהניע אותנו ליצור את Entity Cache.

מה שבנינו

Entity Cache הוא פרוקסי מטמון שקוף ל-HTTP/gRPC הפועל בתוך רשת השירותים (service mesh) של DoorDash, המבוססת על Envoy. הוא ממוקם בנתיב הבקשה ומספק תגובות הנגישות בתדירות גבוהה ממטמון מרכזי, מבלי שכל שירות יצטרך ליישם לוגיקת מטמון משלו.

מכיוון שמטמון הישויות משולב ברשת השירותים, השירותים ממשיכים לבצע את אותן קריאות HTTP או gRPC כמו בעבר. תהליך ההטמעה מתבצע באמצעות תצורת רשת השירותים, ולכן אין צורך לשנות את קוד הלקוח או את קוד השירות במעלה הזרם.

לדוגמה, ניתן לנתב נקודת קצה של gRPC דרך Entity Cache באמצעות תצורה כזו:

- name: example-service/grpc/50051
  redirect:
    enabled: true
    entity_cache: true
    endpoints:
      - path: ^/example.v1.ExampleService/GetExample$
        headers:
          - name: :method
            string_match:
              exact: POST
        rollout: 1

על ידי הגשת תגובות שמורות במטמון עוד לפני שהבקשות מגיעות לשירותים במעלה הזרם, Entity Cache מסייע ל-DoorDash:

  • שיפור זמן ההשהיה על ידי הימנעות מקריאות HTTP/gRPC חוזרות בין שירותים.
  • צמצמו את העומס על ידי צמצום חישובים חוזרים וקריאות למסד הנתונים האחורי.
  • שיפור האמינות על ידי הגשת נתונים שמורים במטמון כאשר השירותים במעלה הזרם איטיים או אינם זמינים.
  • הפחתת עלויות התשתית באמצעות צמצום השימוש המיותר במשאבי מחשוב ובסיסי נתונים.
  • צמצום המאמץ ההנדסי על ידי מתן מטמון מרכזי במקום לדרוש מכל שירות לבנות שכבת מטמון משלו.

מאז השקתו, Entity Cache הוטמע במספר רב של נקודות קצה בדרגות Tier 0 ו-Tier 1, המאופיינות בשיעור שינויים נמוך. כיום הוא מטפל ביותר מ-1.5 מיליון בקשות בשנייה, משיג שיעורי פגיעה במטמון של מעל 90% בנקודות קצה רבות, והפך לשכבת ביצועים ואמינות בפלטפורמה כולה, המבוססת על תשתית רשת השירותים (service mesh) של DoorDash.

סקירה כללית של הארכיטקטורה ברמה גבוהה

Entity Cache מופעל כפרוקסי מטמון ייעודי המשתלב ברשת השירותים (service mesh) שלנו המבוססת על Envoy. שירותי הלקוח אינם משנים את הקוד שלהם. כפי שמוצג באיור 1, רשת השירותים מנתבת באופן אוטומטי בקשות יוצאות דרך Entity Cache תחילה, כאשר השירות במעלה הזרם מוגדר כגיבוי. כאשר מתקבלת בקשה, Entity Cache בודק אם קיימת תגובה תקפה במטמון. אם כן, התגובה מוחזרת מיד; מקרים שבהם לא נמצא מטמון מועברים לשירות במעלה הזרם, אשר מייצר תגובה שנשמרת במטמון לבקשות עתידיות.

איור 1: Entity Cache ממוקם בין רשת השירותים (service mesh) לשירותים במעלה הזרם, ומספק תגובות שמורות במטמון מ-Valkey במקרה של התאמה, ומעביר בקשות שלא נמצאו במעלה הזרם לקבלת נתונים עדכניים. אירועי ביטול תוקף מ-Kafka ו-Cache Advisor מספקים שניהם אותות לגבי עדכניות הנתונים ותהליכי שילוב, כך שהמטמון יכול להיות בטוח, שקוף ומנוהל באופן מרכזי.
  • נתיב הבקשה: Envoy מנתב את הבקשות תחילה ל-Entity Cache, ובמידת הצורך פונה לשירות במעלה הזרם. במקרה של פגיעה במטמון, Entity Cache מספק את התגובה ישירות מ-Valkey, תוך עקיפת התלות בשירותים במעלה הזרם. במקרה של החטאה, הוא מעביר את הבקשה לשירות במעלה הזרם, מאחסן את התגובה ב-Valkey בהתאם למדיניות המטמון, ומחזיר אותה ללקוח.
  • מסלול ביטול תוקף המטמון: כאשר הנתונים הבסיסיים משתנים, שירותים במעלה הזרם משדרים אירועי שינוי כחלק מתהליכי הכתיבה הרגילים שלהם. אירועים אלה עוברים דרך Kafka אל Entity Cache. במקום למחוק רשומות במטמון בכל המופעים, Entity Cache מתעד כי ישות ספציפית עודכנה ומציין את זמן העדכון. בכל בקשה, Entity Cache משווה את הזמן שבו התגובה נשמרה במטמון עם זמן העדכון המתועד. אם התגובה במטמון ישנה יותר מזמן העדכון, היא נחשבת למיושנת. לאחר מכן, Entity Cache משיג נתונים מעודכנים מהשירות במעלה הזרם ומעדכן את המטמון. גישה זו נמנעת ממחיקה מבוזרת ומורכבת, תוך שהיא עדיין מבטיחה שהנתונים המעודכנים יבואו לידי ביטוי במהירות.
  • נתיב ניתוח התעבורה: מטמון הישויות מאמת באופן רציף את נכונות הנתונים באמצעות דגימה של תעבורת הייצור. עבור תת-קבוצה של בקשות, הוא משווה תגובות שמורות במטמון לתגובות בזמן אמת מהשרתים במעלה הזרם ומחשב את ההבדלים ברקע. מנגנון אימות זה מבטיח שהמטמון יישאר מדויק לאורך זמן ומספק את הבסיס הבטיחותי לפריסות מבוקרות. כדי לתמוך בכך, פיתחנו את Cache Advisor, שירות נפרד המתמקד בזיהוי נקודות קצה עם שיעורי שינוי נמוכים, שהן מועמדות חזקות לאחסון במטמון. השירות פועל באופן עצמאי בנקודת הכניסה במעלה הזרם, תוך שימוש במסנן העיבוד החיצוני של Envoy כדי לצפות בדפוסי הבקשות ולחשוף הזדמנויות אלה.
  • מעבר אוטומטי לשירות גיבוי: Envoy עובר אוטומטית לשירות המקור אם Entity Cache אינו זמין.

תכונות שיושמו

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

1. ירידה הדרגתית באמצעות TTL כפול: כפי שמוצג באיור 2, Entity Cache משתמש בשני ספי תפוגה: זמן חיים (TTL) "רך" המגדיר את טריות הנתונים — לדוגמה, 60 שניות — ו-TTL "קשה" המגדיר את משך הזמן המרבי המוחלט — לדוגמה, חמש דקות. בתנאים רגילים, הנתונים במטמון מתעדכנים בהתאם להגדרת ה-TTL ה"רך". כאשר שירותים במעלה הזרם הופכים לאיטיים או אינם זמינים, Entity Cache ממשיך להציג נתונים מעט מיושנים מהמטמון במקום להעביר שגיאות ללקוחות.

איור 2: מטמון הישויות (Entity Cache) משתמש בגיל הנתונים כדי להחליט אם להציג נתונים מהמטמון, לרענן אותם מהמקור או לדרוש נתונים עדכניים. המסקנה העיקרית היא ש-TTL רך מאפשר הצגה חלקה של נתונים מיושנים כאשר המקור איטי, בעוד ש-TTL קשיח מאלץ אחזור נתונים עדכניים לאחר תום תקופת הגיל המרבית.

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

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

באופן מסורתי, אחסון במטמון מחייב פשרה בין זמני TTL ארוכים למען ביצועים, לבין זמני TTL קצרים למען עקביות. Entity Cache מתמודד עם בעיה זו באמצעות ביטול תוקף מונחה אירועים, תוך שימוש ברשימת חסימה. כאשר הנתונים הבסיסיים משתנים, שירותי המקור מפרסמים אירוע ביטול תוקף ל-Kafka. צרכן של Entity Cache רושם חותמת זמן של ביטול התוקף ב-Valkey עבור הישות והמזהים המושפעים. במקרה של פגיעה במטמון, Entity Cache בודק את הערך הזה. אם האובייקט במטמון נלקח לפני חותמת הזמן של הפסילה, הוא מטופל כמיושן ומתרענן מהמקור. במקום למחוק מפתחות מטמון, המערכת מסתמכת על השוואת חותמות זמן. כל אובייקט במטמון מאחסן את זמן אחזורו; הפסילה פשוט רושמת חותמת זמן חדשה יותר. תכנון זה מאפשר לנקודות קצה לשמור על TTL רך וארוך לשיעורי פגיעה גבוהים, תוך שמירה על עקביות כמעט בזמן אמת, עם חביון פסילה P99 המכוון לכשנייה אחת.

3. זיהוי חריגים מבוסס Envoy — מעבר אוטומטי לשירות חלופי: Entity Cache משתלב ברשת השירותים (service mesh) מבוססת Envoy שלנו. כפי שמוצג באיור 3, Envoy מפקח על תקינות הפודים של המטמון ומסלק באופן אוטומטי פודים לא תקינים ממאגר איזון העומסים. אם כל פודי המטמון הופכים ללא תקינים, Envoy מנתב את התעבורה ישירות לשירותים במעלה הזרם, ובכך מבטיח זמינות גם במקרה של כשל מוחלט במטמון.

איור 3: רשת השירות (service mesh) שולחת תעבורה רגילה לפודים תקינים של Entity Cache ומסלקת פודים לא תקינים ממסלול איזון העומס. אם מסלול המטמון אינו זמין, התעבורה מועברת במלואה לשירות במעלה הזרם, תוך שמירה על הזמינות.

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

התרחבות למיליוני בקשות בשנייה

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

  • ניהול זיכרון בקנה מידה גדול: הקצאות תכופות בנתיבי גישה עמוסים הגבירו את העומס על איסוף הזבל (GC) וגרמו לעליות חדות בחביון. יישמנו מאגר מאגרים מותאם אישית כדי לעשות שימוש חוזר בזיכרון ולצמצם את ההקצאות. צעד זה הפחית את העומס על ה-GC, ייצב את השימוש בזיכרון והוריד את חביון העומס של בקשות P99 לכ-2.1 מילי-שניות, תוך שמירה על תפוקה עקבית.
  • "בהלה" במטמון בקנה מידה גדול: במקרה של ישויות פופולריות, תוקף מבוסס TTL ריכז את תעבורת הרענון לנקודה אחת בזמן, מה שיצר קפיצות בעומס במעלה הזרם. יישמנו רענון מוקדם הסתברותי המבוסס על אלגוריתם XFetch. ככל שהרשומות מתקרבות ל-TTL הרך שלהן, הסיכוי שכל בקשה תפעיל רענון הולך וגדל. הדבר מפזר את התעבורה לאורך זמן, מפחית את הקפיצות ומייצב את העומס במעלה הזרם.
  • ריבוי משימות בקנה מידה של מיליוני בקשות: בקשות מקבילות לעתים קרובות שיכפלו את אותה העבודה, במיוחד בהקמת חיבורים ובמקרים של פספוסים במטמון עבור מפתחות פופולריים. הכנסנו דפוס "טיסה" יחיד באמצעות מבנים אטומיים ונטולי נעילה. שיטת "השווה והחלף" (Compare and Swap) מבטיחה שרק גורוטין אחד יבצע חיוג או אחזור לכל מפתח, בעוד שאחרים יעשו שימוש חוזר בתוצאה. ביטול הכפילויות מתבצע בכל פוד בנפרד, ללא תיאום בין פודים. דבר זה ביטל עבודה מיותרת והפחית את התחרות על המשאבים. התפוקה לכל פוד גדלה פי חמישה בערך, שיעורי ההקצאה פחתו ב-50% עד 60%, וזינוקי החביון ב-P99 צומצמו בעד 80%.
  • זיהוי התוכן שיש לאחסן במטמון: עם אלפי נקודות קצה, זיהוי ידני של מועמדים מתאימים לאחסון במטמון לא היה פתרון הניתן להרחבה. 

פיתחנו את Cache Advisor כדי לנתח תעבורה אמיתית בסביבת הייצור ולהנחות את תהליך ההטמעה. הכלי פועל בנקודת הכניסה (ingress) באמצעות מסנן העיבוד החיצוני של Envoy, לוקח דגימות מבקשות, עוקב אחר יציבות התגובות ומעריך את תדירות העדכונים. הוא ממליץ על ערכי TTL ומציג מועמדים מבטיחים. כך זוהו למעלה מ-130 הזדמנויות להטמעה, מה שאפשר אימוץ נרחב ובטוח יותר של טכניקות המטמון.

ההשפעה על המשתמשים/על העסק

"Entity Cache" הפך לשכבת אמינות מרכזית ב-DoorDash, ומטפל כיום ביותר מ-1.5 מיליון בקשות בשנייה עם 99.99999% . יותר מ-100 נקודות קצה ב-50 שירותים שולבו במערכת, והביאו לשיפורים ניכרים בתחומי זמן ההשהיה, המדרגיות ועמידות בפני תקלות.

מבחינת ביצועים, Entity Cache מוסיף עומס מינימלי תוך שהוא מספק שיפורים משמעותיים:

  • זמן ההשהיה של בקשת P99 הוא כ-2.1 מילי-שניות
  • שיעור הפגיעות במטמון עומד באופן עקבי על מעל 90%
  • ירידה של 60% עד 95% במספר הבקשות במעלה הזרם במהלך פעולה רגילה
  • הפחתת זמן ההשהיה בעד 90% עבור נקודות קצה שנוספו לאחרונה
  • אפילו בשירותים הכוללים מטמון מקומי, זמן ההשהיה מקצה לקצה מצטמצם לעתים קרובות בכמחצית, בשל מספר נמוך יותר של קריאות רשת בין-שירותיות ביציאה מהלקוח

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

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

הצעדים הבאים

  1. חלוקת תעבורה דינמית על בסיס השוואת שיעורי שגיאה: כיום, חלוקת התעבורה בין מטמון הישויות (Entity Cache) לשרתים במעלה הזרם (upstream) מתבססת על תצורה סטטית. אנו מפתחים מנגנון העברת תעבורה דינמי, המתאים את הניתוב על סמך השוואת שיעורי שגיאה בזמן אמת: המערכת שולחת יותר תעבורה לשרתים במעלה הזרם כאשר תקינות המטמון יורדת, ומחזירה את התעבורה למטמון ככל שתקינותו משתפרת.
  2. בידוד "שכנים רועשים" לפי אשכול מטמון במעלה הזרם: כיום , כל השירותים חולקים אשכול מטמון יחיד. אנו עוברים למבנה של אשכולות מטמון ייעודיים לכל שירות בעל תעבורה גבוהה, כדי ליצור גבולות משאבים ברורים, ובכך למנוע מבעיות בשירות אחד להשפיע על שירותים אחרים.
  3. הגבלת מקביליות אדפטיבית: מגבלות מקביליות סטטיות אינן מיטביות, שכן הן גורמות לבזבוז קיבולת בעת עומס נמוך או לעליות חדות בחביון בעת עומס גבוה. אנו מיישמים הגבלת מקביליות אדפטיבית, המודדת באופן רציף את ביצועי המערכת ומתאימה אוטומטית את רמת המקביליות בהתאם לחביון ולתפוקה הנצפים, ובכך ממקסמת את הקיבולת תוך שמירה על יעדי החביון.

תודות

הקמת מאגר הישויות (Entity Cache) הייתה תוצר של מאמץ משותף של צוותים רבים ב-DoorDash. ברצוננו להודות במיוחד לצוות התשתית המרכזית (Core Infra): דקוטה באבר, הו-צ'ואן וונג, יי-פאן יאנג וטג'אס לודאיה, שתרומתם הייתה בעלת ערך רב לבניית הפלטפורמה, להפעלתה ולהרחבתה.

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