קופיילוט · שם קוד · איך זה עובד

איך לרמות בשם קוד

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

מנוע · fastText ללא LLM מקומי · CPU המודל · 369MB (היה 7.2GB)
‹ נסו את הקופיילוט מקורות
01

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

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

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

שלך יריב ניטרלי מתנקש
02

פונקציית הניקודDETECT — קרבה מדורגת עם קנסות, אחרי תיקון אניזוטרופיה

הקופיילוט מדרג כל מילה־מועמדת מאוצר הרמזים לפי ציון מדורג: בונוס על קרבה למילים שלך, וקנס הולך וגדל ככל שמתקרבים ליריב, לניטרלי, ובעיקר למתנקש. זה הניסוח (s′ היא קוסינוס ממורכז סביב 25 מילות הלוח — תיקון אניזוטרופיה כך שמילים נפוצות "קרובות לכולם" לא מנצחות):

g(c) = Σ s′(c, b) // top-m of your words — reward λₐ · max(0, s′(c, assassin)) // the black card — avoid hardest λₒ · max(0, max s′(c, opp)) // rival team — avoid strongly λₙ · max(0, max s′(c, neutral))// bystanders — avoid mildly + λ_f · FREQ(c) // prefer mid-frequency words where s′(c, w) = cos(c, w) − mean_b cos(c, b)

שלושת הקנסות הם מדורגים: λₐ ≫ λₒ > λₙ. ככה הקופיילוט "מפחד" מהמתנקש הרבה יותר מאשר מקלף ניטרלי. הרמז שמנצח הוא לא בהכרח הכי קרוב למילים שלך — אלא זה שמשיג את ההפרדה הנקייה ביותר בין שלך לכל השאר.

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

03

למה fastText, ולא LLMמדדנו. הוותיק הקטן ניצח את המודלים הגדולים

זה לא היה ניחוש. ערכנו מבחן ראש־בראש: כל אנקודר שיחק רב מרגלים על אותם לוחות ואותו אוצר רמזים, ומדדנו כמה טוב מנחש עצמאי משחזר את המילים שהאנקודר התכוון אליהן (recovery), ועד כמה הרמז שומר מרחק מהמתנקש.

12 לוחות · אותו אוצר רמזים (שמות עצם/תארים) · מנחש־שופט עצמאי. recovery וגם margin — גבוה יותר = טוב יותר.
אנקודרrecoverymargin (הפרדה)סוג
fastText0.3750.194וקטורים סטטיים
EmbeddingGemma‑300m0.2920.131SOTA‑small 2025
Qwen3‑Embedding‑0.6B0.1250.112סנטנס‑אמבדינג

למה דווקא הסטטי? כי "שם קוד" דורש אסוציאטיביות (מלך→כתר→טירה), לא נרדפוּת. וקטורים סטטיים מבוססי הופעה־משותפת לוכדים בדיוק את זה — וזו הסיבה שספרות ה‑AI של המשחק משתמשת בהם. מודלי סנטנס־אמבדינג מאומנים על דמיון משפטים, ולמילה בודדת הם דוחסים את כל הקוסינוסים לטווח צר וגבוה (qwen בקושי הבדיל בין "מלך·מלכה" ל"מלך·ים"). ועל הלוח אין הקשר — בדיוק היתרון היחיד של מודל קונטקסטואלי מתבטל.

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

04

האתגר העברישורשים, מורפולוגיה, ואניזוטרופיה

חוקיות: שורש, לא מחרוזת

חוקי המשחק אוסרים רמז שחולק שורש עם מילה על הלוח. בעברית השוואת מחרוזות לא מספיקה — "קסם" ו"קוסם" חולקים שורש אבל נראים שונים, ו"בבית" הוא בכלל "בית". הפתרון בנוי בשכבות: למטיזציה מבוססת DictaBERT שמקלפת תחיליות (ב/כ/ל/מ/ה/ו) ונטיות; מעליה חתימת־שורש עיצורית שמנטרלת אותיות שימוש (מ/ה/נ בתחילית, אהו״י באמצע, וסיומות) — כך "רכבת/רכב", "שומר/שמירה" וגם "פחד/מפחיד/פחדן" נתפסים כאותו שורש; ולבסוף בדיקת הכלה שתופסת הכפלות והקטנות שהשוואת שורש מפספסת — "כלבלב" ליד "כלב", "חתלתול" ליד "חתול". זו הֵאוריסטיקה דטרמיניסטית, מהירה ואופליין, שמכוּונת לפסול־ביתר ולא להחמיץ (אין מודל מודרני שמחזיר שורש עברי כשדה — בדקנו).

