ליאור בר-און לפני 7 חודשים כ- 13 דקות קריאה
ארכיטקטורת מערכות LLM – אבני היסוד
LLMs הם הכתום החדש, ומאפשרים למפתחים בודדים לפתח בקלות יכולות שעד לפני שנה-שנתיים היו נחלתם של צוותי ML גדולים, במקרה הטוב.
בסדרת הפוסטים הבאה ננסה לאפיין, מצד הנדסת התוכנה, מה המשמעות של ארכיטקטורת של מערכות LLM, כלומר: כאשר אנו בונים מערכות המשתמשות הרבה ב LLM – מה המבנים הנפוצים וההגיוניים של התוכנה מסביבם.
נתחיל בדוגמה בסיסית
ברמה הבסיסית ביותר, מערכת המשתמשת ב LLM נראית כך:

- המערכת שלנו שולחת prompt (טקסט) למודל LLM. המודל יכול להיות SaaS (כמו OpenAI) או מנוהל ב self-hosting כמו מודלי open source שונים.
- ה LLM יְעַבֵּד את ה prompt – ויחזיר תשובה טקסטואלית.
כמובן, שאם לא עשינו שום דבר מיוחד עם ה prompt, בעצם יצרנו עוד אפליקציית צ׳ט נוסח chatGPT או Gemini. נוכל להוסיף UI נחמד יותר, או צלצולים ברגעים הנכונים – אבל בבסיס יש פה עוד אפליקציית Chat. לא משהו חדש.
כפי שכתבתי בפוסט קודם בנושא, יש ארבע דרכים עקרוניות להשפיע על מודל LLM – כדי לאפשר יכולות חדשות (מסומנות בתרשים בגווני כחול):

