PT ▾
Obter chave de API

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

  1. Altere base_url para https://api.wuxianzhiapi.com/v1,模型名写 sem censura; o SDK openai oficial não precisa de outras alterações
  2. O último bloco de resposta em streaming contém estatísticas de uso; choices está vazio e deve ser verificado antes de ler
  3. Faça retry exponencial apenas para 429 e 503; retry para 400/401/402/403 não faz sentido
  4. 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