מעודכן ליולי 2026 13 דקות קריאה מתקדם

AI Observability
— לראות מה הסוכן עושה

סוכן AI ש"סתם לא עובד" הוא סיוט לדיבוג — קלט לא-דטרמיניסטי, שרשרת קריאות ל-LLM וכלים, ועלויות שמטפסות. Observability הופך את הקופסה השחורה לשקופה: כל trace, כל prompt, כל טוקן ועלות. במדריך: ארבעת עמודי התווך, tracing ו-evals, ו-LangSmith מול Langfuse.

Tracing
מה קרה
Evals
כמה טוב
Cost
כמה עולה
Latency
כמה מהר

למה ניטור רגיל לא מספיק כאן

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

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

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

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

visibility
המבחן

לקוח מתלונן על תשובה שקיבל אתמול. תוך כמה זמן תוכלו לראות בדיוק מה נשלח למודל ומה חזר? אם התשובה אינה "דקה" — זה הפער.

היחידה שהכל נבנה סביבה

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

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

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

וזה גם הסדר הנכון להיכנס לתחום: trace ראשון, מדדים אחר כך. אפשר לגזור מדדים מתוך traces; אי אפשר לשחזר trace ממדדים.

מה נשמר בכל שלב

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

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

איך זה נראה בקוד

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

@contextmanager
def step(trace_id, name, parent=None):
    rec = {"trace_id": trace_id, "name": name,
           "parent": parent, "started": now(),
           "meta": {}}
    try:
        yield rec
        rec["status"] = "ok"
    except Exception as e:
        rec["status"] = "error"
        rec["error"] = str(e)
        raise
    finally:
        rec["ended"] = now()
        store(rec)          # טבלה, לא שירות חיצוני


with step(tid, "answer") as root:
    with step(tid, "retrieve", root) as s:
        docs = search(q)
        s["meta"]["ids"] = [d.id for d in docs]
    with step(tid, "generate", root) as s:
        s["meta"]["prompt"] = final_prompt
        out = call_model(final_prompt)
        s["meta"]["output"] = out
        s["meta"]["tokens"] = out.usage

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

ומה אסור לשמור

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

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

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

לא חייבים לשמור הכל

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

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

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

המספרים שבאמת מעניינים

אחרי ה-traces מגיעים המדדים, ורק חלק מהם משנים החלטות:

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

איפה הכסף באמת הולך

כשמסתכלים לראשונה על פילוח עלות של מערכת LLM, התוצאה כמעט תמיד מפתיעה — ובאותם כיוונים.

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

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

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

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

אותות איכות שלא דורשים סימון ידני

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

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

משוב מהמשתמש, ומה הוא שווה

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

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

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

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

על מה להתריע

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

ומה שעדיף להשאיר לדוח יומי במקום להתרעה מיידית: שינויים קטנים והדרגתיים. הם אמיתיים ושווים מבט, והם לא דורשים להעיר מישהו.

וכלל אחד שמונע את רוב הרעש: התרעה חייבת לומר מה לעשות. "שיעור השגיאות עלה" היא הודעה; "שיעור כשל בקריאות לכלי התשלום עלה מ-1% ל-12% בשעה האחרונה" היא התחלה של תיקון.

להשוות שתי גרסאות בייצור

מערך הערכה אומר אם שינוי משפר את מה שידעתם לבדוק. תצפית אומרת מה הוא עשה למשתמשים אמיתיים — ואלה שתי שאלות שונות שכדאי לשאול את שתיהן.

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

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

מה קורה כשמגיעה תלונה

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

  1. למצוא את ה-trace. לפי מזהה שיחה, משתמש או זמן. אם זה לוקח יותר מדקה — הבעיה הראשונה היא באינדוקס, לא בתשובה.
  2. לקרוא את ההקשר שנשלח בפועל. לא את התבנית — את הטקסט הסופי. במקרים רבים כאן זה נגמר: השדה שהיה אמור להיכנס היה ריק.
  3. לבדוק מה נשלף. אם הקטע הנכון לא היה שם, זו בעיית שליפה והתשובה של המודל הייתה סבירה בהינתן מה שקיבל.
  4. לבדוק את קריאות הכלים. פרמטרים שגויים, תוצאה ריקה שנראתה כמו הצלחה, שגיאה שנבלעה.
  5. ורק עכשיו להסתכל על הפלט עצמו. אם ההקשר היה נכון, השליפה הייתה נכונה והכלים החזירו נכון — אז זו באמת התנהגות של המודל, וזה תיקון בהנחיה או במערך ההערכה.

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

כלים: מה באמת ההבדל

יש כמה כלים ייעודיים לתחום, והבחירה ביניהם פחות קריטית ממה שנדמה. מה שכן שווה להשוות:

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

כשהתקלה אינה אצלכם

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

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

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

איך מתחילים ביום אחד

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

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

מי מסתכל על זה, ומתי

הכשל הנפוץ ביותר במערכות תצפית אינו טכני: הן נבנות, ואיש לא פותח אותן. לוח מחוונים שנצפה פעם בחודש הוא ארכיון, לא תצפית.

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

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

מתי זה מוגזם

טעויות שחוזרות