יום 6: ציור עם סוכן
במשחק האיקס עיגול למדנו שסוכנים חכמים יכולים לבצע פעולות על המסך. היום ניקח את הרעיון הזה צעד גדול קדימה ונבנה מערכת עם ממשק כפול - סוכן וממשק גרפי. משתמשים יכולים לעבוד עם המערכת בכל אחד משני הממשקים ושניהם תמיד מתואמים.
טיפים קצרים וחדשות למתכנתים
במשחק האיקס עיגול למדנו שסוכנים חכמים יכולים לבצע פעולות על המסך. היום ניקח את הרעיון הזה צעד גדול קדימה ונבנה מערכת עם ממשק כפול - סוכן וממשק גרפי. משתמשים יכולים לעבוד עם המערכת בכל אחד משני הממשקים ושניהם תמיד מתואמים.
שיחות עם סוכן לא חייבות לכלול רק הודעות טקסט. בדוגמה של היום נבנה משחק איקס עיגול נגד סוכן ונראה איך להעביר את מצב המשחק בהודעה כדי שהסוכן יחליט על המהלך הבא. דוגמה זו מהווה בסיס לדוגמאות שנראה בהמשך בהן הסוכן משולב במערכת קיימת ומאפשר שני ממשקים: ממשק שיחה וממשק גרפי המשתלבים ביניהם.
שלושת הדוגמאות שראינו במדריכים הקודמים היו עבור סוכנים של תהליכי עבודה, הסוכן מקבל טריגר עושה משהו ומסיים. בדוגמה היום ניקח צעד קדימה ונבנה סוכן שיחה אינטרקטיבי, סוכן שממשיך לקבל הודעות ומתיחס לכל היסטוריית השיחה בכל תשובה חדשה.
ראינו כבר איך ליצור שאלות הבנה מדף אינטרנט, אבל מה קורה אם יש כמה דפי אינטרנט? בדוגמה של היום נראה איך לתת לסוכן שלנו את החופש לחקור לבד כדי שיוכל להחליט אוטונומית מהם המאמרים הכי חשובים ולתקצר אותם עבורנו.
הצד החזק של ספריית Pydantic AI הוא המילה הראשונה בשם הספריה - pydantic. פידנטיק היא ספריית הגדרת טיפוסים והסוכן שלנו היום ישתמש בפידנטיק כדי לוודא שהוא מקבל מהמודל מידע בדיוק בצורה לה הוא מצפה.
ספריית Pydantic AI היא ספריית פיתוח סוכנים בפייתון אגנוסטית למודל. מבחינה רעיונית היא לוקחת את הפשטות מ OpenAI Agents SDK ואת הגמישות והפתיחות להתחבר לכל הספקים מ LangGraph. ב 12 הימים הקרובים אפרסם פה 12 מדריכים קצרים לבניית סוכנים עם הספריה.
מעבר להנאה בעבודה עם Pydantic AI נרצה לשים לב לרעיונות הבסיסיים בפיתוח סוכנים: הפעלת כלים, קבלת פלט מובנה, לולאת הסוכן, דפי הוראות, פרמטרים ספציפיים למודל ועוד. כל דוגמה מציגה רעיון או שיטת עבודה שיעזרו גם אם תכתבו את הסוכן שלכם בספריה אחרת.
הסוכנים לכל הדוגמאות כבר עלו לגיטהאב בריפו:
https://github.com/ynonp/pydanticai-demos
כך שתוכלו להוריד את הפרויקט ולהריץ עם המדריכים.
גיירמו ראוך (מייסד vercel) פרסם בטוויטר קריאה לקרוא את הקוד. אני מתרגם:
אם אתם לא קוראים את הקוד אחד הבאים נכון:
מודלים עושים טעויות של מתחילים ובוחרים ארכיטקטורה לא נכונה. המודל הכי טוב בעולם הרגע הוסיף לי המתנה של 700ms לקוד בלי שום סיבה וכשהערתי על זה הוא ענה שאני צודק.
מעניינת הרשימה שלו אבל לדעתי מפספסת את הנקודה. הדוגמה בסוף היא המפתח.
בנינו מכונה אדירה שיודעת לתרגם טקסט בשפה טבעית לקוד וכמעט שכחנו ששפה טבעית היא לא קוד. היא לא מתארת את כל מה שצריך לעשות בכל המצבים. אנשים שונים יקראו טקסט בשפה טבעית ויבינו ממנו דברים אחרים. לא משנה איזה מכונה תיקח היא לא תוכל להחליט תמיד את ההחלטה הנכונה כי אין החלטה אחת נכונה.
קריאת הקוד היא החוזה בינינו לבין המכונה. אנחנו לא צריכים לוודא שהמכונה כותבת נכון לולאת for אנחנו צריכים לוודא שמכל המקומות בהם אפשר לכתוב לולאת for כדי להגיע לתוצאה שרצינו היא בחרה את המקום שגם אנחנו היינו בוחרים. גיירמו טוען שזה זמני, שעוד מעט המודלים כבר לא יעשו כאלה טעויות, שנצטרך לקרוא את הקוד פחות ופחות. אני חושב שמי שאחראי על מערכת צריך להכיר אותה ולהבין איך היא עובדת והדרך היחידה לעשות את זה היא לקרוא את הקוד.
ואולי יותר חשוב צריך גם לדעת איך לקרוא את הקוד. יום יבוא וההחלטות של המודלים יראו לנו כל כך הגיוניות שיהיה קשה לחשוב על אלטרנטיבה. זה לא המצב היום. כרגע גם בעבודה עם המודלים הכי טובים אם סיימתם יום עבודה ולא הערתם לסוכן על החלטות מהותיות שגויות שהוא קיבל סביר להניח שפספסתם את אותן החלטות מהותיות ושגויות.
לפני כמה ימים הצגתי כאן דוגמה שמראה איך לשבור ריפו באמצעות ערבוב בין merge ל rebase. הפוסט כלל את המשפט "נניח שבשלב מסוים main התקדם ואני רציתי בפיצ'ר שלי לקבל שינויים שנכנסו ב main", בעקבותיו עלתה השאלה "למה לא לעשות rebase בשלב הזה?" התשובה קשורה לתוכן הענפים וכמה כאב ראש כרוך בשינוי. נפרט:
ל JavaScript יש טיפוס נתונים שנקרא number לייצוג מספרים:
> typeof(12)
'number'
משתנה מסוג number הוא בגודל 64 ביט אבל JavaScript עצמה לא משתמשת בכל 64 הביטים כדי לייצג מספרים שלמים. הערכים שמותר לייצג כמספרים הם הטווח:
> Number.MIN_SAFE_INTEGER
-9007199254740991
> Number.MAX_SAFE_INTEGER
9007199254740991
ל JavaScript יש גם טיפוס נתונים בשם bigint שיודע לייצג מספרים הרבה יותר גדולים ואנחנו יוצרים ערך מסוג bigint בעזרת הסיומת n בסוף מספר:
> typeof(12n)
'bigint'
הגודל של bigint מוגבל רק בכמות הזכרון שיש לכם על המחשב. מה קורה כשיוצאים מחוץ לטווח הבטוח? שימו לב:
> Number.MAX_SAFE_INTEGER + 1
9007199254740992
> Number.MAX_SAFE_INTEGER + 2
9007199254740992
> Number.MAX_SAFE_INTEGER + 3
9007199254740994
> Number.MAX_SAFE_INTEGER + 4
9007199254740996
> 9007199254740992 == 9007199254740993
true
נו זה היה כיף. במספרים גדולים זה כמובן לא היה קורה:
> 9007199254740992n == 9007199254740993n
false
אז למה לא להשתמש ב bigint כל הזמן? בגלל JSON כמובן:
> JSON.stringify(9007199254740992)
'9007199254740992'
> JSON.stringify(9007199254740992n)
Uncaught TypeError: Do not know how to serialize a BigInt
at JSON.stringify (<anonymous>)
בשביל ש JavaScript יהפוך מספר גדול ל JSON הוא יצטרך לכתוב ערך שאף אחד לא יוכל לקרוא. מה עושים? הופכים למחרוזת וזוכרים להמיר ל BigInt בחזרה:
BigInt(JSON.parse(JSON.stringify(90071992547409932n.toString())))
90071992547409932n
נ.ב. הסיבה שאנחנו צריכים לדבר על זה היא שאנשים עדיין שולחים לפעמים id בתור מספר במקום בתור מחרוזת וכך כשיש יותר מדי אוביקטים במערכת המזהים מתחילים להישבר. מספרים גדולים זה אחלה לחישובים אבל רוב הזמן יהיה יותר קל לדאוג תמיד לשמור את המזהים שלנו בתור מחרוזות ולא לדאוג לגודל.
תמיד חלמתם לראות את Chrome Devtools MCP בגרסת ה CLI? אם כן ורסל התנדבו לסגור את הפער ופיתחו כלי שליטה בדפדפן משורת הפקודה בקוד פתוח, זהו Vercel Agent Browser. מתקינים כאן: