Kimi 流式输出断了怎么自动重连:判据、续写与账单
数据截至 2026-08,价格与限额以各官网为准。本文只讲计费与接入机制,不列具体价格数字。
先说结论:Kimi 流式输出的重连问题,真正的难点不在「怎么重试」,而在「怎么知道自己断了」。官方文档在流式输出那一页写得很直白——判断数据是否传输完成,只认 data: [DONE],不要用 finish_reason 或其他方式;在收到 [DONE] 之前,即使已经拿到了 finish_reason=stop,也应视作消息不完整。把这条判据落到代码里,重连逻辑才有意义。官方「自动断线重连」页给的范例是整轮重发(把一次请求包在循环里,失败就等一会儿再来一次,达到上限则放弃),而如果你不想从头重来,官方的思路是配合 Partial Mode,把已经收到的内容当作前缀喂回去接着生成。最后别忘了补账:中断时最后那个统计数据块没到,用量得靠自己累积内容再调 Tokens 计算接口补算。
先分清「断」在哪一层
官方在「自动断线重连」页的开场把成因说得很克制:因为并发限制、复杂的网络环境等情况,连接可能因为一些预期外的状况而中断,而这种偶发的中断通常并不会持续很久。这句话其实定了重连的前提——它假设的是短暂抖动,不是长期故障。
错误码页把连接类问题单独列了一组,值得对着看:
- 499
client_closed_request:客户端在服务端返回前断开连接。官方给的典型场景是流式响应被中间代理切断,或者用户主动取消;处置建议是检查 KeepAlive 与超时设置。 - 500
server_error/unexpected_output:服务端内部错误,稍后重试;持续出现要带上request_id联系支持。 - 503
server_unavailable:服务暂时不可用,官方说通常与节点扩容或维护有关。 - 504 网关超时:服务端长时间无响应,网关返回的是 HTML 超时页面。官方明确说这常见于非流式长请求,建议改用流式输出。
这里有个容易被忽略的因果链。问题排查页专门讲过 Connection Error、Connection Time Out 这类错误的排查顺序:先看程序代码或 SDK 是否有默认的超时设置,再看是否用了代理服务器以及代理的网络与超时设置,最后还有一种场景——没启用流式输出时,模型生成的 Tokens 数量过多,等待生成的过程触发了中间某个网关的超时。原因是某些网关应用靠是否收到服务端返回的 status_code 和 header 判断请求是否有效,而在不使用流式输出的场合,Kimi 服务端会等模型生成完毕才发送 header,网关等不及就把连接关了。官方由此推荐启用流式输出来尽量减少这类 Connection 错误。
换句话说:流式输出本身就是一种抗断手段。你在长输出场景遇到的一部分「断线」,恰恰是因为没开流式。
判定「传完了」只认 [DONE]
开启流式后,接口不再返回 Content-Type: application/json,而是 text/event-stream。响应体里每个数据块以 data: 为前缀,紧跟一个合法的 JSON 对象,并以两个换行符结束。所有数据块传输完成后,服务端发送 data: [DONE] 标识传输结束,此时可以断开网络连接。
官方在这里加了一条重点提醒:请始终使用 data: [DONE] 判断数据是否传输完成,而不是使用 finish_reason 或其他方式;如果没收到 [DONE],哪怕已经拿到 finish_reason=stop,也不该当成传输完成。
这条设计有点反直觉——很多人写 SSE 解析器的习惯是「看到 finish_reason 非空就收工」,在 Kimi 这边这么写,就等于把「可能被截断的半截回复」当成了完整结果,重连逻辑根本不会被触发。把判据换成 [DONE],你才有一个明确的失败信号。
还有几个字段层面的细节,直接决定解析代码会不会崩:
content逐块下发,role不会在每个数据块里重复出现,只出现在第一个数据块。- 传入
stream_options: {"include_usage": true}后,服务端会在[DONE]之前返回一个最终统计数据块。这个块的choices为空,本次请求的总用量在顶层usage字段里。 - 正因为存在
choices为空的块,官方明确写了:解析流式响应时不要假设每个 chunk 都存在choices[0],总用量要从最终统计 chunk 的usage读。
不用 SDK 直连 HTTP 时,官方把步骤归纳成四步:请求体里把 stream 设为 true;检查响应头的 Content-Type 是否为 text/event-stream;逐行读取并靠 data: 前缀和换行符判断数据块起止;数据块内容为 [DONE] 时表示传输完成。要主动提前终止也简单,直接关闭 HTTP 连接或丢弃后续数据块即可,比如在循环里 break。
官方那份重连范例,实际是「整轮重发」
「自动断线重连」页给的示例代码结构很朴素:把一次完整的对话请求封成一个函数,外面套一层循环,循环里用 try/except 包住,成功就返回,失败就打印异常、等待一小段时间后继续下一次尝试;尝试次数用尽则打印失败并返回空。官方在代码后面说明,你可以根据具体需求更改这些数值以及满足重试的条件——也就是说重试次数、等待间隔、什么异常才重试,都留给你自己定(具体默认值以官方文档当前版本为准)。
有两点要看清楚。第一,这份示例调用的是非流式接口,它取的是 response.choices[0].message.content;所以它演示的是整轮重发,不是从断点续传。第二,页面自己的定位写的是「为 Kimi API 流式请求实现断线重连,并结合 Partial Mode 从中断处继续生成」——续传那一半的能力,官方指向的是 Partial Mode,而不是这段循环代码。
对短回复来说整轮重发够用;对长输出来说,重发意味着前面已经收到的那部分内容全部作废,整段输入也会重新计入这次新请求的用量。不过「重发等于把输入原样再买一遍」这个直觉并不准确,官方另有一套机制夹在中间:上下文缓存页写明,Context Caching 对所有模型请求自动启用,当系统检测到重复的初始上下文(如 system prompt、知识文档、工具定义等)时,会自动复用已缓存的内容,无需手动创建缓存、无需引用缓存 ID、也无需管理 TTL。整轮重发送过去的 system prompt、知识文档和工具定义,恰好就是这套机制要识别的「重复的初始上下文」。
同一页也给了命中的前提条件:前一个请求的 prompt tokens 要超过官方设定的下限门槛,新的请求才能命中前缀缓存;低于门槛的请求不会被缓存,而是被丢弃(门槛的具体取值以官方文档当前版本为准)。至于命中之后按什么方式计费,官方在这一页只留了一句「计费方式与具体价格,请参阅产品定价页面的计费说明」,本文不做推算,一切以官方定价页为准。
还有一个方向相反的特例值得记在心里:问题排查页写着「因 429 错误中断的请求不会扣费」。所以「断了就一定按原样计费」并不是通例,中断到底会不会在账面上留下消耗,要看它断在哪一层、返回的是哪种错误。想尽量少做无效重发,就得往下看 Partial Mode。关于重试节奏本身的通用做法,站内另有一篇重试与退避策略怎么定可以对照。
用 Partial Mode 从断点接着写
Partial Mode 的用法:在 messages 列表尾部追加一条 role=assistant、partial=True 的消息,把希望模型接着说的内容放进 content,模型就会强制以这段内容开头继续生成。官方特别提醒,模型返回的是「后半截」,所以你要手动把喂进去的前缀拼接到生成结果之前,才组成完整回复。
把它接到重连场景,逻辑就顺了:流式循环里每收到一个 delta.content 就往缓冲区里追加;一旦连接断了而 [DONE] 没到,就拿缓冲区里已经攒下的文本当 partial 前缀,重新发一次请求,让模型顺着往下写。
官方文档里直接演示的是另一个触发场景——输出被 max_tokens 截断。这种情况下 finish_reason 的值是 length,表示生成内容占用的 Tokens 超过了请求设置的上限,官方建议把已输出的内容作为前缀用 Partial Mode 传回去续写。这个场景和网络中断不完全一样,但续写手法是同一套。
两条容易踩的限定条件必须记住,官方都写在了截断续写那一节:
- 思考模式下续写,要把上一轮返回的
reasoning_content一并传回。 示例代码里那条partial消息除了content,还带了reasoning_content字段。 max_tokens会优先被思考消耗。 官方说明kimi-k3默认开启思考,max_tokens设置得较小时,截断点可能落在思考阶段——此时content仍为空、finish_reason已经是length,续写会因为前缀为空而从头生成。所以走这套续写流程时,要把max_tokens设得足够大,确保截断发生在正文阶段。
注意第二条的适用范围:它说的是 kimi-k3 默认开启思考这个前提下的截断行为,别把它当成所有模型的通用结论。
参数名上还有一处官方文档自身的分歧,写代码前先知道为好:Partial Mode 这一页的说明和示例通篇用的是 max_tokens,而问题排查页里另有一条注解——「max_tokens 已弃用(deprecated),请使用 max_completion_tokens,两者含义相同」。两个名字指的是同一件事:调用对话补全接口时允许模型生成的最大 Tokens 数量,模型生成的 Tokens 数超过这个设置就会停止输出下一个 Token。所以上面那两条限定条件本身不受影响,只是你在自己的续写代码里用哪个参数名,按官方文档当前版本为准。问题排查页还顺带给了一个估算思路:先用 Tokens 计算接口算出输入内容的 Tokens 数量,再从所选模型支持的最大上下文窗口里扣除这部分输入,剩下的值就可以作为这次请求的输出上限。这个算法对断线续写同样管用——续写请求的前缀越长,留给输出的余量就越小,不留意的话第二次请求会更容易再撞上 length 截断,变成「断一次续一次、越续越短」的循环。
Partial Mode 还有个 name 字段,作用是强化模型对角色的认知、强制以指定角色的口吻输出,并且 name 本身是输出内容前缀的一部分。角色扮演类应用做断点续写时,这个字段要跟着一起传,否则续上去的语气可能就变了。
重连之后,账单得自己对上
流式统计用量的推荐做法是传 stream_options: {"include_usage": true},等所有数据块传完,从最后那个统计块顶层的 usage 里读 prompt_tokens、completion_tokens、total_tokens。
但官方紧接着点了断线的后果:流式输出可能因为网络连接中断、客户端程序错误等不可控因素被打断,此时最后一个数据块尚未到达,也就无从得知这次请求消耗了多少 Tokens。给出的对策是——保存已收到的每个数据块的内容,并在请求结束后(无论是否成功结束)调用 Tokens 计算接口统计实际消耗量。文档示例里,这个接口是 https://api.moonshot.cn/v1/tokenizers/estimate-token-count,返回值从 data.total_tokens 取。
问题排查页还有一条对重连场景极其关键的说明:客户端没有显示结果,不代表 API 请求失败。当编程工具等待时间过短、代理连接断开或本地超时时,客户端可能停止展示,但服务端请求仍可能已完成并产生实际调用记录。官方列的核对顺序是:请求的 HTTP 状态码与 request_id、API 响应中的 usage 字段、客户端是否自动重试或启动子 Agent 或循环调用工具、控制台的用量看板与计费明细、客户端日志里的超时和连接错误。
这条直接指向重连的副作用:你写的自动重连,本身就是「客户端自动重试」的一种。断得越频繁、重试越激进,账面上多出来的调用就越多,而这些调用在服务端可能是真真切切跑完的。所以重试上限一定要有,别为了「一定要成功」把循环开得太大。成本这条线怎么盯,可以配合站内的API 成本监控怎么做一起看。
有几种「断」,重连救不了
重连的前提是这次失败具有偶发性。下面这些属于确定性失败,循环重试只会把情况变糟:
- 429 里的额度类。
exceeded_current_quota_error对应的是账户欠费停用或者 token 额度不足,得去充值和查账单,不是重试能解决的。 - 429 里的限速类。
rate_limit_reached_error分别对应组织级的并发、RPM、TPM、TPD 限制,官方给的处置是降低并发、按响应提示等待、或者升级 tier。密集重试等于自己给自己加压。 - 429 里的过载类。
engine_overloaded_error是服务节点负载较高,官方建议按照Retry-After提示等待、降低并发并使用指数退避重试,并且特别说明这个错误由服务端容量导致,充值或提升 Tier 不能直接消除它。这三种都返回 429,处置方向却完全不同,error.type必须读。429 的通用处理可以参考站内429 报错怎么处理。 - 401 认证类。官方在错误码页专门提示了平台 Key 隔离:
platform.kimi.com(中国站)与platform.kimi.ai(国际站)的账户、余额和 API Key 完全独立,混用会返回 401,要确认调用端点与 Key 所属平台一致。 model_not_found。官方说这个错误通常是使用 OpenAI SDK 时没设置base_url,请求被发到了 OpenAI 服务器。重试一万次也是同样结果。content_filter。请求输入或模型输出包含被判定为高风险的内容。官方明确说平台无法提供具体命中的安全策略规则,建议缩小请求范围、移除可能引起误判的内容后重试;而且模型生成的内容本身也可能触发这个错误。
顺带一提,当前模型(官方页面列的是 kimi-k3、kimi-k2.7-code、kimi-k2.6)的 n 参数固定为 1,暂不支持一次请求返回多个回复,传大于 1 的 n 会返回 400 错误,流式与非流式均如此——模型清单会变,以官方文档为准。想靠「一次要多个候选,断一个还有备份」来抗断,这条路目前走不通。
最后:先分层,再写重连
如果你是在第三方 Agent 或 IDE 里用 Kimi 遇到的断流,官方问题排查页给的方法是把链路拆成 Kimi API 和第三方工具两层:先用相同的 Key、端点和模型直接调用 Kimi API,直连失败就先解决余额、鉴权、模型权限或请求参数问题;直连成功但工具仍失败,就去看工具日志,重点检查协议转换、流式响应、超时设置和自动重试。官方也提醒,这类第三方工具不由 Kimi 开放平台维护,直连正常而工具异常时需要同时联系工具方。
最后回到那条判据。官方在流式输出页专门加了一条「注意」,要求始终用 data: [DONE] 判断数据是否传输完成,而不是用 finish_reason 或其他方式——这句提醒被放在整节字段说明的最前面,值得当成硬约束照做。把 finish_reason 当完成判据的程序,永远不会触发你精心准备的重连逻辑——它会安安静静地把半截回复当成正确结果返回给用户,而你从日志里什么都看不出来。先把 [DONE] 判据补上,再谈重试次数和退避曲线。接入的基础配置见站内的 Kimi API 接入步骤。