Wu Xianzhi API마이그레이션 가이드
API 중개 서버 마이그레이션 가이드: OpenAI, OpenRouter에서 무검열 API로 전환
현재 OpenAI, OpenRouter 또는 API 중개 서비스를 사용하고 있다면 합법적인 요청을 거부하지 않는 무검열 API로 전환하는 것은 base_url, API 키, 모델 이름 세 가지 설정만 변경하면 됩니다. 이 문서에서는 중개 서비스와 전용 무검열 모델의 차이점을 먼저 설명하고, 매개변수 대조표, 환경 변수를 사용해 기존과 새 엔드포인트에 동시 요청을 보내는 방법, 서비스 시작 전 전환 체크리스트, 그리고 마이그레이션 시 가장 흔히 발생하는 문제를 다룹니다.
업데이트
핵심 요약
- 중개 서버는 여전히 원본 모델을 재판매하며 콘텐츠 정책이 동일합니다. 전용 무검열 모델이어야 응답 거부 문제를 해결할 수 있습니다.
- 마이그레이션 시 다음 세 가지만 변경: base_url을 https://api.wuxianzhiapi.com/v1,密钥,模型名 uncensored로 변경
- embeddings, 이미지, 오디오, 파인튜닝을 지원하지 않으므로 해당 기능은 기존 서비스를 계속 사용하세요.
- 환경 변수를 사용하여 점진적으로 전환하고, 문제가 발생하면 변수 하나만 변경하면 롤백할 수 있습니다.
API 릴레이와 전용 무검열 모델의 차이
먼저 개념을 명확히 해야 마이그레이션 시 방향을 잘못 선택하지 않습니다. 일반적인 API 릴레이는 본질적으로 대형 모델의 호출 할당량을 재판매하거나 집계하여 OpenAI 호환 엔드포인트를 제공하며, 동일한 SDK로 다양한 모델을 전환할 수 있게 합니다. 이는 '접근 및 결제' 문제를 해결합니다(통합 진입로, 통합 청구). 그러나 모델 자체는 동일하며 원본 콘텐츠 정책이 그대로 유지됩니다. 거절해야 할 주제는 여전히 거절되며, 릴레이 주소만 변경해도 이 점은 변하지 않습니다.
전용 무검열 모델은 별개입니다. 타사 모델을 중계하는 것이 아니라 독립적으로 제공되며, 성인 콘텐츠, 창작물, 논쟁적 주제에 대해 거부하지 않습니다. Wu Xianzhi API은 단일 모델만 제공하며 모델명은 uncensored입니다. OpenAI 형식과 호환되어 마이그레이션 비용이 낮지만 명확한 한계가 있습니다: 텍스트 전용이며 이미지, 오디오, 벡터, 파인튜닝을 지원하지 않습니다. 미성년자 관련 성인 콘텐츠는 창작물 여부 관계없이 403 오류를 반환합니다.
따라서 마이그레이션 전에 스스로에게 물어보세요: '인터페이스 불안정, 높은 가격' 문제인가, 아니면 '모델이 합법적 요청을 계속 거절하는' 문제인가? 후자의 경우 릴레이를 변경하는 것은 의미가 없으며, 전용 무검열 API로 전환해야 해결됩니다. 많은 팀은 두 가지를 병행합니다: 일반 작업은 기존 인터페이스를 계속 사용하고, 무검열 출력이 필요한 요청은 별도로 라우팅합니다. 구체적인 방법은 후술합니다.
OpenAI 또는 OpenRouter에서 마이그레이션 시 변경해야 할 세 가지 항목
기존에 OpenAI 공식, OpenRouter 같은 집계 API 또는 중계서를 사용했든, 코드에서 OpenAI 호환 SDK를 사용한다면 변경해야 할 항목은 세 가지뿐입니다: base_url을 https://api.wuxianzhiapi.com/v1로 변경, api_key을 /get-api-key/에서 발급받은 키로 교체, model을 uncensored로 통일. 선택할 수 있는 다른 모델은 없으며, GET /v1/models에도 이 모델만 있습니다.
import os
from openai import OpenAI
messages = [{"role": "user", "content": "你好"}]
# 迁移前(示意):
# client = OpenAI(api_key=os.environ["OLD_API_KEY"], base_url="旧地址")
# resp = client.chat.completions.create(model="旧模型名", messages=messages)
# 迁移后:只动 base_url、api_key、model 这三处
client = OpenAI(
base_url="https://api.wuxianzhiapi.com/v1",
api_key=os.environ["WUXIANZHI_API_KEY"],
)
resp = client.chat.completions.create(model="uncensored", messages=messages, max_tokens=100)
print(resp.choices[0].message.content)curl https://api.wuxianzhiapi.com/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $WUXIANZHI_API_KEY" \
-d '{"model":"uncensored","messages":[{"role":"user","content":"你好"}],"max_tokens":50}'
매개변수 매핑: 지원 여부 확인
아래 표는 마이그레이션 시 자주 마주치는 필드를 정리한 것입니다. 대화 관련 및 OpenAI 형식의 핵심 필드는 그대로 사용 가능합니다. 다른 모델이나 모달리티 관련 기능은 제공되지 않습니다.
| 기존 사용법 | 마이그레이션 처리 방법 |
|---|---|
model (예: GPT 모델) | uncensored로 변경 필수 |
| 형식 동일, 바로 사용 가능 | |
max_tokens | 기본값 2048, 최대 32,000; 초과 시 400 오류 반환 |
stream: true | 지원, 응답 끝에 사용량 블록 자동 추가 |
tools / tool_choice | 지원, OpenAI 형식 |
| 컨텍스트 창 길이 | 프롬프트 및 출력 합계 100,000 토큰 |
| 요청 본문 크기 | 8 MB 이하 |
| 속도 제한 | 키당 분당 300 요청 |
| 벡터 임베딩 | 미지원 |
| 이미지 생성/인식, 음성, 비디오 | 미지원, 텍스트만 처리 |
| 파인튜닝 | 지원하지 않음 |
| 여러 모델로 전환 | 모델이 하나뿐이라 전환할 목록이 없습니다. |
표에 나열되지 않은 기타 선택적 필드는 기본값으로 원본 방식대로 작동한다고 가정하지 마십시오. 안전한 방법은 테스트 환경에서 별도로 실행하여 동작이 예상과 일치하는지 확인한 후 출시하는 것이며, 구체적인 지원 여부는 API 문서을 기준으로 하십시오.
없는 기능의 대안: 벡터, 이미지, 음성
기존 프로젝트에서 대화와 벡터 검색을 함께 사용했다면 마이그레이션 시 '모두 가져오기'를 생각하지 마십시오. 여기서는 텍스트 대화만 제공하므로, 지식베이스 검색이나 의미적 중복 제거와 같은 임베딩 관련 코드는 기존 벡터 서비스를 계속 사용하거나 자체 배포한 벡터 솔루션으로 전환해야 합니다. 대화 부분은 여기로 옮기고 검색 부분은 그대로 두면 서로 영향을 주지 않아 가장 간편한 분리 방식입니다.
이미지와 음성의 경우도 동일합니다. 예를 들어 제품이 '텍스트 + 이미지' 형태라면, 텍스트 생성은 여기로 처리하고 이미지 생성은 기존 이미지 API를 계속 사용하십시오. 음성 합성이 필요하다면 텍스트 생성 후 기존 음성 서비스로 넘기면 됩니다. '텍스트 생성' 단계를 별도의 함수로 추출해 두면, 이후 다른 기능을 조합할 때 수정 범위가 매우 작아집니다.
또 다른 경우로 코드에서 여러 모델을 역할에 따라 사용하는 경우가 있습니다. 예를 들어 저렴한 모델은 분류에, 비싼 모델은 창작에 사용합니다. 여기서는 모델이 하나뿐이므로 분류 작업도 해당 모델이 수행해야 합니다. 다행히 입력 단가는 토큰 100만 개당 $0.25로, 출력 길이가 짧은 분류 작업의 비용은 매우 낮습니다. max_tokens 값을 작게 설정하면 비용은 거의 무시할 수준이 됩니다. 가격 세부 사항은 가격 페이지를 참조하십시오.
병렬 실행: 환경 변수로 두 API 간 전환
마이그레이션 시 가장 피해야 할 것은 '일괄 교체'입니다. 더 안정적인 방법은 코드에 얇은 래퍼 레이어를 추가하고 환경 변수로 어느 API를 사용할지 결정하는 것입니다. 이렇게 하면 일부 트래픽이나 기능만 새 API로 먼저 전환할 수 있으며, 문제가 발생하면 변수 하나만 변경하면 쉽게 롤백할 수 있습니다. 양쪽 모두 OpenAI 호환 형식이므로 래핑이 매우 간단합니다.
import os
from openai import OpenAI
PROVIDERS = {
"old": {
"base_url": os.environ.get("OLD_BASE_URL", ""),
"api_key": os.environ.get("OLD_API_KEY", ""),
"model": os.environ.get("OLD_MODEL", ""),
},
"wuxianzhi": {
"base_url": "https://api.wuxianzhiapi.com/v1",
"api_key": os.environ.get("WUXIANZHI_API_KEY", ""),
"model": "uncensored",
},
}
def get_client(name=None):
name = name or os.environ.get("LLM_PROVIDER", "old")
cfg = PROVIDERS[name]
return OpenAI(base_url=cfg["base_url"], api_key=cfg["api_key"]), cfg["model"]
def chat(messages, provider=None, **kwargs):
client, model = get_client(provider)
return client.chat.completions.create(model=model, messages=messages, **kwargs)
# 通用任务走旧接口,需要无审查输出的请求显式指定新接口
resp = chat([{"role": "user", "content": "写一个黑色幽默的短故事"}],
provider="wuxianzhi", max_tokens=800)
print(resp.choices[0].message.content)변환 단계는 세 가지 수준으로 나뉩니다: 환경별(테스트 환경부터 전환), 기능별(창작 관련 API만 전환), 사용자별(일부 계정만 전환)입니다. 어느 단계든 로그에 기록된 provider 필드를 남겨두는 것이 좋습니다. 이렇게 하면 차이가 발생했을 때 비교하여 문제를 추적할 수 있습니다. 대화 기록도 표준 messages 배열로 저장하는 것을 권장합니다. 이렇게 하면 동일한 세션의 대화 양쪽에서 끊김 없이 이어서 진행할 수 있습니다.
전환 체크리스트
서비스 시작 전 다음 순서대로 확인하면 누락 항목이 거의 없습니다:
- /get-api-key/에서 등록하고 키를 발급받으십시오. $0.50의 무료 체험 크레딧(7일 유효)으로 검증하면 되며, 먼저 충전할 필요는 없습니다.
curl /v1/models를 사용하여 키 유효성 및 네트워크 접근성을 확인하십시오.base_url,api_key,model세 항목을 환경 변수로 변경하고, 키는 코드 저장소에 포함하지 마십시오.- 코드 내 하드코딩된 모델 이름,
max_tokens값 및 embeddings 호출을 검색하십시오. - 스트리밍 처리 코드를 확인하여 마지막
choices이 빈 사용량 블록인 경우를 처리할 수 있도록 하십시오. - 429 및 503에는 지수 백오프 재시도를 추가하고, 402 및 403에는 명확한 안내 분기를 추가하십시오.
- 실제 프롬프트로 회귀 테스트 샘플을 실행하여, 기존에 거부되었던 부분이 정상적으로 출력되는지 중점적으로 확인하십시오.
- 소규모 트래픽으로 점진적으로 전환한 후 사용량과 지연 시간을 비교하여 문제가 없으면 확장하십시오.
- 제품의 대상이 성인 사용자이며 용도가 합법적이어야 합니다. 이는 본 API 사용의 전제 조건입니다.
마이그레이션 시 가장 흔히 발생하는 함정
모델 이름 변경을 잊어버림. 기존 코드에서 gpt 모델이나 일부 집계 플랫폼의 모델 경로를 그대로 보내면 오류 응답이 반환됩니다. 모델 이름을 전역으로 검색하여 최종적으로 uncensored가 전송되도록 하십시오.
max_tokens 초과. 일부 프로젝트에서는 모델이 더 길게 쓰도록 max_tokens을 32000 이상으로 설정합니다. 여기서는 단일 요청 최대 길이가 32,000이며 이를 초과하면 400 오류가 반환됩니다. 또한 프롬프트에 max_tokens을 추가한 경우 토큰 총량이 100,000을 초과할 수 없으므로, 입력이 긴 요청의 경우 출력 상한을 낮춰야 합니다.
스트리밍 사용량 블록.스트리밍이 종료되기 전 서버는 자동으로 usage 필드를 포함한 블록을 추가합니다. 이 블록의 choices는 빈 배열입니다. 만약 파싱 코드가 chunk.choices[0]로 직접 값을 가져오도록 작성되어 있다면 마지막 단계에서 오류가 발생합니다. 일부 이전 코드에서는 사용량을 위해 stream_options을 수동으로 전달하기도 하지만, 여기서는 필요하지 않습니다.
'검열 없음'을 '제약 없음'으로 오해. 합법적인 성인 콘텐츠, 픽션 및 논쟁적 주제는 거부되지 않지만, 미성년자 관련 성 콘텐츠는 픽션 및 역할극을 포함해 항상 차단되며 403 content_blocked이 반환됩니다. 제품 측에서 성인 사용자 접근을 적절히 관리해야 합니다.
잔액 및 체험 만료. 체험 크레딧은 7일 후失效되며, 잔액이 소진되면 402 오류가 반환되고 오류 코드는 no_credit입니다. 애플리케이션에서는 이 오류를 모호한 '서비스 오류'가 아닌 사용자가 이해할 수 있는 메시지로 변환하십시오. 구체적인 시나리오 설계는 사용 사례 문서를 참조하십시오.
자주 묻는 질문
마이그레이션 후 기존 프롬프트를 다시 작성해야 하나요?
형식은 변경할 필요가 없으며 messages 구조가 완전히 동일합니다. 다만, 기존에 거부 응답을 우회하기 위해 작성한 '제너럴(jailbreak)'식 프롬프트는 제거하고 역할과 작업을 명확히 명시하는 것이 좋습니다. 이렇게 하면 토큰을 절약할 수 있을 뿐만 아니라 안정성도 높아집니다.
마이그레이션 기간 중 기존 API와 새 API를 동시에 유지할 수 있나요?
가능하며, 이를 권장합니다. 환경 변수를 사용하여 base_url, 키 및 모델 이름을 결정하고, 일부 기능이나 일부 사용자만 새 API로 전환하십시오. 문제가 발생하면 변수 하나만 변경하면 쉽게 롤백할 수 있습니다.
기존 API의 embeddings 호출을 가져오면 어떻게 되나요?
여기에는 embeddings API가 없으므로 요청 시 404 오류가 반환됩니다. 벡터 검색 부분은 기존 서비스를 계속 사용하고, 대화 요청만 전환하십시오.
마이그레이션 후 효과가 개선되었는지 어떻게 판단하나요?
기존에 거부되거나 수정되었던 실제 프롬프트 샘플을 가져와 회귀 테스트를 수행하십시오. 거부율, 응답 길이 및 usage 블록 내 토큰 수를 기록하십시오. 샘플은 온라인의 일반적인 테스트 세트가 아닌 자체 비즈니스 데이터여야 합니다.