ToCode
1.42K subscribers
3.83K links
טיפים קצרים למתכנתים מאת ינון פרק
Download Telegram
📌 אם כולם צורכים יותר מדי טוקנים

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

We’ve seen usage intensify for all users as they realize the value of agents and subagents in tackling complex coding problems

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

בהסתכלות קדימה אני מהמר שזה הולך להשתנות.

נורות להט ישנות צרכו 60 וואט אבל רוב החשמל הזה הפך לחום. הנורות החסכוניות היום נותנות אור דומה אבל צריכות רק 13-15. נורות לד יורדות ל 8-10 וואט בשביל אותו אור.

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

אם כולם צורכים יותר מדי חשמל זה כנראה סימן שאנחנו צריכים נורות יעילות יותר.
👍21👏1
📌 טייס אוטומטי

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

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

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

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

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

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

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

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

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

https://open.spotify.com/episode/7wTqD5zwl8ZitUeplapvBG?si=f87b7e5cd4c14ff3

אלה הנקודות המרכזיות שלקחתי מהשיחה:

1. לאנטרופיק אין בעיה לרוץ מהר ולשבור דברים. זאת אחת הסיבות לשחרורי גרסאות המאוד מהירים שלהם. קט וו שיתפה שהם עובדים כל הזמן על קיצור הפרוסס מפיתוח ללקוחות, עד לרמה שמפתח יכול לבנות פיצ'ר ומחר זה כבר יהיה בפרודקשן. זה כן אומר שלפעמים מוצרים שמגיעים ללקוחות לא יהיו מספיק מלוטשים וזה משהו שצריך לחיות איתו. וזה גם אומר שיהיו כל הזמן פיצ'רים ומוצרים מיותרים, לפעמים כמה מוצרים או פיצ'רים שעושים את אותו דבר ועם הזמן הם רואים מה עובד ללקוחות ובזה משקיעים. אני חושב שהרבה צוותי פיתוח מרגישים לחץ מלמעלה "לעבוד יותר מהר". מהשיחה עם קט וו היה ברור שלחץ לבד לעבוד יותר מהר לא מספיק - בשביל Delivery מהיר יותר צריך מוכנות של כל החברה וגם הבנה של כולם שיש המון פשרות שצריך לעשות בשביל שזה יקרה. לא לכל אחד זה מתאים.
2. תפקידי מפתחים, מנהלי פרויקט ומעצבים מתאחדים בזכות ה AI. מפתח אצלם אמור להיות מסוגל לזהות צורך של לקוחות, לאפיין פיצ'ר, לבנות אותו, לעצב ולדלוור והכל תוך כמה ימים. האנשים שהם מגייסים הם קודם כל אנשים עם "טעם מוצרי", כלומר אנשים שיודעים לזהות מה חשוב במוצר, מה יעבוד טוב ואיך דברים צריכים להיות ממומשים.
3. עדיין יש משימות פיתוח קשות ומהשיחה נשמע שגם באנטרופיק מאמינים שיהיו דברים קשים בעתיד הנראה לעין. יש משימות שלוקחות להם חודשים (בעיקר בצד ה Backend). יש תיעדוף מאוד קשוח איזה פיצ'רים ייבנו ואיך. יש הבנה שיש פיצ'רים שאפשר לרוץ איתם מהר ואפילו לתת ל AI לבנות מאפס, ויש שינויי תשתית מסובכים שדורשים הרבה מחשבה אנושית. 100% קוד מג'ונרט על ידי AI לא שווה 100% קוד שנכתב בלי בני אדם שמכתיבים מה ייכתב ומוודאים שדברים נכתבים נכון.
4. לקלות של הכנסת פיצ'רים חדשים יש מחיר - משתמשים מרגישים שיש המון פיצ'רים וכל הזמן צריכים להתעדכן כדי לא להשאר מאחור. אם פעם חברת מוצר היתה מכניסה למוצר את הפיצ'רים שמתאימים לשיטת העבודה של רוב הלקוחות, היום מאוד קל להוסיף המון פיצ'רים, כולל כאלה שמתאימים לשיטת עבודה רק של לקוחות בודדים. בתור משתמשים זה אומר שיהיו הרבה פיצ'רים כפולים או כאלה שאנחנו לא צריכים.
5. ספציפית לגבי פיתוח סוכנים וקלוד קוד, קט שיתפה שהרבה פעמים הסוכן לא מצליח לעשות את העבודה. במצב כזה חשוב להיות סקרן, לקרוא לעומק את כל הפלט, להבין מה הסוכן ניסה לעשות ואפילו לתשאל את הסוכן "למה פה שינית כך ולא כך?", "למה רק הרצת את הבדיקות אבל לא נכנסת לדפדפן כדי לראות איך זה יצא?". דרך השיחות האלה היא לומדת על ההתנהגות של המודל ויכולה לתקן את הרתמה (Harness) כדי שהסוכן כולו יעבוד טוב יותר.
6. באותו נושא היא מאוד המליצה לכתוב Eval-ים כדי לתאם ציפיות בין מנהלי פרויקט וצוותי הפיתוח.
7. מודלים חדשים יכולים לייתר יכולות, ולפתוח פיצ'רים חדשים - כשהמודלים לא הצליחו לעשות משימות מורכבות הם הוסיפו מנגנון של Todo List בתוך קלוד קוד. המודל ממלא את רשימת ה Todo והרתמה רצה בלולאה עד שכל הסעיפים בוצעו. ככל שהמודל השתפר לכיוון אופוס או סונט 4.6 הם ראו שאפשר להעביר את כל פיצ'ר ה Todo להיות Tool והמודל מצליח להשתמש בו כדי לייצר לעצמו את הרשימות, ואופוס החדש אפילו לא צריך את זה ועובד טוב גם בלי רשימת Todo. פיצ'ר נוסף שעלה היה פיצ'ר ה Code Review, שהיה מוכן כבר תקופה אבל אף מודל לא הצליח לתת להם תוצאות טובות עד שהגיע אופוס 4.7 ולכן הם חיכו עם שילוב הפיצ'ר עד שהמודל ישתפר. הם מתמודדים עם זה באמצעות פיתוח פיצ'רים גם אם התוצאה עדיין לא מושלמת מתוך הנחה שעוד כמה חודשים תצא גרסה חדשה של המודל שכן תתמודד עם האתגר, ובמקביל כל גרסה חדשה של מודל חוזרים לבדוק אם יש פיצ'רים בסוכן שאפשר להוריד כי המודל כבר מצליח לעבוד טוב יותר בלעדיהם.

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

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

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

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

