For the complete documentation index, see llms.txt. Markdown versions of documentation pages are available by appending .md to the page URL.
主要導覽

管理 GPT-Live 工作階段

設定工作階段、維護上下文,並管理對話生命週期。

連線至 GPT-Live 後,使用工作階段事件來更新上下文、顯示逐字稿,並管理連線的生命週期。模型可以同時聆聽與說話,因此請在應用程式中分別處理接收到的事件、音訊播放與後端任務狀態。

本指南假設你的連線已發出 session.started。如需連線設定與音訊串流的相關資訊,請參閱連線;如需後端作業的相關資訊,請參閱委派與工具

設定工作階段

建立工作階段時,請選擇模型、語音與委派模式。向模型提供對話指示,並加入相關歷史紀錄。隨著對話內容增加,GPT-Live 會自動管理上下文。

組態欄位

設定項目啟動時設定工作階段期間變更
模型設定必填的 model若要變更,請啟動新的工作階段。
指示設定 instructions 以指定對話行為,上限為 16,384 個 Token。使用 session.instructions.append 新增指示。
歷史紀錄input 設為相關的先前文字訊息。預設值為 []附加上下文;不要取代啟動時的歷史紀錄。
語音audio.output.voice 設為支援的語音或已獲授權的自訂語音。預設值為 marin若要變更,請啟動新的工作階段。
委派delegation.type 設為 clientresponses。省略委派設定或將其設為 null 時,會選用用戶端模式。在現有模式內更新 Responses 設定。
儲存store 設為 true,即可從此工作階段建立分支。預設值為 false於啟動時選擇。

語音選項

建立工作階段時,請選擇語音。將 audio.output.voice 設為 API 名稱,例如 "quartz"。GPT-Live 提供下列額外語音選項:

語音API 名稱語言地域風格呈現風格來源
Quartzquartz英語澳洲女性化生成
Rippleripple英語澳洲男性化自然
Vespervesper英語英國男性化自然
Willowwillow英語愛爾蘭女性化自然
Stonestone英語愛爾蘭男性化自然
Gleamgleam英語北美女性化自然
Meridianmeridian英語北美男性化自然
Bossabossa葡萄牙語巴西女性化自然
Tempotempo葡萄牙語巴西男性化自然
Beaconbeacon英語菲律賓男性化生成
Deltadelta英語美國南部女性化生成
Cindercinder英語美國南部男性化生成

地域特色描述的是語音的說話風格,並不保證能忠實呈現當地口音。如需使用自己的錄音建立經核准的語音,請參閱自訂語音

使用 WebSocket 時,請在啟動時選擇共用的 audio.format;工作階段期間無法變更此設定。使用 WebRTC 時,請省略此欄位,因為連線會協商音訊格式。如需格式與串流的詳細資訊,請參閱 WebSocket 音訊格式

更新執行中的工作階段

若工作階段已使用 Responses 委派,可透過 session.update 變更 session.delegation.responses。只需傳送要變更的設定;省略的設定會保留原值。如需設定與更新工作流程的詳細資訊,請參閱設定 Responses 委派

啟動後無法變更委派模式。特別是,將 delegation 設為 null 會選用用戶端模式,而不會重設 Responses 工作階段。啟動欄位 modelinstructionsinputaudiostore 都不是可接受的更新欄位。未知的組態欄位會遭到拒絕。

更新成功時會發出 session.updated,其中包含完整解析後的工作階段組態。如果你提供了 event_id,確認回覆會以 client_event_id 傳回該值。除了確認回覆,也要檢查是否有遭拒絕的指令。更新獲接受僅表示組態已更新,不能據此認定後端任務已執行或模型已發話。

提供歷程記錄與上下文

使用啟動時的歷程記錄接續先前的話題,並在對話進行時附加相關上下文。請將可信任的應用程式指示與使用者訊息及事實性結果分開。

以先前的對話初始化工作階段

建立工作階段時,將先前的文字訊息納入 session.input。例如,將以下 input 欄位新增至工作階段建立組態

export const session = {
  model: "gpt-live-1",
  input: [
    {
      type: "message",
      role: "user",
      content: [
        {
          type: "input_text",
          text: "I need help with my recent order.",
        },
      ],
    },
    {
      type: "message",
      role: "assistant",
      content: [
        {
          type: "output_text",
          text: "What is the order number?",
        },
      ],
    },
  ],
};

此清單最多接受 128 則訊息,合計上限為 8,192 個 Token。支援的角色為 developeruserassistant,每則訊息各含一個文字部分。開發者與使用者訊息使用 input_text;助理訊息使用 textoutput_text。請將可信任的應用程式指示放在 instructions 或開發者訊息中。此清單不接受 system 角色。

請選取下一次互動所需的歷程記錄。input 是啟動欄位,無法用來取代執行中工作階段的歷程記錄。此欄位也無法接受 Responses 委派所使用的所有類型後端輸入項目。

瞭解上下文何時傳入模型

建立工作階段時提供的完整 input,會在工作階段啟動時供模型使用。請將模型從一開始就需要的上下文放在此欄位中。

在工作階段執行期間,session.instructions.appendsession.thinking.appendsession.commentary.append 事件會隨時間逐步將內容傳入模型。這些事件的確認回覆會等到影格處理進度達到上下文注入的預估結束點後才傳回。傳回的 start_msend_ms 描述的是工作階段時間軸上的預估區間,而非發話或播放完成的時間。這些值無法證明模型已處理整份更新內容。請勿假設模型接下來的發話會反映整份更新內容。

如果影格處理進度停止,確認回覆可能會持續處於待處理狀態。關閉工作階段時,尚未完成的附加操作會回報錯誤。請透過 client_event_id 將每個確認回覆與送出時的 event_id 配對,並在等待期間持續處理錯誤。

在對話期間新增上下文

依據你希望模型如何使用更新內容,選擇對應的事件:

  • session.instructions.append:新增可信任的應用程式指示,以影響模型的行為與發話內容。
  • session.thinking.append:新增事實性上下文,但不要求模型立即說出這些內容。
  • session.commentary.append:提供要讓模型說出的資訊;模型可能會改述內容。

每個事件都接受最多 500 個 Token 的純字串 content,以及必填的 delegation_id。若上下文適用於整個工作階段,請使用 null。例如,在應用程式確認使用者已同意並開始查詢後,傳送以下內容:

export function sendUpdate(connection) {
  connection.send({
    type: "session.thinking.append",
    event_id: "context_1",
    delegation_id: null,
    content:
      "The user has already accepted the terms. The account lookup is still running.",
  });
}

等待帶有 client_event_id: "context_1"session.thinking.appended,或處理錯誤。確認回覆表示上下文已獲接受,但不表示模型已發話、音訊已播放,或外部動作已完成。

未立即說出的上下文仍可能影響後續發話,因此不能視為隱私界線。這三種事件都不應包含憑證、機密資訊,以及模型絕不能揭露的文字。指示事件應用於應用程式自行撰寫的行為指示,而非不可信任的工具輸出。請在應用程式中強制執行權限控管與必要的確認程序。

針對頁面導覽、選取操作及其他 UI 變更,請參閱分享 UI 上下文,瞭解如何提供精簡的更新,協助 GPT-Live 理解使用者所指的內容。

對於與後端任務相關的結果,請使用已知的用戶端委派 ID,並遵循傳送正確類型的更新中的說明。此 ID 並非 Responses 回應 ID 或工具呼叫 ID。

應用程式的檢查觸發後,可使用指示引導對話。伺服器可以監控事件,並透過附加至現有工作階段的側頻 WebSocket,或該工作階段的主要 WebSocket 傳送這些修正指示。如需並行檢查、動作封鎖與播放控制的詳細資訊,請參閱套用對話防護機制

建置對話介面

逐字稿與麥克風狀態應獨立於後端進度顯示。收到助理文字並不能讓你知道使用者已聽到多少音訊。

逐字稿增量

監聽 session.input_transcript.delta 以取得使用者語音的逐字稿,並監聽 session.output_transcript.delta 以取得助理語音的逐字稿。每個事件都包含一段文字,以及該片段在工作階段時間軸上的區間:

{
  "type": "session.input_transcript.delta",
  "event_id": "event_transcript_1",
  "delta": "What is",
  "start_ms": 1000,
  "end_ms": 1200
}

