中文 ▾

从试用额度开始

邮箱和密码,密钥立即显示在屏幕上。

https://api.uncensoredllmhub.com/v1

LLM 流式输出未知错误:原因与修复

如果你反复看到 LLM 流式输出出现未知错误,该消息几乎总是隐藏了特定原因:Base URL 错误、速率限制、请求过大或缓冲事件的代理。本页面展示了如何找出原因并修复。

更新于

管道中带有发光数据流,其中一段断裂,放大镜下显示流式输出错误

要点

  • 文本来自客户端,因此使用 curl 重现调用以查看真实的错误正文和状态。
  • 繁忙账户上最常见的原因是 HTTP 429 配合 rate_limited 或 concurrency 代码,且流会一直占用槽位直到结束。
  • 首先检查基础 URL、密钥、模型 ID uncensored、正文大小(8 MB)和总 token 数(100,000)。
  • 仅重试 429 和网络断开,等待 Retry-After,并保持并发数低于密钥限制。

该消息实际告诉你的内容

如果你搜索到 unknown error from llm stream learn more,你很可能正在查看聊天前端、编辑器插件或代理框架中的提示框或红色错误行。该措辞来自客户端。它表示应用请求了流式输出,但在流式传输之前或期间发生了错误,而应用不知道如何描述该错误。API 本身通过 HTTP 状态码和 JSON 错误响应体报告问题,而客户端丢弃了这些详细信息。

这是好消息,因为这意味着你可以找回详细信息。在客户端之外发送相同的请求,读取状态行和正文,原因通常在一两次尝试内就会显而易见。本页面的其余部分按该 API 上倾向于发生的顺序介绍原因,然后提供一个小型流式输出客户端,它会打印真实错误而不是隐藏它。

从一开始就要记住的一点是:流式请求有两个故障点。它可以在第一个字节之前失败,当服务器拒绝请求时(密钥错误、URL 错误、达到限制)。或者它可以在中间失败,当连接在部分文本到达后断开。修复方法不同,因此请注意你看到的是哪一种。如果回答从未开始,请参阅第二至四节。如果回答开始后停止,请参阅代理和超时部分。

首先检查 Base URL、密钥和模型

新设置中的大多数流式输出错误源于三个小错误。排除它们只需一分钟。

  1. Base URL。 它必须是 https://api.uncensoredllmhub.com/v1,包含 /v1 且不带有尾部 /chat/completions。客户端会自行追加路径。如果你将完整的接口粘贴到期望 Base URL 的字段中,客户端会请求一个不存在的路径并报告模糊的失败。
  2. 密钥。请求头为 Authorization: Bearer YOUR_KEY。多余的空格、随密钥复制的换行符,或来自其他服务的密钥都会以相同方式失败。如果不确定,请从 API 密钥页面重新创建或复制密钥。
  3. 模型 ID。 唯一的模型是 uncensored。提供下拉菜单的客户端通常会预填充来自其他提供商的名称。手动输入 ID,并调用 GET /v1/models 以确认服务器列出的内容。

测试这三项的快速方法是 models 调用。它不流式输出,因此可以将连接或密钥问题与流式输出问题区分开:

curl -i https://api.uncensoredllmhub.com/v1/models   -H "Authorization: Bearer $API_KEY"

如果返回正常列表,说明 URL 和密钥均无误,你可以停止怀疑它们。如果失败,请先修复该问题,然后再处理流式输出相关事项。同时检查你的账户是否有额度:API 会在响应的 X-Balance-USD 头中发送你的剩余余额,当密钥在大量使用后突然失效时这很有用。定价页面 解释了充值方式,新账户可以在密钥页面领取 $0.50 的试用额度。

速率限制和占用槽位的流式输出

下一个最常见的原因是 HTTP 429。有三种类型,你的客户端会将它们全部折叠为同一个无用的消息。

信号含义该做什么
429,代码 rate_limited密钥每分钟请求过多放慢速度;完整密钥允许每分钟 300 次,试用密钥允许 60 次
429,代码 concurrency并发请求过多对它们排队;完整密钥允许同时 8 个,试用密钥允许同时 2 个
429 且 Retry-After: 5服务端的临时过载等待 5 秒,然后重试