אימון מודל חדש, ו fine-tuning למודל קיים הם מאמצים הדורשים משאבים ומומחיות רבה. עשרות אלפי דולרים ל fine tune של מודל קטן עד מיליונים רבים מאוד לאימון מודל גדול חדש.
נראה שכ 99% מהפתרונות מבוססי-ה LLM מתבססים על שתי הפרקטיקות הפשוטות והזמינות: Prompt Engineering ו RAG – בהם נתמקד בפוסט. אלו טכניקות זולות מאוד, שניתן להפעיל בהשקעה קטנה וללא התעמקות בקרביים של מודלי LLM.
Agentic workflows הם שורה של Patterns של שימוש ב Prompt Engineering ו RAG על מנת להשיג תוצאות טובות יותר. נדון בהם בהמשך.
נתחיל בתיאור פתרון מינימלי מבוסס-LLM, כזה שמפתח בודד יכול לפתח, ובזמן קצר. נעשה זאת בעזרת הכלי הבסיסי ביותר- Prompt Engineering. שימו לב ל Prompt template הבא:
prompt_template = """You are a teacher grading a question. You are given a question, the student's answer, and the true answer, and are asked to score the student answer as either Correct or Incorrect. Grade the student answers based ONLY on their factual accuracy. Ignore differences in punctuation and phrasing between the student answer and true answer. It is OK if the student answer contains more information than the true answer, as long as it does not contain any conflicting statements. If the student answers that there is no specific information provided in the context, then the answer is Incorrect. Begin! QUESTION: {question} STUDENT ANSWER: {studentAnswer} TRUE ANSWER: {trueAnswer} GRADE: Your response should be as follows: GRADE: (Correct or Incorrect) (line break) JUSTIFICATION: (Without mentioning the student/teacher framing of this prompt, explain why the STUDENT ANSWER is Correct or Incorrect. Use up to five sentences maximum. Keep the answer as concise as possible.) """
מקור
אם נציב במקומות הנכונים ערכים לפרמטרים question, studentAnswer ו trueAnser ונשלח ל LLM לעבד את התשובה – הוא יחזיר לנו ניתוח האם התשובה נכונה או לא, והסבר למה.
בפועל: יצרנו פונקציה ממוקדת ושימושית, שלא הייתה קיימת קודם לכן – בדיקת נכונות של שאלה.
עבור שאלה בהיסטוריה, בנוסח ״מנה את הגורמים העיקריים לפריצת מלחמת העולם הראשונה״ – נוכל לקבל במאמץ קטן מערכת שתפתור בעיה הנדסית שבתכנות אימפרטיבי – לא סביר לפתור. ניתוח הטקסט, הבנת משמעות והתאמה שלו לטקסט לדוגמה (התשובה הנכונה) הוא דבר קשה מאוד ליישם בעזרת שפת תכנות כמו ג׳אווה, וללא מומחיות עמוקה בטכניקות של NLP (קרי: Natural Language Procesing).
בעזרת LLM ומעט prompt engineering – זו משימה פשוטה.
שימו לב שיש אומנות בבחירת ההוראות המדויקות ב prompt וההשפעה שלהן על התוצאה. האומנות הזו נקראת prompt engineering, וכדי להגיע לתוצאה טובה, צריך להכיר מה לרוב עובד, וגם לנסות מספר איטרציות של prompts תוך כדי ניסוי וטעיה.
שימו לב שאנחנו לא מסתמכים פה על הידע של LLM בהיסטוריה (ידע שדווקא יש לו) אלא את היכולת להשוות בין תשובת תלמיד לתשובה שהגדרנו כנכונה, בצורה סמנטית ומעמיקה. זה גם מאפשר לנו לקבע מהי התשובה הנכונה מבחינתנו וגם מאפשר לנו לעסוק בנושאים בהם אין ל LLM ידע מספיק (למשל: חוקי העזר העירוניים של עיריית ת״א). ה LLM משמש פה בעיקר כמומחה לשפה ופחות כמקור הידע. את הידע הזה אנחנו מזריקים לו כחלק מה prompt בדמות התשובה לדוגמה.
נקודה חשובה: אם אנו רוצים להשתמש ב prmopt הנ״ל על לבדוק את התשובה על לשאלה ״באיזו שנה הוקמה מדינת ישראל?״ – אנחנו כנראה עושים כאן עוול. אין צורך ב LLM לבדוק כזו שאלה. LLM הוא יקר לשימוש (כמות ה compute, זמן חישוב ארוך), אינו דטרמניסטי, ודורש תחזוקה על מנת לשמר אותו מ drifts בתוצאות לאורך זמן. עדיף לעשות pattern matching פשוט בקוד כדי לבדוק תשובה לכזו שאלה.
לסיכום
השתמשנו ב LLM לייצר פונקציה שימושית שיכולה להשתלב במערכת קיימת. פונקציה שאם היינו מנסים לפתח בלי LLM – ספק אם היינו מצליחים באותה איכות ובזמן פיתוח דומה. עד כאן זו איננה מערכת LLM אלא מערכת שיש בה פונקציה של LLM, למשל: מערכת לבדיקת וניהול ציונים.

