深度求索API的流式输出基于SSE,以增量Chunk返回内容,能降低首字延迟。本文从协议、最小调用、推理模型差异到生产可靠性讲清落地方法。
在AI指导老师、智能客服、编程助手等产品里,用户最怕的不是答案不完美,而是点击发送后界面长时间没有变化。深度求索API支持流式输出,本质上让模型每生成一小段内容就立刻通过网络返回,前端可以边收边渲染,首字延迟从数秒降到几百毫秒。很多人以为流式只是把 stream 改成 true,实战中却会遇到增量拼接、reasoning_content 混入、代理缓冲、断线重试和用量统计缺失等问题。下面按协议、调用、推理模型与生产落地四个层面拆开讲。
1. 流式输出背后的SSE与增量Chunk。
DeepSeek API 在接口形态上兼容 OpenAI 的 Chat Completions 协议,流式请求通常发往 ,认证使用 Bearer API Key,模型可选择 deepseek-chat 或 deepseek-reasoner。当请求体里设置 stream: true,服务端不会等整段回答生成完再返回 JSON,而是返回 Content-Type 为 text/event-stream 的 Server-Sent Events 流。每条事件以 data: 开头,后面跟一个 JSON 对象,事件之间用空行分隔,最后以 data: [DONE] 标记结束。这个 JSON 的 object 字段通常是 chat.completion.chunk,choices 数组里只有当前新增部分,核心内容位于 choices[0].delta。
理解 delta 是正确使用流式的关键。第一个 chunk 往往包含 role: assistant,content 可能为空;后续 chunk 的 delta.content 可能是半个词、一个标点或一小段文本,开发者必须把这些片段按顺序追加到缓冲区,而不是每次覆盖全文。当 finish_reason 变为 stop、length 或 tool_calls 时,表示生成结束或触发了截断与工具调用。如果开启了 stream_options 的 include_usage,服务端还会在末尾返回一个 choices 为空的 chunk,其中 usage 包含 prompt_tokens、completion_tokens 和 total_tokens,方便做计费与观测。对于 deepseek-reasoner,delta 中还可能同时出现 reasoning_content 和 content,前者是模型推理过程,后者才是最终回答,二者必须分开累积。另一个常见坑是网关缓冲:Nginx 默认的 proxy_buffering 会把小块数据攒起来,导致前端仍然像非流式一样等待,需要关闭缓冲并调大 proxy_read_timeout。
2. 最小可用调用与参数配置。
最小可用调用可以先从 Python 的 openai SDK 开始。安装后把 base_url 指向 ,用 API Key 初始化客户端,然后调用 chat.completions.create,模型填 deepseek-chat,messages 传入系统提示和用户问题,stream 设为 True。返回对象可以直接迭代,每个 chunk 先判断 choices 是否为空,再读取 delta.content;如果 content 为 None 就跳过,否则把字符串写入列表、生成器或直接推给上层。若还需要用量,加上 stream_options={“include_usage”: True},但要注意最后一个 usage chunk 的 choices 经常为空,不能无条件访问 choices[0]。同步代码适合脚本和后台任务,Web 服务更适合异步客户端,避免一个长流占用线程。
参数配置方面,流式并不改变 temperature、top_p、max_tokens、stop 等字段的含义,只是返回不同。生产环境建议显式设置超时,把连接超时控制在十秒左右,把读取超时设到一百二十秒甚至更长,因为长回答可能持续数分钟。Web 前端不要直接暴露 DeepSeek API Key,应通过自己的后端代理,后端收到用户请求后再向上游发起流式调用,并把 SSE 事件转发给浏览器。前端可以用 EventSource 或 fetch 的 ReadableStream 读取,渲染时按五十到一百毫秒节流,避免每个 token 都触发一次组件重绘。如果业务只需要完整 JSON,或者客户端网络极不稳定,保留非流式降级路径比强行流式更稳。取消请求时关闭迭代并释放响应连接,通常服务端会停止继续生成,但已产生的 token 仍会计费。
3. 推理模型、工具调用与多轮消息。
使用 deepseek-reasoner 时,流式输出会多一层 reasoning_content。模型通常先通过多个 chunk 输出推理内容,再输出最终回答,二者可能在同一字段结构下交替出现。正确做法是维护两个缓冲区:reasoning_buffer 和 answer_buffer。UI 上可以把 reasoning_buffer 放在可折叠的“思考中”区域,或者仅用于调试,不要把它混入最终答案,也不要把 reasoning_content 原样写回下一轮 messages。DeepSeek 的接口对消息结构有约束,把推理内容当作普通 assistant 消息回传,轻则语义混乱,重则触发参数错误。对 AI 指导老师类产品而言,这点尤其重要,因为学员需要的是清晰结论和讲解,而不是模型内部的草稿。
工具调用在流式下更复杂,但原理仍然是增量聚合。当模型决定调用函数时,delta 里会出现 tool_calls 数组,每个元素带有 index,首块可能给出 id 和 function.name,后续块只给 function.arguments 的片段。开发者需要按 index 建立字典,把 id、name 和 arguments 字符串逐段拼接,等 finish_reason 为 tool_calls 后,再对 arguments 做 JSON 解析并执行本地函数。执行完成后,把 assistant 消息连同 tool_calls 追加到上下文,再追加 role 为 tool、tool_call_id 对应的结果消息,然后发起下一轮流式请求。多轮对话结束时,只把最终 content 作为 assistant 消息保存;如果一轮中既有 reasoning_content 又有 content,本地日志可以留推理内容,但会话上下文最好只保留 content。这样既保证多轮语义干净,也避免把思维链暴露给最终用户。
4. 生产环境的可靠性、观测与成本。
生产环境里,流式输出最大的敌人不是模型,而是中间链路。Nginx、Ingress、CDN、公司网关都可能默认缓冲响应,需要关闭 proxy_buffering、proxy_cache,设置 X-Accel-Buffering: no,并把 proxy_read_timeout 调到三百秒左右。服务端可以每隔十几秒发送一行以冒号开头的 SSE 注释作为心跳,防止空闲连接被切断。客户端要区分连接超时、首 token 超时和整体读取超时,首 token 超时可以设得比总时长更短,一旦首个 chunk 到达,说明上游已经正常工作。如果流已经输出一半才断开,不要静默重试,因为用户会看到内容重复;更好的做法是保留已生成内容,提供“重新生成”按钮,并在后端记录请求参数和最后一个 chunk 的位置用于排查。
观测指标至少包括首 token 延迟、每秒生成 token 数、完成率、中断率、取消率以及每次请求的 usage。流式和非流式在 DeepSeek 的计费口径上通常一致,差别只在传输,因此不能通过流式“省 token”。上下文缓存命中可以降低重复系统提示和长文档的成本,但它与是否流式无关。日志系统要避免明文记录 API Key、用户隐私和完整提示词,必要时做哈希或脱敏。前端渲染 Markdown 时,增量解析比全量解析更省 CPU,但遇到未闭合代码块、表格时容易闪烁,可以在流式阶段先用纯文本,结束后再格式化。面对 429 限流,指数退避加随机抖动是基础策略,同时要降低并发,而不是无限重试。