אם כשיש בעיה אנחנו לא בטוחים מה גרם לה.

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

אם הקוד נראה לנו ממש סביר, אבל כשאנחנו מבקשים Code Review סוכן אחר מוצא דברים שאנחנו לא ראינו.

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

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

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

הנה שיחה קצרה לדוגמה עם סוכן.

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

אני- "עדיף להשתמש ב Data"

הסוכן- "אתה צודק! ברור שעדיף להשתמש ב Data. מיד מעדכן את הקוד"

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

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

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

מוצר 1: שירות מנוי לטוקנים

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

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

בחירת המודל משפיעה גם היא על מספר הבקשות שתיחשב כל הודעה. מודלים בסיסיים כמו GPT-5 Mini נכללים במנוי ללא הגבלה, כך שב 10$ בחודש אתם יכולים להשתמש בהם לכתוב כמה קוד שרק תחלמו. שדרוג ל GPT 5.4 Mini כבר יעלה לכם אבל עדיין במחיר זול - כל שלוש הודעות נחשבות כמו הודעה אחת. קלוד סונט מתומחר בכפול 1, לכן כל הודעה לקלוד סונט נחשבת כמו "הודעה" אחת מתוך ה-300 החודשיות. קלוד אופוס כרגע לא זמין בתוכנית הבסיסית אבל בתוכנית המתקדמת הוא מתומחר במכפיל של 3, כך שכל שאלה לאופוס נחשבת כמו 3 שאלות שהייתם שואלים את סונט.

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

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

https://opencode.ai/docs/providers/#github-copilot

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

https://hexdocs.pm/tidewave/github_copilot.html

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

מוצר 2 - סוכן קידוד ב VS Code

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

סוכן הקידוד ב VS Code יודע לעשות את כל הדברים שסוכני קידוד מתחרים יודעים. כל הפצ'רים נגישים דרך הרצת פקודה מהירה עם כפתור Ctrl+Shift+P:

