为什么需要流式输出
非流式(stream=false)需要等待完整响应后才返回,用户看到的是长时间的空白等待。流式输出(stream=true)将生成内容以 token 为单位逐步返回,用户可以实时看到文字逐个出现,大幅提升体验。DeepSeek V4 支持 OpenAI 兼容的 SSE(Server-Sent Events)流式协议。
Python 流式调用
from openai import OpenAI
import os
client = OpenAI(
api_key=os.environ.get('DEEPSEEK_API_KEY'),
base_url='https://api.deepseek.com'
)
stream = client.chat.completions.create(
model='deepseek-v4-flash',
messages=[{'role': 'user', 'content': '写一篇 500 字的文章介绍 Python'}],
stream=True
)
for chunk in stream:
if chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end='', flush=True)Node.js 流式调用
import OpenAI from 'openai';
const openai = new OpenAI({
baseURL: 'https://api.deepseek.com',
apiKey: process.env.DEEPSEEK_API_KEY,
});
const stream = await openai.chat.completions.create({
model: 'deepseek-v4-flash',
messages: [{ role: 'user', content: '解释什么是机器学习' }],
stream: true,
});
for await (const chunk of stream) {
const content = chunk.choices[0]?.delta?.content || '';
process.stdout.write(content);
}前端逐字渲染
通过 fetch + ReadableStream 在前端实现打字机效果:
async function streamChat(prompt) {
const response = await fetch('https://api.deepseek.com/v1/chat/completions', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + apiKey
},
body: JSON.stringify({
model: 'deepseek-v4-flash',
messages: [{ role: 'user', content: prompt }],
stream: true
})
});
const reader = response.body.getReader();
const decoder = new TextDecoder();
let fullText = '';
while (true) {
const { done, value } = await reader.read();
if (done) break;
const chunk = decoder.decode(value);
const lines = chunk.split('\n').filter(l => l.startsWith('data: '));
for (const line of lines) {
if (line === 'data: [DONE]') break;
const data = JSON.parse(line.slice(6));
const content = data.choices[0]?.delta?.content;
if (content) {
fullText += content;
document.getElementById('output').textContent = fullText;
}
}
}
}中断流式输出
使用 AbortController 实现用户停止生成:
const controller = new AbortController();
// 绑定中断信号到 fetch
const response = await fetch(url, { signal: controller.signal, ... });
// 用户点击停止
document.getElementById('stopBtn').onclick = () => controller.abort();思考模式的流式处理
启用了思考模式后,流式输出中会交替出现 reasoning_content 和 content,可以分别处理:思考过程折叠为可展开区域,正式回答直接展示。
最佳实践
- 默认使用流式:除非需要完整 JSON 解析,否则 stream=true
- 添加重连机制:网络中断时自动重试
- 节流渲染:前端使用 requestAnimationFrame 批量更新 DOM
- 错误处理:捕获流式错误并提示用户
- 超时控制:设置合理的超时时间,避免无限等待