LLM Agents
היכולת לשלב פונקציות מועצמות-LLM במערכות קיימות ולספק ערך חדש ונוסף – היא מלהיבה בפני עצמה, וראוי שנעשה בה שימוש רחב בכל מקום בה היא מועילה.
LLM פותח בפנינו הזדמנויות גדולות יותר מאשר כתיבת פונקציות חכמות יותר, כמו לתת ל LLM לנהל תהליכים שלמים ומורכבים. העולם מדבר עכשיו על Agents – סוכנים חכמים שיידעו לבצע מגוון פעולות הדומות לבעל מקצוע המתמחה בתחום מסוים. למשל סוכן שהוא עו״ד בתחום הנדל״ן (A real estate attorney agent).
להזכיר: מודל שפה מאומנים על כמות גדולה של מידע ציבורי מהאינטרנט (כמו וויקיפדיה), ועוד מאגרי צד-שלישי או מאגרים פרטיים שזמינים למאמני המודל. הם מכילים ידע רחב מאוד, אך לרוב לא מתמחים לעומק בנושאים ספציפיים. ChatGPT יוכל לענות על תשובות כלליות בנושאי חוק ונדל״ן – אך הוא רחוק להיות שקול לעו״ד מנוסה בתחום. את הפערים האלו אפשר לצמצם בעזרת כלים מסוימים, כמו RAG.
RAG מאפשר לי ״להזריק״ למודל עוד מידע רלוונטי שלא קיים במודל (קרי: המודל לא אומן עליו) בצורה דינמית ומותאמת לשימוש הספציפי. RAG יכול להפוך צ׳ט גנרי מבוסס LLM – לצ׳ט שמצליח לענות בצורה טובה על שאלות מעמיקות בתחום מסוים (נניח: נדל״ן).
מענה על שאלות הוא עדיין שימוש דיי מוגבל, ומה שהיינו רוצים מהסוכנים שלנו (באידאל) הוא לטפל בכל משימה שבעל המקצוע האנושי היה מטפל בה. למשל:
- תן לי חוות דעת על תיק מסוים והצע דרכי פעולה.
- הגב לחוות הדעת של עו״ד השני – על מנת לשכנע בעמדה מסוימת.
- פנה אל הלקוח ואסוף ממנו פרטים נוספים על מנת להכין את חוות הדעת.
- הצע מה הצעד הבא בניהול התיק.
- נהל את התיק קצה-לקצה עד להגעה להצלחה.
היכולות האלו הם עליית מדרגה פונקצינלית מ ״chat חכם שיודע המון״, אבל בעזרת כלים נוספים שעליהם נדבר – אפשר לראות כיצד העולם מתקדם לכיוון הזה.

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

בפועל, אלו רעיונות שעדיין לא הוכיחו את עצמם ב scale. ייתכן שיצוץ משהו דומה בעתיד אולי בארכיטקטורה של Multi-Agents ואולי בארכיטקטורה אחרת – עוד מוקדם מדי לומר.
Retrieval Augmented Generation (RAG)
על הנושא הזה כבר כתבתי, אבל הוא חשוב מספיק כדי שאסכם אותו שוב. נניח אני בונה צ׳ט לאתר שעוסק במסעדות – ואני רוצה לענות ללקוחות על שאלות מסוימות. למשל:

ל LLM, כמודל, אין ידע מספיק כדי לענות על השאלה:
- הוא לא יודע מי המשתמש, והיכן הוא גר. באיזה סניף מדובר.
- הוא לא מכיר את רשת המסעדות ״בורגר סאלון״ – זה לא היה כלול במידע האימון שלו. בכל זאת, הוא הצליח להבין מהשם את ההקשר, ולענות תשובה הגיונית – שזה מרשים!
- הוא לא יודע מה שעות הפתיחה של המסעדה הספציפית – מידע שיכול להתעדכן כל הזמן.
- הוא לא יודע מה התאריך הנוכחי, קרי אפילו אם יידע מה שעות הפתיחה של המסעדה – הוא לא יוכל לספק תשובה טבעית כמו ״היום הם פתוחים עד 20:00, אבל מחר מתשע בבוקר עד חצות״ – מה שכן הייתי רוצה לקבל מצ׳ט אנושי.
יכולנו בעזרת prompt engineering להוסיף context ל prompt שיוסיף עוד מידע. למשל: שעות הפעילות של כל המסעדות שאנחנו מכירים. זה היה עוזר אבל:
- ה prompt היה גדול ומכאן יקר לעיבוד (זמן, כסף)
- ככל שה prompt גדול יותר ה attention של ה LLM נפגע – וייתכן שהוא יתבלבל – ויספק פרטים של מסעדה אחרת.
מכאן השלב הבלתי נמנע הוא לספק prompt דינאמי – עם מידע ממוקד לשאלה הספציפית. זהו תהליך ה RAG:

