📌 הסכנות בהרצת סוכני קידוד על המכונה שלנו
סוכנים חכמים ובפרט סוכני קידוד הם התוכנה הראשונה שמותקנת בקנה מידה גדול ושהתנהגותה אינה דטרמניסטית. אף אחד לא יכול לדעת מראש מה סוכן הקידוד יעשה בתגובה להודעה הבאה. מאפיין זה חושף אותנו לסכנות אבטחה משמעותיות בעבודה עם סוכני קידוד.
בואו נראה כמה דוגמאות להפתעות כאלה לקראת הוובינר השבוע שיעסוק באבטחת מידע בעידן הסוכנים החכמים.
✏ הרעלת מודלי שפה
מקור:
https://ron.stoner.com/how-i-won-a-championship-that-doesnt-exist/
בסוף ינואר 2025 רון סטונר העלה אתר עם תמונה של גביע בו כתוב שהוא זכה באליפות הנימיץ השנתית שהתקיימה במינכן. הוא גם עדכן את הדף של נימיץ בויקיפדיה עם קישור לדף הנצחון שלו. זה הספיק בשביל לגרום ל ChatGPT למצוא את הקישור ולספר שהוא היה הזוכה בתגובה לשאלה בצ'אט.
התרגיל של סטונר הוא שטחי. סטונר גרם למודל להיתקל בשם שלו במהלך חיפוש ברשת - אבל מבהיר לנו עד כמה קל לרמות סוכנים חכמים במיוחד כאלה שיוצאים לחפש ברשת. אותו מנגנון יכול להיות מנוצל לרעה על ידי גורמים זדוניים שיקימו אתרים שיפרסמו חבילות npm שהן בעצם רוגלות, אותן הסוכן יתקין בלי להבין שמדובר ברוגלה.
✏ באג בסוכן יוצר חיוב מוגזם
סוכני קידוד הם כלי פיתוח ייחודי בכך שהם מחוברים לכרטיס אשראי, כך שככל שהסוכן משתמש ביותר טוקנים אנחנו צריכים לשלם יותר. שני באגים מעניינים מבהירים לנו שהחיבור הזה אף פעם לא עובד חלק.
במקרה אחד אנטרופיק החליטו שהם לא רוצים לאפשר לעוזר אישי בשם Hermes להשתמש בתוכנית המנויים שלהם אז הם ניסו לנתב בקשות מ Hermes לחיוב גבוה יותר. התוצאה היתה שמספיק לכתוב את המילה HERMES.md בהודעת קומיט וקלוד קוד יחייב אותך בתשלום גבוה יותר על הפיתוח:
https://github.com/anthropics/claude-code/issues/53262
במקרה אחר אופןקוד (עוד סוכן קידוד) התחבר לתוכנית המנויים של גיטהאב קופיילוט, אבל בגלל באג במצבים מסוימים השתמש ביותר בקשות בתשלום וכך סיים למשתמשים את המנוי מוקדם:
https://github.com/anomalyco/opencode/issues/16937
✏ טעות של המודל מוחקת נתוני פרודקשן
מקור:
https://x.com/lifeof_jer/status/2048103471019434248?s=46
ג'ר קריין, המייסד של PocketOS חיבור את קלוד אופוס לסביבת הפיתוח שלו ב Cursor. הוא שכח שבאיזשהו קובץ טקסט בתיקיית הפרויקט היה כתוב טוקן הגישה לסביבת הפרודקשן - כדי להריץ תהליך תחזוקה שגרתי.
קלוד אופוס נתקל בבעיה, חשב שצריך ליצור מחדש את הסביבה, מצא את הטוקן של סביבת הפרודקשן והשתמש בו כדי ליצור מחדש את סביבת הפרודקשן - וכך מחק את כל נתוני המשתמשים.
בעבודה עם סוכני קידוד אנחנו נוטים לחשוב שיש לנו עוזר אישי מיומן על המחשב שתמיד יעשה מה שטוב לפרויקט. זה נכון ב 99% מהמקרים. לשאר ה-1% עלינו לוודא מנגנוני הגנה טובים בסביבה שימנעו מאנשים או סוכנים פזיזים לעשות נזקים.
✏ הזרקת פרומפט מובילה להשתלטות על מכונות
מקור:
https://neciudan.dev/cline-ci-got-compromised-here-is-how
הצוות של cline (עוד סוכן קידוד) רצה למיין את הבקשות שהם מקבלים ממשתמשים באמצעות AI. אז הם יצרו Github Action שמפעיל את קלוד כדי לשים כל פניה במקום המתאים. הפרומפט לקלוד הכיל את כותרת ה Issue שנפתח והסוכן הופעל עם הרשאה להרצת כלים:
לא לקח הרבה זמן עד שפורצים ראו את זה ויצרו Issue עם שם שגרם לסוכן להתקין חבילת npm זדונית שהם יצרו וכך השתלטו על מכונת המיון, וממנה על כל הפרויקט.
סיפור דומה קרה עם Coderabbit, סביבה ל Code Review ואפשר לקרוא עליו כאן:
https://kudelskisecurity.com/research/how-we-exploited-coderabbit-from-a-simple-pr-to-rce-and-write-access-on-1m-repositories
✏ קידוד מהיר מוביל ליותר באגים
נקודה אחרונה ברשימה היא תרבות העבודה של עידן ה AI - לכתוב המון קוד, לדחוף מהר לפרודקשן אחרי בדיקה קצרה, לסמוך על הסוכן שכותב את הקוד הנכון.
כנראה שמיזוג מהיר של פיצ'רים הוא אחד הגורמים לבאג הזה באופןקוד:
https://github.com/anomalyco/opencode/security/advisories/GHSA-vxw4-wv6m-9hhh
שם אופןקוד פתחו שרת HTTP שלא דורש הזדהות ומאפשר הרצת פקודות על המחשב של המפתח. התוצאה היא שאתרים זדוניים יכולים להריץ קוד וכך להשתיל רוגלות ווירוסים על מחשבים של מפתחים שמריצים אופןקוד וגולשים לאותם אתרים.
✏ סיכום
סוכנים חכמים ובפרט סוכני קידוד הם התוכנה הראשונה שמותקנת בקנה מידה גדול ושהתנהגותה אינה דטרמניסטית. אף אחד לא יכול לדעת מראש מה סוכן הקידוד יעשה בתגובה להודעה הבאה. מאפיין זה חושף אותנו לסכנות אבטחה משמעותיות בעבודה עם סוכני קידוד.
בואו נראה כמה דוגמאות להפתעות כאלה לקראת הוובינר השבוע שיעסוק באבטחת מידע בעידן הסוכנים החכמים.
✏ הרעלת מודלי שפה
מקור:
https://ron.stoner.com/how-i-won-a-championship-that-doesnt-exist/
בסוף ינואר 2025 רון סטונר העלה אתר עם תמונה של גביע בו כתוב שהוא זכה באליפות הנימיץ השנתית שהתקיימה במינכן. הוא גם עדכן את הדף של נימיץ בויקיפדיה עם קישור לדף הנצחון שלו. זה הספיק בשביל לגרום ל ChatGPT למצוא את הקישור ולספר שהוא היה הזוכה בתגובה לשאלה בצ'אט.
התרגיל של סטונר הוא שטחי. סטונר גרם למודל להיתקל בשם שלו במהלך חיפוש ברשת - אבל מבהיר לנו עד כמה קל לרמות סוכנים חכמים במיוחד כאלה שיוצאים לחפש ברשת. אותו מנגנון יכול להיות מנוצל לרעה על ידי גורמים זדוניים שיקימו אתרים שיפרסמו חבילות npm שהן בעצם רוגלות, אותן הסוכן יתקין בלי להבין שמדובר ברוגלה.
✏ באג בסוכן יוצר חיוב מוגזם
סוכני קידוד הם כלי פיתוח ייחודי בכך שהם מחוברים לכרטיס אשראי, כך שככל שהסוכן משתמש ביותר טוקנים אנחנו צריכים לשלם יותר. שני באגים מעניינים מבהירים לנו שהחיבור הזה אף פעם לא עובד חלק.
במקרה אחד אנטרופיק החליטו שהם לא רוצים לאפשר לעוזר אישי בשם Hermes להשתמש בתוכנית המנויים שלהם אז הם ניסו לנתב בקשות מ Hermes לחיוב גבוה יותר. התוצאה היתה שמספיק לכתוב את המילה HERMES.md בהודעת קומיט וקלוד קוד יחייב אותך בתשלום גבוה יותר על הפיתוח:
https://github.com/anthropics/claude-code/issues/53262
במקרה אחר אופןקוד (עוד סוכן קידוד) התחבר לתוכנית המנויים של גיטהאב קופיילוט, אבל בגלל באג במצבים מסוימים השתמש ביותר בקשות בתשלום וכך סיים למשתמשים את המנוי מוקדם:
https://github.com/anomalyco/opencode/issues/16937
✏ טעות של המודל מוחקת נתוני פרודקשן
מקור:
https://x.com/lifeof_jer/status/2048103471019434248?s=46
ג'ר קריין, המייסד של PocketOS חיבור את קלוד אופוס לסביבת הפיתוח שלו ב Cursor. הוא שכח שבאיזשהו קובץ טקסט בתיקיית הפרויקט היה כתוב טוקן הגישה לסביבת הפרודקשן - כדי להריץ תהליך תחזוקה שגרתי.
קלוד אופוס נתקל בבעיה, חשב שצריך ליצור מחדש את הסביבה, מצא את הטוקן של סביבת הפרודקשן והשתמש בו כדי ליצור מחדש את סביבת הפרודקשן - וכך מחק את כל נתוני המשתמשים.
בעבודה עם סוכני קידוד אנחנו נוטים לחשוב שיש לנו עוזר אישי מיומן על המחשב שתמיד יעשה מה שטוב לפרויקט. זה נכון ב 99% מהמקרים. לשאר ה-1% עלינו לוודא מנגנוני הגנה טובים בסביבה שימנעו מאנשים או סוכנים פזיזים לעשות נזקים.
✏ הזרקת פרומפט מובילה להשתלטות על מכונות
מקור:
https://neciudan.dev/cline-ci-got-compromised-here-is-how
הצוות של cline (עוד סוכן קידוד) רצה למיין את הבקשות שהם מקבלים ממשתמשים באמצעות AI. אז הם יצרו Github Action שמפעיל את קלוד כדי לשים כל פניה במקום המתאים. הפרומפט לקלוד הכיל את כותרת ה Issue שנפתח והסוכן הופעל עם הרשאה להרצת כלים:
allowed_non_write_users: "*"
claude_args: >-
--allowedTools "Bash,Read,Write,Edit,Glob,Grep,WebFetch,WebSearch"
prompt: |
**Issue:** #${{ github.event.issue.number }}
**Title:** ${{ github.event.issue.title }}
לא לקח הרבה זמן עד שפורצים ראו את זה ויצרו Issue עם שם שגרם לסוכן להתקין חבילת npm זדונית שהם יצרו וכך השתלטו על מכונת המיון, וממנה על כל הפרויקט.
סיפור דומה קרה עם Coderabbit, סביבה ל Code Review ואפשר לקרוא עליו כאן:
https://kudelskisecurity.com/research/how-we-exploited-coderabbit-from-a-simple-pr-to-rce-and-write-access-on-1m-repositories
✏ קידוד מהיר מוביל ליותר באגים
נקודה אחרונה ברשימה היא תרבות העבודה של עידן ה AI - לכתוב המון קוד, לדחוף מהר לפרודקשן אחרי בדיקה קצרה, לסמוך על הסוכן שכותב את הקוד הנכון.
כנראה שמיזוג מהיר של פיצ'רים הוא אחד הגורמים לבאג הזה באופןקוד:
https://github.com/anomalyco/opencode/security/advisories/GHSA-vxw4-wv6m-9hhh
שם אופןקוד פתחו שרת HTTP שלא דורש הזדהות ומאפשר הרצת פקודות על המחשב של המפתח. התוצאה היא שאתרים זדוניים יכולים להריץ קוד וכך להשתיל רוגלות ווירוסים על מחשבים של מפתחים שמריצים אופןקוד וגולשים לאותם אתרים.
✏ סיכום
Ron Stoner
How I Won a Championship That Doesn’t Exist
Poisoning the LLM knowledge supply chain with a fake Wikipedia edit and a single domain registration
כשאנחנו עובדים עם סוכן קידוד אנחנו מכניסים שותף לא צפוי למחשב. רוב הזמן שותף זה יעזור לנו לכתוב קוד מהר יותר וטוב יותר אבל השגחה ובידוד הם הכרחיים כדי שדברים לא יישברו.
הדברים המרכזיים שעלינו לשים לב אליהם בעבודה השוטפת:
1. קראתי ואני מבין כל שורה שהסוכן כתב, היא מתאימה לפרויקט שלי ולא יוצרת בעיות אבטחה חדשות.
2. הסוכן רץ בסביבה מבודדת - גם אם הוא יחליט לשבור דברים אין לו יכולת לעשות נזק אמיתי.
בוובינר ביום חמישי השבוע נדבר בהרחבה על כל המקרים מכאן ודוגמאות נוספות. מוזמנים להצטרף אלינו בקישור:
https://www.tocode.co.il/talking_ai
הדברים המרכזיים שעלינו לשים לב אליהם בעבודה השוטפת:
1. קראתי ואני מבין כל שורה שהסוכן כתב, היא מתאימה לפרויקט שלי ולא יוצרת בעיות אבטחה חדשות.
2. הסוכן רץ בסביבה מבודדת - גם אם הוא יחליט לשבור דברים אין לו יכולת לעשות נזק אמיתי.
בוובינר ביום חמישי השבוע נדבר בהרחבה על כל המקרים מכאן ודוגמאות נוספות. מוזמנים להצטרף אלינו בקישור:
https://www.tocode.co.il/talking_ai
👏1
📌 אז עדיין צריך הודעות קומיט?
ב 2026 סוכני קידוד יודעים לכתוב הודעות קומיט טובות יותר מאיתנו גם בדיעבד. ניסיתי את זה - הפרומפט:
עם הקומיט שעשיתי כאן:
https://github.com/ynonp/langlets-rails/commit/c07821619789ce2c814f9056088f0b083c7e92c7
נתן לי הסבר הרבה יותר טוב ומדויק מזה שאני כתבתי בהודעת הקומיט. הוא גם הזכיר לי שהקומיט הזה בכלל כלל 4 שינויים נפרדים, כשהודעת הקומיט מדברת על שינוי אחד. מי שיקרא את הקוד עם ההסבר של ה AI יקבל הסבר הרבה יותר טוב למה קרה שם.
ועכשיו השאלה בכותרת היא התלבטות אמיתית.
למה לא לתת ל AI לכתוב את הודעת הקומיט הזאת מראש ולרוץ יותר מהר? מה הטעם לכתוב הודעות קומיט לא מדויקות בעצמי? במקרה בדוגמה הודעת הקומיט שלי לא היתה מדויקת כי נתתי ל AI לכתוב כמה פיצ'רים במקביל ודחפתי הכל בלי לקרוא לעומק. אם זאת שיטת העבודה ברור שחבל על הזמן.
אבל למרות ש AI מתאר יופי מה קרה בקומיט, הוא לא יודע את הקונטקסט האמיתי, את הסיבה האמיתית בגללה דחפתי דווקא את הקוד הזה. הוא לא יודע איזה אופציות אחרות בדקתי, מה חשבתי שעלול להשתבש, מה השתבש או לא השתבש בסוף, בקיצור את כל המסביב של הפיצ'ר.
ב 2026 הודעת קומיט לא צריכה לספר מה קרה. חבל על הביטים. אבל היא כן צריכה לספר את סיפור הרקע. הודעת קומיט טובה היא כמו מכונת זמן שלוקחת אותנו ישר לאותו רגע בזמן בו החלטנו לדחוף דווקא את הקוד הזה. היא Context Dump של מי שישב ליד ההגה והחליט שזה מוכן.
הרבה פעמים כדאי לשלב כוחות. סוכן הקידוד יכתוב הודעות קומיט אוטומטיות בענף משלו. ברגע שזה מוכן אני עובר עם ריבייס, בוחר איזה קומיטים היו בעלי משמעות בתהליך הפיתוח, כותב להם הודעות קומיט משמעותיות וזורק את כל היתר. לא "למה תיקנתי את זה" או "מה היה שבור", אלא "למה דווקא את זה", "מה היו האפשרויות האחרות" ואפילו מה בדיוק הלקוח ראה ואמר כשהוא דיווח על הבאג.
ב 2026 סוכני קידוד יודעים לכתוב הודעות קומיט טובות יותר מאיתנו גם בדיעבד. ניסיתי את זה - הפרומפט:
explain the commit
1. what changed?
2. why?
3. what's still left to do for this issue?
עם הקומיט שעשיתי כאן:
https://github.com/ynonp/langlets-rails/commit/c07821619789ce2c814f9056088f0b083c7e92c7
נתן לי הסבר הרבה יותר טוב ומדויק מזה שאני כתבתי בהודעת הקומיט. הוא גם הזכיר לי שהקומיט הזה בכלל כלל 4 שינויים נפרדים, כשהודעת הקומיט מדברת על שינוי אחד. מי שיקרא את הקוד עם ההסבר של ה AI יקבל הסבר הרבה יותר טוב למה קרה שם.
ועכשיו השאלה בכותרת היא התלבטות אמיתית.
למה לא לתת ל AI לכתוב את הודעת הקומיט הזאת מראש ולרוץ יותר מהר? מה הטעם לכתוב הודעות קומיט לא מדויקות בעצמי? במקרה בדוגמה הודעת הקומיט שלי לא היתה מדויקת כי נתתי ל AI לכתוב כמה פיצ'רים במקביל ודחפתי הכל בלי לקרוא לעומק. אם זאת שיטת העבודה ברור שחבל על הזמן.
אבל למרות ש AI מתאר יופי מה קרה בקומיט, הוא לא יודע את הקונטקסט האמיתי, את הסיבה האמיתית בגללה דחפתי דווקא את הקוד הזה. הוא לא יודע איזה אופציות אחרות בדקתי, מה חשבתי שעלול להשתבש, מה השתבש או לא השתבש בסוף, בקיצור את כל המסביב של הפיצ'ר.
ב 2026 הודעת קומיט לא צריכה לספר מה קרה. חבל על הביטים. אבל היא כן צריכה לספר את סיפור הרקע. הודעת קומיט טובה היא כמו מכונת זמן שלוקחת אותנו ישר לאותו רגע בזמן בו החלטנו לדחוף דווקא את הקוד הזה. היא Context Dump של מי שישב ליד ההגה והחליט שזה מוכן.
הרבה פעמים כדאי לשלב כוחות. סוכן הקידוד יכתוב הודעות קומיט אוטומטיות בענף משלו. ברגע שזה מוכן אני עובר עם ריבייס, בוחר איזה קומיטים היו בעלי משמעות בתהליך הפיתוח, כותב להם הודעות קומיט משמעותיות וזורק את כל היתר. לא "למה תיקנתי את זה" או "מה היה שבור", אלא "למה דווקא את זה", "מה היו האפשרויות האחרות" ואפילו מה בדיוק הלקוח ראה ואמר כשהוא דיווח על הבאג.
GitHub
add sync timestamp route · ynonp/langlets-rails@c078216
Contribute to ynonp/langlets-rails development by creating an account on GitHub.
📌 היום למדתי: "חוץ מ" בגיט
אם יש לי ערימה של קבצים שהשתנו בפרויקט גיט ואני רוצה להוסיף את כולם מלבד אחד (כי הוא מסיפור אחר) תמיד הייתי מפעיל:
כי git add מוסיף קבצים ל staging ו git reset מוציא משם, אז מוסיפים את הכל ומורידים את מה שלא רוצים. היום גיליתי שהשטות הזאת נפתרה לפני יותר מעשר שנים, והיום בכל מקום שמציינים קבצים בגיט אפשר להשתמש בנקודותיים סימן קריאה כדי להגיד "חוץ מ", כלומר:
הגרשיים שם כי zsh (וגם bash ובעצם כמעט כולם) חושב שנקודותיים סימן קריאה זה השלמת היסטוריה. בלי גרשיים zsh ינסה להחליף את api.js בפקודה קודמת מההיסטוריה וגיט אף פעם לא יראה את הסימנים המיוחדים.
וכן זה עובד בכל הפקודות ב git שצריכות קבצים כמו add, rm, restore, log ועוד.
אם יש לי ערימה של קבצים שהשתנו בפרויקט גיט ואני רוצה להוסיף את כולם מלבד אחד (כי הוא מסיפור אחר) תמיד הייתי מפעיל:
$ git add .
$ git reset api.js
כי git add מוסיף קבצים ל staging ו git reset מוציא משם, אז מוסיפים את הכל ומורידים את מה שלא רוצים. היום גיליתי שהשטות הזאת נפתרה לפני יותר מעשר שנים, והיום בכל מקום שמציינים קבצים בגיט אפשר להשתמש בנקודותיים סימן קריאה כדי להגיד "חוץ מ", כלומר:
$ git add . ':!api.js'
הגרשיים שם כי zsh (וגם bash ובעצם כמעט כולם) חושב שנקודותיים סימן קריאה זה השלמת היסטוריה. בלי גרשיים zsh ינסה להחליף את api.js בפקודה קודמת מההיסטוריה וגיט אף פעם לא יראה את הסימנים המיוחדים.
וכן זה עובד בכל הפקודות ב git שצריכות קבצים כמו add, rm, restore, log ועוד.
📌 האם שפת התכנות עדיין חשובה?
בתקופה בה הסוכן כותב 100% מהקוד וארכיטקטורה ואינטגרציות הן האתגר החדש, עד כמה חשובה בחירת שפת התכנות או הפריימוורק? כמה הרהורים:
1. שפת תכנות = אקוסיסטם. בגלל זה כולם כותבים GUI בשפות מבוססות ווב וכלי למידת מכונה בפייתון. אבל מה קורה כשאין אקוסיסטם? למה לנגגרף כתובה בפייתון ולא ב rust? למה אנחנו לא מתחילים לכתוב שרתים באליקסיר?
2. גם אם אני לא מתכנן לקרוא כל שורה בקוד עדיין אני שמח שאני יכול להכנס ולהבין בלוקים של קוד. כשאני בוחר שפה שאני מכיר אני יכול לתקשר עם הסוכן בשפה שלי ומרגיש בנוח בתוך השיחה. מצד שני כלי שורת פקודה ב Rust יכול להיות משמעותית יותר מהיר מאותו כלי ב JavaScript, ואולי זה שווה את המאמץ להבין שפה שאני פחות מכיר.
3. מהירות פיתוח עדיין חשובה גם בעידן ה AI. סוכן AI עובד באיטרציות וניסויים לכן שלב קומפילציה ארוך עובד לרעתי.
4. כלים אוטומטיים חשובים. כלי אוטומטי שבודק טעויות נפוצות בקוד, בעיות סגנון, קוד כפול או קוד שלא נמצא בשימוש שווה זהב כשסוכני קידוד כותבים את הקוד.
אישית אני לא מרגיש נוח לכתוב פרויקט גדול בשפה שאני לא מכיר, אבל את הפרויקט הקטן הבא שלי יש סיכוי טוב שאכתוב בשפה חדשה בזכות ה AI. אני גם תוהה אם כלי הפיתוח Cross Platform למובייל עדיין שווים את המאמץ או שסוכני קידוד יהפכו את התחזוקה של פרויקטי מובייל בשתי השפות (סוויפט וקוטלין) לכל כך קלה שכבר לא יהיה בזה טעם.
מה דעתכם?
בתקופה בה הסוכן כותב 100% מהקוד וארכיטקטורה ואינטגרציות הן האתגר החדש, עד כמה חשובה בחירת שפת התכנות או הפריימוורק? כמה הרהורים:
1. שפת תכנות = אקוסיסטם. בגלל זה כולם כותבים GUI בשפות מבוססות ווב וכלי למידת מכונה בפייתון. אבל מה קורה כשאין אקוסיסטם? למה לנגגרף כתובה בפייתון ולא ב rust? למה אנחנו לא מתחילים לכתוב שרתים באליקסיר?
2. גם אם אני לא מתכנן לקרוא כל שורה בקוד עדיין אני שמח שאני יכול להכנס ולהבין בלוקים של קוד. כשאני בוחר שפה שאני מכיר אני יכול לתקשר עם הסוכן בשפה שלי ומרגיש בנוח בתוך השיחה. מצד שני כלי שורת פקודה ב Rust יכול להיות משמעותית יותר מהיר מאותו כלי ב JavaScript, ואולי זה שווה את המאמץ להבין שפה שאני פחות מכיר.
3. מהירות פיתוח עדיין חשובה גם בעידן ה AI. סוכן AI עובד באיטרציות וניסויים לכן שלב קומפילציה ארוך עובד לרעתי.
4. כלים אוטומטיים חשובים. כלי אוטומטי שבודק טעויות נפוצות בקוד, בעיות סגנון, קוד כפול או קוד שלא נמצא בשימוש שווה זהב כשסוכני קידוד כותבים את הקוד.
אישית אני לא מרגיש נוח לכתוב פרויקט גדול בשפה שאני לא מכיר, אבל את הפרויקט הקטן הבא שלי יש סיכוי טוב שאכתוב בשפה חדשה בזכות ה AI. אני גם תוהה אם כלי הפיתוח Cross Platform למובייל עדיין שווים את המאמץ או שסוכני קידוד יהפכו את התחזוקה של פרויקטי מובייל בשתי השפות (סוויפט וקוטלין) לכל כך קלה שכבר לא יהיה בזה טעם.
מה דעתכם?
❤1👍1
📌 מבחן ה Actually
אחד הרעיונות הגרועים של קלוד קוד וקופיילוט היה לסנן את כל הפלט של המודל. הכוונה שלהם היתה טובה, לחסוך לנו לקרוא המון טקסט לא מעניין, אבל התוצאה חסמה את הגישה למשאב מאוד חשוב באופטימיזציה של ייצור קוד עם סוכן - מבחן התאמת הסוכן לקוד, או מבחן ה Actually.
שימו לב למשפטים נבחרים מתגובה של מודל שפה גדול בסוכן הקידוד פאי (הכל מאותה תשובה אינסופית):
אפילו אם בסוף הוא יכתוב קוד עובד, ברור שאין סינכרון בין מה שאני ביקשתי להשלמה של הסוכן. כמו בני אדם גם סוכני קידוד לא אמורים "להבין פתאום" באמצע המימוש שהם פספסו משהו גדול ולחשוב על כל העסק מחדש. אנחנו רוצים לשלוח את הסוכנים שלנו למשימות בהן ברור מה צריך לכתוב. סוכן שהולך במעגלים מבזבז לנו זמן וטוקנים ובסוף יפספס מקרי קצה ויכתוב מימוש לא אידאלי.
אולי במקום להסתיר את כל הטקסט קופיילוט וקלוד קוד יכולים לשים לנו מד שיראה כמה פעמים המודל כותב את המילה Actually. מעל 20 פעמים בתשובה אחת זה סימן שכדאי לשפר את הפרומפט.
אחד הרעיונות הגרועים של קלוד קוד וקופיילוט היה לסנן את כל הפלט של המודל. הכוונה שלהם היתה טובה, לחסוך לנו לקרוא המון טקסט לא מעניין, אבל התוצאה חסמה את הגישה למשאב מאוד חשוב באופטימיזציה של ייצור קוד עם סוכן - מבחן התאמת הסוכן לקוד, או מבחן ה Actually.
שימו לב למשפטים נבחרים מתגובה של מודל שפה גדול בסוכן הקידוד פאי (הכל מאותה תשובה אינסופית):
Wait, looking at the flow more carefully:
Looking at checking.py more carefully:
But wait - looking at the caller maigret() function
Actually, let me re-read the code more carefully
Actually, let me think about this differently
Wait, but ...
But wait, I should also add the check in
Actually, looking at the code more carefully
Actually the current code already handles this! Look at
Let me think about this differently.
Actually, the simplest and most maintainable approach
Wait, but the user says
Actually wait, let me re-read the user's request
Actually, I think the most correct regex would be
Actually, I need to be more careful
Actually, let me think about this more practically
אפילו אם בסוף הוא יכתוב קוד עובד, ברור שאין סינכרון בין מה שאני ביקשתי להשלמה של הסוכן. כמו בני אדם גם סוכני קידוד לא אמורים "להבין פתאום" באמצע המימוש שהם פספסו משהו גדול ולחשוב על כל העסק מחדש. אנחנו רוצים לשלוח את הסוכנים שלנו למשימות בהן ברור מה צריך לכתוב. סוכן שהולך במעגלים מבזבז לנו זמן וטוקנים ובסוף יפספס מקרי קצה ויכתוב מימוש לא אידאלי.
אולי במקום להסתיר את כל הטקסט קופיילוט וקלוד קוד יכולים לשים לנו מד שיראה כמה פעמים המודל כותב את המילה Actually. מעל 20 פעמים בתשובה אחת זה סימן שכדאי לשפר את הפרומפט.
📌 שלושה מקומות נכונים לשמור זכרון ל AI (לאנשים שמגוונים בסוכני הקידוד)
סוכני קידוד לא זוכרים כלום והמון אנשים מתלוננים על זה. אתה מסביר לסוכן את הארכיטקטורה פעם אחת, פעם שניה, פעם שלישית, פעם 50, ולא משנה כמה פעמים תדבר איתו הוא יהיה בטוח שאתה מעלה לפרודקשן בקוברנטס למרות שאצלך יש שרת פרטי.
יצרניות הסוכנים מנסות לפתור את זה ולהתיחס לבעיית הזכרון בתור ייתרון תחרותי:
1. קלוד קוד שומר זכרונות באופן אוטומטי לקבצים בתיקיית הבית.
2. קופיילוט שומר זכרונות באופן אוטומטי שוב לקבצים בתיקיית הבית.
3. קודקס שומר זכרונות בואפן אוטומטי לקבצים בתיקיית הבית.
בנוסף יש אינסוף פלאגינים שישמחו לשמור זכרונות בצורה אוטומטית בבסיסי נתונים שלהם, שוב בלי דרך קלה לנהל או לשתף את הידע.
עוברים בין סוכנים או מחשבים? שיהיה בהצלחה לזכור מי זוכר מה על הפרויקט שלכם.
במקום להסביר לסוכן דברים שוב ושוב או להתרגז שהוא זוכר דברים לא רלוונטיים אני ממליץ על שיטת העבודה הבאה. דבר ראשון מכבים את הזכרונות האוטומטיים כדי לא לבלבל. דבר שני נשים לב שיש שלוש דרכים טובות לשמור זכרונות בצורה מנוהלת.
✏ שמירת זכרונות ב AGENTS.md
קובץ AGENTS.md הוא קובץ ההוראות המרכזי של הפרויקט. אם אתם עובדים בקלוד קוד תצטרכו ליצור קובץ CLAUDE.md ולקשר ממנו ל agents כי אנטרופיק נודניקים, ואז יהיה לכם מקום אחד מרכזי שכל סוכני הקידוד יודעים לקרוא. הטריק מוסבר כאן:
https://github.com/anthropics/claude-code/issues/6235
מוצאים את עצמכם מזכירים שוב ושוב שבעצם הפרויקט רץ על שרת פרטי? כתבו את זה שם.
מזכירים עוד פעם שאתם מעדיפים להשתמש במשתנים ב CSS? כתבו את זה שם.
גודל מומלץ של קובץ AGENTS.md הוא 150-300 שורות וזה אומר שתהיה נקודה שתצטרכו להיות מדויקים במה אתם כותבים שם. זה מצוין ומכריח אותנו להתמקד.
✏ שמירת זכרונות ב Skill
מנגנון שני שעובד טוב הוא Skills. מודלים היום אוהבים לטעון סקילים ומחפשים אותם. יש בעיה שאנטרופיק קוראים סקילים מתיקיית .claude וקודקס מתיקיית .agents ורק קופיילוט מוכן לקרוא משתי התיקיות אבל אפשר לפתור את זה עם symbolic links.
מה שחשוב הוא שאני יכול ליצור סקילים לפרויקט עבור משימות מסוימות למשל סקיל של פיתוח Front End עם כל הטכניקות איך לכתוב קוד פרונטאנד אצלי בפרויקט. סקיל של deployment שמסביר על מבנה השרתים וסקיל של אבטחה שמסביר על מה להסתכל כשעושים Security Review.
✏ שמירת זכרונות בפרויקט עצמו
יש לי פרויקט ריילס שמכיל את שני הקבצים:
קובץ app.json הוא קובץ הוראות להעלאה ל heroku וקובץ config/deploy.yml הוא קובץ הוראות להעלאה לשרת פרטי עם kamal. ברור שבמצב כזה הסוכן יתבלבל ולא ידע מה סביבת הפרודקשן שלי.
אני יכול לכתוב בקובץ AGENTS.md שסביבת הפרודקשן היא heroku.
אני יכול ליצור סקיל של deployment שמסביר איך להעלות גרסה להרוקו ושיש להתעלם מהקונפיגורציה של kamal.
או שאני יכול פשוט למחוק את config/deploy.yml.
או דוגמה נוספת - נניח שיש לכם קומפוננטת ריאקט שמציגה עמוד עם שלוש תיבות בחירה, אבל תיבת הבחירה לא בנויה בתור קומפוננטה נפרדת. כשתבקשו תיבת בחירה חדשה הסוכן ישכפל את הקוד הקיים וימשיך לא ליצור קומפוננטה. לעומת זאת אם באותו עמוד היתה לכם קומפוננטה של תיבת בחירה שהופיעה 3 פעמים ואתם מבקשים את הרביעית אז הסוכן שוב משכפל את הקוד אבל הפעם הוא משכפל את השימוש באותה קונפוננטה גנרית.
וכן קוד המערכת הוא המקום שהכי קשה לשמור בו זכרונות אבל כשמצליחים האפקט נשמר בצורה הטובה ביותר ולאורך זמן.
כל שלושת המנגנונים טובים יותר מהזכרונות האוטומטיים של סוכני הקידוד: בכולם אפשר לשתף את הזכרונות ולעבור בין סוכני קידוד ובין מכונות ועדיין הזכרונות שלנו יהיו שם. הזכרונות בעבודה על פרויקט חשובים מכדי להשאיר אותם בתור קלף בתחרות בין יצרניות הסוכנים.
סוכני קידוד לא זוכרים כלום והמון אנשים מתלוננים על זה. אתה מסביר לסוכן את הארכיטקטורה פעם אחת, פעם שניה, פעם שלישית, פעם 50, ולא משנה כמה פעמים תדבר איתו הוא יהיה בטוח שאתה מעלה לפרודקשן בקוברנטס למרות שאצלך יש שרת פרטי.
יצרניות הסוכנים מנסות לפתור את זה ולהתיחס לבעיית הזכרון בתור ייתרון תחרותי:
1. קלוד קוד שומר זכרונות באופן אוטומטי לקבצים בתיקיית הבית.
2. קופיילוט שומר זכרונות באופן אוטומטי שוב לקבצים בתיקיית הבית.
3. קודקס שומר זכרונות בואפן אוטומטי לקבצים בתיקיית הבית.
בנוסף יש אינסוף פלאגינים שישמחו לשמור זכרונות בצורה אוטומטית בבסיסי נתונים שלהם, שוב בלי דרך קלה לנהל או לשתף את הידע.
עוברים בין סוכנים או מחשבים? שיהיה בהצלחה לזכור מי זוכר מה על הפרויקט שלכם.
במקום להסביר לסוכן דברים שוב ושוב או להתרגז שהוא זוכר דברים לא רלוונטיים אני ממליץ על שיטת העבודה הבאה. דבר ראשון מכבים את הזכרונות האוטומטיים כדי לא לבלבל. דבר שני נשים לב שיש שלוש דרכים טובות לשמור זכרונות בצורה מנוהלת.
✏ שמירת זכרונות ב AGENTS.md
קובץ AGENTS.md הוא קובץ ההוראות המרכזי של הפרויקט. אם אתם עובדים בקלוד קוד תצטרכו ליצור קובץ CLAUDE.md ולקשר ממנו ל agents כי אנטרופיק נודניקים, ואז יהיה לכם מקום אחד מרכזי שכל סוכני הקידוד יודעים לקרוא. הטריק מוסבר כאן:
https://github.com/anthropics/claude-code/issues/6235
מוצאים את עצמכם מזכירים שוב ושוב שבעצם הפרויקט רץ על שרת פרטי? כתבו את זה שם.
מזכירים עוד פעם שאתם מעדיפים להשתמש במשתנים ב CSS? כתבו את זה שם.
גודל מומלץ של קובץ AGENTS.md הוא 150-300 שורות וזה אומר שתהיה נקודה שתצטרכו להיות מדויקים במה אתם כותבים שם. זה מצוין ומכריח אותנו להתמקד.
✏ שמירת זכרונות ב Skill
מנגנון שני שעובד טוב הוא Skills. מודלים היום אוהבים לטעון סקילים ומחפשים אותם. יש בעיה שאנטרופיק קוראים סקילים מתיקיית .claude וקודקס מתיקיית .agents ורק קופיילוט מוכן לקרוא משתי התיקיות אבל אפשר לפתור את זה עם symbolic links.
מה שחשוב הוא שאני יכול ליצור סקילים לפרויקט עבור משימות מסוימות למשל סקיל של פיתוח Front End עם כל הטכניקות איך לכתוב קוד פרונטאנד אצלי בפרויקט. סקיל של deployment שמסביר על מבנה השרתים וסקיל של אבטחה שמסביר על מה להסתכל כשעושים Security Review.
✏ שמירת זכרונות בפרויקט עצמו
יש לי פרויקט ריילס שמכיל את שני הקבצים:
app.json
config/deploy.yml
קובץ app.json הוא קובץ הוראות להעלאה ל heroku וקובץ config/deploy.yml הוא קובץ הוראות להעלאה לשרת פרטי עם kamal. ברור שבמצב כזה הסוכן יתבלבל ולא ידע מה סביבת הפרודקשן שלי.
אני יכול לכתוב בקובץ AGENTS.md שסביבת הפרודקשן היא heroku.
אני יכול ליצור סקיל של deployment שמסביר איך להעלות גרסה להרוקו ושיש להתעלם מהקונפיגורציה של kamal.
או שאני יכול פשוט למחוק את config/deploy.yml.
או דוגמה נוספת - נניח שיש לכם קומפוננטת ריאקט שמציגה עמוד עם שלוש תיבות בחירה, אבל תיבת הבחירה לא בנויה בתור קומפוננטה נפרדת. כשתבקשו תיבת בחירה חדשה הסוכן ישכפל את הקוד הקיים וימשיך לא ליצור קומפוננטה. לעומת זאת אם באותו עמוד היתה לכם קומפוננטה של תיבת בחירה שהופיעה 3 פעמים ואתם מבקשים את הרביעית אז הסוכן שוב משכפל את הקוד אבל הפעם הוא משכפל את השימוש באותה קונפוננטה גנרית.
וכן קוד המערכת הוא המקום שהכי קשה לשמור בו זכרונות אבל כשמצליחים האפקט נשמר בצורה הטובה ביותר ולאורך זמן.
כל שלושת המנגנונים טובים יותר מהזכרונות האוטומטיים של סוכני הקידוד: בכולם אפשר לשתף את הזכרונות ולעבור בין סוכני קידוד ובין מכונות ועדיין הזכרונות שלנו יהיו שם. הזכרונות בעבודה על פרויקט חשובים מכדי להשאיר אותם בתור קלף בתחרות בין יצרניות הסוכנים.
GitHub
Feature Request: Support AGENTS.md. · Issue #6235 · anthropics/claude-code
Codex, Amp, Cursor, and others are starting to standardize around AGENTS.md (https://agents.md/) — a unified Markdown file that coding agents can use to understand a codebase. By contrast, CLAUDE.m...
📌 מ-מבין ל-בוחר
אני מאוד אוהב את החידות של אריק ווסטל ב Advent Of Code ואת רובן פתרתי לפני שהיה AI והן עזרו לי ללמוד שפות תכנות חדשות. ואז המודלים נהיו מספיק טובים ואיבדתי מוטיבציה. אני רוצה לעצור ולשים לב מה בעצם קרה שם, איזה חלק מהחידות הפסיק לעניין, איזה חלק עדיין מעניין ומה זה אומר על לימודי תכנות בראייה קדימה.
נתחיל ברעיון הפשוט - הפרומפט הבא פתר לי את יום 10 של Advent Of Code בלי שכתבתי שורת קוד אחת. כאן יש את תיאור החידה:
https://adventofcode.com/2025/day/10
זה היה הפרומפט:
זה היה קימי בתוך קלוד קוד. הוא הגיע לתשובה הנכונה גם בקלט הבדיקה וגם על הקלט האמיתי. זה לבד מספיק בשביל להפוך את החידה ללא מאוד מעניינת. זה אגב הפתרון שהוא כתב:
עכשיו מצד אחד אני רוצה להגיד לעצמי שלכתוב כזה פרומפט זה כמו להעתיק מהפתרון ועדיף לפתור לבד, אבל מצד שני אני יודע שזה לא מדויק. להעתיק מהפתרון זה בזבוז זמן כי שינוי הכי קטן בשאלה ואתה כבר לא יודע להתמודד איתה. לכתוב פרומפט זה ידע שממשיך אתך הלאה. לא משנה איזה שינוי יהיה בשאלה, הפרומפט יוכל לפתור אותה.
אבל זה לא כל הסיפור. כשאני פותח את קוד הפייתון שהמודל כתב אני רואה דרך פתרון אחת - פתרון Brute Force שרץ 2 בחזקת n פעמים. פה זה התחיל לעניין. האם אפשר לפתור את זה בפחות עבודה? מה המנגנון? איך כדאי לשמור את המידע?
בנוסף אחרי הפתרון מגיע החלק השני של השאלה ועכשיו יש עוד שאלות מעניינות - האם הפתרון של קלוד יכול להתמודד בשינויים לא גדולים עם החלק השני? האם היה אפשר לדמיין כיוון אחר שכן יצליח להתמודד עם החלק השני?
אז נכנסתי לעובי הקורה וראיתי איך הכפתורים והאורות בחידה ממופים למעשה למערכת משוואות. בעזרת קלוד למדתי שיש כלי בשם z3 שיודע לפתור אוטומטית מערכות משוואות או למצוא אופטימיזציות לפתרונות. התחלתי עם פתרון מונחה עצמים אבל מהר מאוד ראיתי ששום דבר לא משתנה ובסך הכל יש לנו אוביקטי מידע ופונקציות. בסוף הגעתי לקוד הזה ברובי:
אני מאוד אוהב את החידות של אריק ווסטל ב Advent Of Code ואת רובן פתרתי לפני שהיה AI והן עזרו לי ללמוד שפות תכנות חדשות. ואז המודלים נהיו מספיק טובים ואיבדתי מוטיבציה. אני רוצה לעצור ולשים לב מה בעצם קרה שם, איזה חלק מהחידות הפסיק לעניין, איזה חלק עדיין מעניין ומה זה אומר על לימודי תכנות בראייה קדימה.
נתחיל ברעיון הפשוט - הפרומפט הבא פתר לי את יום 10 של Advent Of Code בלי שכתבתי שורת קוד אחת. כאן יש את תיאור החידה:
https://adventofcode.com/2025/day/10
זה היה הפרומפט:
Solve
https://adventofcode.com/2025/day/10
for the demo input
[.##.] (3) (1,3) (2) (2,3) (0,2) (0,1) {3,5,4,7}
[...#.] (0,2,3,4) (2,3) (0,4) (0,1,2) (1,2,3,4) {7,5,12,7,2}
[.###.#] (0,1,2,3,4) (0,3,4) (0,1,2,4,5) (1,2) {10,11,11,5,10,5}
should yield 7
זה היה קימי בתוך קלוד קוד. הוא הגיע לתשובה הנכונה גם בקלט הבדיקה וגם על הקלט האמיתי. זה לבד מספיק בשביל להפוך את החידה ללא מאוד מעניינת. זה אגב הפתרון שהוא כתב:
import itertools
import re
def parse_machine(line):
"""Parse a line into (target_pattern, list_of_button_sets)"""
# Extract bracketed target pattern
target_match = re.search(r'\[([^\]]+)\]', line)
target = target_match.group(1)
# Extract parenthesized button schematics
buttons = []
for m in re.finditer(r'\(([^)]+)\)', line):
btn = tuple(int(x.strip()) for x in m.group(1).split(','))
buttons.append(btn)
return target, buttons
def solve_machine(target, buttons):
n = len(target)
goal = [1 if c == '#' else 0 for c in target]
best = float('inf')
# Try all subsets of buttons
for r in range(len(buttons) + 1):
for combo in itertools.combinations(range(len(buttons)), r):
state = [0] * n
for idx in combo:
for pos in buttons[idx]:
if 0 <= pos < n:
state[pos] ^= 1
if state == goal:
best = min(best, r)
break # for this r, all combos have same size r, so first match is optimal
if best != float('inf'):
break
return best if best != float('inf') else None
def main():
total = 0
unsolved = 0
with open('input.txt') as f:
for line_num, line in enumerate(f, 1):
line = line.strip()
if not line:
continue
target, buttons = parse_machine(line)
best = solve_machine(target, buttons)
if best is None:
print(f"Line {line_num}: NO SOLUTION")
unsolved += 1
else:
total += best
print(f"\nTotal minimum presses: {total}")
if unsolved:
print(f"Unsolved machines: {unsolved}")
if __name__ == '__main__':
main()
עכשיו מצד אחד אני רוצה להגיד לעצמי שלכתוב כזה פרומפט זה כמו להעתיק מהפתרון ועדיף לפתור לבד, אבל מצד שני אני יודע שזה לא מדויק. להעתיק מהפתרון זה בזבוז זמן כי שינוי הכי קטן בשאלה ואתה כבר לא יודע להתמודד איתה. לכתוב פרומפט זה ידע שממשיך אתך הלאה. לא משנה איזה שינוי יהיה בשאלה, הפרומפט יוכל לפתור אותה.
אבל זה לא כל הסיפור. כשאני פותח את קוד הפייתון שהמודל כתב אני רואה דרך פתרון אחת - פתרון Brute Force שרץ 2 בחזקת n פעמים. פה זה התחיל לעניין. האם אפשר לפתור את זה בפחות עבודה? מה המנגנון? איך כדאי לשמור את המידע?
בנוסף אחרי הפתרון מגיע החלק השני של השאלה ועכשיו יש עוד שאלות מעניינות - האם הפתרון של קלוד יכול להתמודד בשינויים לא גדולים עם החלק השני? האם היה אפשר לדמיין כיוון אחר שכן יצליח להתמודד עם החלק השני?
אז נכנסתי לעובי הקורה וראיתי איך הכפתורים והאורות בחידה ממופים למעשה למערכת משוואות. בעזרת קלוד למדתי שיש כלי בשם z3 שיודע לפתור אוטומטית מערכות משוואות או למצוא אופטימיזציות לפתרונות. התחלתי עם פתרון מונחה עצמים אבל מהר מאוד ראיתי ששום דבר לא משתנה ובסך הכל יש לנו אוביקטי מידע ופונקציות. בסוף הגעתי לקוד הזה ברובי:
LightDiagram = Data.define(:state, :buttons) do
# Convert diagram to a system of equations over GF(2) in z3 script syntax.
# Each bit position becomes an equation: XOR of buttons affecting that bit = target state.
# x0..xn are boolean variables (one per button), addition is XOR.
def to_z3
lines = []
buttons.each_with_index do |_, i|
lines << "(declare-const x#{i} Bool)"
end
state.each_with_index do |target, bit|
relevant = buttons.each_with_index.select { |btn, _| btn.bits.include?(bit) }
if relevant.empty?
# No button affects this bit — impossible if target is true
lines << "(assert false)" if target
else
terms = relevant.map { |_, i| "x#{i}" }.join(" ")
lines << "(assert (= (xor #{terms}) #{target}))"
end
end
lines.join("\n")
end
end
Button = Data.define(:bits)
def parse(filename)
diagrams = []
File.readlines(filename).each do |line|
line = line.strip
next if line.empty?
pattern = line[/\[(.*?)\]/, 1]
state = pattern.chars.map { |c| c == '#' }
buttons = []
line.scan(/\((.*?)\)/) do |match|
bits = match[0].split(",").map(&:to_i)
buttons << Button.new(bits:)
end
diagrams << LightDiagram.new(state:, buttons:)
end
diagrams
end
class Z3
def initialize(script)
@script = script
end
# Run z3 and return the raw model output (or nil if unsatisfiable)
def call
full_script = "(set-option :produce-models true)\n#{@script}\n(check-sat)\n(get-model)"
result = `echo '#{full_script}' | z3 -in`
return nil unless result.include?("sat")
result
end
# Return the minimum number of buttons that need to be pressed to satisfy all equations.
# Uses z3's optimization to minimize the count of true variables.
def size
n = @script.scan(/x(\d+)/).map(&:first).map(&:to_i).max
return 0 if n.nil?
n += 1 # number of variables is max index + 1
opt_script = "(set-option :produce-models true)\n#{@script}\n"
# Create integer cost variables: 1 if button pressed, 0 otherwise
n.times do |i|
opt_script += "(declare-const c#{i} Int)\n"
opt_script += "(assert (= c#{i} (ite x#{i} 1 0)))\n"
end
cost_vars = (0...n).map { |i| "c#{i}" }.join(" ")
opt_script += "(minimize (+ #{cost_vars}))\n"
opt_script += "(check-sat)\n(get-model)"
result = `echo '#{opt_script}' | z3 -in`
return nil unless result.include?("sat")
# Count how many x variables are true in the optimal model
count = 0
result.scan(/$define-fun (x+̣) \($ Bool\s+(true|false)\)/) do |_, val|
count += 1 if val == "true"
end
count
end
end
diagrams = parse('input.txt')
pp diagrams.sum { |diagram| Z3.new(diagram.to_z3).size }
הוא יותר ארוך כי הוא מייצר סקריפט ל z3 שיפתור את המשוואה אבל עבורי הוא גם יותר מסודר ובטח יותר מוכן לפתרון של החלק השני.
גם אם אני מבין את שני הפתרונות, רק אחד מהם אני בחרתי.
ב 2026 המציאות השתנתה. מה שמעניין הוא כבר לא "איך" כותבים את הקוד אלא "איזה" קוד כותבים. עוד נצטרך לגלות איך זה ישפיע על לימודי התכנות בעתיד.
❤1
📌 אתה כנראה אוהב לחשוב יותר מאשר לכתוב
מארק אריקסון, המפתח שאחראי על Redux היום, שיתף בפוסט חשש שמשותף להרבה מפתחים שמתחילים להשתמש במצב הסוכן של AI בצורה רצינית כדי לכתוב ערימות של קוד:
"אבל אני אוהב לכתוב קוד", או במילים שלו:
קשה שלא להזדהות, אבל זה פחד שלא עומד במבחן המציאות.
סוכני קידוד צריכים נהג - בן אדם עם אוריינטציה טכנית שיודע לכוון אותם לבנות את הקוד הנכון לבעיה. נכון המילים השתנו אבל הרעיונות לא:
1. כבר לא צריך לזכור איך לכתוב לולאת for; כן צריך לזכור מה זה איטרציה טורית, מקבילית ואסינכרונית ואיזה סוג סריקה מתאים לבעיה שלנו.
2. כבר לא צריך לזכור איך להגדיר מחלקה; כן צריך להבין איזה מחלקות לבחור כדי שיתאימו לפיצ'רים שנצטרך בעוד חודשיים.
3. כבר לא צריך לזכור איך לטפל בשגיאות; כן צריך לבחור באיזה שגיאות לטפל, מתי לבנות מנגנון fallback ומתי לתת לזה להתרסק.
4. כבר לא צריך לזכור איך לבדוק אם מחרוזת מתאימה לתנאי מסוים. כן צריך להבין מה המגבלות של ביטויים רגולאריים, מתי נעדיף להשתמש בהם על פני כתיבת קוד חיפוש ספציפי ומתי בכלל עדיף למצוא ספריה שכבר מטפלת במקרי הקצה.
הקלדה וטעויות תחביר Out; חשיבה וקבלת החלטות In. אני בעד ונראה לי שגם אתם.
מארק אריקסון, המפתח שאחראי על Redux היום, שיתף בפוסט חשש שמשותף להרבה מפתחים שמתחילים להשתמש במצב הסוכן של AI בצורה רצינית כדי לכתוב ערימות של קוד:
"אבל אני אוהב לכתוב קוד", או במילים שלו:
I definitely didn't want to use AI to write code. I loved programming! That's the fun part! I'd already switched back from being a team tech lead to just being an IC, because I had been reduced to only 50% coding time from being stuck in meetings, and that was awful
קשה שלא להזדהות, אבל זה פחד שלא עומד במבחן המציאות.
סוכני קידוד צריכים נהג - בן אדם עם אוריינטציה טכנית שיודע לכוון אותם לבנות את הקוד הנכון לבעיה. נכון המילים השתנו אבל הרעיונות לא:
1. כבר לא צריך לזכור איך לכתוב לולאת for; כן צריך לזכור מה זה איטרציה טורית, מקבילית ואסינכרונית ואיזה סוג סריקה מתאים לבעיה שלנו.
2. כבר לא צריך לזכור איך להגדיר מחלקה; כן צריך להבין איזה מחלקות לבחור כדי שיתאימו לפיצ'רים שנצטרך בעוד חודשיים.
3. כבר לא צריך לזכור איך לטפל בשגיאות; כן צריך לבחור באיזה שגיאות לטפל, מתי לבנות מנגנון fallback ומתי לתת לזה להתרסק.
4. כבר לא צריך לזכור איך לבדוק אם מחרוזת מתאימה לתנאי מסוים. כן צריך להבין מה המגבלות של ביטויים רגולאריים, מתי נעדיף להשתמש בהם על פני כתיבת קוד חיפוש ספציפי ומתי בכלל עדיף למצוא ספריה שכבר מטפלת במקרי הקצה.
הקלדה וטעויות תחביר Out; חשיבה וקבלת החלטות In. אני בעד ונראה לי שגם אתם.
❤1
📌 כמה שכבות של בעיות
אחת התבניות שעדיין מבלבלת סוכנים חכמים היא כשיש כמה שכבות של באגים באותו קטע קוד. לאנגלטס הוא פרויקט קוד פתוח שאני בונה כדי לתרגל ערבית דרך סרטוני וידאו. יש AI שעובר על הסרט, מייצר תמלול ותרגום ומדביק לכל זה תרגילים על המילים. זה אחלה.
הבעיה היא שלפעמים הזמנים של הטקסט לא מסונכרנים עם הוידאו ואז צריך להריץ סיבוב נוסף של AI כדי לסנכרן את הזמנים. הקוד הבא מקבל קובץ זמנים מעודכן ומתקן את הזמנים בקורס קיים:
https://github.com/ynonp/langlets-rails/blob/c846dfe220fa9e25c1f54b3b3b22aaff1a463592/app/jobs/resync_timestamps_job.rb
הקוד גרוע מהרבה בחינות ובדיוק מתאים לתבנית של כמה שכבות של באגים. בקצרה:
1. כל הטקסט של הוידאו נטען לזכרון בשורה 10 (הופכת את כל השורות למערך).
2. אחרי זה רצים בלולאה על כל הטקסט בזכרון ובונים מיפוי בין הזמן החדש לכל משפט. המיפוי הזה הוא בעצם כפילות של מערך הטקסטים.
3. אחרי זה מעדכנים את כל הטקסטים לזמן החדש שלהם.
4. בסיום רצים על השיעורים בקורס ומעדכנים את זמני ההתחלה והסיום שלהם כדי להתאים לזמנים החדשים מהקובץ.
למה AI הסתבך עם זה? אני לא יודע, אבל אני חושד שהקוד כולל כמה תבניות לא נכונות והיה קשה לפתור את הסבך. הבעיות המרכזיות בקוד:
1. הוא ארוך מדי. אני יודע זה לא באג אבל זה חשוב, כי כשקוד ארוך מדי קשה להבין אותו.
2. הוא עושה עבודה מיותרת - טוען לזכרון את כל הטקסטים ואז בונה את המילון, כל זה מבלבל את ה AI.
3. התקלה הברורה היא קביעת הזמנים לשיעורים. זמן סיום של שעור צריך להיות זמן ההתחלה של השעור שאחריו ולא זמן ההתחלה של הטקסט האחרון בו, כדי לתת לוידאו זמן לסיים לנגן.
אבל כל פעם שביקשתי מ AI לתקן את 3 הוא הסתבך והקוד שנוצר לא עבד או לא עבד תמיד.
הפתרון כמובן היה לארגן מחדש את הקוד. ככה זה נראה אחרי שפירקתי אותו:
https://github.com/ynonp/langlets-rails/blob/main/app/jobs/resync_timestamps_job.rb
אחת התבניות שעדיין מבלבלת סוכנים חכמים היא כשיש כמה שכבות של באגים באותו קטע קוד. לאנגלטס הוא פרויקט קוד פתוח שאני בונה כדי לתרגל ערבית דרך סרטוני וידאו. יש AI שעובר על הסרט, מייצר תמלול ותרגום ומדביק לכל זה תרגילים על המילים. זה אחלה.
הבעיה היא שלפעמים הזמנים של הטקסט לא מסונכרנים עם הוידאו ואז צריך להריץ סיבוב נוסף של AI כדי לסנכרן את הזמנים. הקוד הבא מקבל קובץ זמנים מעודכן ומתקן את הזמנים בקורס קיים:
https://github.com/ynonp/langlets-rails/blob/c846dfe220fa9e25c1f54b3b3b22aaff1a463592/app/jobs/resync_timestamps_job.rb
class ResyncTimestampsJob < ApplicationJob
queue_as :default
def perform(course_id, json_data)
course = Course.find(course_id)
medium = course.medium
Rails.logger.info "Starting ResyncTimestampsJob for course #{course.id} (#{course.slug})"
phrases = medium.phrases.ordered_by_timestamp.to_a
if phrases.length != json_data.length
raise "Phrase count mismatch: medium has #{phrases.length} phrases, JSON has #{json_data.length} entries"
end
# First pass: build a hash of phrase.id => new timestamp
updates = {}
json_data.each_with_index do |entry, index|
phrase = phrases[index]
new_timestamp = entry["timestamp"]
if new_timestamp.blank?
raise "Missing timestamp at JSON index #{index}"
end
updates[phrase.id] = new_timestamp
Rails.logger.info "Mapping phrase #{phrase.id} ('#{phrase.text_l1}') => #{new_timestamp}"
end
# Second pass: apply all updates
updates.each do |phrase_id, new_timestamp|
phrase = Phrase.find(phrase_id)
old_timestamp = phrase.timestamp
phrase.update!(timestamp: new_timestamp)
Rails.logger.info "Updated phrase #{phrase_id} timestamp: #{old_timestamp} => #{new_timestamp}"
end
# Update lesson timestamps based on first and last phrase in each lesson
course.lessons.includes(:activities).find_each do |lesson|
lesson_phrase_ids = lesson.activities.joins(:phrases).pluck("phrases.id").uniq
lesson_phrases = phrases.select { |p| lesson_phrase_ids.include?(p.id) }.sort_by(&:timestamp)
if lesson_phrases.any?
first_timestamp = lesson_phrases.first.timestamp
last_timestamp = lesson_phrases.last.timestamp
lesson.update!(start_timestamp: first_timestamp, end_timestamp: last_timestamp)
Rails.logger.info "Updated lesson #{lesson.id} timestamps: #{first_timestamp} => #{last_timestamp}"
end
end
Rails.logger.info "ResyncTimestampsJob completed for course #{course.id}. Updated #{updates.count} phrases."
rescue => e
Rails.logger.error "ResyncTimestampsJob failed for course #{course_id}: #{e.message}"
Rails.logger.error e.backtrace.join("\n")
raise e
end
end
הקוד גרוע מהרבה בחינות ובדיוק מתאים לתבנית של כמה שכבות של באגים. בקצרה:
1. כל הטקסט של הוידאו נטען לזכרון בשורה 10 (הופכת את כל השורות למערך).
2. אחרי זה רצים בלולאה על כל הטקסט בזכרון ובונים מיפוי בין הזמן החדש לכל משפט. המיפוי הזה הוא בעצם כפילות של מערך הטקסטים.
3. אחרי זה מעדכנים את כל הטקסטים לזמן החדש שלהם.
4. בסיום רצים על השיעורים בקורס ומעדכנים את זמני ההתחלה והסיום שלהם כדי להתאים לזמנים החדשים מהקובץ.
למה AI הסתבך עם זה? אני לא יודע, אבל אני חושד שהקוד כולל כמה תבניות לא נכונות והיה קשה לפתור את הסבך. הבעיות המרכזיות בקוד:
1. הוא ארוך מדי. אני יודע זה לא באג אבל זה חשוב, כי כשקוד ארוך מדי קשה להבין אותו.
2. הוא עושה עבודה מיותרת - טוען לזכרון את כל הטקסטים ואז בונה את המילון, כל זה מבלבל את ה AI.
3. התקלה הברורה היא קביעת הזמנים לשיעורים. זמן סיום של שעור צריך להיות זמן ההתחלה של השעור שאחריו ולא זמן ההתחלה של הטקסט האחרון בו, כדי לתת לוידאו זמן לסיים לנגן.
אבל כל פעם שביקשתי מ AI לתקן את 3 הוא הסתבך והקוד שנוצר לא עבד או לא עבד תמיד.
הפתרון כמובן היה לארגן מחדש את הקוד. ככה זה נראה אחרי שפירקתי אותו:
https://github.com/ynonp/langlets-rails/blob/main/app/jobs/resync_timestamps_job.rb
class ResyncTimestampsJob < ApplicationJob
queue_as :default
def perform(course_id, json_data)
Langlets
Langlets - Learn Languages Through Interactive Video Clips
Learn languages through interactive video clips. Practice listening, speaking, and comprehension with songs, TV shows, and real-world content powered by AI.
course = Course.find(course_id)
medium = course.medium
Rails.logger.info "Starting ResyncTimestampsJob for course #{course.id} (#{course.slug})"
phrases = medium.phrases.ordered_by_timestamp.to_a
verify_json_data!(json_data, phrases)
# Update all phrase timestamps in a single pass
json_data.zip(phrases).each do |entry, phrase|
phrase.update!(timestamp: entry["timestamp"])
end
# Update lesson timestamps based on first and last phrase in each lesson
course.sync_lesson_timestamps
Rails.logger.info "ResyncTimestampsJob completed for course #{course.id}. Updated #{phrases.length} phrases."
rescue => e
Rails.logger.error "ResyncTimestampsJob failed for course #{course_id}: #{e.message}"
Rails.logger.error e.backtrace.join("\n")
raise e
end
private
# Expected json_data structure:
# [{ "timestamp" => "00:01:23.456", ... }, ...]
# One entry per phrase, ordered to match medium.phrases.ordered_by_timestamp.
def verify_json_data!(json_data, phrases)
if phrases.length != json_data.length
raise "Phrase count mismatch: medium has #{phrases.length} phrases, JSON has #{json_data.length} entries"
end
missing = json_data.each_with_index.select { |entry, _| entry["timestamp"].blank? }
if missing.any?
raise "Missing timestamps at JSON indices: #{missing.map(&:last).join(', ')}"
end
end
end
עכשיו הפונקציה נכנסת בעמוד אחד על המסך, מופרדת ל-3 חלקים ברורים כשכל חלק ממומש במקום המתאים לו. החלק שמסנכרן זמנים של שעורים נשאר מסובך, אבל המימוש המסובך כבר לא מפריע לקרוא את הג'וב:
def sync_lesson_timestamps
ordered_lessons = lessons.includes(activities: { activity_phrases: :phrase }).sort_by(&:order)
# Precompute sorted unique phrases per lesson to avoid N+1 inside the loop
lesson_phrases_map = ordered_lessons.to_h do |lesson|
phrases = lesson.activities.flat_map { |a| a.activity_phrases.map(&:phrase) }.uniq.sort_by(&:timestamp)
[lesson, phrases]
end
ordered_lessons.each_with_index do |lesson, index|
lesson_phrases = lesson_phrases_map[lesson]
next if lesson_phrases.empty?
start_ts = lesson_phrases.first.timestamp
end_ts = if (next_lesson = ordered_lessons[index + 1])
next_phrases = lesson_phrases_map[next_lesson]
next_phrases.any? ? next_phrases.first.timestamp : lesson_phrases.last.timestamp
else
Phrase.to_string_timestamp(lesson_phrases.last.timestamp_seconds + 5)
end
lesson.update!(start_timestamp: start_ts, end_timestamp: end_ts)
end
end
עכשיו צריך להגיד - אני לא כתבתי פה שורת קוד אחת. הסיפור הוא לא ההקלדה אלא להכנס לקוד, להבין שמתחת לבעיה שמפריעה לי יש עוד שתי בעיות שצריך לפתור לפני שאפשר להתקדם ולהסביר ל AI איך הקוד צריך להיות בנוי כדי לתקן את שתי הבעיות בשכבות הבסיסיות יותר. אחרי שזה נפתר אותו פרומפט שקודם הסתבך מימש את מנגנון תיקון השיעורים ואפילו כתב לו בדיקות אוטומטיות.
קריאה ותכנון הן המיומנויות שהכי משפיעות על מהירות הקידוד שלי היום. האם אפשר לעשות אוטומציה גם להן? ייתכן. בינתיים לא ראיתי שאנחנו מתקרבים.