并发限制是令人惊讶的一点,因为流式输出的工作方式。流式请求占用其槽位直到流结束,而不仅仅是直到第一个 token 到达。如果你的应用为每条消息打开一个流且从不关闭旧流,例如因为用户导航离开且 UI 忘记取消请求,这些槽位会保持占用。在限制为 2 的试用密钥上,两个被遗弃的流就足以使第三条消息失败。

症状是一致的。前几条消息正常,然后开始报错,短暂等待后一切恢复正常。如果符合该情况,请中止不再需要的流式连接(浏览器中使用 AbortController,服务器中关闭响应),并在你自己的代码中限制并发请求的数量。代理通常是罪魁祸首:一个一次性触发十个工具调用的规划器会立即达到试用密钥的限制。

响应头可帮助你了解当前状态。X-RateLimit-Limit-Requests 和 X-RateLimit-Limit-Concurrency 显示适用于你所用密钥的限制,X-Request-Id 用于标识调用,如果你需要就此事联系 支持 时很有用。

请求大小和上下文长度

请求也可能因过大而被拒绝。有两个数字很重要。正文最多 8 MB,提示词加上补全必须适合 100,000 token 的上下文窗口。在每次轮次中重新发送整个对话的聊天前端会缓慢触及这些限制,然后一次性全部失败:聊天工作一小时,然后一条长消息或粘贴的文件使其超出限制,后续所有轮次都会失败,因为历史记录仍在请求中。

如果错误在长会话后开始,请使用短的新对话进行测试。如果有效,则历史记录是原因。通过丢弃旧轮次、将它们总结为一条消息或开始新的聊天来修剪它。大型粘贴文档是另一个触发因素。几百千字节文本文件没问题,但 base64 块或非常大的日志可能比你预期的更快达到 8 MB。

你不必设置 max_tokens,因为补全可以使用窗口中剩余的任何内容。如果你确实设置了它,请确保提示词 token 加上 max_tokens 保持在 100,000 以下。在长历史记录之上硬编码大型 max_tokens 的客户端可能会使总和超过窗口,即使单独提示词看起来没问题。

代理、缓冲和超时

流式输出使用服务器发送事件:一个长寿命的 HTTP 响应,随着生成的内容交付小块。你和 API 之间的任何等待整个响应再转发的内容都会破坏这一点。结果要么是长时间沉默后的一阵突发,要么是超时和通用错误。

在你自己的设置中查找这些:

  • 反向代理。 如果你通过 nginx 或类似代理路由 API,请关闭该位置的响应缓冲,并将读取超时提高到超过你预期的最长回答。来自 100,000 token 窗口的长回答可能需要一段时间。
  • 企业或防病毒代理。 某些代理会检查 HTTPS 流量并保留正文。请通过手机热点进行测试以排除此问题。
  • 无服务器函数。 许多平台限制执行时间或缓冲响应,除非你选择加入流式输出。如果流在每次相同秒数时死亡,平台时间限制可能是原因。
  • 浏览器扩展和 VPN。 罕见,但它们可以切断空闲连接。

指向这里的线索是回答中间的错误,每次尝试都有相同的截断时间。速率限制会在开始时拒绝请求,因此总是在例如 30 秒时发生的流式传输中途切断几乎从来不是限制。

显示真实错误的客户端

当你想要真相而不是友好的消息时使用此方法。它捕获 OpenAI SDK 异常,打印状态和错误正文,并在存在时读取重试提示。

import time
from openai import OpenAI, APIConnectionError, APIStatusError, RateLimitError

client = OpenAI(
    base_url="https://api.uncensoredllmhub.com/v1",
    api_key="YOUR_API_KEY",
)

def stream_once(messages):
    stream = client.chat.completions.create(
        model="uncensored",
        messages=messages,
        stream=True,
    )
    for chunk in stream:
        if chunk.choices and chunk.choices[0].delta.content:
            print(chunk.choices[0].delta.content, end="", flush=True)
        if getattr(chunk, "usage", None):
            print("\n[usage]", chunk.usage)

messages = [{"role": "user", "content": "Write two sentences about harbours."}]