אוצר וסינון

אוצר הרמזים הוא כ‑5,260 שמות עצם ותארים בתדירות בינונית (לא מילות תפקוד, לא זבל נדיר) — כך שכמעט כל מילה עברית מוכרת היא מועמדת לגיטימית, לא רשימה קצרה וקבועה. מילים פוגעניות מסוננות מראש מהאוצר באמצעות רשימת חסימה.

מורפולוגיה: subwords

מכיוון ש‑fastText בנוי על n‑gramים של אותיות, הוא נותן וקטור הגיוני גם למילה שלא ראה מעולם — הטיה, מילה עם אות יחס, או רמז שהמשתמש הקליד. זה מה ששומר על הכיסוי בעברית בלי טבלת מילים ענקית.

אניזוטרופיה: ניקוי המפה

וקטורים בעברית נוטים להצטופף לפי תדירות ואורך, לא רק לפי משמעות — קונוס משותף שמעוות מרחקים. אנחנו מסירים את k=3 הצירים הראשיים (all‑but‑the‑top, Mu & Viswanath) לפני ההקרנה, וזה פותח את המפה חזרה כדי שתראה פיזור סמנטי ולא פיזור־תדירות.

05

המפה הסמנטיתלמה הרמז יושב במרכז המילים שלך

המפה שמתחת ללוח היא ההקרנה ל‑2D של אותו מרחב. בונים מטריצת מרחקי קוסינוס בין כל המילים והרמז, ומקרינים אותה עם MDS קלאסי (Torgerson) — מירכוז כפול של מטריצת המרחקים בריבוע, ושני הווקטורים העצמיים הגדולים. הכול ב‑numpy טהור, בלי תלות נוספת.

הטמעה — כל מילות הלוח + הרמז לווקטורים (fastText).
ניקוי — הסרת קונוס התדירות (all‑but‑top k=3).
מרחקים — מטריצת 1 − cos בין כל הזוגות.
הקרנה — MDS קלאסי לשני ממדים.
ציור — הרמז כצומת זוהר, קווי זהב למילות היעד.

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

06

דחיסה ללא אובדן7.2GB → 369MB, ואותם רמזים בדיוק

המודל המלא של fastText שוקל 7.2GB — רובו מטריצת אימון שמיותרת בהסקה, ומיליוני מילים שלעולם לא נשתמש בהן. דחסנו אותו עם compress‑fasttext (גיזום אוצר־מילים + n‑gramים + fp16), ובדקנו שזה לא פוגע: על 12 לוחות, המודל הדחוס בחר בדיוק את אותו רמז ב‑12 מתוך 12, עם recovery ו‑margin זהים לחלוטין.

20×
קטן יותר (7.2GB→369MB)
12/12
אותו רמז כמו המלא
0.9985
קורלציית גאומטריה
וריאנטים של דחיסה מול המודל המלא. fp16 הוא זה ששוגר.
וריאנטגודלקורלציהאותו רמזrecovery
מלא7.2GB1.0000.375
ברירת־מחדל14MB0.645/120.250
PQ גדול107MB0.966/120.250
fp16 ✓369MB0.998512/120.375
07

חוגת הסיכוןזהיר · מאוזן · נועז — אותה גאומטריה, תיאבון אחר

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

מצבמכסהקנס מתנקש/יריב/ניטרליהתנהגות
זהיר23.0 · 1.5 · 0.5רק רמזים בטוחים, מסרב יותר
מאוזן22.0 · 1.0 · 0.3ברירת המחדל
נועז31.5 · 0.7 · 0.2מכסה יותר, סובל קרבה ליריב

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

08

מגבלות וכנותאיפה זה נשבר, ומה לא מדדנו

הדרך השנייה לרמות. אפשר גם בכוח גס: הריפו durfi/codenames מתעלם מ‑embeddings ומנצל שיש כמות מוגבלת של מפות מפתח — ומסיק לאחור מהלוח איזו מפה שוחקה. ההגנה פשוטה: להגריל מפה אקראית בכל סבב.