Skip to content

第 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 章的"心跳信号"就是它