Wu Xianzhi APIExemplos de código
Código completo de exemplos de chamada de API de IA sem censura: Python, Node.js e cURL
Este é um guia de chamada de API de IA sem censura para desenvolvedores. A interface é compatível com OpenAI Chat Completions; o SDK openai oficial funciona com apenas duas linhas de configuração alteradas. Aqui estão os usos mais comuns: requisições básicas, streaming, chamada de funções, retry de erros, controle de custo com max_tokens e manutenção de contexto em conversas multi-turno. Todo o código pode ser copiado e executado diretamente, lendo a chave de API de variáveis de ambiente.
Atualizado em
Pontos principais
- Altere base_url para https://api.wuxianzhiapi.com/v1,模型名写 sem censura; o SDK openai oficial não precisa de outras alterações
- O último bloco de resposta em streaming contém estatísticas de uso; choices está vazio e deve ser verificado antes de ler
- Faça retry exponencial apenas para 429 e 503; retry para 400/401/402/403 não faz sentido
- A interface é sem estado; em conversas multi-turno, você deve reenviar o histórico e usar max_tokens e corte para controlar custos
Informações básicas da interface e variáveis de ambiente
Memorize os parâmetros fixos, pois todos os exemplos os usarão. O Base URL é https://api.wuxianzhiapi.com/v1, o nome do modelo é fixo em uncensored e a autenticação usa o cabeçalho Authorization: Bearer <chave>. Há apenas dois endpoints: POST /v1/chat/completions para conversas e GET /v1/models para verificar disponibilidade. O formato de requisição e resposta é idêntico ao da OpenAI, então o SDK oficial openai só precisa de alteração no base_url e na chave; o código de negócio permanece inalterado.
A chave é exibida imediatamente após o registro em /get-api-key/, usando apenas e-mail e senha. Novas contas recebem $0,50 de crédito de teste válido por 7 dias, sem necessidade de cartão. Todos os exemplos leem a chave da variável de ambiente WUXIANZHI_API_KEY; não a salve no repositório nem a exponha no front-end. Limites: janela de contexto de 100.000 tokens (entrada + saída), corpo da requisição até 8 MB e limite de 300 requisições por minuto por chave.
export WUXIANZHI_API_KEY="把你的密钥放这里"
# 确认连通性,应返回包含 uncensored 的模型列表
curl https://api.wuxianzhiapi.com/v1/models \
-H "Authorization: Bearer $WUXIANZHI_API_KEY"Se retornar 401, a chave está errada ou a variável de ambiente não carregou; resolva isso antes de continuar. A documentação completa dos parâmetros está em documentação.
cURL: requisição mínima funcional
Recomendamos testar com cURL primeiro para isolar problemas de rede, chave ou formato do corpo da requisição do seu código. O exemplo abaixo usa max_tokens. O JSON retornado contém o texto em choices[0].message.content e o consumo em usage; a cobrança é calculada com base nesses dois números.
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
}'Não é necessário escapar manualmente o JSON em chinês; basta declarar JSON compatível com UTF-8 no cabeçalho, e a maioria dos terminais permite colar diretamente. No PowerShell do Windows, use um arquivo body.json com o corpo e envie via -d @body.json para evitar problemas com aspas.
Chamadas completas em Python e Node.js
Para Python, use o pacote oficial openai (v1+). Execute pip install openai. Ao criar o cliente, passe base_url e api_key. As chamadas subsequentes são idênticas às da OpenAI. O script abaixo pode ser salvo como chat.py e executado diretamente.
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)Use o pacote npm openai (v4+). Instale com npm install openai. Use await no topo do arquivo; salve como chat.mjs ou defina "type": "module" em package.json.
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);As estruturas são idênticas; a diferença é apenas sintática. Se seu projeto já usa chamadas OpenAI, geralmente basta alterar as linhas de inicialização do cliente e definir o modelo como uncensored. Veja o guia de migração para migrações completas.
Como ler streaming (SSE)
Para textos longos ou interfaces de chat, use streaming para não fazer o usuário esperar. Com stream: true, o servidor envia blocos via SSE (Server-Sent Events), cada um como uma linha data: {...}, terminando com data: [DONE]. O SDK já faz o parse; basta iterar.
Atenção: o último bloco do stream contém um bloco usage com choices vazio. Você não precisa passar parâmetros extras para habilitar isso, mas não acesse chunk.choices[0] diretamente; verifique se não está vazio para evitar erro de índice fora dos limites no final do stream.
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);Para ver o raw SSE, use cURL com -N para desativar o buffer. Isso imprime cada bloco imediatamente, sendo útil para depurar se o proxy ou gateway está consumindo a resposta em 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":"数到五。"}]}'Se você estiver encaminhando respostas em streaming atrás de um proxy reverso como Nginx, desative o buffer de resposta para essa rota; caso contrário, o front-end receberá tudo de uma vez, não caractere por caractere.
Chamada de funções: tools e retorno de resultados
O formato segue o padrão OpenAI: declare funções com tools (nome, descrição, JSON Schema). Quando o modelo decide chamar, ele retorna o nome e os parâmetros em JSON dentro de message.tool_calls. Execute a função localmente e envie o resultado como mensagem role: "tool". O modelo só gera a resposta final com base no resultado.
tool_choice padrão é "auto", decidido pelo modelo. Para forçar, passe {"type": "function", "function": {"name": "get_weather"}}; passe "none" para proibir. Exemplo completo: 1ª requisição retorna tool_calls, executa localmente, 2ª requisição envia o resultado.
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)Erros comuns: 1) Não reenviar a mensagem de tool_calls do assistant, tornando a requisição inválida. 2) tool_call_id incorreto. 3) Os parâmetros são strings; use json.loads e trate erros. Não concatene a saída diretamente em comandos ou SQL. O fluxo Node.js é idêntico:
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);
}
Tratamento de erros e retry: como lidar com 429 e 503
As respostas de erro são sempre JSON padronizado: {"error":{"code":...,"message":...}}. No código, você só precisa tentar novamente em dois casos: 429 (limite de 300 requisições por minuto) e 503 (upstream_busy, modelo ocupado, tente novamente em alguns segundos). O tempo limite de conexão da camada de rede também vale a pena tentar novamente. Retentar outros erros não faz sentido: 400 indica problema na própria requisição (como prompt com max_tokens acima de 100k), 401 indica chave inválida, 402 no_credit indica saldo esgotado ou teste expirado, 403 content_blocked indica conteúdo bloqueado; enviar de novo cem vezes trará o mesmo resultado.
A estratégia de backoff usa crescimento exponencial com jitter: aguarde cerca de 1 segundo na 1ª tentativa, 2 segundos na 2ª, 4 segundos na 3ª, defina um limite máximo e um número máximo de tentativas para evitar que várias tarefas em paralelo tentem novamente ao mesmo tempo, o que piora o limite de requisições. O SDK oficial inclui max_retries, que faz algumas tentativas automáticas para 429 e 5xx; para cenários simples, basta aumentar esse valor. Para logs, circuit breaker ou tempos de espera personalizados, escreva seu próprio loop.
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)No Node.js, aumente maxRetries diretamente; o SDK trata o backoff para 429 e 5xx. Use error.status para distinguir erros.
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;
}
}Aviso: se uma requisição em streaming for interrompida, conserve os dados já recebidos. O retry regenera do início e cobra novamente; para textos longos, prefira requisições segmentadas em vez de uma única grande.
Controle de custo e tamanho com max_tokens
Preços: entrada $0,25 / 1M tokens, saída $1,00 / 1M tokens. Saldo pré-pago sem mensalidade, nunca expira. Como o preço de saída é 4x maior, a economia real está na saída. O max_tokens padrão é 2048 (máx 32.000). Para respostas curtas, defina 200-300 para evitar verbosidade e limitar custos.
Calcule: definir max_tokens para 1.000 em uma requisição resulta em custo máximo de $0,001; definir até o limite de 32.000 resulta em custo máximo de $0,016. O crédito de teste grátis de $0,50 equivale a cerca de 500.000 tokens de saída ou 2 milhões de tokens de entrada, suficiente para executar os exemplos deste artigo várias vezes. Lembre-se de que a soma do prompt com max_tokens não pode exceder 100.000, caso contrário o retorno será 400; portanto, reduza o limite de saída quando o input for longo. Para detalhes sobre preços, consulte a página de preços.
Se a resposta for truncada, finish_reason será "length", indicando que o max_tokens acabou, e não que o modelo terminou. Verifique esse campo para decidir se deve continuar a escrita.
Conversas multi-turno: mantendo o contexto
A interface é sem estado; o servidor não retém a requisição anterior. Para continuar a conversa, reenvie todo o histórico de mensagens na ordem: system, depois user e assistant alternados. Isso significa que cada turno adicional aumenta os tokens de entrada, acumulando custo. A cada rodada, o custo de entrada é maior que o anterior.
O limite de contexto é 100.000 tokens (incluindo a saída). Para conversas longas, faça poda. A forma mais simples é manter a mensagem system e as últimas rodadas. Para casos mais complexos, resuma o conteúdo antigo em uma única requisição e insira no system. A classe abaixo implementa essa lógica.
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("刚才说的第二个地方,适合带老人吗?")) # 能接上上一轮Podar por número de mensagens é simples, mas impreciso devido ao tamanho variável. Para controle rigoroso, use usage.prompt_tokens como métrica: comprima o histórico ao atingir 50.000 tokens. Para criar produtos de conversa de longo prazo, consulte os exemplos de design de contexto em cenários de uso.
Perguntas frequentes
Por que o último bloco de dados em streaming não tem conteúdo?
É um bloco de estatísticas de uso adicionado automaticamente, com choices como array vazio e usage contendo o número de tokens. Ao ler, verifique primeiro se choices está vazio e, em seguida, obtenha delta; não é necessário passar parâmetros extras para ativar.
Devo tentar novamente para 429 e 503? Por quanto tempo devo esperar?
Ambos merecem nova tentativa. 429 indica ter excedido o limite de 300 requisições por minuto; 503 com upstream_busy indica que o modelo está temporariamente ocupado. Recomenda-se backoff exponencial com jitter aleatório, começando em 1 segundo, definindo um número máximo de tentativas e evitando tentativas infinitas.
O que fazer quando o modelo não retorna tool_calls durante a chamada de funções?
Isso indica que o modelo considera desnecessária a chamada. Nesse caso, message.content é a resposta final. Se a chamada for obrigatória, defina tool_choice para uma função específica e verifique se a descrição da função e o Schema de parâmetros estão claros.
Conversas em múltiplas rodadas ficarão mais caras?
Sim. A API é sem estado, exigindo o reenvio do histórico a cada vez, e os tokens de entrada se acumulam conforme o número de rodadas. Você pode manter apenas as últimas algumas rodadas ou comprimir o conteúdo antigo em um resumo, limitando a saída com max_tokens.
Preencha o formulário para obter sua chave
Crie uma conta, copie a chave e altere o Base URL. A configuração é simples assim.
Obter chave de API