במדריך הזה מוסבר איך להעביר הודעות בסטרימינג באופן מצטבר ב-Google Chat באמצעות המשאב StreamMessage ב-Chat API. הסטרימינג מאפשר לאפליקציה ל-Google Chat להציג אינדיקטורים של התקדמות בזמן אמת, שלבי ביניים של חשיבה או הפעלת כלים ותשובות טקסט מצטברות לפני שההודעה מסתיימת.
התכונה הזו מיועדת לאפליקציות ל-Chat שמבוססות על AI גנרטיבי או על תהליכי עבודה בקצה העורפי שנמשכים זמן רב, שבהם יצירת תשובה מלאה נמשכת כמה שניות או דקות.
איך פועל סטרימינג של הודעות
הודעה בסטרימינג עוברת דרך מצב סטרימינג פעיל לפני שהיא הופכת למשאב Message רגיל במרחב:
- התחלת שיחה (
spaces.streamMessages.create): האפליקציה ל-Chat יוצרתStreamMessageבמרחב עם שיחות משורשרות, ומפנה להודעה של האינטראקציה עם המשתמש שעליה היא משיבה. ה-API מציג אינדיקטור של התקדמות בזמן אמת בשרשור ומחזיר שם משאב שלStreamMessageו-nextChunkTokenראשוני. - עדכון הסטרימינג (
appendStreamMessageContentאוpatch): כשאפליקציית Chat יוצרת פלט, היא שולחת עדכונים ברצף באמצעות ה-nextChunkTokenהאחרון:- קוראים ל-
spaces.streamMessages.appendStreamMessageContentכדי לשרשר קטעי טקסט חדשים, להוסיף שלבי ביניים, להוסיף ציטוטים בגוף הטקסט או לעדכן אתprogressText. - קוראים ל-
spaces.streamMessages.patchכדי להחליף את חלקי התוכן שמועברים בסטרימינג או לעדכן אתprogressTextבמקום.
- קוראים ל-
- מסיימים או מבטלים את השידור (
commitאוdelete):- מפעילים את
spaces.streamMessages.commitכדי לסיים את השידור ולהמיר אותו למשאבMessageקבוע. אתם יכולים גם לצרף רכיבים שמופיעים רק בתשובה הסופית, כמו כרטיסים, ווידג'טים נלווים ורשימת מקורות בכותרת התחתונה. - כדי למחוק שידור פעיל בלי לשמור הודעה במרחב, צריך להפעיל את
spaces.streamMessages.delete.
- מפעילים את
בזמן שהתשובה נוצרת, רק השולח של ההודעה (referencedMessage) יכול ללחוץ על עצירה כדי לבטל את היצירה. Chat שולח אירוע של פקודת מערכת לביטול לאפליקציית Chat, כדי שתוכלו להפסיק את העבודה בקצה העורפי ולשמור את הפלט החלקי או למחוק את הסטרימינג.
דרישות מוקדמות
כדי להעביר הודעות בסטרימינג באמצעות Chat API, צריך לבצע את הפעולות הבאות:
- חשבון Business או Enterprise ב-Google Workspace עם גישה ל-Google Chat.
- מגדירים את הסביבה:
- יוצרים פרויקט ב-Google Cloud.
- מפעילים ומגדירים את Google Chat API עם שם, סמל ותיאור לאפליקציה ל-Chat.
- יוצרים פרטי כניסה לחשבון שירות ושומרים אותם בתור
credentials.json. כדי להעביר הודעות בסטרימינג, צריך לבצע אימות של האפליקציה עם היקף ההרשאהhttps://www.googleapis.com/auth/chat.bot. אימות משתמש לא נתמך.
- מוסיפים את האפליקציה ל-Chat למרחב משותף עם שרשורים (או לצ'אט אישי שכבר מכיל לפחות הודעה אחת), ומקבלים את שם המשאב של הודעה נגישה שאפשר להשיב לה (
spaces/SPACE_ID/messages/MESSAGE_ID). בדוגמאות ב-Python, מתקינים את ספריית הלקוח של Google API ל-Python ואת
google-auth, ומפעילים את לקוח השירות של Chat API:pip install google-api-python-client google-authfrom google.oauth2 import service_account from googleapiclient.discovery import build SCOPES = ["https://www.googleapis.com/auth/chat.bot"] creds = service_account.Credentials.from_service_account_file( "credentials.json", scopes=SCOPES ) chat = build("chat", "v1", credentials=creds)
התחלת שידור
כדי להתחיל להזרים תשובה, צריך להפעיל את spaces.streamMessages.create ולהעביר StreamMessage בגוף הבקשה:
-
referencedMessage(חובה): שם המשאב של ההודעה שהפעילה את התשובה, בפורמטspaces/{space}/messages/{message}. ההודעה שאליה מפנים צריכה להיות באותו מרחב משותף, ולאפליקציה ל-Chat צריכה להיות גישה אליה. התשובה של Chat תפורסם באותו שרשור כמוreferencedMessage. -
progressText(חובה): תווית סטטוס בטקסט פשוט (עד 250 תווים) שמוצגת לצד אינדיקטור ההתקדמות, למשל"Thinking...". markupSyntax(אופציונלי): תחביר עיצוב הטקסט של ההודעה, כמוMARKUP_SYNTAX_MARKDOWNאוMARKUP_SYNTAX_CHAT(ברירת המחדל היא התחביר שהוגדר באפליקציה ל-Chat אםMARKUP_SYNTAX_UNSPECIFIED). צריך להגדיר אתMARKUP_SYNTAX_MARKDOWNאם מתכננים לכלול ציטוטים מוטבעים.-
streamContentChunks(אופציונלי): קטעיtext,stepאוcitationראשוניים שיוצגו מיד.
שומרים את name (spaces/{space}/streamMessages/{stream_message}) וגם את nextChunkToken מהתגובה לקריאות הבאות.
HTTP
POST https://chat.googleapis.com/v1/spaces/SPACE_ID/streamMessages HTTP/1.1
Authorization: Bearer ACCESS_TOKEN
Content-Type: application/json
{
"referencedMessage": "spaces/SPACE_ID/messages/MESSAGE_ID",
"progressText": "Thinking...",
"markupSyntax": "MARKUP_SYNTAX_MARKDOWN"
}
Python
stream = (
chat.spaces()
.streamMessages()
.create(
parent="spaces/SPACE_ID",
body={
"referencedMessage": "spaces/SPACE_ID/messages/MESSAGE_ID",
"progressText": "Thinking...",
"markupSyntax": "MARKUP_SYNTAX_MARKDOWN",
},
)
.execute()
)
stream_name = stream["name"]
chunk_token = stream["nextChunkToken"]
השיטה מחזירה משאב StreamMessage:
{
"name": "spaces/SPACE_ID/streamMessages/STREAM_MESSAGE_ID",
"progressText": "Thinking...",
"markupSyntax": "MARKUP_SYNTAX_MARKDOWN",
"nextChunkToken": "INITIAL_CHUNK_TOKEN"
}
הוספת קטעי תוכן
כשהאפליקציה ל-Chat יוצרת שלבי ביניים או אסימוני טקסט, צריך להפעיל את spaces.streamMessages.appendStreamMessageContent:
- עוברים את
nextChunkTokenהאחרון בchunkToken. כל קריאה מוצלחת מחזירהnextChunkTokenחדש שצריך להעביר בבקשת העדכון או השמירה הבאה. - החלקים של
textמשורשרים ישירות לטקסט שהועבר בסטרימינג קודם לכן. צריך לכלול רווחים או שורות חדשות לפי הצורך בין החלקים. stepקטעים נוספים לרשימת שלבי הביניים שמוצגים בהודעה.progressTextהוא אופציונלי. אם משמיטים אתprogressTextאו מגדירים אותו כ-"", ב-Chat ממשיך להופיע הערך שלprogressTextשהוגדר קודם.
HTTP
POST https://chat.googleapis.com/v1/spaces/SPACE_ID/streamMessages/STREAM_MESSAGE_ID:appendStreamMessageContent HTTP/1.1
Authorization: Bearer ACCESS_TOKEN
Content-Type: application/json
{
"chunkToken": "INITIAL_CHUNK_TOKEN",
"progressText": "Searching documentation...",
"streamContentChunks": [
{
"step": {
"title": "Search knowledge base",
"description": "Found 3 matching articles."
}
},
{
"text": "See <chat-citation data-id=\"c1\">guide</chat-citation>:\n"
},
{
"citation": {
"id": "c1",
"citedSources": [
{
"title": "System Architecture Guide",
"uri": "https://example.com/docs/arch"
}
]
}
}
]
}
Python
stream = (
chat.spaces()
.streamMessages()
.appendStreamMessageContent(
name=stream_name,
body={
"chunkToken": chunk_token,
"progressText": "Searching documentation...",
"streamContentChunks": [
{
"step": {
"title": "Search knowledge base",
"description": "Found 3 matching articles.",
}
},
{
"text": (
'See <chat-citation data-id="c1">'
"guide</chat-citation>:\n"
)
},
{
"citation": {
"id": "c1",
"citedSources": [
{
"title": "System Architecture Guide",
"uri": "https://example.com/docs/arch",
}
],
}
},
],
},
)
.execute()
)
chunk_token = stream["nextChunkToken"]
החלפת תוכן בסטרימינג או טקסט של התקדמות
אם אתם צריכים לשכתב תוכן שכבר הועבר בסטרימינג (לדוגמה, אחרי הפעלת מסנן בטיחות או עיבוד לאחר מעשה) או לעדכן רק את progressText בלי להוסיף קטעים, אתם יכולים להפעיל את spaces.streamMessages.patch:
- מגדירים את
updateMaskלרשימה מופרדת בפסיקים של שדות לעדכון:progressText,streamContentChunksאוprogressText,streamContentChunks. - כוללים את ה-
nextChunkTokenהאחרון בגוף הבקשה שלStreamMessage, ומתעדים את ה-nextChunkTokenהחדש שמוחזר בתגובה. - כשהערך של
streamContentChunksהואupdateMask, החלקים שסופקו מחליפים את התוכן ששודר בסטרימינג בעבר, במקום להתווסף אליו. כשהשדה
progressTextנמצא ב-updateMask, השדהprogressTextחייב להכיל טקסט פשוט באורך של עד 250 תווים.
HTTP
PATCH https://chat.googleapis.com/v1/spaces/SPACE_ID/streamMessages/STREAM_MESSAGE_ID?updateMask=progressText,streamContentChunks HTTP/1.1
Authorization: Bearer ACCESS_TOKEN
Content-Type: application/json
{
"nextChunkToken": "LATEST_CHUNK_TOKEN",
"progressText": "Formatting response...",
"streamContentChunks": [
{
"text": "Updated response text."
}
]
}
Python
stream = (
chat.spaces()
.streamMessages()
.patch(
name=stream_name,
updateMask="progressText,streamContentChunks",
body={
"nextChunkToken": chunk_token,
"progressText": "Formatting response...",
"streamContentChunks": [
{"text": "Updated response text."}
],
},
)
.execute()
)
chunk_token = stream["nextChunkToken"]
סיום השידור
בסיום היצירה, מפעילים את spaces.streamMessages.commit עם הערך האחרון של chunkToken כדי להפוך את הסטרימינג למשאב Message קבוע:
- אפשר לכלול את
streamContentChunksהסופי בבקשת השמירה, כולל סוגי מקטעים לשמירה בלבד (card,accessoryWidgetו-citedSource). אם כבר העברתם תוכן לא ריק בסטרימינג בשיחות קודמות, אתם יכולים להשמיט את
streamContentChunksכשאתם מבצעים commit. ההודעה הסופית של ה-commit לא יכולה להיות ריקה.
HTTP
POST https://chat.googleapis.com/v1/spaces/SPACE_ID/streamMessages/STREAM_MESSAGE_ID:commit HTTP/1.1
Authorization: Bearer ACCESS_TOKEN
Content-Type: application/json
{
"chunkToken": "LATEST_CHUNK_TOKEN",
"streamContentChunks": [
{
"text": "All checks passed."
},
{
"citedSource": {
"title": "Deployment Runbook",
"uri": "https://example.com/docs/runbook"
}
},
{
"card": {
"cardId": "details-card",
"card": {
"header": {
"title": "Build Status"
},
"sections": [
{
"widgets": [
{
"textParagraph": {
"text": "All 42 checks succeeded."
}
}
]
}
]
}
}
}
]
}
Python
status_card = {
"cardId": "details-card",
"card": {
"header": {"title": "Build Status"},
"sections": [
{
"widgets": [
{"textParagraph": {"text": "All 42 checks succeeded."}}
]
}
],
},
}
commit_response = (
chat.spaces()
.streamMessages()
.commit(
name=stream_name,
body={
"chunkToken": chunk_token,
"streamContentChunks": [
{"text": "All checks passed."},
{
"citedSource": {
"title": "Deployment Runbook",
"uri": "https://example.com/docs/runbook",
}
},
{"card": status_card},
],
},
)
.execute()
)
final_message = commit_response["message"]
print(f"Committed message: {final_message['name']}")
ביטול שידור פעיל
אם מתרחשת שגיאה שבעקבותיה אי אפשר לשחזר או שמשתמש מבטל את היצירה, ואתם לא רוצים להשאיר תשובה חלקית בשרשור, צריך להפעיל את spaces.streamMessages.delete:
HTTP
DELETE https://chat.googleapis.com/v1/spaces/SPACE_ID/streamMessages/STREAM_MESSAGE_ID HTTP/1.1
Authorization: Bearer ACCESS_TOKEN
Python
chat.spaces().streamMessages().delete(name=stream_name).execute()
אחרי שמעבירים סטרימינג ל-Message, צריך להפעיל את spaces.messages.delete כדי למחוק את ההודעה הסופית.
סוגי קטעי התוכן הנתמכים
כל רשומה ב-streamContentChunks מציינת שדה אחד באיחוד StreamContentChunk. אפשר לשלוח חלק מסוגי הנתונים לאורך כל השידור, ואחרים מתקבלים רק ב-spaces.streamMessages.commit:
| שדה המקטע | אמצעי התשלום הנתמכים | השדה הסופי Message |
הערות |
|---|---|---|---|
text |
create, appendStreamMessageContent,
patch, commit |
text |
טקסט מצטבר. השדה שורשר בתאריך appendStreamMessageContent והוחלף בתאריך patch.
הטקסט הסופי שנשלח לא יכול להיות ארוך מ-32,000 בייטים. |
step |
create, appendStreamMessageContent,
patch, commit |
elements.steps.steps[] |
שלב עיבוד ביניים עם title בטקסט פשוט (חובה) ו-description (אופציונלי). |
citation |
create, appendStreamMessageContent,
patch, commit |
elements.citations[] |
Citation מוטבע עם id אלפאנומרי (פחות מ-63 תווים, מותר להשתמש בקווים תחתונים) ו-citedSources. צריך להוסיף תגי markupSyntax: "MARKUP_SYNTAX_MARKDOWN" ותגי <chat-citation data-id="ID">...</chat-citation> תואמים ב-text. שליחת citation עם id קיים מחליפה את הציטוט הקודם. |
card |
commit בלבד |
cardsV2[] |
כרטיס אינטראקטיבי או כרטיס מידע
CardWithId. |
accessoryWidget |
commit בלבד |
accessoryWidgets[] |
AccessoryWidget כפתורים שמוצגים מתחת להודעה, כמו כפתורים לשליחת משוב. |
citedSource |
commit בלבד |
elements.citedSources[] |
קישור לכותרת תחתונה של CitedSource שמוצג מתחת להודעה
בלי תגי ציטוט מוטמעים. |
טיפול בביטול שידור ביוזמת המשתמש
בזמן שהשידור פעיל, רק השולח של ההודעה שאליה מתייחסים (referencedMessage) יכול ללחוץ על עצירה בהודעה שמשודרת. כשהמשתמש מפסיק את הסטרימינג, אפליקציית Chat שולחת אירוע אינטראקציה של פקודת מערכת שמכיל את cancelStream.streamMessage (שם המשאב של spaces/{space}/streamMessages/{stream_message} של הסטרימינג שהופסק) לנקודת הקצה של האפליקציה ל-Chat.
המבנה של המטען הייעודי (payload) של ה-JSON הנכנס תלוי באופן שבו אתם בונים את האפליקציה ל-Chat – כתוסף ל-Google Workspace או באמצעות אירועי אינטראקציה של Chat API:
תוספים ל-Google Workspace
{
"commonEventObject": {
"hostApp": "CHAT"
},
"chat": {
"user": {
"name": "users/USER_ID"
},
"space": {
"name": "spaces/SPACE_ID"
},
"systemCommandPayload": {
"systemCommandMetadata": {
"cancelStream": {
"streamMessage": "spaces/SPACE_ID/streamMessages/STREAM_ID"
}
}
}
}
}
Google Chat API
{
"type": "SYSTEM_COMMAND",
"space": {
"name": "spaces/SPACE_ID"
},
"user": {
"name": "users/USER_ID"
},
"systemCommandMetadata": {
"cancelStream": {
"streamMessage": "spaces/SPACE_ID/streamMessages/STREAM_ID"
}
}
}
כשאפליקציית Chat מקבלת אירוע מסוג cancelStream:
- צריך לאותת ל-background worker להפסיק ליצור טוקנים נוספים או להריץ כלים במורד הזרם עבור
streamMessage. - כדי לפתור את הבעיה, אתם יכולים לבחור באחת מהאפשרויות הבאות:
- לשמור פלט חלקי: התקשרו ל-
spaces.streamMessages.commitעם ה-chunkTokenהאחרון (אופציונלי, הוספת הערה כגון"\n\n_Generation stopped._"). - מחיקת התשובה: מפעילים את
spaces.streamMessages.deleteכדי ששום דבר לא יישמר בשרשור.
- לשמור פלט חלקי: התקשרו ל-
- מחזירים תגובת HTTP
200 OKJSON ריקה ({}) מהגורם המטפל באירועי אינטראקציה.
מגבלות
אלה המגבלות של סטרימינג של הודעות:
- זמינות בפלטפורמות השונות: אפשר לראות את ערוץ ההודעות רק ב-Chat במחשב. בקרוב תהיה תמיכה ב-Android וב-iOS.
- זמן קצוב לתפוגה של סטרימינג:
StreamMessageפעיל מסתיים 10 דקות אחרי שהוא נוצר. האפליקציה ל-Chat צריכה לקרוא ל-spaces.streamMessages.commitאו ל-spaces.streamMessages.deleteתוך 10 דקות מתחילת הסטרימינג.