Claude Platform Docs
Managed Agents將工作委派給您的代理

使用事件增量預覽回應

在模型仍在生成時,將代理的回應文字呈現為即時預覽。

預設情況下,代理的回應文字會以緩衝的 agent.message 事件形式抵達工作階段事件串流。每個事件只會在產生它的模型請求完成後才發出。「Event deltas」(事件增量)可讓您在模型仍在生成時,以即時預覽的方式逐步呈現該文字。

預覽是一種盡力而為的顯示輔助,而緩衝的 agent.message 始終是權威紀錄。忽略預覽的用戶端仍會收到完整且正確的串流。

選擇啟用預覽

預覽是依每個串流連線選擇啟用的。將 event_deltas[] 查詢參數加入您正在讀取的串流,並針對每個您想要預覽的事件類型重複一次。可接受的值為 agent.message 和 agent.thinking。任何其他值都會傳回 400 錯誤,包含超過 100 個值的請求也是如此。

兩個串流端點都接受此參數:

  • 工作階段層級串流: GET /v1/sessions/{session_id}/events/stream
  • 工作階段執行緒串流: GET /v1/sessions/{session_id}/threads/{thread_id}/stream

子代理的預覽會出現在該子代理自己的執行緒串流上。

[] 是 shell 的 glob 模式,因此每當您在 shell 中建構請求時,請為 URL 加上引號。範例將方括號百分比編碼為 %5B%5D,這樣也可行。

預覽事件

當被預覽的事件開始時,串流會發出一個 event_start,攜帶即將到來之事件的類型與 id:

{
  "type": "event_start",
  "event": {
    "type": "agent.message",
    "id": "sevt_01abc..."
  }
}

對於 agent.message,開始事件之後會接著攜帶增量文字的 event_delta 事件。每個增量在 event_id 中指明它所延伸的事件,並在 delta.index 中指明它所延伸的內容區塊:

{
  "type": "event_delta",
  "event_id": "sevt_01abc...",
  "delta": {
    "type": "content_delta",
    "index": 0,
    "content": {
      "type": "text",
      "text": "Here is the summary"
    }
  }
}

對於 agent.thinking,只會發出 event_start,作為思考區塊已開始的訊號。之後不會有 event_delta 事件。結束預覽的緩衝 agent.thinking 事件是一個進度訊號,不帶有任何思考內容。

與持久化事件不同,event_start 和 event_delta 沒有自己的 id 或 processed_at。它們唯一帶有的識別碼是它們所預覽之事件的 id。它們的類型字串也是持久化事件 {domain}.{action} 命名慣例的例外。

累加與調和

每個支援事件增量的 SDK 都包含一個累加器輔助工具,可為您處理 index 的記錄工作。當您需要自訂記錄方式時,本節中的手動模式適用於所有語言。請將其套用於生成的事件類型。

在手動模式中,將預覽文字保存在以 (event_id, index) 為鍵的暫存對應表中,並將緩衝事件視為紀錄。針對每個模型請求調和兩者。

一個回合以單一 session.status_running 事件開始。在正常完成的回合中,每個模型請求接著會依序產生以下事件:

  1. span.model_request_start
  2. event_start
  3. event_delta 事件
  4. 緩衝的 agent.message
  5. span.model_request_end(位於 Span 事件分頁中)

在傳輸層上,這是該序列中被預覽的部分,與連線的其他緩衝事件交錯出現:

event_start     {"event": {"type": "agent.message", "id": "sevt_01abc..."}}
event_delta     {"event_id": "sevt_01abc...", "delta": {"type": "content_delta", "index": 0, "content": {"type": "text", "text": "..."}}}
...
agent.message   {"id": "sevt_01abc...", "content": [...]}

event_delta 行會針對每個文字片段重複一次。在每個事件抵達時加以處理:

  1. 收到 event_start 時,記下所宣告的 id。這些識別碼始終一致:event_start.event.id、每個 event_delta.event_id,以及緩衝 agent.message 的 id 都是相同的值。
  2. 收到每個 event_delta 時,將 delta.content.text 附加到 (event_id, delta.index) 的項目中,並呈現目前累積的文字。某個 index 的第一個增量會建立該項目。
  3. 當緩衝的 agent.message 抵達時,依 id 進行比對,捨棄累積的預覽,改為呈現該訊息的內容。
  4. 收到 span.model_request_end 時,關閉任何尚未被其緩衝事件調和的預覽。它不會再有更多增量。如果回合發生錯誤或被中斷,緩衝事件可能永遠不會抵達,但 span.model_request_end 仍然會抵達。

此模式依賴兩項保證:

  • 以 (event_id, index) 為鍵,依抵達順序串接預覽的增量,會得到緩衝事件中 content[index].text 的前綴。它不一定是完整文字,因為增量可能會在負載下被捨棄。
  • 一個連線針對每個 event_id 最多發出一個 event_start,而緩衝事件是該連線針對該 id 傳遞的最後一項內容。

SDK 累加器輔助工具

每個 SDK 的輔助工具都會處理 index 的記錄工作。Go、Java、Ruby 和 C# 的輔助工具也會以事件的 id 作為累積預覽的鍵。使用 Python、TypeScript 和 PHP 的輔助工具時,請自行維護該對應表,並將每個增量併入其 id 對應的項目中。

以下範例選擇啟用 agent.message 預覽,並將其與緩衝事件調和:

