本指南說明如何使用 Chat API 中的 StreamMessage 資源,在 Google Chat 中逐步串流訊息。串流功能可讓 Google Chat 應用程式在完成訊息前,顯示即時進度指標、中間推論或工具執行步驟,以及遞增文字回覆。
串流功能適用於採用生成式 AI 的 Chat 擴充應用程式,或長時間執行的後端工作流程,這類工作流程需要幾秒或幾分鐘才能生成完整回覆。
訊息串流的運作方式
串流訊息會先經過有效串流狀態,然後才會成為聊天室中的標準 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) 的傳送者可以點選「Stop」(停止) 取消生成。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 應用程式新增至討論串 Chat 聊天室 (或已包含至少一則訊息的 1:1 即時訊息),並取得可存取訊息的資源名稱,以便回覆 (
spaces/SPACE_ID/messages/MESSAGE_ID)。 如要使用 Python 範例,請安裝適用於 Python 的 Google API 用戶端程式庫和
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(如果MARKUP_SYNTAX_UNSPECIFIED,則預設為 Chat 擴充應用程式設定的語法)。如果您打算加入內嵌引用,請設定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:
- 在
chunkToken中傳遞最新的nextChunkToken。每次成功呼叫都會傳回新的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。 - 在
StreamMessage要求主體中加入最新的nextChunkToken,並記錄回應中傳回的新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"]
完成串流
生成作業完成後,請使用最新的 chunkToken 呼叫 spaces.streamMessages.commit,將串流最終確定為永久 Message 資源:
- 您可以在修訂要求中選擇加入最終
streamContentChunks,包括僅限修訂的區塊類型 (card、accessoryWidget和citedSource)。 如果您先前呼叫時已串流非空白內容,則可在提交時省略
streamContentChunks。最終提交的訊息不得空白。
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 接受:
| Chunk 欄位 | 支援的方法 | 最終 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。必須在 text 中使用 markupSyntax: "MARKUP_SYNTAX_MARKDOWN" 和相符的 <chat-citation data-id="ID">...</chat-citation> 標記。傳送含有現有 id 的 citation 會覆寫先前的引用。 |
card |
僅觀看commit |
cardsV2[] |
互動式或資訊CardWithId卡。 |
accessoryWidget |
僅觀看commit |
accessoryWidgets[] |
郵件下方顯示的 AccessoryWidget 按鈕,例如意見回饋按鈕。 |
citedSource |
僅觀看commit |
elements.citedSources[] |
CitedSource 訊息下方顯示的頁尾連結,不含內嵌引用標記。 |
處理使用者取消串流
串流進行期間,只有所參照訊息 (referencedMessage) 的傳送者可以點選串流訊息上的「停止」。使用者停止串流時,Chat 會傳送系統指令互動事件,其中包含 cancelStream.streamMessage (已停止串流的 spaces/{space}/streamMessages/{stream_message} 資源名稱),傳送至 Chat 應用程式端點。
傳入 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 事件時:
- 向背景 worker 發出信號,停止為
streamMessage生成更多權杖或執行下游工具。 - 請使用下列任一方法解決進行中的串流問題:
- 保留部分輸出內容:使用最新的
chunkToken呼叫spaces.streamMessages.commit(可視需要附加附註,例如"\n\n_Generation stopped._")。 - 捨棄回覆:呼叫
spaces.streamMessages.delete,這樣就不會將任何內容儲存至討論串。
- 保留部分輸出內容:使用最新的
- 從互動事件處理常式傳回空白的 HTTP
200 OKJSON 回應 ({})。
限制
訊息串流有下列限制:
- 適用平台:訊息串流功能僅適用於網頁版 Chat。我們很快就會支援 Android 和 iOS。
- 串流逾時:
StreamMessage建立後 10 分鐘會逾時。Chat 擴充應用程式必須在串流開始後 10 分鐘內呼叫spaces.streamMessages.commit或spaces.streamMessages.delete。