1. הוא יקרא את קובץ ה AGENTS.md מתיקיית הפרויקט כדי לשלב הוראות כלליות ומידע על הפרויקט.
2. הוא יקרא skills מתיקיית .agents/skills או מתיקיית .github/skills
3. הוא כולל דפדפן פנימי מובנה כך שאתם יכולים לשאול מה רואים בעמוד או לבקש ללחוץ על כפתורים והסוכן מבצע.
4. הוא מתחבר לשרתי MCP כך שאפשר לחבר אותו לפיגמה, ל Notion, לג'ירה או כל כלי אחר שיעזור לקצר לכם תהליכים.

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

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

הדפדפן המובנה גם מאוד עוזר, אני לוחץ Ctrl+Shift+P, פותח דפדפן ואז בוחר אלמנט ושואל "מה הקוד שיצר את האלמנט הזה?" או "למה כשלוחצים כאן כלום לא קורה?", או "למה פה יש ירידת שורה?".

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

סוכן משורת הפקודה

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

https://github.com/features/copilot/cli
1
בשבילי הרבה יותר נוח להריץ תהליכים ארוכים משורת הפקודה על "טייס אוטומטי". אני אכתוב לו פרומפט קצר אכנס למצב טייס אוטומטי ואתן לסוכן לעבוד. כשהקוד מוכן אני יכול לקרוא אותו ב VS Code ולדייק את הפרומפט שלי, או להכנס למצב תכנון ולתת לסוכן לדיין את הפרומפט.

סוכן שורת הפקודה מדבר בפרוטוקול ACP וכך יכול להתחבר לכלי פיתוח אחרים לדוגמה אפשר לחבר אותו ל pycharm אבל האהוב עליי הוא לחבר אותו ל neovim עם התוסף agentic:

https://github.com/carlos-algms/agentic.nvim

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

תיעוד עבור Ollama נמצא כאן:

https://docs.ollama.com/integrations/copilot-cli

וכאן:

https://docs.ollama.com/integrations/vscode

סוכני קידוד בענן

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

סוכני הקידוד בענן יודעים לעשות את הדברים הבאים:

1. לקבל בקשה ב Chat ולבנות ממנה פיצ'ר.
2. לקבל Issue ולפתור אותו דרך PR.
3. להריץ Code Review מתוך Github Action

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

מתי נשתמש בכל מוצר

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

1. צ'אט עם סוכן בענן + מסלול המנויים מאפשר לי להכנס לכל קוד בכל ריפו ולהבין מה קורה שם. כך אני לומד הרבה יותר טוב איך עובדות ספריות קוד פתוח בהן אני משתמש.
2. פיתוח פיצ'רים עם סוכנים בענן - מעלה Issue, נותן לסוכן בענן לעבוד עליו ולהריץ בדיקות אוטומטיות, חיברתי את Heroku לגיטהאב וכך כל פעם שסוכן כזה בענן מסיים עבודה הוא גם מעלה אותה לסביבת Staging חדשה עבור הענף שנוצר. בפרויקט Full Stack זה אומר שאני יכול להסתכל על המוצר באוויר לפני שאני מגיע לקרוא את הקוד. כשאני לא בטוח מה ואיך בדיוק לפתח אני כותב כמה גרסאות של הפיצ'ר, נותן לסוכן בענן לבנות את כולן ואז מחליט מה יצא הכי טוב.
3. סוכן VS Code או סוכן שורת פקודה בתוך nvim - קוד בצד אחד, סוכן בצד שני זה ממשק שעובד לי טוב כשאני קורא קוד. תוך כדי הקריאה אני שואל את הסוכן שאלות קטנות מה קשור למה, איפה עוד משתמשים בפונקציה מסוימת, למה או איך זה עובד. אפשר גם לבצע שינויים ותיקונים קטנים כאן כמו "תנקה את הקוד הזה", "פה יש לוגיקת catch שאפשר למחוק היא דפנסיבית מדי" וכאלה.
4. סוכן שורת הפקודה - אלה סוכנים שאני מריץ במצב טייס אוטומטי על פיצ'רים גדולים או למחקר ותכנון. אני יכול לדבר עם הסוכן כדי לתכנן ארכיטקטורה, לבקש שידפיס לי קטעי קוד רלוונטים. לקבל הצעות לארגון מחדש של קטעים בקוד שאני לא אוהב. מצב טייס אוטומטי מאפשר לכתוב רעיון לתת לסוכן לעבוד ולחזור אחרי חצי שעה לעבור על מה שנכתב שם. לפעמים זה יהיה מוצלח, לפעמים יהיה שם גרעין מוצלח ואז צריך לשפר את הפרומפט ולפעמים צריך לזרוק את כל הקוד ולנסות משהו אחר לגמרי.
זוכרים שדיברנו לפני כמה ימים על מודל ה Premium Requests של גיטהאב ואיך זה כבר לא עובד להם יותר? אז הנה הגיעה ההודעה הרשמית