依序附加每位說話者的片段,並保留 start_msend_ms。這些值以工作階段時間軸上的毫秒數表示,區間包含起點但不包含終點。它們不是實際時鐘的時間戳記、封包抵達時間,也不是精確的逐字對齊時間。

只有包含逐字稿文字的區間才會產生事件,而網路傳遞的間隔可能不均勻。不要因為沒有收到事件就推斷當時沒有聲音,也不要將單一片段視為完整的使用者回合。逐字稿增量沒有項目 ID,也沒有可明確判定回合已完成的事件。

你可以選擇是否處理逐字稿片段。你可以在對話持續進行時,用這些片段更新 UI、執行檢查,或提早開始工作。若只需簡單的檢查,可考慮使用 gpt-5.6-luna 等小型模型,並設定較低的推理強度。如需範例與連線指引,請參閱回應逐字稿片段

若要實作對話防護機制,請在文字陸續抵達時檢查累積的使用者與助理文字。逐字稿的傳遞不會預留緩衝時間,讓你在播放前核准語音。請參閱視需要控制播放

如果介面會將文字分組為回合,請讓分組保持可修改。保留原始片段,允許使用者與助理的時間區間重疊,並根據錄下的對話調整各項間隔逾時設定。另一位說話者簡短的應答,可能仍屬於正在進行的交流。片段分組本身不得觸發工具執行或取消後端工作。

請將逐字稿時間與音訊播放分開處理。WebSocket 的 session.output_audio.delta 事件沒有時間欄位,也沒有輸出音訊完成事件;WebRTC 則透過媒體軌傳遞音訊。如需音訊處理方式,請參閱連線

顯示字幕

建置可在雙方同時說話時持續延伸的字幕列:

  1. 保留文字原貌。 儲存每位說話者原始的 deltastart_msend_ms。完全依照收到的內容串接文字,包括空格和重複的詞語。不要修剪片段,也不要在片段之間插入空格。
  2. 分別更新每位說話者的字幕。 當雙方語音重疊時,允許使用者與助理的字幕列各自延伸。助理遭打斷後,仍應顯示先前的助理文字,並在助理恢復說話時開始新的一列。
  3. 保持字幕列穩定。 在應用程式中指派顯示 ID,並在文字增加時維持列的順序。不要根據持續變動的文字或結束時間戳記識別字幕列,也不要每次收到片段就將該列移到底部。
  4. 依延遲抵達的片段調整分組。 利用逐字稿時間戳記,將同一位說話者時間相近的片段分為一組。允許延遲抵達的文字更新先前的字幕列,並在保留原始片段的同時調整片段所屬的分組。這些顯示分組並非語意完整的回合;任何間隔門檻都由應用程式自行決定,並需經過測試。
  5. 讓讀者控制捲動。 讀者位於底部時,隨新文字自動捲動。讀者向上捲動時,暫停自動捲動,並提供返回最新字幕的方式。
  6. 在狀態區域顯示工具進度。 使用助理逐字稿事件顯示語音字幕。工具活動與後端結果應顯示在字幕之外;收到結果並不代表助理已經說出該結果。

請測試語音重疊、簡短應答、打斷、長時間停頓,以及雙方文字以不同速率抵達的翻譯情境下,介面的顯示效果。

控制麥克風輸入

傳送 session.input_audio.mute,即可在不結束工作階段的情況下將輸入靜音:

export function sendUpdate(connection) {
  connection.send({
    type: "session.input_audio.mute",
    event_id: "mute_1",
  });
}

等到收到帶有 client_event_id: "mute_1"session.input_audio.muted 後,才能視為指令已被接受。若要恢復輸入,請傳送 session.input_audio.unmute 並等待 session.input_audio.unmuted。這兩種指令都需要處理錯誤。

將輸入靜音不會停止推論、委派工作或生成的語音。需要這些控制功能時,請在應用程式中分別控制麥克風擷取與音訊播放。

在來電者開口前問候

