- קובץ provider_limits.md עם טבלת caps עדכנית, מקור רשמי ותאריך בדיקה לכל ספק שתשתמשו בו
- קובץ providers.yaml עם base_url, model, use case ו-fallback_order לכל ספק חינמי
- סקריפט Python בשם run_once.py שמריץ prompt מול Groq ומול Cerebras דרך אותו OpenAI-compatible client
- מודול rotation_backoff.py עם retry-after, exponential backoff, jitter ו-graceful degradation על 429
- קובץ multi_model_ab_test.csv שמשווה תשובות, latency, provider, status ודירוג שימושיות בין כמה מודלים
- README קצר שמסביר איך להריץ את כל זה בלי לחשוף API keys ובלי להתחייב לתשלום
- תוכל/י לקרוא למודל 70B דרך Groq ו-Cerebras בקוד עם OpenAI-compatible client ולקבל תשובה מתועדת
- תוכל/י להשוות את המגבלות החינמיות של Groq, Cerebras, OpenRouter ו-Google AI Studio ולבחור ספק לפי משימה
- תוכל/י לממש rotation בין ספקים ו-retry עם exponential backoff כדי לשרוד 429 ולהישאר מתחת ל-daily caps
- תוכל/י לבנות multi-model A/B prompt tester שמשווה תשובות ממספר מודלים חינמיים ומייצא טבלת החלטה
- פרקים קודמים: פרק 1 — מפת ה-Free Compute. צריך להבין את ההבדל בין notebook GPU, inference API ו-local inference.
- חשבונות וכלים: Python 3.10 ומעלה, terminal, git, עורך קוד, חשבון Groq, חשבון Cerebras, חשבון OpenRouter וחשבון Google AI Studio. כולם יכולים להתחיל בחינם; חלקם עשויים לבקש אימות בסיסי.
- ידע נדרש: מה זה API key, מה זה HTTP request, ומה זה LLM. לא נלמד כאן Python מאפס, אבל כל הקוד מספיק קצר כדי שתוכלו לערוך אותו.
- זמן משוער: 2.5 עד 3.5 שעות כולל תרגילים. אם כבר יש לכם API keys, אפשר לסיים את הליבה בשעה וחצי.
- עלות: 0 ש"ח לפרק הזה אם נשארים תחת ה-free caps ולא מוסיפים billing. לעבודה עם דאטה של לקוחות ישראליים, נפריד בין ניסוי חינמי לבין שימוש שמחייב תנאי פרטיות טובים יותר.
בפרק 1 בניתם מפת החלטה שמראה מתי צריך GPU notebook, מתי inference API מספיק, ומתי local inference עדיף. בפרק הזה אתם מוסיפים למפה שכבת ביצוע אמיתית: קוד שקורא למודלים גדולים דרך APIs חינמיים, מודד מגבלות, ומחליף ספקים כשמגיעה שגיאת 429. בפרק 3 תשתמשו באותה חשיבה כדי לעבור ל-Colab ו-Kaggle כשכבר לא מספיק לקרוא למודל דרך API וצריך להריץ training, fine-tune או inference עם שליטה בחומרה.
| מונח | עברית | הגדרה קצרה |
|---|---|---|
| Inference API | ממשק הרצת מודל | API שמריץ מודל על שרתי הספק ומחזיר תשובה. אתם שולחים prompt ומקבלים completion, בלי GPU מקומי. |
| OpenAI-compatible | תואם OpenAI | מבנה API שמחקה את Chat Completions של OpenAI. אותו client יכול לעבוד מול Groq, Cerebras, OpenRouter, Gemini-compatible endpoint ועוד. |
| RPM | בקשות לדקה | Requests Per Minute. מגבלה על מספר הקריאות, גם אם כל קריאה קצרה מאוד. |
| RPD | בקשות ליום | Requests Per Day. התקציב היומי של מספר הקריאות. יכול להיגמר מהר ב-batch. |
| TPM | טוקנים לדקה | Tokens Per Minute. מגבלה על כמות הטקסט שנכנסת ויוצאת בדקה. |
| TPD | טוקנים ליום | Tokens Per Day. התקציב היומי של הטוקנים. חשוב במיוחד בסיכומים ארוכים. |
| 429 | יותר מדי בקשות | HTTP status code שאומר שעברתם limit. לא באג במודל; סימן שצריך להאט או לעבור ספק. |
| retry-after | חכה לפני ניסיון נוסף | Header שהספק יכול להחזיר עם מספר שניות להמתנה אחרי 429. |
| Exponential Backoff | המתנה גוברת | אסטרטגיה שבה מחכים יותר זמן בכל retry: 1 שנייה, 2, 4, 8, עם מעט random jitter. |
| Provider Rotation | סבב ספקים | מעבר מסודר בין ספקים כאשר ספק אחד נכשל, הגיע למגבלה, או מתאים פחות למשימה. |
| Graceful Degradation | ירידה מבוקרת באיכות | במקום לקרוס, המערכת מחזירה תשובה חלקית, עוברת למודל קטן יותר, או מבקשת לנסות שוב מאוחר יותר. |
| A/B Prompt Test | השוואת prompt בין מודלים | הרצת אותו prompt על כמה מודלים והשוואת איכות, זמן, עלות ומגבלות לפי rubric. |
למה Inference API הוא הניצחון המהיר
בפרק 1 ראינו שיש שלוש דרכים להריץ מודלים בחינם: notebook GPU, inference API ו-local inference. הנטייה הטבעית של הרבה vibe coders היא לקפוץ ישר ל-GPU: לפתוח Colab, לחפש T4, להתקין transformers, להוריד weights, ואז לגלות שהמודל לא נכנס ל-VRAM או שה-session התנתק. זה חשוב לדעת, אבל זה לא תמיד הצעד הראשון הנכון.
Inference API הוא הדרך הכי קצרה לקבל תוצאה ממודל גדול בלי לנהל חומרה. אתם לא מורידים model weights, לא מחשבים quantization, לא שואלים אם 70B נכנס ל-T4, ולא נלחמים ב-KV cache. אתם שולחים בקשת HTTP אל ספק שכבר מריץ את המודל על חומרה שלו. הספק דואג לשרת, ל-GPU או לחומרה הייעודית, ל-scaling ול-runtime. אתם דואגים ל-prompt, לקוד, למגבלות ולשאלה האם מותר לשלוח לשם את הדאטה.
זה לא אומר ש-inference API הוא תמיד הפתרון הטוב ביותר. אם אתם צריכים fine-tune, תעברו בפרק 3 ל-Kaggle או Colab. אם אתם צריכים פרטיות מלאה, בפרק 4 נלך ל-Ollama ול-local inference. אם אתם רוצים להריץ מודל בלי הגבלות בקצב גבוה, free API לא יספיק לאורך זמן. אבל לרוב המשימות הראשונות — proof of concept, coding helper, סיכום מסמכים לא רגישים, מחקר יומי, בדיקת prompt, סוכן קטן שמחבר כמה כלים — API חינמי נותן ניצחון מהיר ומלמד אתכם את החלק החשוב באמת: איך לבנות שכבת model access שלא תלויה בספק אחד.
הסיבה שהפרק הזה מגיע לפני GPU notebooks היא פסיכולוגית לא פחות מטכנית. כשהלומד רואה שמודל 70B עונה לו דרך קוד של 30 שורות, בלי GPU ובלי התקנות כבדות, המפה מפרק 1 מפסיקה להיות תיאוריה. פתאום ברור למה לא כל בעיה היא בעיית חומרה. אם המשימה היא inference בלבד — כלומר להריץ prompt ולקבל תשובה — אפשר להתחיל מהענן החינמי ולדחות את ענייני VRAM, checkpointing ו-session loss לשלב שבו באמת צריך אותם.
הדבר השני שחשוב להבין: free inference API הוא לא קסם חינמי. הוא עסקה. אתם מקבלים גישה למודל ולחומרה של ספק, ובתמורה מקבלים מגבלות: כמה בקשות בדקה, כמה בקשות ביום, כמה טוקנים בדקה, אילו מודלים זמינים, האם דאטה משמש לשיפור מוצרים, והאם יש SLA. אם מתייחסים ל-free tier כאילו הוא production paid tier, הוא ישבור אתכם. אם מתייחסים אליו כאל שכבת prototype, מחקר, workload קטן או fallback חכם, הוא יכול לחסוך לכם מאות שקלים בחודש בתחילת הדרך.
פתחו תיקייה חדשה בשם free-api-lab. בתוך התיקייה צרו קובץ notes.md ורשמו שלוש שורות: interactive, batch, comparison. ליד כל שורה כתבו דוגמה אחת מהחיים שלכם. למשל: interactive = עוזר קוד מהיר ב-VS Code; batch = סיכום 40 תקצירי מאמרים; comparison = להריץ אותו prompt על ארבעה מודלים ולראות מי כותב טוב יותר בעברית.
התרגיל הקטן הזה חשוב כי הוא מונע החלטות כלליות מדי. אין ספק אחד שהוא "הכי טוב". יש ספק שמתאים למשימה. Groq יכול להרגיש מעולה לצ'אט אינטראקטיבי בגלל latency נמוך, אבל פחות מתאים ל-batch גדול על מודל 70B עם cap יומי נמוך יותר. Cerebras יכול להיות חזק למשימה token-heavy אם אתם מסכימים לקצב בקשות נמוך. OpenRouter מצוין להשוואה בין מודלים כי הוא מאחד מודלים רבים תחת API אחד, אבל availability של free models יכולה להשתנות. Google AI Studio חזק במיוחד ל-long-context ו-multimodal, אבל המספרים המדויקים בדשבורד הם אמת המקור, לא פוסט ישן בבלוג.
יש עוד יתרון לא מובן מאליו: כשאתם בונים סביב OpenAI-compatible client, אתם לומדים ארכיטקטורה נכונה. הקוד שלכם לא אמור לדעת "אני משתמש ב-Groq" בכל שורה. הקוד אמור לדעת "אני קורא לספק שמוגדר בקונפיגורציה". זה ההבדל בין demo שנשבר כשמודל נעלם לבין כלי קטן שאפשר לתחזק. בפרק הזה נכתוב קוד שמתחיל פשוט, אבל המבנה שלו יהיה production-minded: סודות ב-.env, ספקים בקובץ config, limits בטבלה, retries במקום while loop עיוור, ו-output שמספר איזה ספק ענה ומה קרה בדרך.
הפרק כולו יישען על כלל אחד: ה-free tier הוא משאב מתכלה, לא הבטחה אינסופית. לכן לא נלמד רק "איך לשלוח request". זה קל. נלמד איך לדעת מתי request לא אמור להישלח, מתי להמתין, מתי לעבור ספק, מתי להחזיר תשובה חלקית, ומתי להחליט שהמשימה הזאת כבר לא מתאימה למסלול חינמי.
הספקים החינמיים: מי טוב לאיזו עבודה
בואו נמפה את הספקים כמו שממפים כלי עבודה, לא כמו רשימת קניות. כשנגר בוחר כלי, הוא לא שואל "מה הכלי הכי טוב?" אלא "מה אני צריך לחתוך, באיזה חומר, כמה פעמים, ומה יקרה אם הכלי יתחמם?" אותו דבר כאן. ספק inference API הוא לא רק מודל. הוא שילוב של model lineup, latency, caps, תנאי שימוש, זמינות, והיכולת שלכם להחליף אותו כשהוא לא מתאים.
Groq הוא בדרך כלל הבחירה הראשונה לצ'אט מהיר ול-vibe coding. לפי מחקר הקורס והבדיקה הרשמית של דף rate limits, מודלים כמו llama-3.1-8b-instant יכולים לקבל תקרה בסגנון 30 RPM, 14,400 requests/day ו-500K tokens/day, בזמן ש-llama-3.3-70b-versatile מוגבל יותר, למשל 1,000 requests/day ו-100K tokens/day. המספרים האלה רגישים לשינוי ותמיד צריך לבדוק בדשבורד, אבל הדפוס יציב: המודלים הקטנים/מהירים מקבלים יותר מרווח, המודלים הגדולים מקבלים פחות.
Cerebras הוא סוג אחר של חינם. הוא פחות מרגיש כמו צ'אט מהיר והרבה יותר כמו מנוע batch. דף rate limits הרשמי שנבדק ב-2026-06-01 מדבר על free trial tier עם 5 requests/minute ו-30K tokens/minute, ובחלק מהמודלים גם 1M tokens/day. יש כאן נקודה עדינה: אם אתם שולחים 50 סיכומים ארוכים בבוקר, 5 RPM לא מפריע מאוד; הם יסתיימו בהדרגה. אם אתם בונים chatbot שמחכה לתגובה אנושית בכל הודעה, 5 RPM יכול להרגיש כמו פקק תנועה.
OpenRouter הוא router. הערך שלו הוא לא רק free models, אלא העובדה שאפשר לקרוא למודלים רבים דרך API אחד ולשמור response schema אחיד. במחקר הקורס נשמרו 27 free models נכון למאי 2026, עם דפוס של 200 requests/day למודל חינמי ו-20 RPM. אבל free models מסתובבים. ספק יכול להוריד model מ-free, לשנות provider, להוסיף queue, או לשנות context window. לכן בפרק הזה נשתמש ב-OpenRouter בעיקר ל-A/B testing ולבדיקת איכות בין מודלים, לא כעמוד יחיד שעליו עומד production.
Google AI Studio / Gemini API מתאים כאשר המשימה ארוכה, multimodal או צריכה context גדול. מחקר הקורס דיבר על Gemini 2.5 Flash עם כ-1,500 requests/day, אבל דפי Google המעודכנים ל-2026-05-28/29 מדגישים שה-rate limits משתנים לפי מודל, project tier וחשבון, ושאת המספר המדויק רואים ב-AI Studio. זאת תובנה קריטית: אל תבנו קוד שמניח ש-1,500 הוא מספר קבוע. בנו קוד שבו Gemini הוא provider עם limit שנבדק ונרשם בתאריך מסוים.
Hugging Face Inference Providers ו-Together AI הם שימושיים, אבל לא באותה קטגוריה של "חינמי לאורך זמן". HF נותן לפי מחקר הקורס קרדיט חודשי זעיר של $0.10 לחשבון חינמי, וזה יותר trial budget מאשר runtime אמיתי. Together AI מציע signup credit חד-פעמי, למשל סביב $1 במחקר, וזה טוב לבדיקות, לא לתכנון חודשי. נזכיר אותם כדי שתדעו שהם קיימים, אבל לא נבנה את תרגילי הליבה עליהם.
אם המשימה היא interactive, כמו coding helper, assistant פנימי או צ'אט קצר שצריך להרגיש מיידי → אז התחילו ב-Groq, במיוחד עם מודל מהיר ותקציב RPD גדול יחסית.
אם המשימה היא batch עם הרבה טוקנים ומעט לחץ בזמן אמת, כמו daily research digest או סיכום מסמכים לא רגישים → אז בדקו Cerebras, אבל תכננו תור בגלל 5 RPM.
אם אתם רוצים להשוות מודלים, לבדוק prompt בעברית או למצוא מודל שנותן סגנון טוב יותר → אז OpenRouter הוא שכבת ניסוי נוחה, בתנאי ששמות המודלים נשארים בקונפיגורציה ולא hard-coded.
אם המשימה כוללת context ארוך, multimodal input או נוחות דרך Google account → אז Gemini דרך AI Studio יכול להיות הבחירה, אבל המספרים נבדקים בדשבורד לפני שמתחילים.
אם הטקסט כולל מידע לקוחות, הסכמים, מידע רפואי, כספי או כל דבר שלא הייתם שולחים ב-WhatsApp לקבוצה הלא נכונה → אז עצרו. או שמאנונימיזציה, או שעוברים ל-paid terms, או שמחכים לפרק 4 ול-local.
צרו קובץ provider_limits.md. הוסיפו טבלה עם העמודות: ספק, use case, cap ראשון שיישבר, URL לבדיקה מחדש, תאריך בדיקה. מלאו ארבע שורות ראשונות: Groq, Cerebras, OpenRouter, Gemini. גם אם עוד לא פתחתם חשבונות, כתבו את המקור הרשמי שאתם תבדקו ממנו. המטרה היא להפסיק להחזיק limits בזיכרון.
הטעות: להעתיק מגבלה כמו 1,000 requests/day או 200 requests/day ולכתוב אותה בקוד כאילו היא חוק טבע.
למה זה מפתה: מספרים נותנים ביטחון. קל יותר לתכנן סביב מספר אחד מאשר לבדוק דשבורד כל פעם.
מה עושים במקום: בכל טבלת limits כתבו מקור ותאריך בדיקה. בקוד שמרו את המספרים בקונפיגורציה, לא בתוך הפונקציה. בפרויקטים ללקוח ישראלי, הוסיפו תזכורת חודשית של 10 דקות לבדוק אם free tier עדיין מתאים. עלות בדיקה היא 0 ש"ח; עלות pipeline שנופל באמצע עבודה יכולה להיות שעות חיוב שלא תוכלו לגבות.
החלק החשוב בספקים החינמיים הוא לא "למצוא חור במערכת". המטרה אינה לנצל caps עד הסוף, אלא לבנות הרגלי תפעול נכונים. אם אתם יודעים ש-Groq נותן חוויית interactive טובה, תשתמשו בו כשמשתמש מחכה מול המסך. אם אתם יודעים ש-Cerebras מתאים ל-batch, תפעילו אותו בבוקר על תור. אם OpenRouter מתאים להשוואת מודלים, תשתמשו בו ככלי החלטה, לא כתחליף לחשיבה על availability. ואם Gemini דורש בדיקה בדשבורד, תכניסו את הבדיקה לתהליך. זה מה שמפריד בין סקריפט נחמד לבין כלי שאפשר להראות למישהו אחר בלי להתבייש.
Caps: לקרוא RPM/RPD/TPM בלי ליפול
הסיבה המרכזית ש-free APIs מרגישים לא אמינים היא שרוב האנשים קוראים רק שורה אחת מתוך טבלת המגבלות. הם רואים "14,400 requests/day" וחושבים: מעולה, זה מספיק. ואז הסקריפט נופל אחרי 30 בקשות בדקה הראשונה. למה? כי הגעתם ל-RPM לפני שהגעתם ל-RPD. ספקים לא מגבילים רק לפי כמות יומית. הם מגבילים בכמה צירים במקביל, וכל ציר יכול לעצור אתכם.
RPM — Requests Per Minute — הוא קצב. אם ה-RPM הוא 30, אתם יכולים לשלוח בממוצע בקשה אחת כל שתי שניות. זה נשמע סביר לצ'אט, אבל מסוכן ל-batch. אם יש לכם 100 פריטים ואתם מפעילים אותם במקביל עם asyncio.gather בלי semaphore, אתם יכולים לקבל גל של 429 כמעט מיד. זה לא אומר שהספק "לא עובד". זה אומר שהקוד שלכם לא מכבד את הקצב.
RPD — Requests Per Day — הוא התקציב היומי. הוא עונה על שאלה אחרת: כמה קריאות אפשר לעשות ביום. אם יש לכם 1,000 RPD למודל 70B, זה מספיק לבוט פנימי קטן, לא ל-pipeline שמסכם 5,000 שורות CRM. כאן צריך rotation, דגימה, caching או החלטה להשתמש במודל קטן יותר. לפעמים הפתרון הוא לא "עוד ספק" אלא "פחות קריאות": לאחד prompts, לשמור תוצאות, להריץ רק על שורות חדשות, או להוריד frequency.
TPM ו-TPD הם מגבלות הטוקנים. הן חשובות במיוחד בסיכום מסמכים, long-context, מחקר, תרגום או קוד ארוך. שתי בקשות יכולות להיות שונות לגמרי: prompt של 30 מילים לעוזר קוד לעומת PDF של 20 עמודים. אם אתם שולחים מעט בקשות אבל כל בקשה ענקית, RPM לא יהיה הבעיה; TPM או TPD יגיעו קודם. ב-Cerebras למשל יש דגש חזק על token rate, והדוקומנטציה אף ממליצה להגדיר max_completion_tokens באופן סביר כדי לא לגרום להערכת יתר של צריכת הטוקנים.
יש גם caps מיוחדים. Groq Whisper למשל נמדד לפי בקשות אודיו ו-audio seconds. Gemini מדבר על project tier ועל RPD שמאופס בחצות Pacific time. OpenRouter תלוי במודל, provider ותגית free. חלק מהספקים מחזירים headers עם כמה נשאר לכם. חלקם נותנים רק שגיאת 429. ולכן הקוד שלכם צריך להניח ש-cap הוא לא רק מספר, אלא מצב משתנה שנלמד תוך כדי ריצה.
אם יש לכם הרבה פריטים קצרים, כמו 2,000 תגובות קצרות לסיווג → אז RPM/RPD הם הסיכון. בנו queue, הגבילו concurrency, ושמרו cache.
אם יש לכם מעט פריטים ארוכים, כמו 20 מסמכים של 30 עמודים → אז TPM/TPD הם הסיכון. חלקו למסמכים קטנים, צמצמו prompt, והגדירו max output.
אם אתם עובדים עם אודיו, תמונות או קבצים → אז בדקו caps ייעודיים. אל תניחו שהם נספרים כמו טקסט.
אם אתם לא בטוחים → אז הריצו batch קטן של 10 פריטים, רשמו headers, latency, tokens ו-status, ורק אז הגדילו נפח.
בחרו אחת משלוש המשימות שכתבתם ב-notes.md. ליד המשימה כתבו מה כנראה יישבר ראשון: RPM, RPD, TPM או TPD. אל תחפשו תשובה מושלמת. כתבו ניחוש מנומק. למשל: "daily digest של 40 מאמרים — כנראה TPM, כי כל מאמר ארוך". הניחוש הזה יהפוך בהמשך לכלל תפעול.
הטעות: לקחת רשימת פריטים, לפתוח 30 או 100 tasks במקביל, ולהתפלא שמקבלים 429.
למה זה מפתה: ב-Python קל מאוד לכתוב async ולהרגיש שהמערכת "מהירה". אבל הספק רואה burst, לא את הכוונה שלכם.
מה עושים במקום: משתמשים בתור עם concurrency מוגבל, ומחשבים מרווח בטוח. אם ה-limit הוא 30 RPM, התחילו מ-20-24 RPM ולא מ-30. השאירו מרווח ל-retry, לסטיות clock ולבקשות ידניות. free tier לא חייב לעבוד על הקצה.
הדפוס הזה חשוב במיוחד לישראלים שעובדים עם לקוחות קטנים. נניח שאתם בונים כלי שמסכם פניות WhatsApp לעסק מקומי ומוציא המלצות מכירה. אם כל פנייה היא 300 מילים ויש 200 פניות ביום, אפשר להישאר חינמי אם מסכמים פעם בשעה, מאחדים פניות, ושומרים cache. אם מריצים סיכום לכל פנייה בזמן אמת על מודל 70B, תגיעו ל-limit ותייצרו מוצר לא אמין. אותה תוצאה עסקית — "בעל העסק מקבל סיכום" — יכולה לעלות 0 ש"ח או להפוך לכאב ראש, תלוי איך קראתם את ה-caps.
כדי להפוך את זה לכלל עבודה, חשבו על כל קריאה למודל כמו על פעולה בבנק זמן. בכל פעולה יש מחיר בקשות ומחיר טוקנים. הודעה קצרה של משתמש היא אולי בקשה אחת ו-500 טוקנים. מסמך ארוך עם הוראות מפורטות יכול להיות בקשה אחת אבל 18,000 טוקנים. אם אתם בונים כלי שמטפל בפניות לקוחות, אל תמדדו רק "כמה פניות". מדדו גם "כמה טקסט בכל פנייה" ו"כמה תשובה אני מבקש מהמודל". אפשר להקטין צריכת טוקנים בלי לפגוע בתוצאה: לשלוח רק את השדות הרלוונטיים, לסכם היסטוריה ישנה פעם אחת, לדרוש תשובה בפורמט קצר, ולהפריד בין שלב סיווג זול לשלב כתיבה יקר.
דפוס שימושי הוא two-pass routing. במקום לשלוח כל משימה למודל גדול, מריצים קודם מודל קטן ומהיר שמחליט מה סוג המשימה: שאלה פשוטה, סיכום קצר, בעיית קוד, או מקרה שדורש reasoning. רק המקרים הקשים עוברים למודל 70B. זה נשמע כמו אופטימיזציה מוקדמת, אבל בפרויקטים חינמיים זו לפעמים הדרך היחידה להישאר בתוך RPD ו-TPD. אם 80% מהפניות הן פשוטות, המודל הקטן חוסך לכם את רוב הקריאות היקרות. יתרון נוסף: הלוגים נעשים ברורים. אתם יכולים לראות כמה משימות באמת דרשו מודל גדול, ולא להסתמך על תחושה.
דפוס נוסף הוא daily budget envelope. בתחילת היום אתם קובעים תקציב: למשל עד 700 קריאות ל-Groq 70B, עד 300 קריאות ל-Cerebras, ועד 100 קריאות ל-OpenRouter לצורך השוואות. הקוד לא חייב לדעת את ה-quota הרשמי המלא; הוא צריך לדעת את התקציב הבטוח שלכם. ברגע שמתקרבים ל-80% מהתקציב, עוברים למודל קטן יותר או מכניסים בקשות לתור. ברגע שמתקרבים ל-95%, מפסיקים שליחה אוטומטית ומחזירים הודעת עומס. זה לא רק מגן מפני 429; זה מגן מפני הפתעות עסקיות, כי אתם שולטים בקצב במקום לתת לספק לעצור אתכם.
הקמה בטוחה: API keys, .env ולקוח אחיד
לפני שנכתוב request אחד, נסדר את הבית. רוב הדליפות בפרויקטים קטנים לא קורות בגלל hacker מתוחכם. הן קורות כי מישהו כתב API key בתוך קובץ, עשה git commit, העלה GitHub repo ציבורי, ואז גילה שהמפתח שלו זמין לכל העולם. גם אם free tier לא מחייב כרטיס אשראי, דליפת מפתח היא בעיה: אפשר לשרוף לכם quota, להשתמש בחשבון שלכם לרעה, או להכניס אתכם להפרת תנאים.
הכלל הפשוט: סודות חיים ב-.env, דוגמה חיה ב-.env.example, ושום secret לא נכנס ל-git. הקובץ .env נשאר אצלכם מקומית. הקובץ .env.example נכנס ל-repo ומראה למשתמשים אילו משתנים צריך להגדיר. אם אתם עובדים בצוות, מעבירים secrets דרך password manager, לא דרך Slack ולא דרך WhatsApp. אם אתם עובדים מול לקוח בישראל, בקשו ממנו לפתוח key בחשבון שלו, לא לשלוח לכם key אישי קבוע בלי בעלות ברורה.
צרו קובץ .env.example עם השורות הבאות בלבד: GROQ_API_KEY=, CEREBRAS_API_KEY=, OPENROUTER_API_KEY=, GEMINI_API_KEY=. אל תכניסו ערכים אמיתיים. זה קובץ הסבר, לא מחסן סודות.
# .env.example
GROQ_API_KEY=
CEREBRAS_API_KEY=
OPENROUTER_API_KEY=
GEMINI_API_KEY=
פתחו או צרו קובץ .gitignore והוסיפו את השורה .env. אחרי זה הריצו git status ובדקו שה-.env האמיתי לא מופיע. אם הוא מופיע, עצרו. אל תמשיכו עד שהוא מחוץ ל-git.
עכשיו נבנה client אחיד. הספרייה openai ב-Python מאפשרת לשנות base_url ו-api_key, ובכך להשתמש באותו pattern מול ספקים תואמי OpenAI. זה לא אומר שכל ספק תומך בכל parameter; צריך לקרוא docs. אבל בשביל קריאת chat completion בסיסית, זה מספיק טוב לתרגול ולרוב ה-prototypes.
python -m venv .venv
# Windows PowerShell
.\.venv\Scripts\Activate.ps1
python -m pip install openai python-dotenv pyyaml
אם PowerShell חוסם activation בגלל execution policy, אפשר להריץ את ה-Python מתוך ה-venv ישירות, או להשתמש ב-terminal אחר. העיקרון לא משתנה: תלות אחת ל-client, תלות אחת לקריאת env, ותלות אחת לקריאת YAML בהמשך. אל תתקינו frameworks כבדים לפני שיש request עובד.
# run_once.py
import os
import time
from dataclasses import dataclass
from dotenv import load_dotenv
from openai import OpenAI
load_dotenv()
@dataclass
class Provider:
name: str
env_key: str
base_url: str
model: str
PROVIDERS = {
"groq_70b": Provider(
name="groq_70b",
env_key="GROQ_API_KEY",
base_url="https://api.groq.com/openai/v1",
model="llama-3.3-70b-versatile",
),
"cerebras": Provider(
name="cerebras",
env_key="CEREBRAS_API_KEY",
base_url="https://api.cerebras.ai/v1",
model="llama3.3-70b",
),
}
def call_provider(provider_name: str, prompt: str) -> dict:
provider = PROVIDERS[provider_name]
api_key = os.getenv(provider.env_key)
if not api_key:
raise RuntimeError(f"Missing {provider.env_key} in .env")
client = OpenAI(api_key=api_key, base_url=provider.base_url)
start = time.perf_counter()
response = client.chat.completions.create(
model=provider.model,
messages=[
{"role": "system", "content": "Answer clearly and briefly."},
{"role": "user", "content": prompt},
],
temperature=0.2,
max_tokens=400,
)
elapsed = time.perf_counter() - start
return {
"provider": provider.name,
"model": provider.model,
"latency_seconds": round(elapsed, 2),
"answer": response.choices[0].message.content,
}
if __name__ == "__main__":
prompt = "Explain in Hebrew why inference APIs can run 70B models without my own GPU."
for provider_name in ["groq_70b", "cerebras"]:
result = call_provider(provider_name, prompt)
print("=" * 80)
print(result["provider"], result["model"], result["latency_seconds"])
print(result["answer"])
שימו לב לשני דברים בקוד. הראשון: שמות המודלים כאן הם נקודת התחלה, לא תורה מסיני. Cerebras, Groq וכל ספק אחר יכולים לשנות שמות, להוסיף aliases או להגביל מודלים לפי חשבון. אם שגיאת model not found חוזרת, אל תנסו לתקן עשרים דברים. בדקו קודם את דף models של הספק ועדכנו רק את הערך בקונפיגורציה.
השני: עדיין אין כאן retry. בכוונה. לפני שמוסיפים מנגנון התאוששות, צריך request עובד אחד. debugging של retry סביב key לא תקין הוא מתכון לבזבוז זמן. קודם מוודאים שה-key נכון, ה-base_url נכון, המודל זמין, והתשובה חוזרת. רק אחר כך מוסיפים rotation.
הטעות: לחשוב שאם יוצרים חמישה API keys באותו חשבון, קיבלתם פי חמישה free tier.
למה זה מפתה: זה נראה כמו פתרון קל. עוד key, עוד quota.
מה עושים במקום: קוראים איך הספק מודד limits. Google למשל מדגישה ש-rate limits חלים ברמת project, לא key. Groq מדבר על organization-level limits. הפתרון הנכון הוא להקטין קצב, לשמור cache, או לעשות rotation בין ספקים שונים לפי תנאים; לא לעקוף מדיניות עם key farming.
אם אתם בונים משהו עבור לקוח, צרו גם README קטן כבר עכשיו. כתבו בו: איך יוצרים venv, איך מעתיקים .env.example ל-.env, איפה שמים keys, איזה פקודה מריצים, ואיך יודעים שהכל עבד. זה נשמע מוקדם, אבל README שנכתב בזמן ההקמה מדויק יותר מ-README שנכתב אחרי שלושה ימים. הוא גם מונע מכם לשכוח החלטות כמו "השתמשנו ב-Groq לצ'אט וב-Cerebras ל-batch".
קריאה ראשונה למודל 70B בלי GPU
עכשיו מגיע הרגע שהופך את כל הקורס למוחשי: להריץ מודל גדול בלי GPU. חשוב לומר את זה במדויק. אתם לא "מריצים 70B על המחשב שלכם". אתם קוראים לספק שמריץ את המודל על חומרה שלו. זה הבדל משמעותי, כי הוא מסביר גם את הקסם וגם את המגבלות. הקסם: אין VRAM, אין weights, אין התקנה. המגבלות: quota, latency, זמינות, תנאים, פרטיות.
נריץ את הקוד בשלושה צעדים: קודם Groq, אחר כך Cerebras, ואז נשווה את התשובה. אם אחד מהם לא זמין בחשבון שלכם, אל תיתקעו. החליפו למודל זמין לפי docs. מטרת התרגיל היא לא להוכיח שדווקא שם מודל מסוים עובד לנצח, אלא להבין שהקוד יכול להחליף provider בלי לשנות את שאר האפליקציה.
זמן: 25-30 דקות. תוצר: קובץ run_once.py שמוציא תשובה משני ספקים ומדפיס provider, model ו-latency.
- פתחו חשבון Groq וצרו API key. שימו אותו ב-.env תחת
GROQ_API_KEY. - פתחו חשבון Cerebras וצרו API key. שימו אותו ב-.env תחת
CEREBRAS_API_KEY. - ודאו שה-.env לא מופיע ב-
git status. - העתיקו את הקוד של
run_once.pyמהסעיף הקודם. - הריצו
python run_once.py. אם provider אחד נכשל בגלל שם מודל, בדקו את דף models הרשמי ועדכנו רק את שדהmodel. - שמרו את הפלט בקובץ
first_run_output.txt: provider, model, latency ותשובה. - כתבו ב-notes.md משפט אחד: איזה provider הרגיש מתאים יותר ל-interactive ואיזה מתאים יותר ל-batch.
איך הצלחה נראית: בטרמינל מופיעות שתי תשובות או תשובה אחת ושגיאה מוסברת. הצלחה אינה אומרת שכל provider עבד; הצלחה אומרת שהקוד מבודד provider config, מדווח מה קרה, ולא מסתיר כישלון.
שנו רק את model ואת base_url בסקריפט. אם נאלצתם לשנות לוגיקת function, רשמו למה. המטרה היא להרגיש בגוף את הערך של OpenAI-compatible client: אותו pattern, ספק אחר.
אחרי הקריאה הראשונה, אל תמהרו לבנות מוצר. הנטייה היא להתלהב ולחבר UI. עצרו לעשר דקות ועשו postmortem קטן. כמה זמן לקחה הקריאה? האם התשובה הייתה טובה בעברית? האם prompt קצר מדי? האם output ארוך מדי? האם היה warning על rate limit? האם קיבלתם usage tokens? האם יש headers שמספרים כמה נשאר? מידע כזה הוא ההבדל בין "עובד אצלי" לבין "אני מבין איך זה יתנהג כשיהיו 100 בקשות".
הנה שדרוג קטן לקוד שמדפיס גם error בצורה שימושית. לא כל ספרייה חושפת את כל headers באותה צורה, ולכן נשמור את זה פשוט: נתפוס exception, נדפיס provider, סוג שגיאה והודעה קצרה. בשלב ה-rotation נוסיף טיפול עדין יותר ב-429.
def safe_call(provider_name: str, prompt: str) -> dict:
try:
return call_provider(provider_name, prompt)
except Exception as exc:
return {
"provider": provider_name,
"ok": False,
"error_type": type(exc).__name__,
"error_message": str(exc)[:500],
}
אם אתם מלמדים את זה בתוך צוות, אפשר להפוך את התרגיל לתחרות קטנה: מי מצליח לקבל תשובה טובה בעברית עם prompt קצר יותר? אבל אל תתנו לתחרות להפוך ל-benchmark מזויף. latency משתנה לפי עומס, מודל, אזור גיאוגרפי וחיבור. איכות תשובה תלויה ב-prompt. מה שמעניין אותנו הוא לא מספר חד-פעמי אלא תהליך מדידה: אותו prompt, אותו זמן, אותה טבלת תוצאות.
Rotation ו-Backoff: איך לא להישבר על 429
עכשיו אנחנו עוברים מהדגמה לכלי. קריאה אחת למודל היא לא מערכת. מערכת צריכה לדעת מה לעשות כשהקריאה נכשלת. שגיאת 429 Too Many Requests אינה כישלון נדיר; היא חלק מהחיים ב-free tier. לפעמים הגעתם ל-RPM, לפעמים ל-TPM, לפעמים ל-RPD, ולפעמים הספק עמוס. קוד טוב לא כועס על 429. הוא קורא את הסימן, מחכה אם צריך, עובר ספק אם מתאים, ומחזיר תשובה מבוקרת אם נגמרו כל האפשרויות.
המבנה שנבנה כולל ארבע שכבות: provider config, queue/concurrency control, retry עם backoff, ו-fallback provider. אם כל אלה נכשלים, מגיעה שכבת graceful degradation: למשל להחזיר למשתמש "המערכת עמוסה, שמרתי את הבקשה לתור" או להריץ מודל קטן יותר עם איכות נמוכה יותר. בפרויקט אמיתי, graceful degradation הוא מה שמונע מלקוח להרגיש שהכל קרס.
כתבו ב-notes.md את סדר ה-fallback האישי שלכם. לדוגמה: primary: Groq 8B, backup: Cerebras, comparison: OpenRouter, degraded: שמור לתור והרצה מאוחר יותר. אל תבחרו לפי יוקרה; בחרו לפי מה שהמשימות שלכם צריכות.
נוציא את הספקים לקובץ YAML. זה חשוב כי free models משתנים. אם OpenRouter משנה שם מודל או Groq מעדכן model id, אתם לא רוצים לערוך את הלוגיקה. אתם רוצים לשנות שורה אחת בקונפיגורציה. בנוסף, YAML מאפשר להוסיף metadata: use_case, daily_budget, rpm_safe, notes, source_url. גם אם הקוד לא משתמש בכל השדות ביום הראשון, השדות האלה הופכים את הפרויקט לקריא.
# providers.yaml
providers:
- name: groq_fast
env_key: GROQ_API_KEY
base_url: https://api.groq.com/openai/v1
model: llama-3.1-8b-instant
use_case: interactive
rpm_safe: 24
source_url: https://console.groq.com/docs/rate-limits
- name: groq_70b
env_key: GROQ_API_KEY
base_url: https://api.groq.com/openai/v1
model: llama-3.3-70b-versatile
use_case: high_quality_interactive
rpm_safe: 20
source_url: https://console.groq.com/docs/rate-limits
- name: cerebras_batch
env_key: CEREBRAS_API_KEY
base_url: https://api.cerebras.ai/v1
model: gpt-oss-120b
use_case: batch_summary
rpm_safe: 4
source_url: https://inference-docs.cerebras.ai/support/rate-limits
ועכשיו נבנה פונקציה שמנסה provider אחד, ואם הוא מחזיר rate limit או שגיאה זמנית, מנסה שוב בצורה מנומסת. הקוד כאן אינו library מושלם; הוא template לימודי שאפשר לקחת לפרויקט. העיקר הוא המבנה: לא לולאה אינסופית, לא sleep קבוע, לא הסתרת שגיאות, ולא מעבר ספק בלי לתעד מה קרה.
# rotation_backoff.py
import os
import random
import time
from dataclasses import dataclass
from typing import Any
import yaml
from dotenv import load_dotenv
from openai import OpenAI
load_dotenv()
@dataclass
class ProviderConfig:
name: str
env_key: str
base_url: str
model: str
rpm_safe: int
use_case: str
def load_providers(path: str = "providers.yaml") -> list[ProviderConfig]:
data = yaml.safe_load(open(path, encoding="utf-8"))
return [ProviderConfig(**item) for item in data["providers"]]
def is_rate_limit_error(exc: Exception) -> bool:
text = str(exc).lower()
return "429" in text or "rate limit" in text or "too many requests" in text
def backoff_seconds(attempt: int, base: float = 1.0, cap: float = 30.0) -> float:
wait = min(cap, base * (2 ** attempt))
jitter = random.uniform(0, 0.4 * wait)
return wait + jitter
def call_once(provider: ProviderConfig, prompt: str, max_tokens: int = 500) -> dict[str, Any]:
api_key = os.getenv(provider.env_key)
if not api_key:
raise RuntimeError(f"Missing {provider.env_key}")
client = OpenAI(api_key=api_key, base_url=provider.base_url)
start = time.perf_counter()
response = client.chat.completions.create(
model=provider.model,
messages=[
{"role": "system", "content": "Be useful, concise and accurate."},
{"role": "user", "content": prompt},
],
temperature=0.2,
max_tokens=max_tokens,
)
return {
"ok": True,
"provider": provider.name,
"model": provider.model,
"latency_seconds": round(time.perf_counter() - start, 2),
"answer": response.choices[0].message.content,
}
def call_with_rotation(prompt: str, provider_order: list[str], max_attempts_per_provider: int = 2) -> dict[str, Any]:
providers = {provider.name: provider for provider in load_providers()}
history = []
for provider_name in provider_order:
provider = providers[provider_name]
for attempt in range(max_attempts_per_provider):
try:
result = call_once(provider, prompt)
result["attempt_history"] = history
return result
except Exception as exc:
item = {
"provider": provider.name,
"attempt": attempt + 1,
"error_type": type(exc).__name__,
"error_message": str(exc)[:300],
}
history.append(item)
if is_rate_limit_error(exc):
time.sleep(backoff_seconds(attempt))
continue
break
return {
"ok": False,
"provider": None,
"answer": "המערכת הגיעה למגבלות הספקים החינמיים כרגע. שמרו את הבקשה לתור או נסו שוב מאוחר יותר.",
"attempt_history": history,
}
if __name__ == "__main__":
result = call_with_rotation(
prompt="Write a Hebrew checklist for validating free API rate limits before a batch run.",
provider_order=["groq_fast", "groq_70b", "cerebras_batch"],
)
print(result)
זמן: 30 דקות. תוצר: קובץ rotation_backoff.py שמחזיר status, provider_used, attempt_history ו-answer או degraded answer.
- צרו
providers.yamlעם לפחות שלושה providers: Groq מהיר, Groq איכותי יותר, Cerebras batch. - העתיקו את
rotation_backoff.pyוהריצו אותו על prompt קצר. - שנו בכוונה שם מודל לא נכון אצל provider הראשון ובדקו שהקוד עובר הלאה במקום לקרוס.
- הורידו
max_attempts_per_providerל-1 כדי לראות את ה-history קצר וברור. - הוסיפו שדה
degraded_reasonלתשובה הסופית כשכל הספקים נכשלים. - שמרו דוגמת output מוצלחת ודוגמת output כושלת בתיקייה
logs/.
איך הצלחה נראית: כש-provider אחד נכשל, אתם רואים בהיסטוריה מי נכשל ולמה, והתוכנית מחזירה תשובה מספק אחר או הודעת degradation ברורה. אין stack trace ענק למשתמש הקצה.
הוסיפו ל-provider_limits.md עמודה בשם reset_notes. כתבו ליד Groq: "בדוק headers ו-dashboard". ליד Gemini: "RPD resets midnight Pacific; verify in AI Studio". ליד OpenRouter: "free model availability rotates". ההערות האלה יזכירו לכם שהמספרים אינם רק מספרים.
בפרויקטים אמיתיים, כדאי להוסיף גם quota ledger קטן: קובץ JSON או SQLite שבו אתם רושמים כמה קריאות שלחתם לכל provider ביום הנוכחי. זה לא חייב להיות מדויק כמו dashboard של הספק, אבל הוא עוזר לקבל החלטות מקומיות. אם אתם יודעים שכבר שלחתם 900 מתוך 1,000 קריאות יומיות למודל מסוים, אפשר לעצור לפני שהספק עוצר אתכם. בעסק ישראלי קטן שמריץ סיכום פניות פעם ביום, ledger כזה יכול להיות ההבדל בין מערכת שעובדת חודש לבין מערכת שנופלת ביום שישי בצהריים כשאין מי שיתקן.
אל תזלזלו גם בתוכן של הודעת הכישלון. הרבה מפתחים כותבים למשתמש "Error" או מציגים stack trace. זה אולי מספיק בסקריפט אישי, אבל לא בכלי אמיתי. הודעת degradation טובה אומרת מה קרה בלי להאשים את המשתמש: "הגעתי כרגע למגבלת הספק החינמי, שמרתי את הבקשה לתור ואנסה שוב בעוד 10 דקות". אם יש פעולה חלופית, הציעו אותה: "אפשר להריץ עכשיו עם מודל קטן יותר" או "אפשר להמשיך בלי סיכום אוטומטי". כך גם כשה-free tier מגביל אתכם, החוויה נשארת מקצועית.
בשלב הזה כדאי להפריד בין שלושה סוגי שגיאות. שגיאת קונפיגורציה — API key חסר, model id לא קיים, base_url שגוי — לא צריכה retry. היא צריכה להיכשל מהר עם הודעה למפתח. שגיאת עומס או 429 כן צריכה retry/backoff, כי היא מצב זמני. שגיאת תוכן — prompt ארוך מדי, קובץ לא נתמך, policy block — צריכה תיקון input ולא מעבר ספק עיוור. אם כל השגיאות מקבלות אותו טיפול, המערכת תבזבז זמן: היא תנסה שוב key חסר, תעבור ספק בגלל prompt גרוע, או תסתיר בעיית privacy מאחורי fallback.
לכן מומלץ שכל attempt_history יכלול גם classification. לא רק error_message, אלא קטגוריה: config_error, rate_limit, transient_provider_error, content_error, privacy_block. בגרסה הראשונה אפשר לסווג לפי טקסט השגיאה; בהמשך לפי exception types ו-status codes. זה נותן לכם dashboard קטן כמעט בחינם. אחרי שבוע תדעו אם הבעיה שלכם היא באמת quota, או בעצם model ids לא יציבים, prompt ארוך מדי, או משתמשים ששולחים מידע שאסור לשלוח.
Multi-model A/B tester: להשוות תשובות במקום לנחש
אחת הטעויות היקרות בעבודה עם מודלים היא לבחור מודל על בסיס שמועה. מישהו אומר ש-Qwen מצוין לקוד, מישהו אחר אומר ש-Llama טוב בעברית, ושלישי אומר ש-DeepSeek זול וחכם. כל זה יכול להיות נכון או לא נכון, אבל למשימה שלכם יש prompt, קהל, שפה, סגנון, ואילוצים. לכן נבנה כלי קטן שמריץ את אותו prompt על כמה providers ומייצא CSV. לא benchmark אקדמי. כלי החלטה יומיומי.
ה-A/B tester שלכם צריך למדוד ארבעה דברים: האם הקריאה הצליחה, כמה זמן היא לקחה, מה התשובה, ואיך אתם מדרגים אותה לפי rubric. לא מספיק להגיד "מודל A יותר טוב". יותר טוב במה? דיוק? עברית טבעית? קוד שרץ? פחות hallucination? סיכום קצר יותר? אם לא מגדירים rubric לפני הריצה, המוח האנושי יבחר את התשובה שנשמעת בטוחה יותר, לא בהכרח את הטובה יותר.
בחרו prompt אמיתי מהעבודה שלכם וכתבו לו rubric של שלושה קריטריונים. לדוגמה: דיוק טכני, עברית שימושית, צעדים שאפשר לבצע. ליד כל קריטריון כתבו סולם 1-5. אל תשתמשו ב"אהבתי" כקריטריון.
# ab_tester.py
import csv
import time
from rotation_backoff import load_providers, call_once
PROMPT = """
אתה עוזר טכני. הסבר למפתח מתחיל איך לבדוק אם free API מתאים ל-batch של 200 prompts ביום.
תן תשובה בעברית, עם 5 צעדים ועם אזהרה אחת על rate limits.
""".strip()
PROVIDER_NAMES = ["groq_fast", "groq_70b", "cerebras_batch"]
def run_ab_test() -> None:
providers = {provider.name: provider for provider in load_providers()}
rows = []
for name in PROVIDER_NAMES:
provider = providers[name]
start = time.perf_counter()
try:
result = call_once(provider, PROMPT, max_tokens=700)
rows.append({
"provider": name,
"model": provider.model,
"status": "ok",
"latency_seconds": result["latency_seconds"],
"answer": result["answer"].replace("\n", " "),
"accuracy_score": "",
"hebrew_score": "",
"actionability_score": "",
"decision": "",
})
except Exception as exc:
rows.append({
"provider": name,
"model": provider.model,
"status": "error",
"latency_seconds": round(time.perf_counter() - start, 2),
"answer": str(exc)[:500],
"accuracy_score": "",
"hebrew_score": "",
"actionability_score": "",
"decision": "",
})
with open("multi_model_ab_test.csv", "w", newline="", encoding="utf-8-sig") as f:
writer = csv.DictWriter(f, fieldnames=rows[0].keys())
writer.writeheader()
writer.writerows(rows)
if __name__ == "__main__":
run_ab_test()
print("Wrote multi_model_ab_test.csv")
זמן: 25-30 דקות. תוצר: קובץ CSV שמראה איזה מודל מתאים למשימה שלכם ולמה.
- בחרו prompt אחד אמיתי. לא prompt צעצוע. משהו שתוכלו להשתמש בו השבוע.
- בחרו שלושה או ארבעה providers/models מתוך
providers.yaml. אם OpenRouter זמין לכם, הוסיפו מודל free אחד משם. - הריצו
python ab_tester.pyופתחו את ה-CSV בגיליון. - מלאו ידנית ציונים 1-5 לשלושת הקריטריונים שהגדרתם.
- כתבו בשדה
decisionמשפט כמו: "Groq fast מספיק ל-interactive; Cerebras טוב לסיכום ארוך; OpenRouter model X כשל בעברית". - שמרו את prompt, rubric ותאריך הריצה בתוך README כדי שתוכלו לחזור על הבדיקה בעוד חודש.
איך הצלחה נראית: יש לכם קובץ CSV שמאפשר לבחור מודל למשימה, לא תחושת בטן. גם שגיאות הן מידע: הן אומרות איזה provider לא יציב לכם עכשיו.
הטעות: להכניס שם model של OpenRouter או ספק אחר ישירות לתוך הקוד ולהניח שהוא יהיה חינמי גם בעוד חודש.
למה זה מפתה: בתחילת הפרויקט רוצים רק לגרום לזה לעבוד. קונפיגורציה מרגישה כמו עיכוב.
מה עושים במקום: כל model id חי ב-providers.yaml. בתחילת ריצה, אפשר להוסיף health check קטן שמנסה prompt קצר. אם model לא זמין, עוברים ל-provider הבא ומעדכנים את הטבלה. כך שינוי חיצוני לא מכריח אתכם לערוך קוד.
יש כאן עוד שיעור עמוק: free tier הוא מקום מצוין ללמוד מודלים, אבל הוא לא מקום טוב להתאהב במודל. היום מודל מסוים כותב יפה בעברית, מחר הוא עובר provider, מקבל throttling או נעלם מ-free. אם אתם בונים abstraction נכון, זה לא אסון. אתם מחליפים קונפיגורציה, מריצים A/B test מחדש, וממשיכים. אם כל ה-prompt engineering שלכם תלוי במודל יחיד, תשלמו על זה ביום שבו הוא משתנה.
פרטיות, עלות נסתרת והחלטה מתי לא להשתמש ב-free API
עד עכשיו דיברנו על מגבלות טכניות. עכשיו נדבר על מגבלה שלא תמיד מופיעה בטבלת caps: האם בכלל מותר לשלוח את הדאטה שלכם לספק חינמי. אין תשובה אחת לכל הספקים ולכל התוכניות. חלק מהתוכניות החינמיות משתמשות בתוכן כדי לשפר מוצרים. חלק נותנות opt-out רק בתשלום. חלק מתאימות לניסוי אישי אבל לא לחומר לקוח. לכן ההחלטה על free API היא לא רק הנדסית. היא גם החלטת פרטיות, אמון וסיכון.
בפרויקטים אישיים, אפשר להיות גמישים. prompt על רעיון לאפליקציה, סיכום מאמר ציבורי, הסבר לקוד open source — בדרך כלל אין בעיה גדולה. בפרויקטים עם לקוחות ישראליים, במיוחד עורכי דין, רופאים, פיננסים, HR, חוזים, מידע אישי או נתוני מכירות, צריך לעצור. גם אם העלות היא 0 ש"ח, הסיכון אינו 0. לפעמים הפתרון הוא למחוק פרטים מזהים. לפעמים הוא לעבור לתוכנית paid עם תנאים מתאימים. לפעמים הוא local inference בפרק 4.
אם הטקסט כולל פרטים מזהים של לקוחות, חוזים, מידע רפואי, מידע כספי או סודות עסקיים → אז אל תשלחו אותו ל-free API לפני אנונימיזציה או בדיקת תנאים.
אם מדובר בדאטה ציבורי, טקסט שלכם, prompt ניסיוני או benchmark פנימי לא רגיש → אז free API מתאים ללמידה ול-prototype.
אם יש SLA, התחייבות ללקוח או תהליך שחייב לרוץ כל יום → אז free tier יכול להיות fallback או סביבת dev, אבל לא תמיד production.
אם אתם צריכים להריץ הרבה בלי תלות בספק → אז התחילו לתכנן local בפרק 4 או budget קטן לספק paid. לפעמים 30-100 ש"ח בחודש חוסכים שעות תחזוקה.
חזרו לשלוש המשימות שכתבתם בתחילת הפרק. ליד כל אחת כתבו: yes, anonymize או no. yes = מותר לשלוח כמו שהוא. anonymize = מוחקים שמות, טלפונים, אימיילים ופרטים מזהים. no = לא שולחים ל-free API; עוברים ל-local או paid terms.
הטעות: לחשוב שאם לא שילמתם, אין החלטה עסקית.
למה זה מפתה: העלות גלויה: 0 ש"ח. הסיכון סמוי: פרטיות, זמינות, תנאים, quota, שינוי מודלים.
מה עושים במקום: לכל use case כתבו data classification קצר. אישי/ציבורי? לקוח? רגיש? אם זה לקוח, כתבו מי מאשר שליחה לענן. אם אין אישור, אל תשלחו. זה נשמע בירוקרטי, אבל זה הרגל שמבדיל מפתח חובב ממישהו שאפשר לסמוך עליו.
יש גם עלות נסתרת של זמן. נניח שאתם מנסים להישאר חינמיים בכל מחיר ומבלים שש שעות בבניית rotation בין חמישה ספקים כדי לחסוך 40 ש"ח בחודש. אם זה פרויקט לימודי, מעולה. אם זה לקוח שמשלם לכם לפי שעה, אולי בזבזתם יותר משחסכתם. בקורס הזה אנחנו לומדים איך להגיע ל-0 ש"ח, אבל לא נהפוך את ה-0 לאידיאולוגיה עיוורת. לפעמים free הוא הכי חכם. לפעמים הוא רק שלב ביניים.
שגרת עבודה: להישאר חינמי בלי לשבור פרודקשן
הדרך להישאר ב-free tier אינה טריק חד-פעמי. היא שגרה. בכל פעם שהספקים משנים מודל, מגבלה או תנאי, הקוד שלכם צריך להישאר מובן. בכל פעם שהשימוש גדל, אתם צריכים לדעת אם אתם עדיין בתוך הקופסה החינמית או שכבר הפכתם את הפרויקט לאמין מדי בשביל free tier. זו בעיה טובה: אם ה-workload גדל, סימן שהכלי שימושי. אבל צריך לראות את זה לפני שהמשתמשים רואים 429.
| תדירות | מה עושים | זמן |
|---|---|---|
| כל יום עבודה | בדקו בקצרה את קובץ הלוג: כמה קריאות הצליחו, כמה 429 היו, איזה provider ענה בפועל. אם הכלי לא רץ היום, אין מה לבדוק. | 2-3 דקות |
| כל שבוע | הריצו prompt בדיקה קצר על כל provider פעיל. עדכנו providers.yaml אם שם מודל השתנה. בדקו האם ה-A/B tester עדיין מצביע על אותו מודל מנצח. | 15 דקות |
| כל חודש | פתחו את דפי rate limits או הדשבורדים הרשמיים, עדכנו provider_limits.md עם תאריך חדש, והחליטו האם workload שגדל עדיין מתאים ל-free tier. | 25 דקות |
זמן: 20 דקות. תוצר: קובץ provider_limits.md שמסכם את הספקים שאתם באמת מתכוונים להשתמש בהם החודש.
- פתחו את דפי המקור הרשמיים: Groq rate limits, Cerebras rate limits, Gemini rate limits ו-OpenRouter free models או models API.
- מלאו לכל ספק: use case, model id, RPM, RPD, TPM/TPD אם יש, source URL ותאריך בדיקה.
- הוסיפו עמודת first_cap_to_hit: מה כנראה יישבר ראשון אצלכם.
- הוסיפו עמודת decision: use, fallback, compare only או avoid.
- הוסיפו הערת פרטיות: public only, anonymize או sensitive-no.
- בסוף הקובץ כתבו משפט: "אני בודק את הטבלה מחדש בתאריך ___".
איך הצלחה נראית: אפשר לפתוח את הקובץ בעוד חודש ולהבין למה בחרתם כל ספק, בלי לזכור את כל הפרק. אם מישהו אחר מצטרף לפרויקט, הוא מבין מה מותר להריץ, איפה, ומתי לבדוק מחדש.
שימו לב שהתרגיל הזה הגיע בסוף, למרות שהתחלנו ממנו בקטן. עכשיו יש לכם מספיק הקשר כדי למלא אותו ברצינות. בתחילת הפרק טבלת limits הייתה רשימת מספרים. עכשיו היא מסמך תפעולי: היא מחברת use case, cap, privacy, fallback ותאריך. זה בדיוק מה שצריך כדי להריץ free inference בלי להמר.
אם אתם רוצים להפוך את התוצרים של הפרק לתבנית קבועה, שמרו את התיקייה כ-template. בכל פרויקט חדש העתיקו רק חמישה דברים: provider_limits.md, providers.yaml, rotation_backoff.py, ab_tester.py ו-README. אחר כך מחקו ספקים שלא רלוונטיים והוסיפו prompt בדיקה אמיתי. זה יחסוך לכם את השגיאה הנפוצה של להתחיל כל פרויקט AI מ-blank file ואז להמציא מחדש ניהול מפתחות, retries ו-logging. תבנית טובה אינה מגבילה אתכם; היא מורידה את הרעש כדי שתוכלו להתמקד בשאלה העסקית או היצירתית.
מבחינת תחזוקה, יש סימן ברור לכך שהפרויקט גדל מעבר ל-free tier: אתם מתחילים להשקיע יותר זמן בניהול מגבלות מאשר בבניית הערך. אם כל שבוע אתם מחליפים מודלים, מחכים ל-reset, מכבים features כדי לא לעבור quota, או מתווכחים עם לקוח למה הסיכום הגיע באיחור, הגיע הזמן להחליט. או שמשדרגים provider אחד לתשלום קטן, או שמעבירים חלק מהעומס ל-local, או שמשנים את המוצר כך שיעבוד ב-batch ולא בזמן אמת. היכולת להישאר בחינם היא כוח; ההתעקשות להישאר בחינם בכל מצב היא לפעמים חולשה.
לסיום, זכרו שהמטרה של הפרק אינה "לעקוף מגבלות" אלא לבנות שכבת inference חכמה. שכבה כזו יודעת לבחור ספק, לקרוא מגבלות, להתייחס לפרטיות, למדוד איכות, ולהיכשל בצורה מכובדת. ברגע שיש לכם אותה, אתם יכולים להתנסות מהר מאוד: יום אחד Groq, יום אחר Cerebras, שבוע הבא מודל חינמי חדש ב-OpenRouter, ובפרק 4 גם Ollama מקומי. המודל יכול להשתנות; השכבה שלכם נשארת.
עוד בדיקה קטנה לפני שסוגרים: נסו להסביר למישהו אחר את ה-stack שלכם בשתי דקות. אם אתם אומרים "זה קורא ל-Groq ואז אולי ל-Cerebras" בלבד, ההסבר עדיין דל. הסבר טוב נשמע כך: "המשימות האינטראקטיביות עוברות לספק מהיר, batch עובר לספק token-heavy, כל קריאה נרשמת בלוג, 429 מפעיל backoff, ומידע רגיש לא יוצא בלי אנונימיזציה". אם אתם מצליחים להגיד את זה בקול, סימן שהפרק הפך אצלכם ממידע למודל עבודה. כתבו את ההסבר הזה בראש ה-README, כי הוא יעזור גם לכם בעוד חודש וגם לכל אדם שיצטרף לפרויקט ולא קרא את הפרק. זו גם בדיקת איכות פשוטה לפני כל demo, פנימי או חיצוני, במיוחד לפני מסירה ללקוח חדש.
בנו את provider_limits.md שלכם עם מקור ותאריך בדיקה. גם אם עוד לא כתבתם שורת קוד אחת, המסמך הזה ישנה את הדרך שבה אתם עובדים. הוא ימנע מכם לבחור ספק לפי hype, ימנע hard-coding של מגבלות ישנות, וייתן לכם בסיס ל-rotation אמיתי. אחרי שיש לכם את הטבלה, הקוד הוא רק יישום.
ענו על 5 השאלות. אם אתם יכולים לענות על 4 מתוך 5 בלי לחזור לטקסט, אתם מוכנים לפרק הבא.
- למה RPD גבוה לא מספיק אם RPM נמוך? (רמז: batch קצר יכול להישבר בדקה הראשונה)
- איך OpenAI-compatible client מאפשר להחליף ספק בלי לשנות את כל הקוד? (רמז: base_url, api_key, model בקונפיגורציה)
- מתי Groq מתאים יותר מ-Cerebras, ומתי Cerebras מתאים יותר מ-Groq? (רמז: interactive latency מול token-heavy batch)
- למה rotation בין API keys אינו תחליף טוב ל-rotation בין ספקים? (רמז: limits נמדדים לעיתים ברמת project או organization)
- איך תחליטו אם prompt מסוים מותר לשליחה ל-free API או חייב local/paid? (רמז: data classification והאם יש מידע לקוחות/סודות)
הפרק הזה לקח את הרעיון מפרק 1 — לא כל inference צריך GPU משלכם — והפך אותו לשכבת עבודה אמיתית. ראיתם איך ספקים כמו Groq, Cerebras, OpenRouter ו-Google AI Studio משרתים משימות שונות, ולמדתם לקרוא את free tier כסט של מגבלות ולא כמתנה אינסופית. ההבחנה המרכזית היא פשוטה: מודל גדול דרך API יכול להיות קל מאוד להפעלה, אבל רק אם מתייחסים ל-caps, לפרטיות ול-fallback כחלק מהקוד ולא כהערת שוליים.
התוצרים שבניתם — provider_limits.md, providers.yaml, run_once.py, rotation_backoff.py ו-A/B tester — הם לא רק תרגילים. הם תשתית קטנה שתוכלו לקחת לכל פרויקט AI חדש. במקום לשאול "איזה מודל הכי טוב?" אתם יודעים לשאול "איזה provider מתאים למשימה, מה יישבר ראשון, ומה קורה כשזה נשבר?" זו שאלה הרבה יותר מקצועית.
בפרק הבא נעבור ל-GPU notebooks בפועל: Colab ו-Kaggle. שם כבר לא נשתמש רק ב-API שמישהו אחר מריץ עבורנו, אלא נלמד איך להחזיק session חי, לשמור checkpoints, להתמודד עם ephemeral disk, ולהריץ workloads שצריכים GPU אמיתי ועדיין עולים 0 ש"ח.
צ'קליסט — סיום פרק 2
- ☐ יצרתי תיקיית free-api-lab עם notes.md
- ☐ כתבתי שלוש משימות: interactive, batch ו-comparison
- ☐ יצרתי provider_limits.md עם ספקים, caps, מקור ותאריך בדיקה
- ☐ יצרתי .env.example בלי סודות אמיתיים
- ☐ וידאתי ש-.env נמצא ב-.gitignore ולא ייכנס ל-git
- ☐ הרצת
run_once.pyמול לפחות ספק אחד בהצלחה - ☐ תיעדתי latency, provider, model ותשובה ראשונה
- ☐ יצרתי providers.yaml עם לפחות שלושה providers או models
- ☐ מימשתי rotation/backoff או לפחות הרצת template שמדגים fallback
- ☐ שמרתי attempt_history עבור כישלונות
- ☐ בניתי A/B tester או CSV ידני שמשווה בין מודלים
- ☐ דירגתי תשובות לפי rubric ולא לפי תחושת בטן
- ☐ סימנתי לכל use case האם הוא public, anonymize או sensitive-no
- ☐ קבעתי תזכורת חודשית לבדוק מחדש את provider_limits.md
- ☐ אני יודע/ת להסביר מתי free API מספיק ומתי צריך לעבור ל-GPU notebook, local או paid