Premium request units, or PRUs, will be replaced by GitHub AI Credits which are a monthly allotment of credits consumed based on token consumption (input, output, and cached tokens) according to the listed API rates per model. This change aligns Copilot pricing with actual usage and is an important step toward a sustainable, reliable Copilot business and experience for all users.
1
📌 איך לחבר את השירות שלכם לסוכן חכם

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

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

דוגמה: חיבור לדפדפן עם MCP

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

אני מתחיל עם שרת ה MCP והקוד שלו שזמין בריפו הזה:

https://github.com/microsoft/playwright/tree/main/packages/playwright-core/src/tools/mcp

נקודת הכניסה לשרת היא הקובץ program.ts עם השורה:

await mcpServer.start(factory, config.server);


הקובץ היותר מעניין הוא backend/tools.ts שמחזיק את רשימת הכלים:

export const browserTools: Tool<any>[] = [
...common,
...config,
...console,
...cookies,
...devtools,
...dialogs,
...evaluate,
...files,
...form,
...keyboard,
...mouse,
...navigate,
...network,
...pdf,
...route,
...runCode,
...screenshot,
...snapshot,
...storage,
...tabs,
...tracing,
...verify,
...video,
...wait,
...webstorage,
];


וכל כלי מוגדר על ידי הפונקציה defineTabTool לדוגמה:

const snapshot = defineTabTool({
capability: 'core',
schema: {
name: 'browser_snapshot',
title: 'Page snapshot',
description: 'Capture accessibility snapshot of the current page, this is better than screenshot',
inputSchema: z.object({
target: z.string().optional().describe(elementTargetDescription),
filename: z.string().optional().describe('Save snapshot to markdown file instead of returning it in the response.'),
depth: z.number().optional().describe('Limit the depth of the snapshot tree'),
boxes: z.boolean().optional().describe('Include each element\'s bounding box as [box=x,y,width,height] in the snapshot'),
}),
type: 'readOnly',
},

handle: async (tab, params, response) => {
let resolved: { locator: playwright.Locator | undefined, resolved: string } = { locator: undefined, resolved: '' };
if (params.target)
resolved = await tab.targetLocator({ target: params.target });
response.setIncludeFullSnapshot(params.filename, resolved.locator, params.depth, params.boxes);
},
});


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

    {
"name": "browser_snapshot",
"description": "Capture accessibility snapshot of the current page, this is better than screenshot",
"inputSchema": {
"type": "object",
"properties": {
"filename": {
"description": "Save snapshot to markdown file instead of returning it in the response.",
"type": "string"
},
"depth": {
"description": "Limit the depth of the snapshot tree",
"type": "number"
}
},
"$schema": "https://json-schema.org/draft/2020-12/schema",
"additionalProperties": false
},
"annotations": {
"title": "Page snapshot",
"readOnlyHint": true,
"destructiveHint": false,
"openWorldHint": true
}
},


זה תיאור מאוד מפורט שמציג מה אפשר לעשות עם הכלי, ויש שיגידו יותר מדי מפורט. כשטענתי את שרת ה MCP הזה בתוך קופיילוט הוא הוסיף כ-3,500 טוקנים לכל בקשה (לא רק כלי ה snapshot, אלא ה MCP כולו).

מה זה אומר?

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

אז איך זה עובד עם Skill?

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

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

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

בדוגמה של ה snapshot שראינו קודם החלק הרלוונטי מקובץ ה Skill הוא:

  Snapshots