# 預覽快照,以事件 id 為鍵。accumulate_managed_agents_event 會將每個
# event_start / event_delta 折疊成 agent.message 快照;緩衝的
# agent.message 會取代它。
previews: dict[str, BetaManagedAgentsAgentMessageEvent] = {}

# 在此連線上啟用 agent.message 預覽
with client.beta.sessions.events.stream(
    session.id, event_deltas=["agent.message"]
) as stream:
    client.beta.sessions.events.send(
        session.id,
        events=[
            {
                "type": "user.message",
                "content": [{"type": "text", "text": "Describe the repo in one sentence."}],
            },
        ],
    )

    for event in stream:
        match event.type:
            case "event_start":
                snapshot = accumulate_managed_agents_event(None, event)
                if snapshot is not None:
                    previews[event.event.id] = snapshot
                print(f"event_start             {event.event.type} {event.event.id}")
            case "event_delta":
                preview = accumulate_managed_agents_event(previews.get(event.event_id), event)
                if preview is not None:
                    previews[event.event_id] = preview
                    text = "".join(block.text for block in preview.content)
                    print(f"event_delta             preview: {text!r}")
            case "agent.message":
                # 緩衝事件才是正式記錄:它會取代並關閉預覽
                preview = accumulate_managed_agents_event(previews.pop(event.id, None), event)
                text = "".join(block.text for block in preview.content)
                print(f"agent.message           {event.id} {text!r}")
            case "span.model_request_end":
                # 不會再有 delta 了。關閉所有其
                # 緩衝事件從未到達的預覽。
                for event_id in previews:
                    print(f"span.model_request_end  closing preview for {event_id}")
                previews.clear()
            case "session.status_idle":
                break

預覽工作階段執行緒事件

在多代理工作階段中,每個工作階段執行緒都有自己的事件串流。它接受相同的 event_deltas[] 參數及相同的值。

一個連線只會預覽它正在讀取的執行緒。工作階段層級串流會預覽主要執行緒,而子執行緒的預覽永遠不會被交叉發布到該串流。若要在模型生成時觀看子代理的文字,請開啟該子代理的執行緒串流。

執行緒串流的路徑以 /threads/{thread_id}/stream 結尾。/events/stream 只存在於工作階段層級,因此沒有 /threads/{thread_id}/events/stream 端點。

event_start 和 event_delta 在執行緒串流上的結構與在工作階段層級串流上相同,且累加與調和模式可照原樣套用。請為每個串流連線執行一個累加器實例。

# 列出工作階段的執行緒並挑選一個子執行緒:子執行緒帶有非 null 的
# parent_thread_id,而主執行緒的 parent_thread_id 為 null。
child_thread = next(
    thread
    for thread in client.beta.sessions.threads.list(session.id)
    if thread.parent_thread_id is not None
)

# 子執行緒的串流接受與工作階段串流相同的
# event_deltas 參數。
with client.beta.sessions.threads.events.stream(
    child_thread.id,
    session_id=session.id,
    event_deltas=["agent.message"],
) as stream:
    for event in stream:
        match event.type:
            case "event_delta":
                print(event.delta.content.text, end="")
            case "agent.message":
                # 緩衝事件才是權威記錄;呈現其內容
                print()
                for block in event.content:
                    if block.type == "text":
                        print(block.text, end="")
                print()
            case "session.thread_status_idle":
                break

讀取迴圈會在 session.thread_status_idle 時結束,這是當工作階段執行緒的回合完成且執行緒進入閒置時所發出的事件。

限制

  • 盡力而為: 在負載下,伺服器可能會捨棄某個事件的增量。發生這種情況時,您會收到文字的連續前綴,之後該事件不會再有任何增量。緩衝的 agent.message 仍會完整抵達。切勿將累積的預覽視為最終結果。
  • 重新連線時不重播: 增量只會在連線開啟期間傳遞給選擇啟用的該連線。這同樣適用於工作階段層級串流和每個工作階段執行緒串流。在模型請求開始後才開啟的連線,不會收到該進行中事件的任何增量。無法重新請求遺漏的增量。
  • 單一執行緒,僅限文字: 預覽涵蓋連線正在讀取的執行緒上的助理文字。工具使用、工具結果和 MCP 結果永遠不會被預覽。
  • 永不持久化: event_start 和 event_delta 只存在於即時串流上。它們不會出現在工作階段的事件歷史記錄(GET /v1/sessions/{session_id}/events)或任何工作階段執行緒的事件歷史記錄中。

預覽疑難排解

您看到的情況代表的意義
串流中有緩衝事件,但沒有 event_start 或 event_delta您正在讀取的連線沒有選擇啟用,或者該回合從未涉及您正在串流的執行緒。event_deltas[] 是依連線套用,而非依工作階段套用。若要找出執行的是哪個執行緒,請列出工作階段的執行緒(GET /v1/sessions/{session_id}/threads)。
串流在預覽期間中斷增量不會被重播。請依照重新連線程序操作:重新開啟串流並列出事件歷史記錄。歷史記錄包含您中斷連線期間發出的所有緩衝事件,包括您的預覽正在等待的 agent.message。
串流 URL 傳回 404路徑或某個 ID 有誤,或者請求完全沒有帶上 managed-agents beta 標頭。執行緒端點受 beta 限制,因此沒有該標頭時它們並不存在。
傳回指明 event_deltas 的 400只接受 agent.message 和 agent.thinking。

後續步驟

傳送事件、串流回應,並在執行中途中斷或重新導向您的工作階段。

在單一工作階段中協調多個代理。

Was this page helpful?