Wu Xianzhi APIContoh Kode
Contoh API AI tanpa sensor: kode lengkap Python, Node.js, cURL
Panduan ini ditujukan untuk pengembang yang ingin menggunakan API AI tanpa sensor. Endpoint ini kompatibel dengan Chat Completions OpenAI, sehingga SDK openai yang Anda kenal hanya perlu mengubah dua baris konfigurasi agar dapat digunakan. Panduan ini membahas secara lengkap beberapa hal yang paling sering digunakan: permintaan dasar, streaming, pemanggilan fungsi, retry kesalahan, pengendalian biaya dengan max_tokens, serta cara mempertahankan konteks dalam percakapan multi-round. Semua kode dapat langsung disalin dan dijalankan, dengan kunci API yang dibaca dari variabel lingkungan.
Diperbarui pada
Poin Penting
- Ubah base_url ke https://api.wuxianzhiapi.com/v1,模型名写 uncensored; SDK openai tidak perlu perubahan lain
- Blok terakhir respons streaming adalah statistik penggunaan dengan choices kosong; periksa terlebih dahulu
- Lakukan retry eksponensial hanya untuk 429 dan 503; retry untuk 400/401/402/403 tidak bermakna
- API stateless; Anda harus mengirim ulang riwayat untuk multi-turn dan menggunakan max_tokens serta pemangkasan untuk mengontrol biaya
Informasi Dasar API dan Variabel Lingkungan
Ingat parameter tetap ini. Base URL: https://api.wuxianzhiapi.com/v1. Model: uncensored. Auth: Authorization: Bearer <key>. Endpoint: POST /v1/chat/completions, GET /v1/models. Format sama OpenAI. SDK openai hanya perlu base_url dan key.
Kunci API ditampilkan segera setelah Anda mendaftar di /get-api-key/. Cukup dengan email dan kata sandi. Akun baru mendapatkan kredit uji coba senilai $0.50 yang berlaku selama 7 hari tanpa perlu mengikat kartu kredit. Semua contoh dalam panduan ini membaca kunci API dari variabel lingkungan WUXIANZHI_API_KEY. Jangan menyimpan kunci API ke dalam repositori kode atau halaman frontend. Beberapa batasan perlu Anda ketahui: jendela konteks 100,000 token (total prompt dan output), ukuran badan permintaan tidak boleh melebihi 8 MB, dan batas laju 300 permintaan per menit per kunci API.
export WUXIANZHI_API_KEY="把你的密钥放这里"
# 确认连通性,应返回包含 uncensored 的模型列表
curl https://api.wuxianzhiapi.com/v1/models \
-H "Authorization: Bearer $WUXIANZHI_API_KEY"Jika langkah ini mengembalikan 401, periksa kunci atau variabel lingkungan. Lihat deskripsi parameter lengkap di dokumentasi API.
cURL: Permintaan Minimum yang Berfungsi
Terlepas dari bahasa pemrograman yang Anda gunakan, disarankan untuk menjalankan tes menggunakan cURL terlebih dahulu. Cara ini membantu memisahkan masalah jaringan, kunci API, dan format permintaan dari kode bisnis Anda. Berikut adalah contoh permintaan biasa yang menyertakan max_tokens. Isi respons JSON pada choices[0].message.content adalah teks balasan, sedangkan usage berisi jumlah token input dan output yang digunakan. Biaya dihitung berdasarkan kedua angka tersebut.
curl https://api.wuxianzhiapi.com/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $WUXIANZHI_API_KEY" \
-d '{
"model": "uncensored",
"messages": [
{"role": "system", "content": "你是一个直来直去的写作助手。"},
{"role": "user", "content": "用三句话描述一场暴雨前的小镇。"}
],
"max_tokens": 300
}'Perhatikan bahwa teks bahasa Mandarin dalam JSON tidak perlu di-escape secara manual. Selama header permintaan menyatakan kompatibilitas JSON UTF-8, teks tersebut dapat langsung disalin dan ditempelkan di sebagian besar terminal. Jika Anda melakukan debugging di PowerShell Windows, penanganan tanda kutip bisa menjadi rumit. Disarankan untuk menyimpan badan permintaan ke dalam file body.json, lalu mengirimkannya menggunakan -d @body.json.
Pemanggilan Lengkap Python dan Node.js
Untuk Python, gunakan paket resmi openai (versi 1 ke atas). Jalankan pip install openai terlebih dahulu. Saat membuat klien, masukkan base_url dan api_key. Cara pemanggilan selanjutnya sama persis dengan memanggil OpenAI. Skrip di bawah ini dapat langsung disimpan sebagai chat.py dan dijalankan.
import os
from openai import OpenAI
client = OpenAI(
base_url="https://api.wuxianzhiapi.com/v1",
api_key=os.environ["WUXIANZHI_API_KEY"],
)
resp = client.chat.completions.create(
model="uncensored",
messages=[
{"role": "system", "content": "你是一个直来直去的写作助手。"},
{"role": "user", "content": "用三句话描述一场暴雨前的小镇。"},
],
max_tokens=300,
)
print(resp.choices[0].message.content)
print("输入 tokens:", resp.usage.prompt_tokens, "输出 tokens:", resp.usage.completion_tokens)Pakai npm openai v4+. Install npm install openai. Gunakan await. Simpan sebagai chat.mjs atau set package.json "type": "module".
import OpenAI from "openai";
const client = new OpenAI({
baseURL: "https://api.wuxianzhiapi.com/v1",
apiKey: process.env.WUXIANZHI_API_KEY,
});
const resp = await client.chat.completions.create({
model: "uncensored",
messages: [
{ role: "system", content: "你是一个直来直去的写作助手。" },
{ role: "user", content: "用三句话描述一场暴雨前的小镇。" },
],
max_tokens: 300,
});
console.log(resp.choices[0].message.content);
console.log("用量:", resp.usage);Struktur sama. Ganti inisialisasi dan model ke uncensored. Lihat panduan migrasi.
Cara Membaca Output Streaming (SSE)
Saat menulis teks panjang atau membuat antarmuka obrolan, Anda harus menggunakan streaming. Jika tidak, pengguna harus menunggu hingga seluruh teks selesai digenerate sebelum melihat karakter pertama. Setelah Anda mengatur stream: true, server akan mengirimkan data secara bertahap menggunakan SSE (Server-Sent Events). Setiap bagian berupa satu baris data: {...}, dan diakhiri dengan data: [DONE]. SDK resmi telah menangani parsing untuk Anda; Anda hanya perlu melakukan iterasi pada data tersebut.
Ada satu detail yang mudah menjadi jebakan: pada akhir aliran streaming, akan muncul satu blok data tambahan yang berisi usage. Pada blok ini, choices adalah array kosong. Anda tidak perlu menambahkan parameter khusus untuk mengaktifkannya, namun dalam kode Anda tidak boleh langsung mengakses chunk.choices[0]. Anda harus memeriksa apakah array tersebut kosong terlebih dahulu, jika tidak, kesalahan indeks di luar batas akan terjadi saat aliran hampir berakhir.
import os
from openai import OpenAI
client = OpenAI(
base_url="https://api.wuxianzhiapi.com/v1",
api_key=os.environ["WUXIANZHI_API_KEY"],
)
stream = client.chat.completions.create(
model="uncensored",
messages=[{"role": "user", "content": "写一段 200 字左右的悬疑小说开头。"}],
max_tokens=600,
stream=True,
)
usage = None
for chunk in stream:
if chunk.usage: # 最后一块:用量统计
usage = chunk.usage
if not chunk.choices: # 用量块没有 choices
continue
delta = chunk.choices[0].delta.content
if delta:
print(delta, end="", flush=True)
print()
if usage:
print("输入", usage.prompt_tokens, "输出", usage.completion_tokens)import OpenAI from "openai";
const client = new OpenAI({
baseURL: "https://api.wuxianzhiapi.com/v1",
apiKey: process.env.WUXIANZHI_API_KEY,
});
const stream = await client.chat.completions.create({
model: "uncensored",
messages: [{ role: "user", content: "写一段 200 字左右的悬疑小说开头。" }],
max_tokens: 600,
stream: true,
});
let usage = null;
for await (const chunk of stream) {
if (chunk.usage) usage = chunk.usage;
const delta = chunk.choices?.[0]?.delta?.content;
if (delta) process.stdout.write(delta);
}
console.log("\n用量:", usage);Gunakan cURL dengan -N untuk melihat data mentah. Ini sangat berguna untuk debugging apakah proxy atau gateway menelan respons streaming.
curl -N https://api.wuxianzhiapi.com/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $WUXIANZHI_API_KEY" \
-d '{"model":"uncensored","stream":true,"max_tokens":100,
"messages":[{"role":"user","content":"数到五。"}]}'Jika menggunakan reverse proxy seperti Nginx, nonaktifkan buffering respons untuk jalur ini agar frontend menerima data secara bertahap, bukan sekaligus.
Function Calling: tools dan Mengirim Hasil Alat
Format OpenAI. Deklarasi di tools. Hasil di message.tool_calls. Eksekusi fungsi, kirim balik role: "tool".
tool_choice secara default adalah "auto", yang memungkinkan model memutuskan sendiri; saat Anda perlu memaksa pemanggilan fungsi tertentu, kirim {"type": "function", "function": {"name": "get_weather"}}; kirim "none" untuk melarang pemanggilan. Contoh di bawah ini menunjukkan alur lengkap: permintaan pertama mendapatkan tool_calls, Anda menjalankan fungsi lokal, lalu permintaan kedua menyertakan hasil alat.
import json, os
from openai import OpenAI
client = OpenAI(
base_url="https://api.wuxianzhiapi.com/v1",
api_key=os.environ["WUXIANZHI_API_KEY"],
)
def get_weather(city: str) -> dict:
# 这里用假数据代替真实的天气接口
return {"city": city, "temp_c": 18, "condition": "多云"}
tools = [{
"type": "function",
"function": {
"name": "get_weather",
"description": "查询指定城市的当前天气",
"parameters": {
"type": "object",
"properties": {"city": {"type": "string", "description": "城市名"}},
"required": ["city"],
},
},
}]
messages = [{"role": "user", "content": "杭州现在天气怎么样?"}]
first = client.chat.completions.create(
model="uncensored", messages=messages, tools=tools, tool_choice="auto", max_tokens=500
)
msg = first.choices[0].message
if msg.tool_calls:
messages.append(msg) # 必须把带 tool_calls 的 assistant 消息原样放回历史
for call in msg.tool_calls:
args = json.loads(call.function.arguments)
result = get_weather(**args)
messages.append({
"role": "tool",
"tool_call_id": call.id,
"content": json.dumps(result, ensure_ascii=False),
})
final = client.chat.completions.create(
model="uncensored", messages=messages, tools=tools, max_tokens=500
)
print(final.choices[0].message.content)
else:
print(msg.content)Tiga kesalahan umum: pertama, lupa memasukkan kembali pesan tool_calls dari role assistant ke dalam riwayat percakapan, lalu langsung menambahkan pesan tool, sehingga format permintaan menjadi tidak valid; kedua, tool_call_id tidak cocok; ketiga, parameter yang diberikan oleh model berupa string, sehingga harus diproses menggunakan json.loads terlebih dahulu. Pastikan Anda memiliki penanganan kesalahan jika parsing gagal, jangan langsung menyambungkan output model ke dalam perintah atau SQL.
import OpenAI from "openai";
const client = new OpenAI({
baseURL: "https://api.wuxianzhiapi.com/v1",
apiKey: process.env.WUXIANZHI_API_KEY,
});
const getWeather = (city) => ({ city, temp_c: 18, condition: "多云" });
const tools = [{
type: "function",
function: {
name: "get_weather",
description: "查询指定城市的当前天气",
parameters: {
type: "object",
properties: { city: { type: "string", description: "城市名" } },
required: ["city"],
},
},
}];
const messages = [{ role: "user", content: "杭州现在天气怎么样?" }];
const first = await client.chat.completions.create({
model: "uncensored", messages, tools, tool_choice: "auto", max_tokens: 500,
});
const msg = first.choices[0].message;
if (msg.tool_calls?.length) {
messages.push(msg);
for (const call of msg.tool_calls) {
const args = JSON.parse(call.function.arguments);
messages.push({
role: "tool",
tool_call_id: call.id,
content: JSON.stringify(getWeather(args.city)),
});
}
const final = await client.chat.completions.create({
model: "uncensored", messages, tools, max_tokens: 500,
});
console.log(final.choices[0].message.content);
} else {
console.log(msg.content);
}
Penanganan Error dan Retry: Eksponensial untuk 429, 503
Semua respons kesalahan adalah JSON terpadu: {"error":{"code":...,"message":...}}. Dalam program Anda, hanya ada dua jenis kesalahan yang perlu di-retry: 429 (melebihi batas 300 permintaan per menit) dan 503 (upstream_busy, model sedang sibuk sementara, coba lagi beberapa detik kemudian). Timeout koneksi lapisan jaringan juga layak untuk di-retry. Retry untuk kesalahan lain tidak ada gunanya: 400 berarti permintaan itu sendiri yang bermasalah (misalnya prompt ditambah max_tokens melebihi 100k), 401 berarti kunci API tidak valid, 402 no_credit berarti saldo habis atau kredit uji coba telah kedaluwarsa, dan 403 content_blocked berarti konten diblokir, sehingga mengirim ulang berapapun kali hasilnya akan tetap sama.
Strategi backoff menggunakan pertumbuhan eksponensial ditambah jitter acak: permintaan ke-1 menunggu sekitar 1 detik, ke-2 sekitar 2 detik, ke-3 sekitar 4 detik, dengan batas atas dan jumlah maksimum untuk mencegah beberapa tugas paralel melakukan percobaan ulang secara bersamaan, yang dapat memperburuk dampak batas laju. SDK resmi menyertakan max_retries, yang secara default melakukan beberapa percobaan ulang untuk status 429 dan 5xx; untuk skenario sederhana, Anda cukup meningkatkan nilainya; untuk logging, pemutusan sirkuit, atau waktu tunggu kustom, Anda perlu menulis loop sendiri.
import os, random, time
import openai
from openai import OpenAI
# max_retries=0:关闭 SDK 自带重试,完全由下面的函数控制
client = OpenAI(
base_url="https://api.wuxianzhiapi.com/v1",
api_key=os.environ["WUXIANZHI_API_KEY"],
max_retries=0,
timeout=60,
)
def chat_with_retry(messages, max_attempts=5, **kwargs):
for attempt in range(max_attempts):
try:
return client.chat.completions.create(
model="uncensored", messages=messages, **kwargs
)
except (openai.RateLimitError, openai.InternalServerError,
openai.APIConnectionError, openai.APITimeoutError) as e:
if attempt == max_attempts - 1:
raise
wait = min(30, 2 ** attempt) + random.uniform(0, 1)
print(f"{type(e).__name__},{wait:.1f} 秒后重试(第 {attempt + 1} 次)")
time.sleep(wait)
except openai.APIStatusError as e:
# 400 / 401 / 402 / 403 / 404:重试无效,直接交给上层处理
print("不可重试:", e.status_code, e.response.text)
raise
resp = chat_with_retry([{"role": "user", "content": "你好"}], max_tokens=100)
print(resp.choices[0].message.content)Di Node.js, Anda juga dapat langsung meningkatkan maxRetries, dan SDK akan menangani 429 dan 5xx sesuai strategi backoff. Untuk membedakan kesalahan, cukup periksa error.status.
import OpenAI from "openai";
const client = new OpenAI({
baseURL: "https://api.wuxianzhiapi.com/v1",
apiKey: process.env.WUXIANZHI_API_KEY,
maxRetries: 5,
timeout: 60_000,
});
try {
const resp = await client.chat.completions.create({
model: "uncensored",
messages: [{ role: "user", content: "你好" }],
max_tokens: 100,
});
console.log(resp.choices[0].message.content);
} catch (err) {
if (err instanceof OpenAI.APIError) {
if (err.status === 402) console.error("余额不足,请充值后再试");
else if (err.status === 403) console.error("内容被拦截:", err.message);
else console.error("请求失败:", err.status, err.message);
} else {
throw err;
}
}Jika streaming terputus, simpan data yang sudah diterima. Retry akan mulai dari awal dan membebani biaya lagi. Untuk teks panjang, gunakan permintaan bertahap.
Mengontrol Biaya dan Panjang dengan max_tokens
Biaya: input $0.25/juta token, output $1.00/juta token. Saldo prabayar, tidak ada biaya bulanan, saldo tidak akan expired. Output 4x lebih mahal. max_tokens default 2048, max 32,000. Set 200-300 untuk hemat biaya.
Hitung biayanya: satu permintaan dengan max_tokens diatur ke 1.000, biaya output terburuk adalah $0,001; diatur ke batas atas 32.000, biaya terburuk adalah $0,016. Saldo uji coba $0,50 setara dengan sekitar 500.000 token output, atau 2.000.000 token input, cukup untuk menjalankan semua contoh dalam artikel ini berkali-kali. Perhatikan bahwa jumlah prompt dan max_tokens tidak boleh melebihi 100.000, jika tidak akan langsung mengembalikan 400, jadi saat input sangat panjang, turunkan batas output secara bersamaan. Penjelasan harga lebih rinci terdapat di halaman harga.
Detail lainnya: jika respons terpotong, finish_reason dalam respons akan menjadi "length", yang menunjukkan bahwa max_tokens tidak mencukupi, bukan karena model telah selesai menulis. Saat menulis teks panjang, periksa bidang ini untuk memutuskan apakah akan melanjutkan penulisan.
Multi-turn: Menjaga Konteks Sendiri
API stateless; server tidak menyimpan permintaan sebelumnya. Kirim ulang riwayat lengkap secara berurutan: system, lalu user/assistant bergantian. Setiap turn menambah token input dan biaya. Biaya input per turn meningkat seiring percakapan berjalan.
Batas 100,000 token. Ringkas konten lama menjadi ringkasan singkat menggunakan satu permintaan, lalu masukkan ke system message untuk menghemat ruang.
import os
from openai import OpenAI
client = OpenAI(
base_url="https://api.wuxianzhiapi.com/v1",
api_key=os.environ["WUXIANZHI_API_KEY"],
)
class Chat:
def __init__(self, system: str, keep_last: int = 20):
self.system = {"role": "system", "content": system}
self.history = [] # 只存 user / assistant 消息
self.keep_last = keep_last
def say(self, text: str, max_tokens: int = 500) -> str:
self.history.append({"role": "user", "content": text})
recent = self.history[-self.keep_last:]
resp = client.chat.completions.create(
model="uncensored",
messages=[self.system] + recent,
max_tokens=max_tokens,
)
reply = resp.choices[0].message.content
self.history.append({"role": "assistant", "content": reply})
return reply
bot = Chat("你是一位说话简短的旅行顾问。")
print(bot.say("我想去云南玩五天,有什么建议?"))
print(bot.say("刚才说的第二个地方,适合带老人吗?")) # 能接上上一轮Gunakan usage.prompt_tokens sebagai referensi. Kompres history saat mendekati 50,000 token. Lihat aplikasi untuk contoh desain konteks.
Pertanyaan Umum
Mengapa blok data streaming terakhir tidak memiliki konten?
Itu adalah blok statistik penggunaan yang ditambahkan secara otomatis, dengan choices berupa array kosong dan usage berisi jumlah token. Saat membaca, periksa apakah choices kosong, lalu ambil delta; tidak perlu parameter tambahan untuk mengaktifkannya.
Apakah 429 dan 503 harus dicoba ulang? Berapa lama harus menunggu?
Keduanya layak dicoba ulang. 429 menandakan melebihi batas 300 per menit, sedangkan upstream_busy pada 503 menandakan model sedang sibuk sementara. Disarankan menggunakan backoff eksponensial dengan jitter acak, dimulai dari 1 detik, menetapkan jumlah maksimum percobaan, dan tidak mencoba ulang secara tak terbatas.
Bagaimana jika model tidak mengembalikan tool_calls saat pemanggilan fungsi?
Hal ini menunjukkan model menganggap tidak perlu memanggil fungsi, sehingga message.content adalah jawaban akhir. Jika pemanggilan fungsi wajib dilakukan, Anda dapat menetapkan tool_choice ke fungsi tertentu, serta memeriksa apakah deskripsi fungsi dan Skema parameternya ditulis dengan jelas.
Apakah percakapan multi-putaran akan semakin mahal?
Ya. Antarmuka bersifat stateless, sehingga riwayat harus dikirim ulang setiap kali, dan token input bertambah seiring jumlah putaran. Anda dapat mempertahankan hanya beberapa putaran terakhir, atau meringkas konten awal menjadi ringkasan, serta membatasi output menggunakan max_tokens.
Isi formulir untuk mendapatkan kunci API
Buat akun, salin kunci, ubah Base URL. Konfigurasinya sangat sederhana.
Dapatkan Kunci API