After each command, playwright-cli provides a snapshot of the current browser state.

> playwright-cli goto https://example.com
### Page
- Page URL: https://example.com/
- Page Title: Example Domain
### Snapshot
[Snapshot](.playwright-cli/page-2026-02-14T19-22-42-679Z.yml)
You can also take a snapshot on demand using playwright-cli snapshot command. All the options below can be combined as needed.

# default - save to a file with timestamp-based name
playwright-cli snapshot

# save to file, use when snapshot is a part of the workflow result
playwright-cli snapshot --filename=after-click.yaml

# snapshot an element instead of the whole page
playwright-cli snapshot "#main"

# limit snapshot depth for efficiency, take a partial snapshot afterwards
playwright-cli snapshot --depth=4
playwright-cli snapshot e34

# include each element's bounding box as [box=x,y,width,height]
playwright-cli snapshot --boxes


אפשר למצוא את קובץ הסקיל המלא בגיטהאב שלהם:

https://github.com/microsoft/playwright-cli/blob/main/skills/playwright-cli/SKILL.md

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

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

בוובינר ביום חמישי נדבר בהרחבה על שתי הטכניקות האלה, נעבור על הקוד גם של הסקיל וגם של ה MCP ונחליט אחת ולתמיד (או לפחות לשבוע הקרוב) איך כדאי לחבר את השירות שלנו לסוכנים חכמים.
📌 איך (ולמה) לתת ל AI לטפל בריבייסים

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

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

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

מזל שיש לנו AI.

המתג -p של קופיילוט מאפשר להעביר פרומפט משורת הפקודה. יחד עם --allow-all ו --autopilot יש לנו מפלצת סקריפטים. אני יוצר את הסקריפט git-llmrebase

  # ~/.git-llmrebase
#!/usr/bin/env bash
branch=$(git rev-parse --abbrev-ref HEAD)
target="$1"

ollama launch copilot --model glm-5.1:cloud -- --allow-all --autopilot --share -p \
"Do an LLM rebase to ${target}: run git diff ${branch}...${target} review all changes from their merge-base and re-implement them on the ${target}. Move branches so ${target} won't change and ${branch} will point to the new implementation. Instead of applying the patches one by one just read the differences from ${target} and re-build the most recent changes of ${branch} there. End result: branch ${branch} is a single commit branch with the most recent changes and ${target} as its parent"


ואז מחבר אותו לגיט עם:

chmod +x ~/.git-llmrebase
git config --global alias.llmrebase '!~/.git-llmrebase'


ועכשיו נוכל להריץ:

git llmrebase foo


ולתת ל AI לשבור את הראש ולמצוא רק את השינויים הרלוונטיים.

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

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

העברת פרמטרים As-Is

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

def retry_on_failure(func):
def wrapper(*args, **kwargs):
try:
return func(*args, **kwargs)
except Exception:
print("Retrying...")
return func(*args, **kwargs)
return wrapper

@retry_on_failure
def say_my_name(name: str):
print(name)

say_my_name('demo')


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

בשביל שזה יעבוד wrapper צריכה להגדיר את אותו Type Hint כמו הפונקציה say_my_name, אבל הדקורטור הוא גנרי, איך יודעים מה הפרמטרים שהוא צפוי לקבל?

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

from typing import Callable, TypeVar, ParamSpec

P = ParamSpec('P')
T = TypeVar('T')

# ParamSpec captures the exact arguments (*args, **kwargs) of the wrapped function.
def retry_on_failure(func: Callable[P, T]) -> Callable[P, T]:
def wrapper(*args: P.args, **kwargs: P.kwargs) -> T:
try:
return func(*args, **kwargs)
except Exception:
print("Retrying...")
return func(*args, **kwargs)
return wrapper


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

@retry_on_failure
def say_my_name(name: str):
print(name)

say_my_name(10)


בדיקת קיום פונקציה בלי לחייב ירושה

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

class ItemA:
def __init__(self):
self.price = 10

class ItemB:
def __init__(self):
self.price = 5

def total_price(items):
return sum(item.price for item in items) * 1.18

print(total_price([ItemB(), ItemA(), ItemA(), ItemA()]))