若要在 session.started 之後要求助理問候:

  1. 傳送一個新的 session.instructions.append,並帶上 delegation_id: null。內容應包含問候語、使用語言,以及明確指示:不要等待來電者,立即問候,然後暫停並聆聽。保留既有的啟動指示。
  2. 等待 session.instructions.appended,並確認其 client_event_id 與你的指令相符。如果指令遭拒,請先處理,再繼續。
  3. 保持音訊輸入持續運作,包括來電者開口前的靜音。在 WebSocket 上,持續傳送 session.input_audio.append;在 WebRTC 上,保持協商好的輸入音軌啟用。觀察輸出的逐字稿與音訊,確認問候內容。

在來電者開口前,使用應用程式指定的語言;不要根據姓名、電話號碼或位置推斷語言。如需提示詞設計方式,請參閱語音模型提示詞

如果問候需要遵循應用程式指示,請先透過 session.instructions.append 傳送這些指示,再使用內容簡短的 session.commentary.append 提示助理開始。例如:“Begin the conversation now, following the instructions provided.”保持音訊輸入持續運作,包括來電者開口前的靜音。

指示可用來要求問候,但不保證措辭完全一致或播放不被打斷。API 不會發出開場已完成的事件,收到確認回覆也不表示來電者已聽到問候。若音訊必須逐字一致,請由應用程式控制播放。請針對應用程式支援的語言與打斷情境測試問候。

播報告知聲明

使用 session.instructions.append 要求以指定措辭播報告知聲明。session.commentary.append 可能會改述文字。例如,在 session.started 之後傳送:

export function sendUpdate(connection) {
  connection.send({
    type: "session.instructions.append",
    event_id: "disclosure_1",
    delegation_id: null,
    content:
      "Immediately say the following disclosure exactly and in full before responding to the caller: This call may be recorded for quality and training purposes.",
  });
}

按照在來電者開口前問候所述,保持音訊輸入持續運作。請審慎選擇播報時機:在對話中傳送指示,可能會打斷正在播放的語音。

這只是要求使用指定措辭,並不保證會完全照著播報。請先驗證完整的語音聲明內容與實際播放情況,再將其標記為已播報。session.instructions.appended 僅確認指示已被接受。若音訊播報必須完全一致,請透過應用程式播放已驗證的錄音或已產生的音訊片段,並在播放期間控制 GPT-Live 的輸出。請參閱視需要控制播放

管理較長的對話

GPT-Live 會在長時間對話中自動管理上下文,不需要設定任何組態參數。你在工作階段開始時提供的指示,在整個壓縮過程中都會保留,無需重新傳送。

預設上下文視窗可容納 128,000 個 Token,包括你的指示、對話文字,以及不會出現在逐字稿中的音訊 Token。

GPT-Live 會在背景摘要較早的對話記錄。當上下文使用量超過 90% 時,它會在同一個工作階段內啟動替代語音引擎。替代引擎會收到你的原始指示,以及最多 8,192 個 Token 的對話記錄,其中包含近期訊息,以及較早訊息的摘要(若有)。準備摘要不會立即改變目前執行中引擎的上下文。

較早的對話細節可能會被摘要或省略。請在應用程式中保留重要事實、已確認的動作與目前任務狀態,並在需要時提供相關上下文。

儲存工作階段並建立分支

建立工作階段時,在組態中將 store 設為 true,以儲存錄音,供日後下載或建立分支。儲存功能預設為 false,且必須為你的專案啟用。下載與建立分支都需要已完成並儲存的錄音,以及允許持久儲存的資料政策。錄音會在 30 天後到期。啟用零資料保留時,store 會被視為 false,且無法下載錄音或建立分支。請參閱 GPT-Live 資料控制

例如,將此欄位加入 WebSocket session.start 事件或 WebRTC 建立請求中的 session 物件:

{
  "store": true
}

session.started 或 WebRTC 建立回應中儲存來源工作階段 ID。分支會從已儲存的工作階段狀態啟動一個 具有新 ID 的新工作階段。它不會重新開啟原始連線,也不會重複使用來源工作階段 ID。

透過應用程式使用的傳輸方式啟動分支:

傳輸方式啟動分支
WebSocket連線至 wss://api.openai.com/v1/live/sessions/{source_session_id}/fork
WebRTCPOST /v1/live/sessions/{source_session_id}/fork 傳送新的 SDP offer。將傳回的 transport.sdp answer 套用至新的對等連線。