- אנחנו מקבלים את ה prompt מהמשתמש
- אנחנו מעבירים אותו לתהליך ה RAG בכדי לנסות ולשפר אותו (להעשיר את ה context)
- אנחנו מחפשים מילות מפתח ב prompt, למשל את השם ״בורגר סאלון״.
- אנחנו שולפים מבסיס הנתונים (נקרא בעולם הזה: Knowledge Base) שהכנו מראש, מידע ואת שעות הפעילות העדכניים של בורגר סאלון.
- אנחנו מעשירים את ה prompt ב context רלוונטי:
- תאריך של היום
- מיקום של המשתמש (שלפנו geoLocation מהדפדפן)
- מידע כללי על מסעדת בורגר סאלון ושעות פתיחה עדכניות
- נשלח את ה prompt המשופר ל LLM – על מנת לקבל תשובה איכותית, שלא היינו יכולים לקבל ללא תהליך ה RAG
ה prompt המשופר יכול להראות כך:
INFORMATION: current time is {datetime} the user current location is {address} Information about the restaurant: {restaurant_general_info} {restaurant_opening_hours} QUERY: {user_query} INSTRUCTIONS: You are a helpful agent providing information about restaurants. Answer the users QUERY using the INFORMATION text above. Keep your answer ground in the facts of the INFORMATION. If the INFORMATION doesn’t contain the facts to answer the QUERY answer you don't know.
התוצאה, כמובן, תהיה בסדר גודל מוצלח יותר, מ prompt שלא כולל מידע דינאמי ספציפי.
RAG הוא עולם בפני עצמו, הכולל טכניקות שונות כיצד לבחור איזה מידע לשלוף, כיצד לבחור כמה מידע לשלוף, כיצד למיין אותו ב prompt, כיצד לאנדקס את המידע, וכיצד לנטר ולשפר את תהליך ה Retrieval. קצרה היריעה מלדון בכל הנושאים הללו.
Tools Use
בואו נחזור למערכת בדיקת המבחנים שיצרנו, ונראה מצב שבו LLM הוא לא רק יקר יותר – אלא הרבה פחות מוצלח בתוצאה. למשל: בדיקת פתרון בעיה מתמטית.

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

היום, אם תלכו ל chatGPT ותתנו לו לפתור בעיה מתמטית עם מספר רב ספרות – סיכוי טוב שהוא יענה תשובה מדויקת:

השיפור שאתם רואים אינו שיפור במודל GPT – אלא שיפור באפליקציית ה chatGPT. האפליקציה סיפקה למודל כלי של חישוב מתמטי שהוא יכול להשתמש בו.
ברגע שהמודל מזהה שעליו לפתור בעיה מתטמטית, הוא מפעיל את הכלי החיצוני – ואז משלב את התוצאה של הכלי בתשובה.
הכלי עצמו, לא משתמש ב LLM. זהו כלי שפותח בעזרת קוד אימפרטיבי – כזה שקל לו לבצע חישובים מתמטים מדויקים, ובמהירות. הוא פיצוי למודל – בנקודות שבוא המודל הוא חלש. לעתים קרובות, הפיצוי הזה מאוד מוצלח.

