시작 전 점검 목록
처음부터 확인하여 중간에 돌아오는 시간을 절약하세요.
- 등록용 이메일 주소가 필요합니다.
- Python 3, JDK 15 이상(예제에 텍스트 블록 사용), Go, 또는 curl 확장이 있는 PHP 등 본 시스템의 임의의 실행 환경이 필요합니다.
- 서비스는 성인만 이용 가능하므로 만 18세 이상인지 확인하세요.
- 순수 텍스트 대화만 원한다는 점을 인지하세요. 여기에는 벡터, 이미지, 음성, 파인튜닝 모델이 없으며 단일 모델만 제공됩니다.
- 키를 환경 변수에 저장하고 소스 코드에 직접 작성하거나 저장소에 커밋하지 마세요.
인터페이스는 매우 단순합니다. 주소는 https://api.wushenchaapi.com/v1이며, OpenAI의 채팅 완성 API와 호환되므로 기존에 작성한 요청 본문을 그대로 사용할 수 있습니다.
예상 소요 시간: 등록 1분, 환경 설치(본 시스템에 따라 다름), 첫 요청 30초 이내. 이 시간 내에 결과가 없으면 네트워크 또는 키 문제일 수 있으므로 하단 오류 해결 목록으로 이동하세요. 순서를 지키세요: 먼저 models, 다음 chat, 먼저 동기식, 다음 스트리밍. 각 단계를 확인한 후 다음 단계로 진행하세요.
등록 및 키 받기
/get-api-key/로 이동하여 이메일과 비밀번호로 등록하세요. 등록 완료 후 키가 즉시 표시되므로 복사하세요. 몇 가지 주의사항:
- 계정당 키는 하나만 생성됩니다.
- 키를 재생성할 수 있지만 이전 키는 즉시 무효화되므로, 프로덕션 환경에서 키를 교체하기 전에 새 키를 먼저 배포해야 합니다.
- 신규 계정에는 $0.50의 무료 체험 크레딧이 제공되며 7일 동안 유효합니다. 결제 정보 입력이 필요하지 않습니다.
- 무료 체험 기간이 만료되거나 크레딧이 소진되면 요청 시 402 오류와
no_credit오류 코드가 반환됩니다. 선불 크레딧을 충전하면 계속 사용할 수 있으며, 구독이 아닌 선불 방식이므로 잔액은 만료되지 않습니다.
키를 환경 변수에 설정하세요: macOS/Linux에서는 export API_KEY=your_key, Windows PowerShell에서는 $env:API_KEY="your_key"을 실행하세요. 이후 모든 예제에서는 API_KEY에서 값을 읽어옵니다.
1단계: /v1/models로 연결성 검증
채팅 요청을 보내기 전에 비용이 들지 않는 GET 요청을 보내 주소, 네트워크, 키가 모두 정상인지 확인하세요:
curl https://api.wushenchaapi.com/v1/models \
-H "Authorization: Bearer $API_KEY"200 상태 코드와 모델 목록(단일 uncensored 모델 포함)이 반환되면 연결이 성공한 것입니다. 401은 키 오류 또는 누락, 타임아웃은 로컬 네트워크 또는 프록시 문제를 의미합니다. 연결성 문제와 요청 본문 문제를 분리하여 확인하는 것이 연동 단계에서 시간을 절약하는 가장 좋은 방법입니다.
Python: requests
SDK 없이도 requests.post 하나로 충분합니다. 세 가지 주의사항: timeout을 반드시 설정하세요; r.ok을 확인한 후 choices에 접근하세요; 실패 시 응답 본문은 {"error":{"code":...,"message":...}} 형식입니다.
import os
import requests
url = "https://api.wushenchaapi.com/v1/chat/completions"
headers = {
"Authorization": "Bearer " + os.environ["API_KEY"],
"Content-Type": "application/json",
}
payload = {
"model": "uncensored",
"messages": [{"role": "user", "content": "用两句话描述一场雨夜里的追逐戏。"}],
"max_tokens": 300,
}
r = requests.post(url, headers=headers, json=payload, timeout=120)
print(r.status_code)
data = r.json()
if r.ok:
print(data["choices"][0]["message"]["content"])
print(data["usage"])
else:
print(data["error"]["code"], data["error"]["message"])성공 시 usage 필드에 prompt_tokens과 completion_tokens이 포함되므로, 개발 중에는 매번 출력하여 비용 규모를 파악하는 것을 권장합니다.
요청 본문 필드별 분석
네 가지 언어 모두 동일한 JSON을 전송하므로, 먼저 이를 이해하면 어떤 언어로든 쉽게 변환할 수 있습니다.
| 필드 | 필수 | 설명 |
|---|---|---|
| model | 필수 | uncensored로 고정됩니다. |
| messages | 필수 | 배열이며, 각 항목은 role과 content를 포함합니다. role은 system, user, assistant 중 하나여야 합니다. |
| max_tokens | 선택 | 기본값은 2048이며, 단일 요청 최대 한도는 16,000입니다. 긴 텍스트 생성 시 직접 늘려야 합니다. |
| temperature / top_p / stop | 선택 | 표준 샘플링 매개변수로, 원본 그대로 전달됩니다. |
| stream | 아니요 | true일 때 SSE 스트리밍을 사용합니다. |
응답에서 가장 자주 확인하는 세 가지 항목이 있습니다. choices[0].message.content는 본문이며, choices[0].finish_reason는 정상 종료인지 길이로 인해 잘렸는지 알려줍니다. usage은 이번 요청의 토큰 사용량입니다. 세 항목 모두 확인해야 완전한 연동이 완료됩니다.
다음 두 가지 하드 제한 사항을 기억해 두십시오: 요청 본문은 8 MB를 초과할 수 없으며, 키당 분당 300회 요청이 제한됩니다. 대량 작업 시 무작정 동시 요청을 보내지 마십시오. 먼저 간단한 동시 요청 상한선을 설정하십시오.
Java: java.net.http
JDK 11부터 HttpClient가 기본 제공되므로 추가 의존성이 필요하지 않습니다. 아래 예제에서는 JDK 15의 텍스트 블록을 사용하여 JSON을 작성했으며, 구버전에서는 문자열 연결이나 선호하는 JSON 라이브러리를 사용하여 직렬화할 수 있습니다.
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
public class Demo {
public static void main(String[] args) throws Exception {
String key = System.getenv("API_KEY");
String body = """
{"model":"uncensored",
"messages":[{"role":"user","content":"写一段两百字以内的悬疑小说开头。"}],
"max_tokens":400}
""";
HttpRequest req = HttpRequest.newBuilder(
URI.create("https://api.wushenchaapi.com/v1/chat/completions"))
.timeout(Duration.ofSeconds(120))
.header("Authorization", "Bearer " + key)
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(body))
.build();
HttpResponse<String> resp = HttpClient.newHttpClient()
.send(req, HttpResponse.BodyHandlers.ofString());
System.out.println(resp.statusCode());
System.out.println(resp.body());
}
}팁: 본문에 중국어가 포함된 경우, BodyPublishers.ofString은 기본적으로 UTF-8로 인코딩되므로 추가 처리가 필요하지 않습니다. 프로덕션 환경에서는 HttpClient를 싱글톤으로 만들어 재사용하십시오. 매번 요청할 때마다 새로 생성하지 마십시오.
Go: net/http
Go 표준 라이브러리도 충분합니다. 중요한 점은 http.DefaultClient를 사용하되 타임아웃을 설정하지 않는 것입니다. 설정하지 않으면 서버가 응답하지 않을 때 goroutine이 계속 대기하게 됩니다.
package main
import (
"bytes"
"fmt"
"io"
"net/http"
"os"
"time"
)
func main() {
body := []byte(`{"model":"uncensored","messages":[{"role":"user","content":"给一个反派角色写三句独白。"}],"max_tokens":300}`)
req, err := http.NewRequest("POST", "https://api.wushenchaapi.com/v1/chat/completions", bytes.NewReader(body))
if err != nil {
panic(err)
}
req.Header.Set("Authorization", "Bearer "+os.Getenv("API_KEY"))
req.Header.Set("Content-Type", "application/json")
client := &http.Client{Timeout: 120 * time.Second}
resp, err := client.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
out, _ := io.ReadAll(resp.Body)
fmt.Println(resp.StatusCode, string(out))
}응답 본문은 io.ReadAll로 모두 읽은 후에 구문 분석하십시오. 구조화된 처리가 필요한 경우, 해당 struct를 정의하여 encoding/json로 역직렬화하면 됩니다. 필드는 choices, message, content, usage 등입니다.
PHP: curl
PHP에서는 curl 확장을 사용하십시오. json_encode에 JSON_UNESCAPED_UNICODE 플래그를 추가해야 합니다. 그렇지 않으면 중국어가 \uXXXX로 변환되는데, 이는 작동은 하지만 디버깅 시 읽기 어렵습니다.
<?php
$payload = [
"model" => "uncensored",
"messages" => [["role" => "user", "content" => "写一首八行的现代诗,主题是末班地铁。"]],
"max_tokens" => 300,
];
$ch = curl_init("https://api.wushenchaapi.com/v1/chat/completions");
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 120,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer " . getenv("API_KEY"),
"Content-Type: application/json",
],
CURLOPT_POSTFIELDS => json_encode($payload, JSON_UNESCAPED_UNICODE),
]);
$res = curl_exec($ch);
if ($res === false) {
die("curl 错误: " . curl_error($ch) . "\n");
}
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
echo $status, "\n";
$data = json_decode($res, true);
echo $data["choices"][0]["message"]["content"] ?? $res, "\n";두 가지 유형의 실패를 구분하십시오: curl_exec이 false를 반환하면 네트워크 계층 문제입니다. 내용이 반환되었지만 상태 코드가 200이 아니면 API 계층 문제이며, error.code를 읽어야 합니다.
첫 호출 시 자주 발생하는 문제
- 401: 헤더를
Authorization:密钥로 작성하여Bearer접두어를 누락했습니다. 또는 환경 변수가 새로 연 터미널에서 적용되지 않았습니다. - 404: 경로에
/v1이 누락되었거나,chat/completions를 오타냈습니다. - 400: JSON이 유효하지 않거나, 프롬프트에 max_tokens를 추가하여 100,000 토큰의 상한을 초과했습니다.
- 402: 잔액이 소진되었거나 무료 체험 기간이 만료되었습니다.
- 출력 잘림:
max_tokens의 기본값은 2048이며, 단일 요청 최대 길이는 16,000입니다. 긴 텍스트를 생성할 때는 명시적으로 값을 크게 설정하십시오. - 스트리밍 사용: 요청 본문에
"stream": true을 추가하십시오. 응답은 SSE 형식이며, 마지막에는 자동으로 usage 데이터 블록이 추가됩니다.
연동이 완료되면 다음 단계로 프롬프트 작성법을 확인하여 출력 품질을 조정하십시오. 오류가 발생하면 오류 코드 및 문제 해결 매뉴얼을 참조하십시오. 파라미터 전체 설명은 문서에서, 가격은 가격 페이지에서 확인하십시오.
연동이 완료되면 서비스 출시 전에 다음 세 가지를 보완하십시오.
튜토리얼의 예제는 최소한의 사용 가능한 버전입니다. 실제 서비스에 적용하려면 다음 세 가지 항목을 반드시 보완해야 합니다.
- 시간 초과: 예제에서는 긴 텍스트 생성 속도를 고려해 120초로 설정했습니다. 동기 대기 방식이라면 페이지 허용 시간 내에 단축하고 스트리밍을 함께 사용해 사용자가 먼저 결과를 볼 수 있게 하세요.
- 오류 분기 처리.401, 402, 403은 재시도해도 효과가 없는 오류이므로 경보를 발생하거나 사용자에게 알려야 합니다. 429과 503만 백오프 재시도가 적합합니다. 구체적인 구현 방법은 문제 해결 매뉴얼에 나와 있으며 여기서는 생략합니다.
- 사용량 기록.매번 응답의 usage를 로그에 한 줄로 기록하십시오. 숫자만 기록하고 사용자 내용은 로그에 기록하지 마십시오. 월말 정산 및 이상 사용량 확인에 필요합니다.
키 관리에 대해 한 가지 더 말씀드립니다. 키는 하나뿐이며 유출 시 재생성해야 합니다. 재생성 시 현재 사용 중인 모든 서비스가 동시에 중단됩니다. 따라서 키를 여러 스크립트와 여러 머신의 설정에 흩어지게 두지 마십시오. 키 설정을 중앙 집중화하여 교체 시 누락되지 않도록 하십시오.
마지막으로 콘텐츠 경계에 대해 설명합니다. 합법적인 성인 콘텐츠, 소설의 가상 설정, 논쟁적인 주제는 거부되지 않지만, 미성년자 관련 성 콘텐츠는 모두 차단되며 403 오류를 반환합니다. 가상 설정이나 역할극도 예외는 아닙니다. 귀하의 애플리케이션이 성인 사용자를 대상으로 한다면 등록 프로세스에 연령 확인 절차를 추가하는 것을 권장합니다.
마지막으로 자체 점검 순서를 제공합니다. 모니터 옆에 붙여두셔도 좋습니다: 키가 환경 변수에 있는지 확인, models 엔드포인트 연결 확인, 요청 본문이 유효한 JSON인지 확인, 모델이 uncensored인지 확인, max_tokens가 충분한지 확인, 응답의 finish_reason이 stop인지 length인지 확인, usage가 기록되었는지 확인. 일곱 항목 모두 정상일 때 연동이 완료된 것입니다.