Streaming

למה streaming חשוב בסוכן אגנטי

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

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

סוגי אירועים בזרם של agent

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

רמת הפירוט המדויקת תלויה במצב הסטרימינג (stream mode) שמבקשים — לפעמים מספיק לקבל רק את טקסט התשובה הסופית תוך כדי כתיבה, ולפעמים רוצים לראות את כל אירועי הביצוע הפנימיים כדי להציג "מה ה-agent עושה עכשיו" באופן מפורט.

צריכת סטרים בקוד: async iteration

במקום agent.invoke, קוראים ל-agent.stream עם אותם ארגומנטים בדיוק — הוא מחזיר iterable אסינכרוני שאפשר לעבור עליו עם for await...of, ומקבלים chunk חדש בכל פעם שיש עדכון.

TypeScript
const stream = await agent.stream(
  {
    messages: [
      { role: "user", content: "מה מזג האוויר בתל אביב, ומה ההזמנות הפתוחות שלי?" },
    ],
  },
  { configurable: { thread_id: "chat-4", userId: "user-42" } }
);

for await (const chunk of stream) {
  console.log(chunk);
}

דוגמה מלאה: הצגת התקדמות לפי סוג אירוע

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

TypeScript
for await (const chunk of stream) {
  switch (chunk.type) {
    case "tool_call_start":
      console.log(`🔧 מפעיל כלי: ${chunk.toolName}`);
      break;
    case "tool_call_end":
      console.log(`✅ ${chunk.toolName} הסתיים`);
      break;
    case "text":
      process.stdout.write(chunk.content);
      break;
  }
}

מתי להשתמש ב-stream ומתי ב-invoke

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

stream מתאים בכל מקום שיש משתמש שמחכה מול מסך: צ'אט, כלי CLI אינטראקטיבי, או כל ממשק שרוצה להראות שה-agent "חי" ועובד, ולא רק ספינר אילם עד שהתשובה מוכנה.

שאלות נפוצות

איך מעבירים את הסטרים מהשרת לדפדפן?

agent.stream רץ בשרת, ולכן מעבירים את ה-chunks לדפדפן בתגובת HTTP מוזרמת, למשל Server-Sent Events: כל chunk נשלח כאירוע ברגע שהוא מגיע, והדפדפן מציג אותו. כדאי לשלוח לדפדפן רק את מה שהממשק צריך — טקסט וסטטוס של כלים — ולא את כל האירועים הפנימיים, שעלולים לכלול מידע שלא נועד למשתמש.

מה קורה כשהמשתמש סוגר את הדף באמצע ההרצה?

אם לא מטפלים בזה, ה-agent ממשיך לרוץ בשרת, מפעיל כלים וצורך טוקנים בלי שאיש מחכה לתוצאה. כדאי לזהות ניתוק של הלקוח ולבטל את ההרצה, למשל עם AbortSignal שמעבירים בהגדרות ההרצה (בדקו בתיעוד את השם המדויק). אם הפעולה צריכה להסתיים בכל מקרה, עדיף להריץ אותה כ-job רקע ולהציג את התוצאה כשהמשתמש חוזר.

האם streaming עובד יחד עם structured output?

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