אנחנו רואים כיצד LLM הוא אינו ״קליע כסף״ לכל בעיה, אלא השילוב שלו עם כלים קלאסיים (קוד אימפרטיבי, קרי פונקציה בג׳אווה / פייטון / וכו׳) מקדמים אותנו לעבר החזון של סוכן LLM חכם ורב-יכולות.
מערכת יכולה להשתמש במגוון כלים, לא רק כלי אחד. חלק מהכלים יכולים להיות מבוססי קוד אימפרטיבי, חלקם מבוססי מערכות צד שלישי (מערכת לחיזוי מזג האוויר) וחלקם מבוססי מודלי ML המתאימים יותר למשימה ספציפית (למשל: רגרסיה).
הבחירה באיזה כלי להשתמש, שאלה מופשטת בהנתן prompt טקטואלי ממנו אמורים להסיק את הבחירה, יכולה גם היא להעזר ביכולות LLM. הנה prompt לדוגמה:
system_prompt = """You are an assistant that has access to the following set of tools. Here are the names and descriptions for each tool: {rendered_tools} None - if the query require none of the tools above. Given the user input, return the name of the most appropaite tool to respond to the query effectively."""
במקום של {rendered_tools} נשתול מפה המתארת את שמות ה Tools ואת התיאורים המילוליים של מה כל Tool עושה ומתי נכון להשתמש בו. יש פה עניין של prompt engineering, בחירת מילים המובילה לתוצאות טובות.
בשלב הבא, נבדוק אלו arguments ה tool שנבחר זקוק – ונפרסר את ה query של המשתמש כדי לשלוף את הארגומנט הנכון מהשיחה עם המשתמש. למשל: המספר לו אנו רוצים לחשב את השורש. גם הפעולה הזו יכולה להתבצע בעזרת LLM.
מכאן, אנחנו יכולים להפעיל את ה tool (פונקציית חישוב ביטוי מתמטי) – ולשלב את התוצאה בתשובה למשתמש. שילבנו את הבנת הטקסט וההקשר של ה LLM עם חישוב מדויק ש LLM אינו מוצלח בו.
כלים יכולים לספק מגוון השלמות דינאמיות למגבלות של ה LLM. למשל: RAG. במקום להבין מראש איזה מידע חסר – ולהזין אותו כ context על ה prompt, לפעמים יעיל יותר לתת ל LLM להסיק בעצמו איזה מידע חסר לו – ושהוא יבקש אותו, בעזרת פנייה ל Tool המתאים. למשל: Tool המספק שעות פעולה של מסעדה.
כלים אחרים הם כאלו שמבצעים פעולות. למשל: LLM הוא מודל סגור ולא יכול לבצע הזמנה למסעדה. מצד שני הוא יכול להסיק שהלקוח מבקש לבצע הזמנה, ואז להפעיל Tool שפונה ל API של המסעדה, עם פרטי ההזמנה הרצויים שה LLM שלף מהשיחה – ולבצע את ההזמנה בפועל.
השימוש בכלים מרחיב ומגוון את יכולות ה LLM ומקרב אותנו לחזון ה LLM Agent. עדיין חסרים לנו כמה כלים, עליהם נדבר בפוסט הבא.
לסיכום
LLM הוא ״סוג של קסם״, המהווה פריצת דרך ביכולות שלנו לפתור בעיות בעזרת תוכנה. למרות שהמודלים הולכים ומשתפרים, LLM בצורה גנרית יפתור מעט מאוד בעיות. על מנת לפתור בעיות מגוונות אנחנו צריכים לבצע עבודה הנדסית (prompt engineering, RAG, tools) מה שמאפשר לנו באמת לבנות פתרונות מגוונים מבוססי LLM.
החזון המדובר היום הוא LLM Agents שיחליפו מומחים בתחומם, לפחות חלקית. הדרך לשם – היא עקב לצד אגודל – בניית עוד יכולת ועוד יכולת, ושיפור היכולות. ההתקדמות בתחום הזה היא לא פחות ממדהימה, הן בהיבט המודלים שהולכים ומשתפרים (דיוק, עלויות), והן ברמת הטכניקות ההנדסיות המאפשרות לרתום את המודלים והפיכתם לפתרונות לבעיות עסקיות.
לאחר שעסקתי קצת בנושא בחודשים האחרונים, אני ממליץ פחות לתכנן מערכות Multi-Agents ויותר לבנות יכולות עסקיות אחת-אחת ולראות להיכן צומחים משם. כמו כן, ניתן לפתור המון בעיות בעזרת LLM – וזה דיי מגניב, אבל לא תמיד משתלם. פונקציות המבוססות על LLM, במיוחד המורכבות שבהן, דורשות ניטור ותחזוק שוטפים לא מובטלים. המודל הוא סטוכסטי ולא תמיד צפוי או הגיוני. את זה צריך לנטר, ו to mitigate כל הזמן. גם בעקבות שינויים שלא היינו מצפים שישפיעו (עדכנו מעט את ה prompt, יש נתונים נוספים ב knowledge base, עברנו להשתמש במודל מתקדם יותר).
כרגיל, חשוב לבחור בכלי הנכון למשימה, ולא להסתנוור. לא פעם עדיף להשתמש במודל ML קלאסי או אלגוריתם קוד פשוט אבל מספיק טוב – ולא לתחזק פונקציית LLM שהיה קל לכתוב – אך דורשת תחזוקה מתמשכת.
שיהיה בהצלחה!