分支會繼承已儲存的工作階段組態,但須遵循下列傳輸規則。若要建立 WebSocket 分支,請傳送 session.start,其中必須包含 session 物件;使用 {} 表示不覆寫任何設定。不要提供新模型,也不要重複提供原始指示或輸入。你可以覆寫 store、Responses 委派設定,以及新 WebSocket 的音訊格式。WebRTC 分支可以覆寫 store、Responses 委派設定與前端用戶端權限。建立分支時若省略 store,便會繼承來源工作階段的設定。

WebSocket 分支 不會 繼承來源的音訊格式:請明確設定 audio.format,或使用預設的 24 kHz PCM16。它也會捨棄繼承的前端資料通道權限。WebRTC 分支會協商音訊格式,並拒絕 audio.format;除非你加以覆寫,否則它們會保留前端權限設定。

等到收到 session.started 後,再傳送後續的 WebSocket 指令。WebRTC 透過 HTTP 請求啟動,其資料通道不得收到第二個 session.start

啟動 WebSocket 分支

設定 OPENAI_API_KEY。這些範例使用應用程式所保存的已儲存來源工作階段 ID。它們會確認啟動成功,然後關閉分支。若要繼續對話,請在 session.started 之後,依照 WebSocket 連線流程傳送與接收音訊。如需啟動欄位與事件,請參閱分支 WebSocket 參考資料

import OpenAI from "openai";
import { ForksWS } from "openai/resources/live/forks/ws";

async function forkSession(sourceSessionId) {
  const ws = new ForksWS(new OpenAI(), { session_id: sourceSessionId });
  let finalized = false;
  try {
    for await (const event of ws) {
      if (event.type === "open") {
        ws.send({ type: "session.start", session: {} });
      } else if (event.type === "error") {
        throw event.error;
      } else if (event.type === "message") {
        if (event.message.type === "session.started") {
          console.log("Fork ready:", event.message.session.id);
          // This startup example closes the fork after confirming it is ready.
          ws.send({ type: "session.close" });
        } else if (event.message.type === "session.closed") {
          console.log("Final usage:", event.message.usage);
          finalized = true;
          break;
        }
      }
    }
    if (!finalized) throw new Error("Connection closed before session.closed");
  } finally {
    ws.close();
  }
}

啟動 WebRTC 分支

在前端建立新的 SDP offer,並將其傳送至後端。以下後端範例會使用該 offer,以及應用程式所保存的已儲存來源工作階段 ID:

import OpenAI from "openai";

async function forkSession(sourceSessionId, offerSdp) {
  const client = new OpenAI();
  const fork = await client.live.sessions.fork(sourceSessionId, {
    transport: { type: "webrtc", sdp: offerSdp },
  });
  console.log(JSON.stringify(fork));
}

將回應傳回前端,套用 transport.sdp 作為新對等連線的應答,並保留新的 session.id。API 金鑰應保留在後端。

後續的側通道連線和工作階段控制請使用新的工作階段 ID。請另外保存應用程式的任務狀態:還原對話狀態並不代表待處理的後端動作已完成。重試動作前,請先核對尚未確定的結果。如果沒有已儲存的工作階段可建立分支,請使用已儲存的歷史記錄初始化新的工作階段

下載錄音

已儲存的錄音完成收尾後,使用 GET /v1/live/sessions/{session_id}/content 下載音訊。回應為二進位立體聲 WAV,左聲道為輸入音訊,右聲道為輸出音訊。以下範例使用應用程式中已儲存的工作階段 ID,並將回應以串流方式寫入 recording.wav

import OpenAI from "openai";
import { createWriteStream } from "node:fs";
import { pipeline } from "node:stream/promises";

async function downloadRecording(sessionId) {
  const client = new OpenAI();
  const response = await client.live.sessions.downloadRecording(sessionId);
  if (!response.body) throw new Error("Recording response has no body");
  await pipeline(response.body, createWriteStream("recording.wav"));
}

處理錯誤並結束工作階段

持續讀取工作階段事件,直到工作階段完成收尾。請區分指令遭拒、連線失敗和工作階段完成這三種情況,讓應用程式能採取適當的復原措施。

處理遭拒的指令

讀取確認訊息時,也要讀取 error 事件。若包含 error.client_event_id,此欄位會指出哪個傳出的指令失敗:

