Appearance
第 12 章:Streaming——打字机 ✍️
12.1 两种上菜方式
打开 ChatGPT、DeepSeek 的网页版——模型回答的时候,字是一个一个蹦出来的。光标闪烁,文字逐字出现,像有人在对面打字。
这就是流式输出(Streaming)。
但如果你用过一些 API 调试工具,或者直接拿 curl 调接口——有时候模型沉默了五秒钟,然后一整段文字一次性全吐出来。
这就是非流式输出。
用厨房的话说:
- 非流式 = 厨师在后厨闷头做,你干等,二十分钟后一整盘菜端上来
- 流式 = 厨师做一片切一片,切一片递一片,你看着肉一片片落到盘子里
| 模式 | 体验 | 本质 |
|---|---|---|
| 流式 | 打字机,一个字一个字蹦 | 生成一个 token 就发一个 |
| 非流式 | 等,然后整段出现 | 全部生成完了一起发 |
12.2 快不快?两个指标
流式输出让你"看到字在蹦"——但蹦的速度有快有慢。这个速度有两个标准指标:
① TTFT(Time To First Token)——第一个字多久蹦出来
从你发出请求到屏幕上出现第一个字,中间的等待时间。就是你盯着光标闪、但还没出字的那段空白。
② tok/s(tokens per second)——蹦起来之后有多快
第一个字出来之后,每秒钟能蹦出多少个 token。
| 指标 | 衡量什么 | 体感 |
|---|---|---|
| TTFT | 启动延迟——等多久才开始蹦 | "怎么还没反应?" |
| tok/s | 持续速度——蹦起来之后多快 | "这打字也太慢了吧" / "嗖嗖的" |
粗略的体感参考:
| tok/s | 感受 |
|---|---|
| 20 以下 | 明显觉得慢,像在等人一字一字憋 |
| 30~50 | 正常阅读速度,不焦虑 |
| 50~80 | 很流畅 |
| 100+ | 几乎感觉不到延迟,字刷一下就出来了 |
还记得引言黑话字典里的"输出速度"吗?说的就是 tok/s。现在你知道它是怎么量化的了。
流式输出体验好的核心原因之一:TTFT 通常比非流式的整体等待时间短得多。 你不需要等全部生成完——第一个 token 出来你就能开始看了。
速度对比
2 tok/s
20 tok/s
60 tok/s
12.3 API 层面:就一行代码的区别
python
# 非流式
response = client.chat.completions.create(
model="deepseek-v4-pro",
messages=[...],
stream=False # 等厨房做完,整盘端
)
# 流式
response = client.chat.completions.create(
model="deepseek-v4-pro",
messages=[...],
stream=True # 做一个 token 发一个 token
)就一个参数:stream: true 还是 stream: false。
但接收方式完全不同。非流式直接拿完整 response。流式得逐块接收:
python
for chunk in response:
print(chunk.choices[0].delta.content, end="")
# 一个字一个字往外蹦12.4 什么时候用哪个
| 场景 | 推荐 | 理由 |
|---|---|---|
| 聊天 App、网页对话 | 流式 | 用户能看到字在蹦,体验好,不焦虑 |
| 后台批量处理 | 非流式 | 不需要给人看过程,代码处理更简单 |
| API 调试 | 非流式 | 一次性拿完整结果,好排查问题 |
| 需要边生成边判断 | 流式 | 看到前面不行可以提前中断,省 token |
一句话:给人看的用流式,给机器看的用非流式。
流式输出有一个隐藏好处:你可以边看边判断。如果前几句就发现模型跑偏了,直接断开连接——后面没生成的 token 不会计费。非流式做不到这一点,因为你拿到结果的时候所有 token 已经全部生成完了,钱已经花了。
又一次回到第 10 章的结论:token 就是钱。能少生成就少生成。
12.5 流式底下的东西:SSE
流式输出用的是 SSE(Server-Sent Events)——服务端推送。
不是 WebSocket。不是长轮询。
SSE = 服务端单方向往客户端推数据。就像水管,水龙头拧开了,水一直流,不用你每次拿杯子去接。
流式请求发出去后,连接不会断开。服务端生成一个 token 就推一个 token,推完最后一个 token 再关连接。
第 9 章提到的"心跳信号"——排队时服务端发来的空行——就是 SSE 在工作。它持续发空行或 keep-alive 注释,意思是"我在呢,别挂,还没轮到你的菜。"
本章要点
| 概念 | 一句话 |
|---|---|
| 流式 | 打字机——生成一个 token 发一个,看着它蹦 |
| 非流式 | 整段发送——做完了一起端上来 |
| TTFT | 第一个字多久蹦出来——启动延迟 |
| tok/s | 蹦起来之后每秒多少个——持续速度 |
| 代码区别 | stream: true / stream: false |
| 选哪个 | 给人看用流式,给机器看用非流式;流式还能中断省钱 |
| SSE | 服务端单向推送,第 9 章的"心跳信号"就是它 |