התקנה
אינסטרומנטציה
ומה כל אחד מהם פולט בפועל:
כל מה שבתוך ההיקפים יכול להשמיט את
session_id ואת agent_id. ההיקפים קושרים את הזהות למשתני הקשר (context variables), וכל קריאה לשיטת אירוע קוראת אותה משם, כך שלעולם לא צריך להעביר מזהים מפונקציה לפונקציה.
שלושתם עובדים גם עם async with, ולא רק עם with.
קינון סוכנים בונה את העץ. parent_id והעומק מחושבים מתוך המחסנית:
איך היקף נסגר
agent() מטפל בחריגות בשבילך:
השגיאה נפלטת לפני
agent_end, כי ה-dashboard סוגר את ה-span ב-agent_end, וכל מה שמגיע אחריו לא משויך לשום דבר. ביטול אינו כישלון, ולכן הרצות שבוטלו לא מזהמות את תצוגת השגיאות. החריגה תמיד נזרקת מחדש: היקף אף פעם לא בולע אותה.
שיטות האירועים
חמש עשרה שיטות בשש משפחות. רובן באות בזוגות — אתה פולט את אירוע הפתיחה ואחריו את אירוע הסגירה, וה-SDK מודד את ה-span שביניהם.שתי משפחות בני האדם פועלות בכיוונים הפוכים.
אף פריימוורק לא מסמן את הזוג השני, ולכן תמיד תצטרך לפלוט אותו בעצמך.
דוגמה
לולאת קריאות לכלים מול ה-API של OpenAI, בלי פריימוורק סוכנים:docs/manual/examples/.
חוטים ו-async
משתני הקשר עוברים אוטומטית למשימות asyncio. הם לא עוברים לחוטים חדשים, כי חוט מתחיל עם הקשר ריק.propagate(), קריאות האירועים ב-worker זורקות TypeError שמציין את התיקון, במקום שהאירועים ינחתו בלי session. זה מכוון: ה-ingest מדלג על אירוע בלי session ועונה 200, וזה בדיוק הכשל השקט ששכבת הזהות נועדה למנוע.
אינסטרומנטציה לפריימוורק שאין לו מתאם
כל פריימוורק סוכנים נותן לך את אותן שלוש נקודות חיבור. מפה אותן ותקבל trace מלא — ארבעת המתאמים שמגיעים עם ה-SDK לא עושים יותר מזה.1
תחום את ההרצה
2
תחום כל כלי
בכל רכיב שהפריימוורק מכנה tool wrapper או middleware.
3
עטוף כל קריאה למודל בזוג אירועים
אינסטרומנטציה ידנית ואוטומטית משתלבות. מתאם שרץ בתוך היקף שכתבת ידנית מצטרף ל-session של ההיקף הזה, והסוכן של המתאם נרשם כילד של הסוכן שכתבת ידנית — כך מתקבל עץ אחד ולא שניים. זה שימושי כשאתה מוסיף אינסטרומנטציה ידנית לפריימוורק אחד לצד פריימוורק נתמך.
למה אין מתאם ל-AutoGen
למה אין מתאם ל-AutoGen
יש לכך שתי סיבות, ושלוש נקודות החיבור שלמעלה הן התשובה לשתיהן:
autogen-coreלא מתוחזק מאז ספטמבר 2025.- AG2 לא חושף נקודת רישום ברמת התהליך כולו, מקבילה ל-hooks של הפריימוורקים האחרים, ולכן אינסטרומנטציה שלו פירושה לעטוף כל סוכן בכל מקום שבו הוא נוצר.
לעומק
איך ההקלטה עובדת בפועל. שום דבר מזה לא נדרש כדי להתחיל.איך נראית הקלטה בכל פריימוורק
איך נראית הקלטה בכל פריימוורק
לכל הקלטה יש אותו מבנה: span נפתח, העבודה מקוננת בתוכו, ולכל אירוע פתיחה יש אירוע סגירה משלו.הזוג הוא יחידת הבסיס. כל אירוע סגירה נושא משך זמן שה-SDK מודד מאירוע הפתיחה שלו.להלן הרצה אמיתית אחת לכל פריימוורק — כל אחת נלכדה מהדוגמאות שמגיעות עם ה-SDK, ושם המודל עבר נרמול. שים לב כמה מידע מתקבל מקריאה אחת.צמתים הופכים לזוגות hook, כך שמתקבל latency לכל צומת בלי שהם יציפו את רשימת הסוכנים.
- LangGraph
- CrewAI
- LlamaIndex
- Pydantic AI
- סוכנים מותאמים אישית
14 events
איך session מתחיל ומסתיים
איך session מתחיל ומסתיים
אין אירוע סיום ל-session. את ה-session לא סוגרים — הוא פשוט קבוצת אירועים שחולקים את אותו
session_id.הסטטוס נגזר מהמבנה של ה-trace:כלומר, session מסתיים כשכל הזוגות נסגרו. המתאמים פולטים את
agent_end בשבילך, ובזמן הכיבוי הם סוגרים כל מה שעדיין פתוח ומסמנים אותו כלא שלם — הרצה שקרסה מסתיימת בסטטוס done עם פער גלוי, במקום להישאר תלויה.זו הסיבה ש-session יכול להשתרע על פני שתי קריאות.
interrupt() של LangGraph משהה את ההרצה, ה-span השורשי נשאר פתוח בכוונה, והקריאה שממשיכה את ההרצה סוגרת אותו. שתי הקריאות הן session אחד.זהות: session_id, agent_id ומי מנפיק אותם
זהות: session_id, agent_id ומי מנפיק אותם
session_id ו-agent_id הם אופציונליים בכל שיטות האירועים. אם משמיטים אותם, הם נלקחים מההיקף העוטף:TypeError שמציין את התיקון, במקום לפלוט אירוע בלי session — אירוע שה-ingest היה מדלג עליו ובכל זאת עונה 200.ההיקפים קושרים את הזהות למשתני הקשר. אלה עוברים אוטומטית למשימות asyncio, אבל לא לחוטים חדשים — עטוף את ה-worker ב-failproofai_sdk.propagate().מי מנפיק איזה מזהה
איך מתאמים קובעים את session_id
ההתאמה הראשונה קובעת:- אפשרות
session_idמפורשת - מטא-דאטה ברמת הקריאה
- היקף
session()העוטף - מטא-דאטה של הפריימוורק
- מזהה ההרצה של הפריימוורק עצמו
שמור על קרדינליות נמוכה ב-agent_id
זהו ה-facet העיקרי בכל תצוגה של ה-dashboard, והוא עמודה מסוג LowCardinality(String). ערך שמשתנה בכל הרצה פוגע ביעילות העמודה וממלא את התפריט הנפתח של המסנן ברשומה נפרדת לכל הרצה.המתאמים מגנים על העמודה הזו בשבילך:המזהה האמיתי נשמר ב-
fw_agent_id / fw_run_id, שם עדיין אפשר לתשאל אותו בלי שהוא יהיה facet.סוגי האירועים לפי קבוצות — ומה כל פריימוורק רושם
סוגי האירועים לפי קבוצות — ומה כל פריימוורק רושם
מה כל פריימוורק רושם, לפי מדידה בהרצות שלמעלה:
מקף פירושו שאין לפריימוורק מושג כזה.
human_pause ו-human_interrupt מתארים אדם שפועל על הסוכן, ואף פריימוורק לא מסמן זאת — את אלה עליך לפלוט בעצמך.זוגות, קורלציה ומשך
זוגות, קורלציה ומשך
אירוע אף פעם לא מגיע לבד. אירוע אחד פותח span, אחר סוגר אותו, ואירוע הסגירה נושא משך זמן שה-SDK מודד מאירוע הפתיחה.
כללי קורלציה
- השתמש באותו
tool_call_id,hook_id,pause_idאוinput_idגם באירוע הסיום התואם. - ה-SDK מחשב את
duration_msעבורtool_result,hook_completed,agent_resumeו-human_input. העברה שלו לשיטות האלה זורקתValueError. duration_msכן מתקבל ב-model_response, כי רק מי שמבצע את הקריאה יודע מה ה-latency האמיתי של הספק. הוא חייב להיות מספר שלם — ערך float זורקValueErrorכבר בנקודת הקריאה, כי השרת קורא את העמודה כמספר שלם לא מסומן של 32 סיביות, ועבור כל ערך אחר היה שומר NULL.- מפתחות הקורלציה תחומים לפי סוג ולפי session, כך שקריאה לכלי ו-hook יכולים לחלוק מזהה בבטחה, ושני sessions שרצים במקביל יכולים להשתמש באותם מזהים בלי להתנגש. הם לא תחומים לפי סוכן: זוג שנפתח תחת סוכן אחד ונסגר תחת סוכן אחר עדיין מתואם, וזה המצב הרגיל בפריימוורקים מרובי סוכנים.
request_idמזווג אתmodel_requestעםmodel_response. בלעדיו, אירועי מודל מזווגים לפי הסדר בכל סוכן, כך שקריאות מקבילות מזווגות לא נכון.- זוג שמפוצל בין תהליכים עדיין מתואם בהמשך הצינור, אבל ה-SDK לא יכול לחשב את משך הזמן שלו בתוך התהליך.
- מפת האירועים הממתינים מחזיקה לכל היותר 10,000 אירועי פתיחה, וכשהיא מתמלאת היא מפנה את הרשומה הישנה ביותר.
מה יש בחבילה, ואיך instrument() מוצא את הפריימוורק שלך
מה יש בחבילה, ואיך instrument() מוצא את הפריימוורק שלך
התקנת הגדר אם הסדר שגוי, התהליך רץ עם ה-SDK מיובא, המתאם מותקן לכאורה, ואף אירוע לא נפלט. נרשמת בלוג אזהרה שאומרת בדיוק את זה — לכן כשהרצה לא מתעדת כלום, בדוק קודם את הלוגים.
failproofai-sdk מתקינה הכול, כולל ארבעת המתאמים. ה-extras מושכים את הפריימוורק, לא את המתאם.import failproofai_sdk מחויב חוזית לאפס תלויות. הדבר נאכף על ידי בדיקה שמתקינה את ה-wheel הבנוי עם --no-deps, ועל ידי בדיקה נוספת שמוכיחה שאף פריימוורק לא מגיע ל-sys.modules.הזיהוי האוטומטי קורא את
sys.modules, ולא את רשימת החבילות המותקנות, כך שפריימוורק שהתקנת אבל אף פעם לא ייבאת לא עובר אינסטרומנטציה, וגם לא ייובא בשמך. כדי לראות מה מחובר:instrument("crewai") במכונה שאין בה CrewAI לא זורק חריגה. הוא רושם אזהרה בלוג ומחזיר (), כך שפריימוורק אחד חסר לעולם לא מפיל תהליך שמבצע אינסטרומנטציה גם לפריימוורקים אחרים.האזהרה כוללת את ה-ImportError המקורי, וההודעה שלו מציינת את פקודת ההתקנה המדויקת — כך שהתיקון נמצא בלוגים שלך, ולא מוסתר.FAILPROOFAI_SDK_STRICT=1 כדי שבמקום זאת תיזרק חריגה. הדגל הזה נקרא פעם אחת ונשמר במטמון, לכן הגדר אותו בסביבה לפני שהתהליך מתחיל, ולא באמצע ההרצה.איך אירועים מגיעים ל-Cloud
איך אירועים מגיעים ל-Cloud
ה-spool הוא מה שהופך את זה לבטוח: הסוכן שלך אף פעם לא נחסם בהמתנה לרשת, והשבתה של Cloud פירושה תיקייה שהולכת וגדלה, ולא אירועים שאבדו.כל flush כותב קובץ אצווה אחד: קודם
.tmp, אחר כך fsync, ולבסוף שינוי שם אטומי:.jsonl, כך שלעולם לא יקרא קובץ שנכתב רק בחלקו. שם הקובץ כולל חותמת זמן, מזהה תהליך ומספר רץ, כך ששני תהליכים שמבצעים flush באותה אלפית שנייה לא יכולים להתנגש. התור מוגבל ל-10,000 אירועים; מעבר לכך הוא משליך את הישנים ביותר ורושם זאת בלוג.ה-daemon קורא כל אצווה ומחיל עליה השחרה בזיכרון לפני ההעלאה. הוא לא משכתב את
קובץ ה-spool שקרא.הגדר את
collector.redact ל-off רק כשיש דרישה מפורשת לשמור payloads כלשונם;
גם ה-SDK וגם ה-daemon מכבדים את ההגדרה הזו. השחרה מינימלית תופסת מפתחות API
נפוצים, אסימוני bearer, אסימוני JWT והשמה של סודות למשתנים. היא לא יכולה לזהות
מידע רגיש שמנוסח כטקסט חופשי.ה-daemon מוחק כל אצווה תוך אלפיות שנייה מרגע שליחתה, כך ש-ls מתחרה ב-collector ומציג רק חלק קטן ממה שפלטת — ואי אפשר להבחין בין זה לבין SDK שלא תיעד כלום.כדי לוודא שהאירועים באמת הגיעו, בדוק ב-dashboard. כדי לראות את ה-spool מתמלא, עצור קודם את ה-daemon.כשהאינסטרומנטציה נכשלת
כשהאינסטרומנטציה נכשלת
כל callback רץ בתוך עוטף שתפקידו היחיד הוא לזרוק חריגות מחדש, כך שהקריאה שלך נמצאת בתוך
try אחד בדיוק, וכל מה שה-SDK עושה קורה מחוצה לו.ברירת המחדל נכונה ב-production ושגויה בזמן דיבוג, כי כל מה שהיא יכולה להוכיח הוא ש”זה לא קרס”. הגדר
FAILPROOFAI_SDK_STRICT=1 כדי שכשל שהיה נבלע בשקט יתריע בקול רם.בעיות נפוצות
span שאף פעם לא מסתיים
span שאף פעם לא מסתיים
לאירוע פתיחה אין אירוע סגירה:
model_request בלי model_response, או tool_use בלי tool_result. השתמש בהיקפים, שמבטיחים את הזוג גם כשגוף הבלוק זורק חריגה. אם אתה קורא לשיטות האירועים ישירות, השתמש ב-try וב-finally.העברת duration_ms זורקת ValueError
העברת duration_ms זורקת ValueError
הערך נמדד מאירוע הפתיחה התואם, ולכן הוא נדחה ב-
tool_result, hook_completed, agent_resume ו-human_input. הוא מתקבל ב-model_response, כי רק אתה יודע מה ה-latency האמיתי של הספק, ושם הוא חייב להיות מספר שלם.אירועים מחוט worker זורקים TypeError
אירועים מחוט worker זורקים TypeError
החוט לא ירש את ההקשר. עטוף את ה-callable ב-
failproofai_sdk.propagate(). ראה חוטים ו-async.שדה נוסף נעלם או דרס משהו
שדה נוסף נעלם או דרס משהו
שדות נוספים ממוזגים אחרונים, כך ששדה ששמו זהה לשדה אמיתי, כמו
model או outcome, ידרוס אותו וישנה עמודה שמורה. תן לשדות שלך קידומת ייחודית; המתאמים משתמשים בקידומת fw_.במסנן הסוכנים יש אלפי רשומות
במסנן הסוכנים יש אלפי רשומות
agent_id הוא facet בעל קרדינליות נמוכה, והכנסת אליו מזהה הרצה. השתמש בשם של תפקיד או של צומת, ושמור את המזהה האמיתי בשדה של ה-payload.מה הלאה
איך זה עובד
זוגות, מזהים, מחזור החיים של session ומסירה.
קריאת trace
עקוב אחרי שרשרת הסיבתיות ב-session שזה עתה לכדת.
מתאמי פריימוורק
LangGraph, CrewAI, LlamaIndex ו-Pydantic AI.