{
  "type": "error",
  "event_id": "event_error",
  "error": {
    "type": "invalid_request_error",
    "code": "immutable_field_update",
    "message": "The delegation type cannot change after session startup.",
    "param": "session.delegation.type",
    "client_event_id": "event_update"
  }
}

錯誤代碼可能為 null,錯誤也可能不含用戶端事件 ID。請處理這些情況,不要假設指令已成功。若錯誤涉及不可變更的欄位,請保留目前的組態,或使用所需設定建立新的工作階段。

處理內容審核

內容審核可能以兩種方式影響工作階段:

  • 部分內容審核事件會結束工作階段。
  • 其他事件則會切斷助理目前這段發言的剩餘音訊,並發出 error 事件,但不會結束工作階段。

即使音訊正在播放,也要讀取 error 事件。不要假設每個內容審核錯誤都會關閉工作階段,也不要認為音訊中斷就代表連線失敗。讓應用程式狀態與工作階段生命週期保持一致,並且不要將遭中斷的語音訊息標記為已完整傳達。應用程式層級的對話防護機制與這項內建內容審核行為仍是各自獨立的機制。

用量與正常關閉

session.usage.updated 會回報累計語音時長,單位為秒:

{
  "type": "session.usage.updated",
  "event_id": "event_usage_1",
  "usage": { "seconds": 12 },
  "context_window": { "usage_ratio": 0.42 }
}

這些是快照,不是要加總的增量。後端 Token 用量另行計算;請從巢狀的 Responses 完成事件中保留這些資料。用量計算方式請參閱成本最佳化

若要正常關閉:

  1. 完成應用程式所需的所有 Responses 委派工作,包括待處理的函式結果與後續回應。
  2. 傳送 session.close 前,先註冊 session.closed 事件監聽器。
  3. 傳送 session.close,並停止向工作階段提交新工作。在等待尚未處理的工作階段事件全數處理完畢時,請維持 WebSocket 或 WebRTC 連線、資料通道及任何已連接的側通道接收器運作。
  4. session.closed 讀取最終的 usage.secondsreason 及工作階段快照。保留先前透過 response.event 收到的委派工作用量資料。
  5. 收到該事件後,再清理傳輸連線和音訊裝置。若收尾失敗,或超過應用程式設定的逾時期限,請回報收尾未完成並釋放資源。

傳送 session.close 會取消排隊中的 Responses,並拒絕後續指令。進行中的回應可以完成,但正在等待函式結果的回應,在開始關閉後便無法繼續。對於應用程式透過用戶端委派執行的工作,請另外決定要完成還是取消。

session.closed 事件可確認收尾已完成;其中內嵌的工作階段資料是組態快照。僅憑通訊端關閉無法確認成功,而在有效的最終事件之後收到傳輸連線關閉代碼,也不會推翻收尾已完成的事實。若在傳送指令後立即關閉 WebRTC,可能會導致最終事件無法送達。

最終事件的 reason 會說明工作階段結束的原因:

原因含義
close_requested應用程式傳送了 session.close 或呼叫了掛斷端點。
expired工作階段已達時長上限。
content安全篩選器結束了工作階段。
remote_hangup遠端主要連線已正常結束。
connection_lost主要連線或上游連線意外中斷。

即使結束原因是連線中斷或安全機制終止,session.closed 事件仍可確認收尾已完成。若未收到該事件,最終用量仍無法確認。需要儲存的工作階段可能因為儲存錄音而需要較長時間才能完成收尾;請在設定應用程式的逾時期限時,將儲存所需時間納入考量。

連線失敗後的復原

建立工作階段時發生 HTTP 錯誤,表示工作階段尚未進入 session.started 階段。請分別處理啟動錯誤與工作階段執行期間的錯誤。若運作中的連線在 session.closed 之前失敗,請保留最近觀察到的用量,並將最終用量標記為尚未確認。

如果有可用的已儲存工作階段,請為其建立分支,從已儲存的狀態啟動新的工作階段。否則,請使用相關的已儲存歷史記錄建立替代工作階段。重試待處理動作前,請先與後端核對其狀態,並阻擋前一個工作階段的過時結果。請明確還原應用程式狀態,不要假設新連線會接續前一個工作階段或其待處理工作。