호환성이 실제로 보장하는 것
OpenAI 호환 API는 OpenAI SDK가 보내는 동일한 HTTP 요청을 받습니다. 베이스 URL과 키만 변경하면 클라이언트는 계속 작동합니다. 이 약속은 프로토콜 레이어에 위치합니다: 경로 /v1/chat/completions, Authorization 헤더의 Bearer 토큰, model 및 messages이 포함된 JSON 본문, choices 및 usage이 포함된 응답입니다. 스트리밍은 동일한 서버 전송 이벤트 패턴을 따릅니다.
동일한 모델, 동일한 동작, 동일한 제한 또는 동일한 엔드포인트 세트를 약속하지 않습니다. 원래 API를 만든 회사가 무엇을 제공할지 결정하며, 다른 모든 제공업체는 독립적으로 무엇을 복사할지 결정합니다. 호환성을 클라이언트 코드를 다시 작성하지 않도록 하는 방법으로 간주하세요. 다른 모든 것이 변경되지 않는다는 보장은 아닙니다.
차이점 비교
이 표는 제공업체 간에 차이가 나는 영역과 이 API에서 해당 사항을 나열합니다. 오른쪽 열은 어떤 서비스를 평가할 때 자체 테스트를 위한 프롬프트로 사용할 수 있습니다.
| 영역 | 이 API | 모든 제공업체에서 확인할 사항 |
|---|---|---|
| 모델 ID | 하나의 ID: uncensored | 이전 모델 이름이 허용되는지, 매핑되는지 또는 거부되는지 |
| 엔드포인트 | /v1/chat/completions, /v1/responses, /v1/models | 코드에서 호출하는 모든 엔드포인트가 존재하는지 |
| 모달리티 | 텍스트 전용 | 필요한 경우 이미지, 오디오 및 비디오 지원 |
| 임베딩, 파인튜닝 | 제공되지 않음 | 그런 호출이 대신 어디로 갈지 |
| 컨텍스트 창 | 100,000 토큰, 프롬프트 및 생성 텍스트 포함 | 제한이 입력만 포함하는지 아니면 양쪽 모두를 포함하는지 |
| 동시성 및 속도 제한 | 전체 키: 동시 8개, 분당 300개. 체험 키: 동시 2개, 분당 60개 | 제한이 어떻게 측정되고 거부가 어떻게 보고되는지 |
| 함수 호출, JSON 모드 | 지원됨 | 스트리밍된 함수 호출과 같은 예외 케이스 |
| 콘텐츠 동작 | 합법적인 성인용 사용에 맞게 콘텐츠 거부 없이 답변하도록 조정됨 | 모델이 반환하는 내용을 변경하는 콘텐츠 필터링 레이어 |
| 결제 | 선불 크레딧, 토큰별, 구독 없음 | 최소 금액, 만료, 구독 등급 |
이 API의 가격 행은 입력 토큰 100만 개당 $0.15, 출력 토큰 100만 개당 $0.50입니다. 다른 모든 서비스의 경우 기억이나 서드파티 요약에 의존하기보다 현재 가격 페이지를 읽으세요.
모델 ID 및 동작
가장 큰 실용적인 차이점은 모델 자체입니다. OpenAI에서는 이름이 지정된 모델 메뉴에서 선택할 수 있습니다. 여기서는 "model": "uncensored"을 보내고 독립적인 제공업체가 실행하는 단일 오픈 가중치 모델을 받습니다. 이는 어떤 모델 공급업체의 공식 API가 아니며 여러 공급업체로 요청을 전달하는 라우터도 아닙니다.
이것은 두 가지 결과를 가져옵니다. 첫째, 문자열을 변경하여 모델 크기를 A/B 테스트할 수 없습니다. 하나의 모델을 실행하고 프롬프트와 샘플링을 그 주변에 맞춰 조정해야 합니다. 둘째, 다른 모델을 위해 작성된 프롬프트는 명령어 따르기, 서식 습관, 거부 행동이 모두 다르기 때문에 작은 수정이 필요할 수 있습니다. 이 모델은 합법적인 성인 사용에 대한 콘텐츠 거부 없이 답변하도록 조정되었으므로, 더 엄격한 모델을 위해 작성된 긴 안전 프롬프트는 종종 단축할 수 있습니다.
변하지 않는 한 가지 하드 제한이 있습니다: 미성년자가 관련된 성적 콘텐츠는 금지됩니다.
없는 엔드포인트 및 기능
호환성은 전체 OpenAI API 영역에서 거의 완전하지 않습니다. 여기서는 격차가 의도적입니다: 이 서비스는 텍스트만 처리하고 그 외에는 처리하지 않습니다.
- 이미지, 오디오 또는 비디오 생성이 없습니다.
- 임베딩 엔드포인트가 없으므로 검색 파이프라인에는 별도의 임베딩 제공업체가 필요합니다.
- 파인튜닝이 없습니다.
존재하는 기능은 대부분의 채팅 애플리케이션을 다룹니다: POST /v1/chat/completions, POST /v1/responses, 스트리밍, tools 및 tool_choice을 통한 함수 호출, response_format을 통한 JSON 모드. temperature, top_p, stop, seed 및 페널티와 같은 샘플링 제어는 모델에 전달됩니다.
애플리케이션이 기능을 혼합하는 경우 일반적인 패턴은 임베딩 및 이미지에 원래 제공업체를 유지하고, 무검열로 처리하려는 텍스트 생성만 새 베이스 URL로 보내는 것입니다. 비용 및 트레이드오프 분석이 분할을 통해 작동합니다.
제한, 오류 및 헤더
속도 제한은 부하 상황에서 코드가 어떻게 동작해야 하는지 결정하기 때문에 마이그레이션 시 사용자를 놀라게 하는 부분입니다. 이 API는 전체 키에 대해 동시 요청 8개와 분당 300개 요청, 최대 본문 크기 8 MB를 설정합니다. 체험 키에는 동시 요청 2개와 분당 60개 요청이 적용됩니다. 한도를 초과하는 요청은 HTTP 429 오류를 반환합니다. 오류 코드는 도달한 한도를 알려줍니다: 분당 요청 수는 rate_limited, 동시 요청 과다는 concurrency로 표시됩니다. 일시적인 과부하도 429를 반환하며 Retry-After: 5 헤더를 추가합니다.
코드를 확인하고 헤더를 확인하세요. 상태만 보지 마세요. concurrency 오류를 즉시 재시도하면 상황이 악화됩니다. 짧은 대기 시간이 이를 해결합니다. 스트리밍 요청은 스트리밍이 끝날 때까지 슬롯을 점유하므로, 동시 요청 수는 진행 중인 호출뿐만 아니라 열린 스트림 수를 기준으로 계산됩니다.
응답에는 X-Request-Id, X-Balance-USD, X-RateLimit-Limit-Requests 및 X-RateLimit-Limit-Concurrency이 포함됩니다. 잔액 헤더는 제공업체별 추가 항목입니다. OpenAI SDK 코드는 이를 무시하지만 지출을 추적하기 위해 읽을 수 있습니다. 잔액은 GET /v1/balance 및 OpenAI 스타일의 GET /v1/dashboard/billing/credit_grants을 통해서도 사용할 수 있습니다.
마이그레이션 체크리스트
애플리케이션을 제공업체 간에 이동할 때마다 동일한 짧은 목록을 따르세요. 이렇게 하면 사용자가 경험하기 전에 대부분의 예상치 못한 상황을 방지할 수 있습니다.
- 베이스 URL, 키 및 모델 ID를 함께 교체하고 구성 파일에 숨겨진 이전 모델 이름을 저장소에서 검색하세요.
- 새로운 쪽에 존재하지 않는 엔드포인트에 대한 호출을 제거하고 해당 엔드포인트가 있는 제공업체로 라우팅하세요.
- 프롬프트 세트를 실행하고 출력을 비교하세요. 다른 모델에서는 다른 어휘와 서식이 예상됩니다.
- 사용자와 API 사이의 모든 프록시 및 로드 밸런서를 통해 스트리밍을 테스트하세요.
- 오류 코드와 Retry-After 헤더를 읽는 429에 대한 재시도 로직을 추가하세요.
- 요청별 토큰 사용량을 기록하면 예상치 못한 비용이 월말이 아닌 며칠 내에 나타납니다.
빠른 호환성 테스트
이 목록을 포함한 기능 목록을 신뢰하지 마세요. 애플리케이션이 수행하는 호출을 실행하고 결과를 비교하세요. 의존하는 부분을 테스트하는 짧은 스크립트는 몇 분 정도 걸립니다:
from openai import OpenAI
client = OpenAI(
base_url="https://api.apicompatible.com/v1",
api_key="YOUR_API_KEY",
)
# 1. Plain completion
r = client.chat.completions.create(
model="uncensored",
messages=[{"role": "user", "content": "Reply with the word ready."}],
temperature=0,
seed=7,
)
print("plain:", r.choices[0].message.content)
# 2. JSON mode
j = client.chat.completions.create(
model="uncensored",
messages=[{"role": "user", "content": "Return a JSON object with keys name and age for a fictional person."}],
response_format={"type": "json_object"},
)
print("json:", j.choices[0].message.content)
# 3. Streaming
chunks = client.chat.completions.create(
model="uncensored",
messages=[{"role": "user", "content": "Count from one to five."}],
stream=True,
)
print("stream:", "".join(c.choices[0].delta.content or "" for c in chunks if c.choices))
코드에서 함수를 사용하는 경우 함수 호출 케이스를 추가하고, 실제 프롬프트 크기에 가까운 긴 컨텍스트 케이스를 추가하세요. 각 매개변수에 대한 세부 정보는 문서에 있으며, API 키 페이지에서는 $0.50 체험 크레딧을 청구하는 방법을 확인할 수 있습니다. 이는 이러한 종류의 확인에 충분합니다.