for attempt in range(4):
    try:
        stream_once(messages)
        break
    except RateLimitError as e:
        wait = int(e.response.headers.get("retry-after", 5))
        print("429:", e.body, "- waiting", wait, "s")
        time.sleep(wait)
    except APIStatusError as e:
        print("status", e.status_code, e.body)
        print("request id:", e.response.headers.get("x-request-id"))
        break
    except APIConnectionError as e:
        print("connection problem:", e)
        time.sleep(2)

Node 中的相同想法,使用中止信号以便被遗弃的流释放其槽位:

import OpenAI from "openai";

const client = new OpenAI({
  baseURL: "https://api.uncensoredllmhub.com/v1",
  apiKey: process.env.API_KEY,
});

const controller = new AbortController();

try {
  const stream = await client.chat.completions.create(
    {
      model: "uncensored",
      messages: [{ role: "user", content: "Write two sentences about harbours." }],
      stream: true,
    },
    { signal: controller.signal }
  );
  for await (const chunk of stream) {
    process.stdout.write(chunk.choices[0]?.delta?.content ?? "");
  }
} catch (err) {
  console.error("status:", err.status, "body:", err.error);
}
// call controller.abort() when the user leaves the page

以及原始 curl 调用,它从画面中移除每个客户端。-N 关闭 curl 自己的缓冲,-i 打印状态行和头,包括 X-Request-Id:

curl -N -i https://api.uncensoredllmhub.com/v1/chat/completions   -H "Authorization: Bearer $API_KEY"   -H "Content-Type: application/json"   -d '{"model":"uncensored","stream":true,"messages":[{"role":"user","content":"Say hello."}]}'

如果 curl 流式传输文本正常而你的应用不行,则 API 健康且问题位于应用、其代理或其设置中。如果 curl 显示 429 或其他状态,你现在有了确切的原因。

不会使情况恶化的重试规则

重试有助于解决瞬态问题,但对永久性问题有害。简短的策略可以让你避免麻烦。

  • 重试 429 和连接中断。当存在 Retry-After 时等待它,否则退后几秒并添加一些随机抖动,以便并行工作者不会同步重试。
  • 不要重试身份验证失败或请求过大的情况。结果不会改变,每次重试只会增加噪音。
  • 将尝试次数限制为三到四次,然后向用户显示真实错误文本。
  • 将你自己的并发请求数控制在密钥限制以下。完整密钥下使用 6 的信号量,可以为使用同一密钥的第二个工具调用留出空间。
  • 如果流式连接在半途断开,请保留部分文本。将该文本作为助手消息重新发送,并请求模型继续生成,而不是从头重新生成。

失败或被拒绝的请求不会收费,因此使用重复测试调用进行调试不会消耗你的额度。成功的请求按每 100 万输入 token $0.15、每 100 万输出 token $0.50 计费,而正常完成的部分流式响应只是一个简短的答案。关于请求格式的更多详细信息请参阅 API 文档。

如果你已完成上述所有操作但仍看到该消息,请将失败调用的 X-Request-Id 发送至 支持页面,并附上尝试的时间以及失败是发生在第一个 token 之前还是之后。这些信息足以追踪发生的情况。

问答

为什么我的应用从 LLM 流中收到未知错误且没有任何详细信息?

该措辞来自客户端应用,它隐藏了底层的 HTTP 状态。使用 curl 并加上 -i 参数重复请求,以查看真实的状态码和 JSON 错误主体。

429 错误是否意味着服务已宕机?

通常不是。这表示你超过了每分钟限制或并发限制,或者服务通过 Retry-After 要求你等待 5 秒。请降低请求频率或排队请求并重试。

为什么前几条消息正常,随后却失败?

流会占用并发槽位,直到它们完成。如果之前的流从未关闭,或者历史记录已超过上下文窗口,后续请求将失败,直到槽位释放或历史记录被修剪。

失败的流式输出请求会收费吗?

失败或被拒绝的请求不会收费,因此你可以自由测试。完成的请求按 token 以正常价格计费。

只需填写一份表单即可获得密钥

创建账户,复制密钥,更改基础 URL。这就是全部设置。

获取 API 密钥

https://api.uncensoredllmhub.com/v1