ToCode
رفتن به کانال در Telegram
1 419
مشترکین
اطلاعاتی وجود ندارد24 ساعت
اطلاعاتی وجود ندارد7 روز
-430 روز
آرشیو پست ها
1 419
חשבתי, טעיתי, למדתי.
מבין השלושה רק האחרון הוא בחירה ולכן רק האחרון הוא קשה.
אי אפשר לא לחשוב. מגיל צעיר מאוד יש לאנשים מחשבות על העולם, הבנה מסוימת איך דברים עובדים ודעות בלי סוף.
ואי אפשר לא לטעות. הדעה שלי על העולם מבוססת על חוויות חיים, ניסיונות, הסברים, דברים ששמעתי, ראיתי או טעמתי. היא יותר מספרת על איך אני מבין את העולם מאשר על איך העולם עובד.
ההזדמנות לצמיחה מגיעה כשאני מגלה שטעיתי. חשבתי שפרויקט מסוים יהיה הצלחה אבל הוא לא היה. חשבתי שייקח לי חודשיים למצוא עבודה אבל בסוף לקח חצי שנה. חשבתי ש perl תהיה שפת התכנות של העתיד ובסוף פייתון היתה. עכשיו מה?
1. שלב ראשון הוא לשים לב שטעיתי. לא רק בתוך הטעות אלא גם אחריה. וואו חשבתי שייקח לי חודשיים למצוא עבודה אבל בסוף לקח חצי שנה והנה הגעתי למקום חדש. מעניין למה טעיתי בהערכה שלי לפני חצי שנה.
2. שלב שני הוא לשער למה טעיתי (וכן הנה הרקורסיה. גם השערה זו יכולה להיות טעות). חשבתי שייקח לי חודשיים למצוא עבודה חצי שנה כי פעמים קודמות זה מה שזה לקח; כי בזמן שעבדתי קיבלתי המון הצעות ממגייסים; כי במקום בו עבדתי לפני הפיטורים כולם רק אמרו כמה אני יודע הכי טוב; כי בעיתון כתבו שהשוק במצב טוב עכשיו; כי ראיתי חברים שמצאו עבודה תוך חודשיים בשנה שלפני הפיטורים.
3. שלב שלישי זה איפה שדברים נהיים מעניינים. פה אני מזהה מה ההבדל בין הדברים שראיתי למצב שלי או דקויות שלא שמתי לב אליהן כשהסתכלתי. משפט כמו "חשבתי שייקח לי חודשיים למצוא עבודה כי בזמן שעבדתי קיבלתי המון הצעות ממגייסים" יכול להביא למסקנה שהצעות ממגייסים הן לא מדד טוב לכמה יהיה קל למצוא עבודה, או מה שיותר סביר שפספסתי משהו באותן הצעות. "חשבתי שקיבלתי המון הצעות רלוונטיות ממגייסים אבל בבחינה יותר מעמיקה אני מבין שחלק גדול מהצעות אלה היו ניסיונות הונאה או משרות לא רלוונטיות".
הלמידה היא אפקטיבית כשהיא עוזרת לי לקחת צעד קדימה ולהסתכל אחרת על העולם. לשים לב לדקויות שקודם פספסתי. לשנות את האופן בו אני מתייחס לסימנים בעולם. צעד קדימה בדרך שאין לה סוף.
1 419
חשיבה. מימוש. מודלים.
אפילו אם ניקח מודל לא חכם במיוחד כמו gpt5-mini ונבקש ממנו לכתוב משהו מאופיין היטב שאנחנו כבר יודעים איך לכתוב ושכל התשתית בשבילו מוכנה הוא יצליח וכנראה די טוב. לדוגמה:
1. הוסף למסך הפרופיל שדה חדש עבור כתובת. (במערכת שכבר יש בה מסך פרופיל ו flow של עריכה ושדות שנשמרים מתוך הפרופיל בבסיס הנתונים ומנגנון מתועד לעדכון הסכימה בבסיס הנתונים).
2. הוסף למסך הפרופיל שדה חדש עבור תמונת משתמש. יש לשמור את התמונה ב base64 בבסיס הנתונים.
3. כתוב תהליך רקע חדש שפעם בחמש דקות מוודא שעדיין יש תקשורת לבסיס הנתונים. (בתנאי שיש במערכת מנגנון שיודע להריץ תהליכי רקע ודרך מתועדת בה נכתבים תהליכי רקע ומוגדים זמני ריצה לכל תהליך).
4. הוסף כפתור למסך הניהול שמאפס למשתמש את הסיסמה (בהנחה שכבר יש פונקציה לאיפוס סיסמה במערכת).
רוב כלי ה AI לכתיבת קוד כבר משתמשים במנגנון כזה. הם יתנו למודל חכם לבנות תוכנית עבודה ואז למודל פשוט ומהיר יותר יתנו את החלק של הכתיבה. וגם המודלים הכי חכמים לא מצליחים לייצר פיתרונות יצירתיים ותשתיתיים לבעיות. הם לא יכולים לחשוב "מחוץ לקופסה" כי עבורם הקופסה מייצרת את החשיבה. המצב הנוכחי זה הפרומפט ולפיו הם יודעים לחזות מה יהיה הטקסט הבא.
כך נולד Workflow החלומות בעבודה עם AI: בן אדם חושב, בן אדם בונה תשתית, AI מממש פיצ'רים על בסיס תשתית זו כדי "לנצל" כמה שאפשר את התשתית, AI נתקע ומתחיל לעשות שטויות, בן אדם חושב ומרענן את התשתית. מה שמשפר את ה Workflow הזה זה לא מודלים יותר טובים אלא תשתית קוד יותר טובה - קוד מתועד, מסודר, שברור ל AI ולאנשים איך לממש את הפיצ'ר הבא.
ב Workflow החלומות, הנקודה בה AI נתקע ומתחיל לעשות שטויות היא לא באג היא פיצ'ר. היא לא משהו שצריך למנוע או לברוח ממנו או לחפש מודל חזק יותר שכן יצליח להתגבר עליה ולא מקום שבו צריך "לשייף קצת את הקוד" של ה AI בשביל שיעבוד.
הנקודה בה AI נתקע היא מטרת המשחק. היא ההבדל המזוקק בין בן אדם ל AI. בנקודה הזאת אנחנו פורחים כמתכנתים ומקבלים הזדמנות לחשוב, לבנות ולייצר את העולם של המערכת אותה אנחנו בונים. מתכנתים טובים מחפשים את הנקודה הזאת וצומחים ממנה.
1 419
טיפ וים - מצב סוכן עם opencode
אוהבים את המחיר של Github Copilot ואת מצב הסוכן שלהם, אבל אין לכם כח לצאת מהטרמינל? בין כל הרעש של כלי AI מצאתי היום אחד ממש קסום לשתף. הוא נקרא opencode ואלה התכונות שאני הכי אהבתי:
1. מתחבר לקופיילוט כך שאפשר להשתמש בחשבון 10$ בחודש הקיים שלכם בשביל המודלים (ויכול גם להתחבר ל ollama אם יש לכם מודל מקומי או ל Open Router או ל together ai עבור ערימה ענקית של מודלים בענן. וכן ברור שגם לכל המסחריים הרגילים).
2. עובד מהטרמינל בסגנון קלוד קוד או קודקס.
3. מתחבר ל vim בעזרת פלאגין:
https://github.com/NickvanDyke/opencode.nvim?tab=readme-ov-file
איך זה עובד? בינתיים מעולה:
1. בלחיצת כפתור מתוך וים נפתח פאנל שיחה עם AI בסגנון תיבת הצד של קופיילוט
2. ניתן לשאול שאלות על הקוד, לבקש מימוש של קטעים קטנים או ריפקטור גדול יותר. ה opencode, כמו קלוד קוד כבר מושך את החלקים שהוא צריך ומעדכן אותם.
3. במהלך המימוש אופןקוד מדפיס לתיבת הצד את כל הקוד שהוא כותב. הוא גם מראה כמה השיחה עלתה וכמה הוא לקח מה Context Window.
4. אפשר לבטל את כל השינויים עם פקודת undo. מומלץ עדיין לשמור הכל ב git כשה AI יצר משהו שאתם אוהבים.
שני דברים שעדיין לא מצאתי (אולי עדיין אין) זה אינטגרציה אוטומטית עם גיט בסגנון aider שכל שינוי אוטומטית נכנס לקומיט ואפשרות לערוך הודעות ישנות כדי לנווט את השיחה לכיוון אחר. כן אפשר להשתמש ב undo עד שמגיעים להודעה הישנה שרוצים לערוך ואז לשנות אותה אבל זה קצת פחות נוח מכפתור העריכה של VS Code.
1 419
שדה reasoning ב Structured Output
שימו לב לקלאס הבא מתוך דף תיעוד של openai שמתאר תשובה של סוכן שבודק אם ביקשו ממנו עזרה בשיעורי בית בחשבון:
class MathHomeworkOutput(BaseModel):
is_math_homework: bool
reasoning: str
guardrail_agent = Agent(
name="Guardrail check",
instructions="Check if the user is asking you to do their math homework.",
output_type=MathHomeworkOutput,
)
קוד הדוגמה המלא לא כולל שום התיחסות למידע שנכתב לתוך reasoning. כן הם בודקים אם is_math_homework הוא אמיתי, אבל reasoning? אף אחד לא מסתכל עליו.
אז למה הוא שם? שלוש סיבות חשובות שגם אני ראיתי בעבודה עם סוכנים:
1. מנגנון Structured Output עדיין לא עובד מספיק טוב. סוכנים לפעמים לא מצליחים להגיב בלי טקסט חופשי ולכן בקשות בלי שדה reasoning יכולות פשוט להיתקע.
2. אמינות - כשאני מבקש מ LLM הסבר למה הוא עשה משהו אני מקבל תשובות טובות ואמינות יותר.
3. תיעוד - כשקוראים לוגים ועוברים על תשובות של סוכנים כדי להבין מה קרה בתוכנית שדה reasoning יכול לשקף לנו מה גרם לסוכן להחזיר תשובה שלא ציפינו לה וכך לתת לנו את המידע לתקן או לשפר את הקוד שלנו.
וטיפ לסיום - נכון להיום Structured Output זה בדיוק דוגמה לפיצ'ר מסוג "חשיבה אופטימית" שממחיש את הפער בין ההייפ סביב AI לסיפור האמיתי שלהם ואת הקושי לפתור בעיות של LLM-ים באמצעות הנדסה. בשביל שזה יעבוד openai בנו שכבת retry בתוך ה API שלהם כך שכשאנחנו מבקשים מידע מובנה מה API בעצם OpenAI פונים למודל שוב ושוב עד שהוא מסכים להחזיר את המידע לפי המבנה שהעברנו. הפיתרון ההנדסי הזה נשמע טוב על הנייר אבל בינתיים הוא לא עובד, וכולם משתמשים בפיתחי מילוט כמו שדה reasoning (וגם זה לא תמיד עובד). יש לי כבר שתי מערכות שהוצאתי מ Structured Output והעברתי לקריאה רגילה לסוכן ופיענוח ידני של הפלט ובשתיהן המעבר שיפר משמעותית את התוצאות וגם איפשר לי לגוון במודלים.1 419
חזרה לבית הספר. כיף. לימודי תכנות. AI.
הרבה נושאים היום לכבוד היום הראשון ללימודים. ננסה לחבר אותם יחד. יותר שאלות מתשובות היום אבל אולי זו התקופה.
חזרה ללימודים
אני זוכר את הכאב בכף היד בסוף יום לימודים. אני זוכר את עצמי יושב בכיתה, מקשיב וכותב. בית הספר נוצר כדי ללמד אנשים מגיל צעיר "איך עושים דברים כאן", איך להקשיב לסמכות, איך לעשות דברים גם אם אתה לא מבין את המטרה שלהם, מה זה ידע ואיך ידע עובר ממבוגר לצעיר, מחכם לתלמיד, ממורה לילד.
זה לא קיים יותר.
מורה שרוצה להצליח היום צריך להיות יותר מעניין מ ChatGPT. צריך להשקיע במוטיבציה וצריך לדחוף את התלמידים שלו ללמוד. חומר הלימוד זמין לכולם. בתי ספר מנסים להסתגל ולתת לתלמידים לכתוב עבודות ולחקור בעצמם. לפעמים זה עובד, לרוב לא. המורים בעצמם לא מבינים מה חשוב וכיוון הידע התהפך. הילדים יודעים להשתמש בכלי AI טוב יותר מהמורים שלהם. הילדים יודעים לתת ל AI לכתוב את העבודה בשבילם. הילדים מבינים איך לרמות את המערכת כי הם מבינים שהמערכת מרמה אותם.
האתגר של בתי ספר הוא לחזור למנטרה הבסיסית, ללמד את הצעירים "איך עושים דברים כאן". לא בסיסמה אלא בכל הרבדים של המערכת. אנחנו רחוקים שנות אור משם.
לימודי תכנות
תקופה ארוכה האתגר בלימודי תכנות היה שתוכנות נהיו מסובכות מדי. אין לילד דרך לכתוב משחק טטריס שהוא יהנה לשחק בו כי הוא התרגל לשחק פורטנייט. הפער גדול מדי. ואז הגיע AI.
עכשיו אותו ילד יכול ללכת ל base44 ולבנות "משהו". זה יכול להיות משחק סנייק או טטריס או תוכנת ציור או אתר לבית הספר או מערכת דף קשר לכיתה. אבל גם אם איכשהו הצלחת לכתוב משחק שכיף לשחק בו עדיין לא למדת כלום על תכנות. קראתי סקירה של מתכנת צעיר שמספר שהוא לומד תכנות כבר שלושה חודשים ומצליח לבנות מערכות ווב ב Django בעזרת AI ומרגיש שהוא מבין את כל הקוד שכתוב שם ויכול קצת לשנות דברים, אבל לא יודע איך להתחיל משהו מאפס ומבקש עצות. האם זה צעד ראשון נכון ללימודי תכנות? אני לא בטוח.
אם בתי ספר צריכים ללמד "איך עושים דברים כאן" אז בתי ספר לתכנות צריכים להתמקד בחשיבה, בהבנת מערכות מורכבות, באלגוריתמים, בארכיטקטורה. בבניית סטנדרט של הבנה שבאמת מתאים לרמת ההבנה הנדרשת ממפתחים לעתיד. תקופה ארוכה שכנענו מתכנתים צעירים שאפשר לכתוב מערכות "מהר" ו"בקלות" עם הפריימוורק הנכון. דחפנו כלים של תכנות ויזואלי כדי להבין עקרונות של תכנות תוך כדי בניית דברים יפים או כיפיים. אולי הגיע הזמן להפריד, לשים לב שאפשר לבנות מוצרי תוכנה מדהימים עם AI אבל כדי ללמוד תכנות כדאי להתחיל מרעיונות פשוטים ולחבר אותם לדברים גדולים יותר. אולי אנחנו צריכים לחזור ל Lisp.
בינה מלאכותית
"לא מאמינים לי? תשאלו את ה Chat"
כל שיחה על בינה מלאכותית היא הטעיה. מודל שפה גדול לא "חושב". המידע שהוא מדפיס לא אמין ולא תמיד קוהרנטי. לשאול את הצ'ט זו המלצה טובה כמו ללכת לקרוא בקפה. אני מאמין במדע בגלל שרעיונות מורכבים בנויים על בסיס רעיונות פשוטים יותר, בגלל הוכחות וטיעונים והסברים ופרדיגמות. אני מאמין ב ChatGPT כי הוא כותב את "התשובות הנכונות". אבל מה שוות התשובות הנכונות בלי המבנה שהוביל לגילויין? ומה אני מלמד תלמיד בית ספר כשאני אומר לו לשאול את ה Chat?
בתי ספר צריכים ללמד ילדים צעירים "איך עושים דברים כאן". במקום זה אנחנו מרדדים את השיח ומנסים ללמד אותם איך לעבור מבחן שאף אחד לא צריך. הורים, בואו ננצל את היום הראשון ללימודים ונדבר עם הילדים על מהפכת המידע, על זמינות הידע, על ההבדל בין עובדות לדעות, על החובה לחפש את האמת, להטיל ספק, לגבש דעה, לחבר רעיונות פשוטים לתיאוריות מורכבות. נדבר על איך מודל שפה גדול עובד, מאיפה ה Chat לוקח את המידע, מי אימן את ה Chat. נראה להם איך ניסוח שונה של השאלה יכול לייצר תשובה שונה לגמרי.
הם היו צריכים לקרוא לזה "מכונת יצירת טקסטים".
1 419
שני אתגרים חדשים בכתיבת סוכני AI
היות ומודלי שפה אינם דטרמניסטיים ואינם צפויים מפתחים שכותבים סוכני AI צריכים להתמודד עם שני אתגרים ייחודיים למערכות אלה:
הראשון הוא כתיבת הפרומפטים. אנחנו רגילים לכתוב "קוד" כלומר טקסט בשפה פורמלית אותו לא ניתן לפרש במספר דרכים והרצה שלו גורמת למחשב לבצע פעולות לפי הסדר שקבענו. בכתיבת סוכן בנוסף לקוד אנחנו כותבים "פרומפט" שזה הנחיות והמלצות לאותה מכונה לא דטרמניסטית. לפעמים ה AI יקשיב להנחיה שלנו, לפעמים יתעלם, לפעמים ייתקע. פרומפט הוא לא קוד אבל הוא גם לא טקסט שמוצג למשתמש.
פרומפט הוא סוג של קוד: אחרי שינוי פרומפט צריך להריץ מחדש את כל הבדיקות, אנחנו משפרים פרומפטים וכשמחליפים מודל צריך לעדכן את כל הפרומפטים שלנו (בדומה לאופן בו אנחנו צריכים לשדרג קוד כשאנחנו מחליפים פריימוורק או מכוונים למערכת הפעלה אחרת).
מצד שני זה לא קוד כמו שאנחנו רגילים לכתוב: פרומפט טוב כולל דוגמאות מעולם התוכן, כדאי לנו לשתף את מנהלי המוצר בכתיבת הפרומפטים ואולי ההבדל הכי גדול הוא שפרומפט לא יכול להיכשל. לא משנה מה נבקש תמיד נקבל מהמודל משהו.
הבדל שני הוא הבדיקות. אנחנו רגילים לנסות להריץ את הקוד שכתבנו ולראות מה קורה. מיטיבי לכת מריצים את הקוד בכמה סביבות למשל בכמה דפדפנים. בכתיבת סוכני AI אני מוצא שאחרי כל שינוי אני צריך לבדוק את אותו דבר 4-5 פעמים כי ההשפעה היא סטטיסטית ולא תמיד נראה את השינוי בהפעלה ראשונה. גם בדיקות אוטומטיות הופכות להיות פחות אמינות - כן בבדיקות יחידה אני אשתמש בתשובות מודל ״שמורות״ רק כדי לראות איך הקוד שלי מתנהג, אבל בבדיקות קצה לקצה קשה להבין מה זה "כשלון בבדיקה". משתמשים שמדברים עם AI רגילים לזה שהשיחה הולכת למקום אחר כל פעם ומוכנים להכיל את גורם ההפתעה. אין לנו עדיין פריימוורקים לכתיבת בדיקות שיודעים להכיל את זה באופן דומה.
1 419
encoded.map { |token| inv[token] }.join
end
class BytePairHash
attr_accessor :vocab, :maxlen
def initialize
@maxlen = 1
@vocab = (0..255).map(&:chr).each_with_index.to_a.to_h
end
def size
vocab.size
end
def inverted
vocab.invert
end
def encode_next_token(text)
maxlen
.downto(0)
.find { |l| vocab.key?(text[...l]) }
.then { |l| text[...l] }
.then { |token| [vocab[token], text[token.length..]] }
end
def add_pair(pair)
reverse_lookup = @vocab.invert
new_token = reverse_lookup[pair[0]] + reverse_lookup[pair[1]]
@maxlen = [@maxlen, new_token.length].max
@vocab[new_token] = @vocab.values.max + 1
[pair, @vocab[new_token]]
end
end
class BPEHashBuilder
attr_reader :bpe_hash
def initialize(bpe_hash)
@bpe_hash = bpe_hash
end
def extend_vocabulary(tokens)
pair = tokens
.each_cons(2)
.tally
.max_by { |(_, c)| c }
.then { |(v, c)| c > 1 ? v : nil }
bpe_hash.add_pair(pair) unless pair.nil?
end
end
end
def replace_all(tokens, new_pair, new_token)
loop do
index = tokens.each_cons(2).find_index(new_pair)
break unless index
tokens[index..index+1] = new_token
end
end
vocab = Tokenizer::BytePairHash.new
builder = Tokenizer::BPEHashBuilder.new(vocab)
text = File.read('the-verdict.txt')
tokens = Tokenizer.encode(text, vocab)
loop do
new_pair, new_token = builder.extend_vocabulary(tokens)
break if new_pair.nil?
replace_all(tokens, new_pair, new_token)
end
encoded = Tokenizer.encode('hello world', vocab)
pp encoded
pp Tokenizer.decode(encoded, vocab)
רוצים בשביל המשחק לממש בשפה שאתם אוהבים? אל תתביישו ושתפו בתגובות את המימוש שכתבתם אני אשמח לראות ובטוח שתלמדו מהתהליך.1 419
מה זה Byte Pair Encoder
אנחנו יודעים שמודל שפה גדול הוא בסך הכל מכונה שיודעת לנחש בצורה מאוד טובה מה ה"מילה" הבאה בטקסט. אבל בהקשר של מודל השפה מה זה בכלל אומר "מילה"? ואיך המודל יודע איזה מילים יש בעולם? ואיך הוא לא מתבלבל כשאני כותב רק חלק ממילה או מילה שלא קיימת? ומה הם אותם טוקנים שעבורם אנחנו משלמים בעבודה עם מודלי השפה?
היחידה הבסיסית איתה מודל שפה גדול עובד נקראת טוקן ובפוסט זה אסביר מה זה Byte Pair Encoder וגם נכתוב אחד ב Ruby כדי להבין איך LLM רואה את העולם.
הדבר הראשון שאתם צריכים לדעת כשחושבים על איך LLM רואה את העולם הוא ש LLM הוא מכונה סטטיסטית ולכן בשביל "לנחש" מה המילה הבאה הוא צריך קודם להפוך את המילים למספרים רציפים. התהליך שבו אנחנו הופכים מילים למספרים נקרא Tokenization וכל מספר שמתקבל נקרא טוקן.
אז איך הופכים משפט לאוסף של מספרים? רעיון ראשון שלא עובד כל כך טוב הוא לרוץ על המילים ולתת לכל מילה מספר אקראי. נשמור את המספרים האלה ובפעם הבאה שניתקל במילה נשתמש באותו מספר. המילון שמחזיק את המיפוי מכל מילה למספר שמתאים לה נקרא אוצר המילים. הרעיון הזה לא עובד כל כך טוב כי הוא לא מאפשר למודל לראות חלקי מילים או מילים חדשות, ולא מאפשר למודל לראות את הקשר בין מילים עם אותיות דומות.
רעיון שני שלא עובד כל כך טוב הוא האפשרות ההפוכה - נחליף כל אות במספר (למשל ערך ה ASCII שלה) ונאמן את המודל לנחש את האות הבאה.
כשאנחנו בונים אוצר מילים אנחנו רוצים לשלב בין שני הרעיונות - מצד אחד אנחנו רוצים שכל מילה תקבל מספר באוצר המילים כדי שהמודל יוכל "לראות" את אותה המילה כל פעם שהיא מופיעה בטקסט. מצד שני אנחנו רוצים לאפשר למודל לייצג גם מילים שלא ראינו מראש באוצר המילים. הדרך לשילוב נקראת Byte Pair Encoding וזה נראה כך:
1. נותנים לכל אות מספר, למשל ערך ה ASCII שלה.
2. לוקחים קטע טקסט שיש בו המון מילים. ממנו נבנה את אוצר המילים. מחליטים גם על גודל אוצר המילים הרצוי.
3. מחפשים בקטע את זוג האותיות שמופיע הכי הרבה פעמים. נותנים לו מספר ומוסיפים אותו בתור "מילה" לאוצר המילים. אחרי זה מחליפים כל מופע של אותו זוג בטוקן החדש שיצרנו.
4. חוזרים על התהליך עד שאוצר המילים מגיע לגודל הרצוי.
שימו לב שהמילים שאנחנו בונים בצורה הזאת יכולות להיות באורך 1 (אם אות מסוימת לא מופיעה אף פעם בתור זוג שחוזר על עצמו), באורך 2 וגם יותר ארוכות. ניקח לדוגמה את הטקסט הבא לצורך בניית אוצר מילים:
aa aa bb aabb
אז באיטרציה הראשונה אנחנו מחליפים כל אות במספר. בשביל הדוגמה אני מחליף את a ב-1, את b ב-2 ואת רווח ב-0:
[1, 1, 0, 1, 1, 0, 2, 2, 0, 1, 1, 2, 2]
עכשיו אני מזהה את הרצף שמופיע הכי הרבה פעמים זה יהיה 1,1 שמופיע 3 פעמים ולכן אני יוצר מספר חדש, המספר 4 שמחליף את 1,1:
[4, 0, 4, 0, 2, 2, 0, 4, 2, 2]
בסיבוב הבא יש לי כמה אפשרויות אני יכול לבחור את 4,0 שמופיע פעמיים, את 0,4 שמופיע פעמיים או את 2,2 שמופיע פעמיים. בואו ניקח את 4,0 וניתן לו את הערך 5:
[5, 5, 2, 2, 0, 4, 2, 2]
עכשיו אוצר המילים שלנו כבר מורכב מ:
" " - 0
a - 1
b - 2
aa - 4
"aa " - 5
שימו לב שהמספר 5 הוא טוקן שמייצג טקסט באורך 3 תווים. הזוג הבא הכי נפוץ הוא 2,2 שמופיע פעמיים אז נקרא לו 6 ונקבל:
[5, 5, 6, 0, 4, 6]
ומפה כבר אי אפשר להמשיך כי כל הזוגות מופיעים רק פעם אחת. קיבלנו אוצר מילים בו נוכל להשתמש כדי לקודד כל טקסט חדש. כל מילה תהפוך למספר אחד או יותר ואפשר לקודד גם מילים שלא הופיעו בתור "מילים" באוצר המילים המקורי כלומר גם מילים חדשות.
בעולם האמיתי כמובן שהטקסט ממנו אנחנו בונים את אוצר המילים צריך להיות הרבה יותר ארוך ולהיות כמה שיותר דומה מבחינת תדירות הופעת המילים לטקסט האמיתי שהמודל יצטרך לנחש. היינו רוצים שיהיו כמה שיותר מילים באוצר המילים ושיהיו כמה שפחות מילים שהמודל לא מכיר. אתם יכולים לראות דוגמה להמחשה בקישור:
https://www.bpe-visualizer.com
יש הרבה ספריות שעושות BPE ובקונטקסט של עבודה בטוח כדאי לקחת ספריה קיימת לכזה קידוד. אני מימשתי אחד בשביל המשחק ברובי בביצועים די גרועים וזה הקוד:
module Tokenizer
def self.encode(text, vocab)
remaining = text
encoded = []
until remaining.empty?
token, remaining = vocab.encode_next_token(remaining)
encoded << token
end
encoded
end
def self.decode(encoded, vocab)
inv = vocab.inverted1 419
ואלה בדיוק דברים שמפתחים אנושיים, אפילו ג'וניורים, מאוד טובים בהם. כבני אדם אנחנו יודעים לשים לב כשעובדים עלינו, אנחנו שמים לב כשדברים לא הגיוניים, אנחנו יודעים לשאול שאלות ולהזיז דברים למקום המתאים להם. גם אם אנחנו לא תמיד זוכרים אם צריך לכתוב desc או description או אם זה
redirect או redirect_to.
הנה ההזדמנות בעבודה עם AI - לקבל גירסה של פיתרון שהיא טיוטה. לשאול עליה שאלות. להבין מה המשמעות של כל בחירה ובסוף להחליט על המבנה הנכון עבור המערכת שלכם. ואז לעדכן את קוד המערכת ואת קבצי ההוראות לסוכן כדי שפעם הבאה התשובה תהיה קצת יותר עקבית.1 419
שינויים קטנים שמצטברים
כל עוד AI מתעקש לייצר את אותן בעיות בקוד שהוא כותב וכל עוד למרות כל הבעיות הוא חוסך לנו זמן כדאי שנכיר את אותן תבניות ובעיות נפוצות. הנה קטע קוד שקיבלתי מ AI:
class UserSelectionsController < ApplicationController
before_action :require_login
before_action :find_chat_and_message
def create
# Handle initial selection creation (if needed in the future)
# For now, redirect to chat
redirect_to chat_path(@chat)
end
def update
# Use the service to handle the selection
service = UserSelectionService.new(
chat: @chat,
message: @message,
user: current_user
)
if params[:text_input].present?
service.handle_selection(text_input: params[:text_input].strip)
elsif params[:option_id].present?
service.handle_selection(option_id: params[:option_id])
else
redirect_to chat_path(@chat), alert: "Invalid selection"
return
end
redirect_to chat_path(@chat)
rescue => e
Rails.logger.error "UserSelection error: #{e.message}"
Rails.logger.error e.backtrace.join("\n")
redirect_to chat_path(@chat), alert: "Something went wrong"
end
private
def find_chat_and_message
@chat = current_user.chats.find(params[:chat_id])
@message = @chat.messages.find(params[:message_id])
rescue ActiveRecord::RecordNotFound
redirect_to new_chat_path, alert: t('chat.not_found')
end
end
לא צריך להכיר רובי בשביל לראות את הבעיות:
1. פונקציית create ריקה. אפילו ההערה מסבירה שזה רק הכנה לעתיד. בן אדם לא היה משאיר אותה, AI פוחד למחוק.
2. הפונקציה השניה update מסתיימת בפקודת rescue שכותבת ללוג את השגיאה ומחזירה למשתמש הודעה Something went wrong. פונקציית find_chat_and_messag תופסת שגיאה ומחזירה למשתמש הודעה מתוך קובץ ההודעות המתורגמות. בן אדם היה בוחר דרך אחת ומשתמש בה בשתי הפונקציות. כש AI כותב קוד הוא לא יודע מה הוא כתב קודם.
3. הפונקציה require_login מוודאת שיש משתמש נוכחי מחובר. הפונקציה find_chat_and_message משתמשת במשתמש הנוכחי כדי להגיע לשיחה. אין טעם לקרוא לשתיהן כי השנייה כבר כוללת גם את הלוגיקה של הראשונה. AI לא יכול לראות את זה.
4. הפונקציה update כוללת שני מנגנונים לטיפול בשגיאות, יש שם if else שמטפל במצב בו לא עבר פרמטר שהפונקציה ציפתה לקבל וגם rescue שמטפל בבעיות אחרות. בן אדם היה מוודא שקוד הטיפול בשגיאה, כלומר הקריאה ל redirect_to תופיע רק פעם אחת.
5. בפונקציה update קוד הטיפול בשגיאות מטפל בכל Exception. ב find_chat_and_message יש טיפול רק ב ActiveRecord::RecordNotFound.
6. הטיפול בשגיאות הוא תמיד מקומי. כש AI כותב את קוד הטיפול בשגיאות הוא לא יכול לשים לב שאפשר לכתוב קוד טיפול בשגיאות במקום יותר "גבוה" בשרשרת הקריאות כדי לכסות יותר מקרים.
7. הפונקציה update כוללת את הבלוק הזה:
if params[:text_input].present?
service.handle_selection(text_input: params[:text_input].strip)
elsif params[:option_id].present?
service.handle_selection(option_id: params[:option_id])
...
הפונקציה handle_selection שמופעלת מתוך הבלוק כוללת את הבלוק הזה:
def handle_selection(option_id: nil, text_input: nil)
if text_input.present?
handle_text_selection(text_input)
elsif option_id.present?
handle_option_selection(option_id)
else
raise ArgumentError, "Either option_id or text_input must be provided"
end
end
קיבלנו את אותה בדיקה בשני מקומות עם שני מנגנוני זריקת שגיאה שונים. בן אדם היה כותב ב update:
service.handle_selection(params)
ונותן ל if הפנימי לבדוק מה עבר, או מפצל את הקוד ב service לשתי פונקציות ומוותר על ה if שם. AI לא יודע מה הוא כבר כתב אז הוא משכפל.
כל הבעיות האלה לא ייחודיות לרובי ולא ייפתרו על ידי "קבצי הוראות טובים יותר" או "מודלים חכמים יותר". אלה בעיות מובנות במודלי שפה גדולים - קוד לא עקבי, פחד למחוק, חוסר יכולת לראות קשר בין חלקים שונים במערכת ובחירה מושכלת באיזה חלק במערכת צריך לכתוב כל מנגנון.1 419
היום למדתי: פונקציית random ב CSS
אני מודה כששמעתי על הפיצ'ר random ב CSS השאלה הראשונה שלי היתה - מספרים אקראיים ב CSS? למה??
אבל אז הורדתי את Safari Technology Preview החדש וניסיתי למשל את הדמו של הכוכבים:
body {
background: black;
}
.star {
background-color: white;
border-radius: 50%;
aspect-ratio: 1/1;
width: random(2px, 10px, 1px);
position: fixed;
top: random(0%, 100%);
left: random(0%, 100%);
}
לינק לקודפן:
https://codepen.io/ynonp/pen/XJmYaae
ובאמת יש משהו נחמד ברקע שכל פעם נטען עם כוכבים במקום אחר.
מצד שני - תמיכת דפדפנים מאוד בעייתית, אין קונצנזוס על הפיצ'ר ולא נראה שמישהו חוץ מאפל רוצה לבנות אותו (אין אפילו עמוד ב mdn או ב caniuse).
כאן יש מדריך די מקיף מהבלוג של וובקיט על הפיצ'ר וכל הדברים המדליקים שאפשר יהיה לעשות עם random יום אחד אם הוא ייכנס לחיים שלנו:
https://webkit.org/blog/17285/rolling-the-dice-with-css-random/
עד אז נמשיך להגריל ערכים באמצעות JavaScript.
اکنون در دسترس! پژوهش تلگرام ۲۰۲۵ — مهمترین بینشهای سال 
