주요 포인트
- 이 텍스트는 클라이언트에서 제공되므로 curl을 사용하여 호출을 재현하여 실제 오류 본문과 상태를 확인하세요.
- HTTP 429 (code: rate_limited 또는 concurrency)는 바쁜 계정에서 가장 흔한 원인이며, 스트림은 종료될 때까지 슬롯을 유지합니다.
- 기타 작업 전에 베이스 URL, 키, 모델 ID uncensored, 본문 크기(8 MB) 및 총 토큰 수(100,000)를 확인하세요.
- 429 오류 및 네트워크 끊김에만 재시도하고, Retry-After를 기다리며, 동시성 요청을 키 한도 내에 유지하세요.
이 메시지가 실제로 알려주는 것
llm 스트림에서 알 수 없는 오류가 발생하면 더 자세히 알아보기를 검색했다면, 채팅 프론트엔드, 편집기 플러그인 또는 에이전트 프레임워크에서 토스트 알림이나 빨간색 오류 줄을 보고 있을 가능성이 높습니다. 이 문구는 해당 클라이언트에서 비롯됩니다. 이는 앱이 스트리밍된 답변을 요청했지만, 스트림 시작 전 또는 중 오류가 발생했고 앱이 이를 설명할 방법을 몰랐다는 의미입니다. API 자체는 HTTP 상태 코드와 JSON 오류 본문으로 문제를 보고하며, 클라이언트는 해당 세부 정보를 무시했습니다.
좋은 소식입니다. 클라이언트 외부에서 동일한 요청을 보내고 상태 줄과 본문을 읽으면 원인이 한두 번의 시도 만에 명확해집니다. 이 페이지의 나머지 부분에서는 이 API에서 일반적으로 발생하는 순서대로 원인을 설명한 후, 숨기는 대신 실제 오류를 출력하는 작은 스트리밍 클라이언트를 제공합니다.
처음부터 기억해야 할 한 가지: 스트리밍된 요청에는 두 가지 실패 지점이 있습니다. 서버가 요청을 거부할 때(잘못된 키, 잘못된 URL, 한도 초과) 첫 번째 바이트가 오기 전에 실패할 수 있습니다. 또는 일부 텍스트가 도착한 후 연결이 끊겨 중간에 실패할 수 있습니다. 해결 방법이 다르므로 두 가지 중 어떤 것인지 주의 깊게 확인하세요. 답변이 시작되지 않는다면 두 번째부터 네 번째 섹션을 참조하세요. 답변이 시작되었다가 중단된다면 프록시 및 타임아웃 섹션을 참조하세요.
베이스 URL, 키 및 모델을 먼저 확인하세요
새로운 설정에서의 대부분 스트리밍 오류는 세 가지 작은 실수에서 비롯됩니다. 이를 확인하는 데는 몇 분 정도 걸립니다.
- 베이스 URL.
https://api.uncensoredllmhub.com/v1여야 하며,/v1을 포함하고 끝에/chat/completions이 붙지 않아야 합니다. 클라이언트는 경로를 자체적으로 추가합니다. 베이스가 예상되는 필드에 전체 엔드포인트를 붙여넣으면 클라이언트는 존재하지 않는 경로로 요청하여 모호한 오류를 보고합니다. - 키. 헤더는
Authorization: Bearer YOUR_KEY입니다. 키에 불필요한 공백이나 줄바꿈이 있거나 다른 서비스의 키를 사용하면 동일한 방식으로 실패합니다. 확신이 서지 않으면 API 키 페이지에서 키를 다시 생성하거나 복사하세요. - 모델 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초를 기다린 후 다시 시도하십시오 |
동시성 한도는 스트리밍 방식 때문에 사람들이 놀라게 하는 요소입니다. 스트리밍된 요청은 첫 번째 토큰이 도착할 때가 아니라 스트림이 끝날 때까지 슬롯을 점유합니다. 앱이 모든 메시지에 대해 스트림을 열지만 이전 스트림을 종료하지 않는 경우(예: 사용자가 화면을 이동하여 UI가 요청 취소를 잊은 경우) 이러한 슬롯이 점유된 상태로 남습니다. 한도가 2인 체험 키의 경우, 중단된 스트림 두 개만으로도 세 번째 메시지 실패를 유발할 수 있습니다.
증상이 일관적입니다. 처음 몇 개의 메시지는 작동하다가 오류가 발생하고, 잠시 기다리면 다시 모든 것이 정상으로 돌아옵니다. 이러한 패턴과 일치한다면 더 이상 필요하지 않은 스트림을 중단하세요(브라우저에서는 AbortController를 사용하고 서버에서는 응답을 닫음). 또한 자체 코드에서 동시 호출 수를 제한하세요. 에이전트가 흔히 문제의 원인입니다. 한 번에 10개의 함수 호출을 실행하는 플래너는 체험 키에서 즉시 속도 제한에 도달합니다.
응답 헤더를 통해 현재 상태를 확인할 수 있습니다. X-RateLimit-Limit-Requests 및 X-RateLimit-Limit-Concurrency는 사용된 키에 적용되는 한도를 보여주며, X-Request-Id는 지원에 문의할 때 호출을 식별하는 데 사용됩니다.
요청 크기 및 컨텍스트 길이
요청이 너무 커서 거부될 수도 있습니다. 두 가지 숫자가 중요합니다. 본문 크기는 최대 8 MB까지 가능하며, 프롬프트와 완성 텍스트의 합계는 100,000 토큰 컨텍스트 창에 들어와야 합니다. 매번 전체 대화 내용을 다시 보내는 채팅 프론트엔드는 이러한 제한에 천천히 도달했다가 갑자기 초과됩니다: 채팅은 한 시간 동안 작동하다가 긴 메시지 하나나 붙여넣은 파일 하나로 한계가 넘어가고, 이후의 모든 턴은 요청에 여전히 역사가 포함되어 있어 실패합니다.
오류가 긴 세션 후에 시작된다면 짧은 새 대화로 테스트하세요. 작동한다면 기록이 원인입니다. 오래된 턴을 삭제하거나 요약하여 하나의 메시지로 만들어 기록을 정리하거나, 새 채팅을 시작하세요. 큰 붙여넣기 문서도 다른 트리거입니다. 수백 킬로바이트의 텍스트 파일은 괜찮지만, base64 blob이나 매우 큰 로그 파일은 예상보다 빨리 8 MB에 도달할 수 있습니다.
max_tokens을 설정할 필요가 없습니다. 생성된 텍스트는 남은 한도까지 사용할 수 있기 때문입니다. 설정할 경우 프롬프트 토큰 수와 max_tokens의 합계가 100,000 미만인지 확인하세요. 긴 이력에 큰 max_tokens을 하드코딩하면 프롬프트만 괜찮아 보여도 합계가 창을 초과할 수 있습니다.
프록시, 버퍼링 및 타임아웃
스트리밍은 서버 전송 이벤트를 사용합니다. 이는 생성되는 작은 청크를 전달하는 장기 HTTP 응답입니다. API와 당신 사이에 전체 응답을 전달하기 전에 대기하는 모든 요소는 이를 깨뜨립니다. 그 결과 긴 침묵 후 데이터 폭주가 발생하거나, 타임아웃과 일반적인 오류가 발생합니다.
자체 설정에서 다음 항목을 확인하세요:
- 리버스 프록시. API를 nginx 또는 유사한 프록시로 라우팅하는 경우 해당 위치의 응답 버퍼링을 끄고 예상되는 최대 응답 시간보다 읽기 타임아웃을 높게 설정하세요. 100,000 토큰 창에서 생성된 긴 답변은 시간이 꽤 걸릴 수 있습니다.
- 기업용 또는 안티바이러스 프록시. 일부는 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
그리고 모든 클라이언트를 배제하는 raw 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이 있으면 기다리세요. 없으면 몇 초 동안 대기하고 병렬 작업자가 동시에 재시도하지 않도록 약간의 랜덤 지터를 추가하세요. - 인증 실패나 요청 크기 초과에 대해 재시도하지 마세요. 결과가 바뀌지 않으며, 각 재시도는 노이즈만 추가합니다.
- 시도를 3~4회로 제한한 후 사용자에게 실제 오류 텍스트를 표시하세요.
- 자신의 동시성을 키 제한보다 낮게 제한하세요. 전체 키에 6의 세마포어를 사용하면 동일한 키를 사용하는 두 번째 도구를 위한 여유 공간이 생깁니다.
- 스트림이 중간에 끊긴 경우 부분 텍스트를 유지하세요. 처음부터 재생성하는 대신 해당 텍스트를 어시스턴트 메시지로 보내 모델에 계속 생성하도록 요청하세요.
실패하거나 거부된 요청에는 요금이 청구되지 않으므로 반복된 테스트 호출로 디버깅해도 크레딧이 소모되지 않습니다. 성공적인 호출은 입력 토큰 100만 개당 $0.15, 출력 토큰 100만 개당 $0.50에 청구되며, 정상적으로 완료되는 부분 스트림은 단순히 짧은 답변입니다. 요청 형식에 대한 자세한 내용은 API 문서에서 확인할 수 있습니다.
위 모든 작업을 수행했음에도 메시지가 표시되면 실패한 호출의 X-Request-Id를 시도 시간과 실패가 첫 번째 토큰 전후에 발생했는지 여부와 함께 지원 페이지로 보내세요. 이 정보로 발생한 일을 추적하기에 충분합니다.
