# 串流

如何以正規化事件串流接收回應，以及串流失敗如何回報。

## 串流輸出

串流是選用能力，以型別斷言取得：

```go
streamAgent, ok := agent.(llmrouter.StreamAgent)
if !ok {
	log.Fatalf("%s 不支援串流", agent.Name())
}

events, err := streamAgent.SendStream(ctx, messages, nil, llmrouter.ReasoningHigh, llmrouter.ModeDefault)
if err != nil {
	log.Fatal(err)
}

for evt := range events {
	switch evt.Type {
	case llmrouter.StreamEventText:
		fmt.Print(evt.TextDelta)
	case llmrouter.StreamEventUsage:
		fmt.Printf("\n[usage] in=%d out=%d\n", evt.Usage.Input, evt.Usage.Output)
	case llmrouter.StreamEventError:
		log.Fatal(evt.Err)
	}
}
```

## 事件型別

Chat Completions 與 Responses 兩種上游 SSE 都會被正規化成同一組事件，呼叫端不需要分辨來源。

```go
const (
	StreamEventText      StreamEventType = "text"
	StreamEventReasoning StreamEventType = "reasoning"
	StreamEventToolCall  StreamEventType = "tool_call"
	StreamEventUsage     StreamEventType = "usage"
	StreamEventDone      StreamEventType = "done"
	StreamEventError     StreamEventType = "error"
)
```

## 串流錯誤

上游若回非 SSE 內容，錯誤會包成 `*llmrouter.StreamError`（帶 `Provider` / `Code` / `Body`）並以 `llmrouter.ErrStreamUnsupported` 作為 `Unwrap` 目標，因此 `errors.As` 取得狀態碼、`errors.Is` 判斷能力缺失可以並存。串流 body 以 64 MiB 封頂，錯誤訊息中的 frame 截至 512 bytes。

## 相關頁面

- [串流符號](/zh/api-reference-streaming)：`StreamEvent` 欄位與 SSE 輔助函式
- [逾時與上限](/zh/configuration-limits)：讀取上限
