מודלים לשפות גדולות (LLMs) נמצאים בכל מקום, החל מהאפליקציות היומיומיות ועד כלים מתקדמים. השימוש בהם קל. אבל מה אם אתה צריך להפעיל את המודל שלך? בין אם יש לך מודל מותאם אישית או מתמודדים עם נתונים רגישים לפרטיות, המורכבות גדלה. בפוסט זה, נשתף את מה שלמדנו בעת בניית מערכת ההשלכות שלנו LLM. נוכל לכסות את אחסון וההפצה של מודלים, עיצוב ארכיטקטורת השירות, ופתרון בעיות בעולם האמיתי כגון מסלול, זרימה וניהול microservices. התהליך כולל אתגרים, אבל בסופו של דבר, נבנה מערכת אמין ואספנו שיעורים ראויים לשיתוף. הוצאת LLMs הם כוח מגוון רחב של יישומים - מן chatbots וסוכני זרימת עבודה כלים אוטומציה חכמה. בעוד הדפסה מוגברת הדור, שיחת כלים, ופרוטוקולים רב-סוכנים חשובים, הם פועלים ברמה מעל המנוע הליבה: LLM יסוד. רבים מהפרויקטים מסתמכים על ספקים חיצוניים, כגון: , או אבל עבור יישומים מסוימים, זה הופך במהירות לבעיה. מה אם הספק מתכווץ? מה אם אתה צריך שליטה מלאה על עיכוב, מחיר, או זמן הפעלה? הכי חשוב - מה אם אתה דואג לפרטיות ואינך יכול להרשות לעצמך לשלוח נתוני משתמשים לצד שלישי? פתיחה תאומים אנתרופי פתיחה תאומים אנתרופי זה המקום שבו אירוח עצמי הופך להיות חיוני. שירות מודל מעודכן או מעוצב מראש מספק שליטה, אבטחה, ואת היכולת להתאים את המודל לצרכים עסקיים ספציפיים. בניית מערכת כזו לא דורשת צוות גדול או משאבים נרחבים. נבנה אותו עם תקציב צנוע, צוות קטן, ורק כמה כבל. המגבלות האלה השפיעו על החלטת האדריכלות שלנו, הדורשת מאיתנו להתמקד בפועלות ויעילות. סקירה כללית אלה הם המרכיבים הבסיסיים היוצרים את עמוד השדרה של המערכת. שפה משותפת ברחבי השירותים היא חיונית, כלומר פורמטים של בקשה/תגובה עקביים, תוכניות פרמטרים של יצירה, מבנים של היסטוריית דיאלוגים, וסריליזציה שעובדת בכל מקום - מ-frontend ל-backend ל-model runner. ניהול מודלים מרובים, סוגים של בקשות ועדיפויות המארח דורשים החלטות מנוהלות מכוונות.אנו מתארים כיצד בקשות המשתמשים הנכנסות מועברות דרך המערכת – מנקודת הכניסה הראשונית לנקודת העובד המתאימה – ואיך התשובות מועברות חזרה. איפה מודלים חיים, ואיך הם מוכנים לשימוש בייצור? אנו נדון בבדיקות המפתח לבצע, כולל הבטחת האמינות של המודל. תצפית.איך אתה יודע שהדברים עובדים?אנו נציג לך אילו מדדים אנו עוקבים, כיצד אנו עוקבים אחר כישלונות, ואת הסנדרים שאנו משתמשים בהם כדי להבטיח בריאות המערכת ואמינותה. תוכנה וקוד נתונים בחירת התוכנית הנכונה להעברת נתונים היא קריטית.הפורמט המשותף בין שירותים מקל על האינטגרציה, מקל על שגיאות ושיפר את התאמה.המטרה שלנו הייתה לעצב את המערכת כדי לעבוד בקלות עם מודלים מאורגנים באופן עצמאי וספקים חיצוניים – מבלי לחשוף הבדלים למשתמש. למה עיצוב תכנים חשובים אין סטנדרט אוניברסלי לחילופי נתונים LLM. ספקים רבים עוקבים אחר תוכניות דומות , while others — like או רבים מהספקים האלה מציעים SDKs תואמים ל-OpenAI שמחזיקים באותה תבנית, אם כי לעתים קרובות עם מגבלות או קבוצות תכונות מופחתות (למשל, , פרויקטים אחרים כגון המטרה היא לאחד את השינויים האלה על-ידי אריזתם לתוך ממשק תואם OpenAI. פתיחת קלוד תאומים OpenAI-compatible SDK של Anthropic שכבת התאימות OpenAI של Gemini OpenRouter פתיחת קלוד תאומים OpenAI-compatible SDK של Anthropic שכבת התאימות OpenAI של Gemini OpenRouter Sticking to a single predefined provider’s schema has its benefits: אתה מקבל API מאובחן היטב, יציב. אתה יכול לסמוך על SDKים וכלים קיימים. אבל יש גם חסרונות אמיתיים: זה יוצר סגור ספקים, מה שהופך את זה קשה יותר לתמוך ספקים מרובים. הוא מגביל את הגמישות כדי להרחיב את התוכנית עם תכונות מותאמות אישית הדרושות לצרכים עסקיים או דרישות צוות מדע נתונים. אתה חשוף לשינויים שבורים או הפחתות מחוץ לשליטתך. מערכות אלה לעיתים קרובות נושאות מגבלות מורשת המגבילות שליטה בדגנים עדינים. To address this, we chose to define our - תבנית שתוכננה סביב הצרכים שלנו, שאנו יכולים לאחר מכן למפות לתבניות חיצוניות שונות במידת הצורך. own internal data model Internal Schema Design לפני שמתמודדים עם האתגרים, בואו נקבע את הבעיה ואת הציפיות שלנו לפתרון: הפצת קלה לפורמטים הנדרשים על ידי ספקים חיצוניים ולהיפך. תמיכה מלאה בתכונות ספציפיות לצוותינו העסקיים ומדעי הנתונים. ודא כי התוכנית ניתן להרחיב בקלות כדי להתאים את הדרישות העתידיות. התחלנו על ידי סקירה של תוכניות LLM גדולות כדי להבין איך ספקים מבנה הודעות, פרמטרים, ופיצויים. זה נפוץ ברוב המערכות, כולל: core domain entities הודעות (לדוגמה, מהיר, היסטוריה) פרמטרים של ייצור (למשל, טמפרטורה, top_p, beam_search) ישנם פרמטרים מסוימים, כגון , או אלמנטים אלה נמצאים מחוץ לתחום הליבה של LLM ואינם חלק מהתוכנית המשותפת.במקום זאת, הם מטופלים כמו הרחבות אופציונליות.בכל פעם תכונה הופכת להיות מקובלת באופן נרחב או נחוצה לשיתוף פעולה רחב יותר, אנו מעריכים את השילוב שלה לתוכנית הליבה. service_tier usage_metadata reasoning_mode ברמה גבוהה, תוכנית ההכנסה שלנו מבוססת על מרכיבים מרכזיים אלה: מודל – משמש כמפתח מסלול, פועל כמזהה מסלול, ומאפשר למערכת להפנות את הבקשה לקוטר העובד המתאים. פרמטרים של הדור – הגדרות מודל הליבה (למשל, טמפרטורה, top_p, max_tokens). הודעות – היסטוריית שיחות ותשלומים מיידיים. כלים – הגדרות של כלים שהמודל עשוי להשתמש בהם. זה מוביל אותנו לתוכנית הבאה, המוצגת ב הוא מציג את המבנה ואת הכוונה של העיצוב, אם כי כמה פרטים של יישום נמחקו למען הפשטות. פיננסית כמו פיננסית כמו class ChatCompletionRequest(BaseModel): model: str # Routing key to select the appropriate model or service messages: list[Message] # Prompt and dialogue history generation_parameters: GenerationParameters # Core generation settings tools: list[Tool] # Optional tool defenitions class GenerationParameters(BaseModel): temperature: float top_p: float max_tokens: int beam_search: BeamSearchParams # Optional, non-core fields specific to certain providers provider_extensions: dict[str, Any] = {} ... # Other parameters We deliberately moved generation parameters into a separate nested field instead of placing them at the root level. This design choice makes a distinction between פרמטרים (למשל, טמפרטורה, top-p, הגדרות מודל) ו קבוצות רבות במערכת האקולוגית שלנו מאחסנות פרמטרים קבועים אלה במערכות תצורה חיצוניות, מה שהופך את ההפרדה הזו ליעילה וגם הכרחית. קבועה משתנה אנו כוללים שדה נוסף בשם within the פרמטרים אלה משתנים באופן משמעותי בין ספקי LLM שונים, אימות והפרשנות של שדות אלה היא הרכיב שיודע כיצד לתקשר עם ספקית מודל ספציפית.כך אנו נמנעים מקבילות מעבר מיותרות שנגרמות על-ידי אימות נתונים מיותר בין שירותים מרובים. provider_extensions GenerationParameters delegated to the final module that handles model inference כדי להבטיח תאימות אחורית, תכונות תפריט תוצאת חדשות מוצגות כגון in the request schema. These fields act as feature flags — users must set them to opt into specific behaviors. This approach keeps the core schema stable while enabling incremental evolution. For example, reasoning traces will only be included in the output if the corresponding field is set in the request. explicit, optional fields These schemas are maintained in a shared Python library and used across services to ensure consistent request and response handling. שיתוף פעולה עם ספקי צד שלישי התחלנו על-ידי הסבר כיצד נבנה את הפלטפורמה שלנו – אז למה להתעסק עם תאימות בין ספקים חיצוניים? ייצור נתונים סינתטיים עבור פרוטופינג ניסויים על ידי צוותי מדעי הנתונים שלנו. משימות למטרה כללית שבהן כמה מודלים קנייניים פועלים טוב יותר מחוץ לקופסה. מקרים של שימוש לא רגיש שבהם פרטיות, עיכוב או שליטה על תשתית הם פחות קריטיים. ניתן לסכם את זרימת התקשורת הכוללת עם ספקים חיצוניים כדלקמן: תהליך זה כולל את הצעדים הבאים: שירות LLM-Gateway מיוחד האחראי על תקשורת עם ספק מקבל בקשה למשתמש בפורמט התוכנית שלנו. הבקשה מופנת לתבנית ספציפית לספק, כולל כל extension_provision. הספק החיצוני מעבד את הבקשה ומחזיר תשובה. LLM-Gateway שירות מקבל את התשובה ומפותח אותו בחזרה לתוך התוכנית התגובה הסטנדרטית שלנו. זוהי תוכנית ברמה גבוהה שמסבירה כמה מיקרו-שירותים בודדים.פרטים על רכיבים ספציפיים ופורמט התגובה לסטרימינג יהיו מכוסים בסעיפים הבאים. פורמט Streaming תשובות LLM נוצרות בהדרגה - טוקן על ידי טוקן - ולאחר מכן מצטברות לתוך for efficient transmission. From the user’s perspective, whether through a browser, mobile app, or terminal, the experience must remain זה דורש מנגנון תחבורה אשר תומך . chunks fluid and responsive low-latency, real-time streaming ישנן שתי אפשרויות עיקריות להשיג זאת: WebSockets: ערוץ תקשורת דופלקס מלא המאפשר אינטראקציה משני כיוונים מתמשכת בין לקוח לשרת. Server-Sent Events (SSE): פרוטוקול סטרימינג מבוסס HTTP חד-צדדי המשמש באופן נרחב לעדכונים בזמן אמת. WebSockets WebSockets אירועי שליחת שרתים (SSE) אירועי שליחת שרתים (SSE) למה SSE על WebSockets? גם אם שתי האפשרויות אפשריות, — particularly for OpenAI-compatible APIs and similar systems. This is due to several practical advantages: SSE is the more commonly used solution for standard LLM inference פשוטות: SSE פועל מעל HTTP סטנדרטי, לא דורש שדרוגים מיוחדים או משא ומתן. תאימות: הוא פועל באופן מקורי בכל הדפדפנים העיקריים ללא ספריות נוספות. זרימה חד משמעית: רוב תשובות LLM זורמות רק משרת ללקוח, אשר תואם את העיצוב של SSE. Proxy-Friendliness: SSE משחק טוב עם תשתית HTTP סטנדרטית, כולל פרוקיות הפוך. שיפור או משא ומתן בגלל היתרונות האלה, . SSE is typically chosen for text-only, prompt-response streaming use cases עם זאת, מקרים מסוימים של שימוש מתפתחים דורשים תקשורת עשירה יותר, בעלת עיכוב נמוך, דו-כיוונית - כגון תרגום בזמן אמת או אינטראקציות דיבור לדיבור. התמודדות עם הצרכים הללו באמצעות פרוטוקולים אלה מתאימים יותר עבור input ו-output multimodal מתמשכים. API בזמן אמת של OpenAI WebSockets API בזמן אמת של OpenAI מכיוון שהמערכת שלנו מתמקדת אך ורק אנחנו נשארים עם עבור הפשטות שלה, תאימות, והתאמה עם המודל הזרם שלנו. text-based interactions SSE תגיות Stream Content עם כשמדובר במסלול, הצעד הבא היה להגדיר את data to include in the stream. Effective streaming requires more than just raw text — it needs to provide sufficient כדי לסייע לצרכנים מתחת למסלול, כגון ממשקי משתמש וכלי אוטומציה.הזרם חייב לכלול את המידע הבא: SSE what structure, metadata, and context מטא-נתונים ברמת הכותרת מידע זיהוי בסיסי כגון ID בקשה. תוצאת הליבה – התוויות או החוטים שנוצרו על-ידי המודל – מסופקת בהדרגה כאשר רצפים (n) זורמים בחזרה, חתיכה על-ידי חתיכה. כל דור יכול להכיל רצפים מרובים (למשל, n=2, n=4) .הסדרות האלה נוצרות באופן עצמאי ומזוהות במקביל, כל אחת מחולקת למגוון משלה של חתיכות מתקדמות. שימוש ו- Metadata ברמה של טוקן. זה כולל מספר טוקנים שנוצרו, נתוני זמן, ואבחון אופציונלי כגון logprobs או עקבות סיבה. לאחר הגדרת המבנה של התגובה הזורמת, נחשב גם מספר דרישות לא פונקציונליות חיוניות לאמינות ופיתוח עתידי. עיצוב הזרם שלנו נועד להיות: מובנה – ההבדל ברור בין סוגי התוכן לבין גבולות האירועים. ניתן להרחיב – מסוגל לשאת מטא-נתונים אופציונליים מבלי לשבור את הלקוחות הקיימים. חזק – עמיד בפני נתונים שגויים, מאוחרים או חלקיים. באפליקציות רבות, כגון or סדרות מרובות (השלמות) נוצרות במקביל כחלק מבקשת דור יחיד. side-by-side comparison diverse sampling הפורמט המקיף ביותר לתגובות זרימה מוגדר ב- על פי הספציפיות, חתיכת דור יחיד עשויה לכלול סדרות מרובות אריאל : OpenAI API התייחסות choices OpenAI API התייחסות בחירות Array רשימה של אפשרויות סיום צ'אט. יכול להכיל יותר מרכיב אחד אם n הוא גדול מ 1. choices array רשימה של אפשרויות סיום צ'אט. יכול להכיל יותר מרכיב אחד אם n הוא גדול מ 1. Although, in practice, individual chunks usually contain only a single delta, the format allows for multiple sequence updates per chunk. It’s important to account for this, as future updates might make broader use of this capability. Notably, even the הוא נועד לתמוך במבנה זה. תגיותPython SDK תגיותPython SDK בחרנו לעקוב אחר אותה מבנה כדי להבטיח תאימות עם מגוון רחב של תכונות פוטנציאליות.התכנית הבאה מציינת דוגמה מהיישום שלנו, שבו דור יחיד מורכב משלושה רצפים, זורמים שישה חתיכות לאורך זמן: Chunk 1 – Generation Start. זה מסמן את תחילתו של כל הדור. זה אינו מכיל תוכן אמיתי, אבל כולל מטא-נתונים משותפים, כגון מזהה הדור, סימן זמן, ותפקיד (למשל, עוזר, וכו '). Two sequences begin streaming in parallel. Each is tagged with a unique identifier to distinguish it from others. Chunk 2 — Sequence Start (Green & Purple). Chunk 3 – Sequence Start (Blue) & Sequence Delta. הסדרה השלישית מתחילה (כחולה), בעוד ששתי הסדרות הראשונות (ירוקה ופולנית) זורמות תוכן משך דרך אירועים דלטה. The green and blue sequences continue streaming deltas. The purple sequence finishes — this includes a structured finish_reason (like stop, length, etc.). Chunk 4 — Midstream Updates & Finish (Purple). Both the green and blue sequences complete. Each sequence’s lifecycle is now fully enclosed between its respective start and finish markers. Chunk 5 — Remaining Sequence Finishes. This chunk closes the generation and may include global usage statistics, final token counts, latency info, or other diagnostics. Chunk 6 — Generation Finish. As you see, to make the stream robust and easier to parse, we opted to , במקום להסתמך על מנגנונים מעורפלים כגון בדיקת אפס, EOFs, או טוקי קסמים.הגישה המאורגנת הזו מפשטת את פירוק מתחת לעולם, במיוחד בסביבות שבהן השלבים מרובים זורמים במקביל, וגם משפרת את האפשרות להתמודד עם פגמים במהלך פיתוח ובדיקה בזמן ביצוע. explicitly signal Start and Finish events for both the overall generation and each individual sequence בנוסף, אנו מציעים תוספת חלק מהטעויות – כגון בקשות שגויות או בעיות אישור – יכולות להופיע ישירות דרך קודי התגובה הסטנדרטיים של HTTP. , we have two options: either abruptly terminate the HTTP stream or emit a well-formed SSE error event. We chose the latter. Abruptly closing the connection makes it hard for clients to distinguish between network issues and actual model/service failures. By using a dedicated error chunk, we enable more reliable detection and propagation of issues during streaming. Error during the generation process Backend Services and Request Flow במרכז המערכת יש נקודת כניסה אחת: . It handles basic concerns like authentication, usage tracking and quota enforcement, request formatting, and routing based on the specified model. While it may look like the Gateway carries a lot of responsibility, each task is intentionally simple and modular. For external providers, it adapts requests to their APIs and maps responses back into a unified format. For self-hosted models, requests are routed directly to internal systems using our own unified schema. This design allows seamless support for both external and internal models through a consistent interface. LLM-Gateway מודלים עצמאיים As mentioned earlier, מתאים לסטרימינג תשובות למשתמשים סופיים, אך אינו בחירה מעשית. כאשר בקשה מגיעה, היא חייבת להיות ממוקמת לקוטר עובד מתאים להשלמת מודל, והתוצאה זורמת בחזרה בעוד שמערכות מסוימות מתמודדות עם זה באמצעות פרוקיות HTTP שרשרת ודרכה מבוססת כותרת, בניסיון שלנו, גישה זו הופכת להיות קשה לניהול ולהתפתחות כפי שהלוגיקה גדלה במורכבות. Server-Sent Events (SSE) internal backend communication Our internal infrastructure needs to support: תזמון מודע לתחום העדיפויות – בקשות עשויות להיות ברמות דחופות שונות (לדוגמה, אינטראקטיביות לעומת קבוצות), ותפקידים בעלי עדיפות גבוהה חייבים להתמודד קודם. — Certain nodes run on higher-performance GPUs and should be preferred; others serve as overflow capacity. Hardware-aware routing — Each worker is configured to support only a subset of models, based on hardware compatibility and resource constraints. Model-specific dispatching כדי לענות על דרישות אלה, אנו משתמשים to decouple task routing from result delivery. This design provides better flexibility and resilience under varying load and routing conditions. We use for this purpose, though other brokers could also be viable depending on your latency, throughput, and operational preferences. RabbitMQ was a natural fit given its maturity and alignment with our existing tooling. message broker RabbitMQ ארנב ארנב עכשיו בואו נסתכל מקרוב על איך מערכת זו מתבצעת בפועל: אנו משתמשים , allowing us to route requests based on model compatibility and node capabilities. The process is as follows: dedicated queues per model The LLM-Gateway service (represented as the user) initiates an HTTP request to trigger a text generation task. starts a new to manage this request. Client Sends Request. Scheduler service Request Handler The request is handled by the , which selects the appropriate queue (marked in green on the image) based on the requested model and appends the message to it. Task Routing via Scheduler service. Scheduler עובד לוקח את המשימה עובד פירוט מתאים (רק עובד אחד מוצג עבור הפשטות, אבל יש הרבה) המנוי לקו לוקח את המשימה ומתחיל לעבד. The worker streams the response chunk-by-chunk into the , to which the . Streaming the Response. Response Queue Scheduler replica handling the request is subscribed The Scheduler listens to the reply queue and receives the response chunks as they arrive. Receiving Response Chunks. The chunks are converted to SSE format and streamed to the client. SSE Streaming. להתמודד , אנו נמנעים מלהטריד את המסר ברוקר: large payloads Instead of embedding large input or output data directly in the task, we upload it to an . external S3-compatible store התייחסות (כגון כתובת URL או מזהה משאב) כלולה במטא-נתונים של המשימה, והעובד משיג את התוכן האמיתי בעת הצורך. Applying the Design with RabbitMQ כשמדובר , each הוא RabbitMQ רגיל דוגמה נוספת היא דוגמה מסוימת, אנו דורשים , which can be achieved using . In this setup, messages with higher priority values are delivered and processed before lower priority ones. For , שבו הודעות צריכות להיות מיועדות תחילה לחלקים הזמינים היעילים ביותר, can help. Consumers with higher priority receive messages as long as they are active; lower-priority consumers only receive messages when the higher-priority ones are blocked or unavailable. routing and publishing messages Request Queue זנב priority-aware scheduling message priorities hardware-aware routing עדיפויות הצרכן זנב message priorities עדיפויות הצרכן If message loss is unacceptable, the following must be in place: המפרסם מאשר לוודא שהבורגר קיבל והאחסן את ההודעה. and so data survives restarts. Durable queues persistent messages קווורום שורות עבור עמידות חזקה יותר באמצעות רבייה.הם תומכים גם הודעות פשוטות ופריטריונים של הצרכנים כמו RabbitMQ 4.0. המנכ"ל מאשר Publisher confirms קווורום קוויר קווורום קוויר מסרים פשוטים ועדיפויות צרכנים על ידי RabbitMQ 4.0 עד כה, אנחנו מכסים כיצד משימות פורסמו - אבל איך זה הצעד הראשון הוא להבין איך work in RabbitMQ. The broker supports a concept called , אשר מחוברים לחיבור יחיד ונמחקים באופן אוטומטי כאשר החיבור נסגר, מה שהופך אותם להתאים באופן טבעי להתקנה שלנו. streamed response temporary queues קווים בלעדיים קווים בלעדיים exclusive queues אנחנו יוצרים , ensuring it’s automatically cleaned up when the replica shuts down. However, this introduces a challenge: while each service replica has a single RabbitMQ queue, it must handle . one exclusive queue per Scheduler service replica many requests in parallel כדי להתמודד עם זה, אנו מתייחסים לקו RabbitMQ כאל , routing responses to the correct Scheduler replica. Each user request is assigned a כל תשובות שנמצאות בתוך התשובה אנו שומרים על תוספת עם שורות בזיכרון לטווח קצר – אחת לכל בקשה פעילה. שורות נכנסות מתאימות לשורות אלה בהתבסס על המזהה ומועברות בהתאם. שורות אלה בזיכרון נזרקות ברגע שהבקשה הושלמה, בעוד שורות RabbitMQ נמשכות לכל החיים של העתקה השירות. transport layer unique identifier Scheduler in-memory routing layer Schematically this looks as follows: A central dispatcher within the Scheduler dispatches chunks to the appropriate in-memory queue, each managed by a dedicated handler. Handlers then stream the chunks to users using SSE-protocol. Inference ישנם מספר מסגרות בוגרות זמינות להשגת LLM יעילה, כגון: and המערכות הללו מיועדות וליצור טוקי תגובה בזמן אמת, לעתים קרובות עם תכונות כגון סטייה מתמשכת ואופטימיזציה של זיכרון GPU. כמו מנוע ההשלכות הליבה, עם כמה שינויים מותאמים אישית: VLLM הסכמה process multiple sequences in parallel vLLM VLLM VLLM SGLANG הסכמה — to better suit our generation logic and support structured constraints. Custom beam search implementation תמיכה במערכות הפצה מובנות – המאפשרת למודלים להחזיר פלטים התואמים לפורמטים ספציפיים לעסק. באמצעות ניסיון, למדנו שגם עדכוני ספריה קטנים יכולים - בין אם באיכות היציאה, דטרמיניזם, או התנהגות תואמת.בגלל זה, הקמנו צינור בדיקה חזק: significantly alter model behavior בדיקת מתח כדי לגלות בעיות תואמות, דליפות זיכרון, או רגרסיות יציבות. to ensure consistent outputs for fixed seeds and parameter sets. Determinism testing בדיקת רשת פרמטרים כדי לכסות מגוון רחב של הגדרות הדור, מבלי להתגבר. Storage and deployment רוב המערכות המודרניות פועלות — בין אם בענן או בתוך Kubernetes (K8s). בעוד שההתקנה הזו עובדת היטב עבור שירותי backend טיפוסיים, היא מציגה אתגרים סביב . LLM models can be מודל הבישול משקל ישירות לתמונות של Docker – הופך במהירות לבעיה: containerized environments model weight storage tens or even hundreds of gigabytes in size — Even with multi-stage builds and caching, transferring large model files during the build phase can dramatically increase CI time. Slow builds הפצה איטית – כל הפצה דורשת ציור תמונות גדולות, אשר יכול לקחת כמה דקות ולגרום לעיכובים או עיכובים. — Neither Docker registries nor Kubernetes nodes are optimized for handling extremely large images, resulting in bloated storage usage and bandwidth strain. Resource inefficiency כדי לפתור את הבעיה, נפרד from the Docker image lifecycle. Our models are stored in an , and fetched just before inference service startup. To improve startup time and avoid redundant downloads, we also use כדי לאחסן משקולות מודל על כל נקודה. model storage external S3-compatible object storage local persistent volumes (PVCs) local persistent volumes (PVCs) local persistent volumes (PVCs) Observability מערכת כזו – מבוססת על דורש כדי להבטיח אמין וביצועים בקנה מידה. streaming, message queues, and real-time token generation robust observability In addition to standard service-level metrics (CPU, memory, error rates, etc.), we found it essential to monitor the following: עומק ציון, אחיזה של הודעות ומספר הצרכנים – מעקב אחר מספר ההודעות המתיחות, גודל הציון הנוכחי ומספר הצרכנים הפעילים עוזר לזהות מחסומים בהפצת המשימות וחוסר איזון בשימוש בעובדים. Token/chunk throughput – מעקב אחר מספר הטוקינים או חתיכות התגובה שנוצרו לשנייה מסייע לזהות רגרסיה של עיכוב או עוצמה. מעקב מפוזר – כדי לזהות איפה בקשות נכשלות או עוצרים בין רכיבים (גשר, ברוקר, עובדים וכו '). — since inference processes can crash under rare conditions (e.g., bad input or extreme parameter values), proactive monitoring of liveness and readiness is critical. Inference engine health checks Distributed tracing מעקב מפוזר שיפורים נוספים בעוד המערכת שלנו מוכנה לייצור, יש עדיין אתגרים חשובים והזדמנויות לאופטימיזציה: Using a to boost inference performance. distributed KV-cache תמיכה בביטול בקשה כדי לשמור על מחשב כאשר הפלטים אינם נחוצים יותר. יצירת צינור משלוח מודל פשוט עבור צוותי מדע הנתונים. מסקנה בעוד בניית מערכת LLM אמין ובלתי תלוי ספקים עשוי להיראות מסובך בהתחלה, זה לא דורש להמציא מחדש את הגלגל. כל מרכיב - סטרימינג באמצעות SSE, חלוקת משימות באמצעות מספקי הודעות, ופירוט המנוהל על ידי זמני ריצה כמו vLLM - משרת מטרה ברורה והוא מבוסס על כלים קיימים, נתמכים היטב. In the next post, we’ll explore more advanced topics such as distributed KV-caching, handling multiple models across replicas, and deployment workflows suited to ML-oriented teams. סופרים טוקיה , סטניסלב שימוולוס סטניסלב שימוולוס סטניסלב שימוולוס טוקיה , Maxim Afanasyev Maxim Afanasyev Maxim Afanasyev ההכרה עבודה שנעשתה בטוקיו דמיטרי קריוקוב דמיטרי קריוקוב דמיטרי קריוקוב