אבל מה עושים כשרוצים להוסיף כאן Type Hints? לא נרצה להגדיר בצורה מפורשת בפונקציה שהיא מקבלת רק דברים מסוג ItemA או ItemB כי מחר מישהו יוסיף קלאס חדש עם מאפיין price. גם לא נרצה לשנות את ההגדרה של ItemA או ItemB ולהתחיל להגדיר עבורם היררכיית ירושה חדשה. אנחנו רוצים פשוט להגדיר שהפונקציה מקבלת רשימה של דברים שיש להם מאפיין price.

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

from typing import Protocol

class ItemA:
def __init__(self):
self.price = 10

class ItemB:
def __init__(self):
self.price = 5

class HasPrice(Protocol):
@property
def price(self) -> float:
...

def total_price(items: list[HasPrice]):
return sum(item.price for item in items) * 1.18

print(total_price([ItemB(), ItemA(), ItemA(), ItemA()]))


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

ערכי החזר מסוגים שונים

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

def same(x):
return x


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

x = same("hello")
print(x + 5)


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

G = TypeVar("G")
def same(x: G) -> G:
return x

x = same("hello")
print(x + 5)
עכשיו בודק הטיפוסים של פייתון כבר ידע להגיד ש x שחוזר מ same("hello") הוא מטיפוס מחרוזת ולכן אי אפשר לחבר לו 5.

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

T = TypeVar("T")

def add_item(item: T, args):
return (item, *args)

v = add_item(4, [1, 'a', 'b'])
print(len(v[0]))


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

את args אי אפשר להגדיר בתור רשימה גנרית או tuple גנרי. אנחנו רוצים להיות יותר מדויקים ולהגיד שאנחנו מחזירים בדיוק את מה שקיבלנו. לאיבר הראשון אין אורך אבל לשני ולשלישי כבר יש.

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

from typing import TypeVarTuple, TypeVar, Any

Ts = TypeVarTuple("Ts")
T = TypeVar("T")

def add_item(item: T, *args: *Ts) -> tuple[T, *Ts]:
return (item, *args)

v = add_item(4, 1, 'a', 'b')
print(len(v[0]))


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

עכשיו בודק הטיפוסים מזהה את הבעיה בהדפסת האורך של v[0] אבל יתן לי להדפיס את האורך של v[2].

שרשור מתודות על אוביקט בירושה

נמשיך לדוגמה הבאה ונכתוב מחשבון:

class Calc:
def __init__(self):
self.value = 0

def add(self, n: int):
self.value += n
return self

c = Calc()
c.add(10).add(20).add(30)
print(c.value)


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

    def add(self, n: int) -> Calc:
self.value += n
return self


אבל אז אני אסתבך בירושה. שימו לב לקוד הבא:

class Calc:
def __init__(self):
self.value = 0

def add(self, n: int) -> Calc:
self.value += n
return self

class AdvancedCalc(Calc):
def sub(self, n: int) -> AdvancedCalc:
self.value -= n
return self

c = AdvancedCalc()
c.add(10).sub(15).add(30)
print(c.value)


הקריאה ל add הפכה את המשתנה מ AdvancedCalc ל Calc עבור בודק הטיפוסים כיוון שזה מה ש add מחזירה. גישה טובה יותר תגיד לפייתון שהפונקציה add מחזירה את אותו טיפוס של self - אם התחלנו עם Calc זה מה שנחזיר, ואם התחלנו עם AdvancedCalc נחזיר את AdvancedCalc. הקוד משתמש בטיפוס בשם Self, עוד חידוש של פייתון 3.11:

from typing import Self

class Calc:
def __init__(self):
self.value = 0

def add(self, n: int) -> Self:
self.value += n
return self

class AdvancedCalc(Calc):
def sub(self, n: int) -> Self:
self.value -= n
return self

c = AdvancedCalc()
c.add(10).sub(15).add(30)
print(c.value)


טיפוסים רקורסיביים

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

JsonValue = Union[int, float, str, bool, None, Dict[str, 'JsonValue'], List['JsonValue']]

def parse_api_response(payload: JsonValue):
pass


גרסאות חדשות יותר של פייתון מאפשרות לוותר על המרכאות באמצעות הגדרת Type Alias:

type JsonValue = Union[int, float, str, bool, None, Dict[str, JsonValue], List[JsonValue]]


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