דיבאגינג עם AI עובד הכי טוב כשנותנים למודל את מה שהייתם נותנים לעמית שיושב לידכם: את השגיאה המלאה, את הקוד שזרק אותה, מה ציפיתם, מה קרה במקום ומה כבר פסלתם. המודל לא יכול להריץ את התוכנית שלכם או לראות את הנתונים שלכם, כך שכל מה שהוא יודע על הבאג מגיע ממה שאתם מדביקים. ההרגל השימושי ביותר הוא לבקש את הסיבה לפני התיקון.
הדביקו הכול, לא רק את השגיאה
שתי הלשוניות למטה מתארות את אותו באג. סקריפט קורא קובץ CSV שיוצא מ-Excel וקורס עם KeyError: 'email', למרות שלקובץ יש בבירור עמודת email.
KeyError אומר שלמילון אין מפתח בשם 'email'. אפשר להימנע מהשגיאה עם .get(), שמחזיר None במקום לזרוק חריגה:
email = row.get("email")
או לבדוק קודם:
if "email" in row:
email = row["email"]
התשובה הראשונה צודקת לגבי מה זה KeyError, והעצה שלה מזיקה כאן. עם row.get("email") הקריסה נעלמת, וכל מייל הופך ל-None. המודל ענה לגרסה הנפוצה ביותר של השגיאה כי זה כל מה שהפרומפט תיאר.
הדיווח המלא עבד בזכות שתי שורות. "רק העמודה הראשונה נכשלת" ו-"נשמר מ-Excel כ-CSV UTF-8" הם הרמזים שמצביעים על ה-byte order mark, ואף אחד מהם לא נמצא בהודעת השגיאה. רק לעיתים רחוקות יודעים איזה מהפרטים שלכם הוא הרמז, ובגלל זה מדביקים את כולם.
חמשת הדברים שצריך לכלול
- השגיאה המלאה. כל ה-traceback או פלט הקונסול, לא פרפרזה. מספרי השורות ושרשרת הקריאות מראים איפה הכשל התחיל, ולעיתים קרובות זה כמה רמות מהמקום שבו הוא צץ.
- הקוד שזרק אותה. הפונקציה שנכשלת והקוד שקורא לה. אם השגיאה מזכירה שורה, ודאו שהשורה הזו נמצאת במה שאתם מדביקים.
- מה ציפיתם מול מה שקרה. משפט אחד לכל אחד. בבאגים בלי שגיאה בכלל (פלט שגוי, דף ריק, שאילתה איטית), זה כל דיווח הבאג.
- הסביבה שלכם. גרסת השפה, מערכת ההפעלה, וגרסאות ה-framework והספריות כשהן יכולות להשפיע. באגים של קידוד, נתיבים ותאריכים תלויים לעיתים קרובות בפלטפורמה.
- מה כבר ניסיתם. זה מונע מהמודל להציע את זה שוב, והתוצאה של כל ניסיון היא ראיה. "הסרת החלק של המייל גורמת לזה לעבוד" צמצמה את באג ה-CSV לעמודה אחת.
לבקש את הסיבה לפני התיקון
בקשה לתיקון מזמינה את המודל לשנות קוד עד שהשגיאה נעלמת. בקשה לסיבה מבקשת ממנו לחשוב למה השגיאה קורית, והתיקון נובע מזה. בקשו רשימה קצרה ומדורגת של סיבות עם דרך לבדוק כל אחת, ואז הריצו את הבדיקות בעצמכם. התבנית הזו עושה את זה:
TypeError: Cannot read properties of undefined (reading 'map')function UserList() {
const [users, setUsers] = useState();
useEffect(() => {
fetch("/api/users")
.then((res) => res.json())
.then((data) => setUsers(data));
}, []);
return (
<ul>
{users.map((u) => (
<li key={u.id}>{u.name}</li>
))}
</ul>
);
}- הקומפוננטה מתרנדרת לפני שקיימים נתונים.
useState()מתחיל כ-undefined, ו-React מרנדר את הקומפוננטה פעם אחת לפני שה-effect רץ, כך ש-users.mapנקרא עלundefined. זה לבדו מפיק בדיוק את השגיאה שלכם, בכל טעינה. בדיקה: הוסיפוconsole.log(users)ממש לפני ה-return. אם הוא מדפיסundefinedוהשגיאה מגיעה מיד אחריו, זה זה. - ה-API מחזיר משהו שאינו מערך. אם הוא היה מחזיר אובייקט כמו
{ users: [...] }, השגיאה הייתה שונה (users.map is not a function), כך שזו לא השגיאה שהדבקתם. זה עדיין יכול להיות הבעיה הבאה אחרי שסיבה 1 תתוקן. בדיקה:console.log(data)בתוך ה-.thenהשני. - הבקשה נכשלת. עוד לא מעורבת: כי הרינדור הראשון זורק שגיאה, React לא מריץ את ה-effect אף פעם, כך שהבקשה אפילו לא נשלחת. בדיקה: לשונית Network לא מראה שום בקשה ל-
/api/users, מה שגם מאשר את סיבה 1.
התשובה עושה משהו שתשובה שמתחילה בתיקון מדלגת עליו: היא פוסלת סיבות כי השגיאה שהן היו מפיקות שונה מזו שהדבקתם, או כי הקוד אף פעם לא מגיע רחוק מספיק כדי שהן יקרו. זו גם הסיבה שהטקסט המדויק של השגיאה חשוב. בקשה מהמודל לפרט סיבות לפני שהוא עונה היא צורה קלה של chain of thought prompting: הנימוק בא קודם והמסקנה נשענת עליו.
לבנות שחזור מינימלי
שחזור מינימלי הוא התוכנית הקטנה ביותר שעדיין מראה את הבאג: נתונים שנכתבו ידנית במקום קריאה למסד נתונים, פונקציה אחת במקום כל המודול. בנייה של שחזור כזה מוצאת לעיתים קרובות את הבאג עוד לפני ששואלים מישהו, כי כל חלק שמסירים או משאיר את הבאג (הוא לא היה מעורב) או גורם לו להיעלם (הוא היה). כשזה לא קורה, השחזור הוא הפרומפט האידיאלי: קצר מספיק כדי שהמודל יקרא כל שורה, ונקי מקוד לא קשור שעלול לשלוח אותו לרדוף אחרי הבעיה הלא נכונה.
אם הבאג תלוי בנתונים, כללו כמה שורות שמפעילות אותו. מודל יכול לחשוב על [{"id": 1, "name": null}]; הוא לא יכול לחשוב על "כמה שורות בפרודקשן".
כשהתיקונים מפסיקים לעבוד
אם התיקון השלישי של המודל נכשל באותה צורה, בקשה רביעית לתיקון כנראה לא תצליח יותר. שני דברים עוזרים יותר:
- תנו לו ראיות חדשות. הוסיפו שורת print או log שמראה את הערכים בפועל בנקודת הכשל, הריצו, והדביקו את הפלט. ראיה שסותרת את התיאוריה של המודל היא הדרך המהירה ביותר לתיאוריה טובה יותר.
- פתחו שיחה חדשה. שרשורי דיבאגינג ארוכים מתמלאים בתיאוריות נטושות ובגרסאות ישנות של הקוד, והמודל עלול להמשיך לבנות עליהן. צ'אט חדש עם הקוד הנוכחי, השגיאה, הראיות ושורה שאומרת "כבר נפסלו: X ו-Y" מגיע לעיתים קרובות רחוק יותר בתשובה אחת.
היזהרו עם תשובות בטוחות בעצמן על ההתנהגות של ספרייה. מודל יכול לתאר אפשרות או פונקציה שלא קיימות; ראו הזיות של AI כדי ללמוד איך לבדוק. כשהקוד לא שבור אבל אתם לא מבינים למה הוא עושה את מה שהוא עושה, פרומפט להסבר קוד הוא הכלי הטוב יותר.
שאלות נפוצות
איך מבקשים מ-ChatGPT או מ-Claude לתקן את הקוד שלי?
הדביקו את הודעת השגיאה המלאה ואת הקוד שזרק אותה, ואז הוסיפו שלוש שורות קצרות: מה ציפיתם, מה קרה במקום ומה כבר ניסיתם. בקשו את הסיבה הסבירה ביותר ואיך לאשר אותה לפני שאתם מבקשים תיקון. "תתקן את זה" ריק מקבל תיקון לגרסה הנפוצה ביותר של השגיאה, שאולי היא לא שלכם.
כדאי להדביק את כל הפרויקט שלי ל-AI?
לא. הדביקו את הפונקציה שבה השגיאה קורית, את הקוד שקורא לה ודוגמה של הנתונים שהיא מקבלת. עוד יותר טוב, צמצמו את הבעיה לתוכנית הקטנה ביותר שעדיין מראה אותה. קבצים לא קשורים מאטים את התשובה ונותנים למודל יותר מקומות לחפש בעיה שלא נמצאת שם.
למה התיקון של ה-AI מעלים את השגיאה אבל התוכנית עדיין לא עובדת?
התיקון טיפל בסימפטום. למשל, החלפה של row["email"] ב-row.get("email") עוצרת KeyError, אבל אם המפתח חסר בגלל באג מוקדם יותר, כל המיילים הם עכשיו None בשקט. בקשה קודם לסיבה, ולדרך לאשר אותה, מונעת תיקונים שרק מסתירים את הבעיה.
מה עושים אם ה-AI ממשיך להציע תיקונים שלא עובדים?
הפסיקו לבקש תיקונים ותנו לו ראיות במקום. דווחו מה כל ניסיון שינה, הוסיפו שורת print או log שמראה את הערכים בפועל, והדביקו את הפלט. אם השיחה ארוכה, פתחו חדשה עם סיכום נקי: הקוד, השגיאה, הראיות והתיקונים שכבר נפסלו.