获取 API 密钥

无审查 API 接入教程:注册、验证、首次调用

这篇教程只做一件事:让你在十分钟内跑通第一次请求。不绕 SDK,直接用各语言的标准库发 HTTP,因为这里本质上只有一个 POST 接口,看清请求长什么样,以后换任何框架都不会慌。示例覆盖 Python 的 requests、Java 的 java.net.http、Go 的 net/http 和 PHP 的 curl,每段代码都能直接复制运行。

更新于

要点

  • 注册只要邮箱和密码,新账户有 $0.50 试用额度,7 天有效,无需绑定支付信息。
  • Base URL 是 https://api.wushenchaapi.com/v1,模型名固定写 uncensored,鉴权头是 Authorization: Bearer。
  • 先 GET /v1/models 验证 key,再 POST /v1/chat/completions,两步分开排查最快。
  • 四种语言都要设超时,并且读取 error.code 而不是只看 HTTP 状态码。

开工前的检查清单

先过一遍,省得半路回头。

  • 一个能收信的邮箱,用来注册。
  • 本机有任意一种运行环境:Python 3、JDK 15 及以上(示例用到文本块)、Go、或带 curl 扩展的 PHP。
  • 确认自己是 18 岁以上的成年人,服务只面向成年用户。
  • 知道自己要的是纯文本对话:这里只有一个模型,没有向量、图片、语音、微调。
  • 准备好用环境变量保存密钥,不要写进源码,更不要提交到仓库。

接口约定很少:地址 https://api.wushenchaapi.com/v1,格式与 OpenAI 的聊天补全兼容,所以你以前写过的请求体基本可以原样搬过来。

耗时预估:注册一分钟,装环境视你本机情况,第一次请求本身不超过三十秒。如果超过这个时间还没出结果,多半是网络或密钥问题,直接跳到文末的排错清单。顺序别乱:先 models,后 chat,先同步,后流式,每一步确认再往下走。

注册并拿到 key

打开 /get-api-key/,用邮箱加密码注册。注册完成后密钥立即显示,复制下来即可。几个细节:

  1. 每个账户只有一把 key。
  2. 可以重新生成,但旧 key 会立刻失效,线上服务换 key 前要先把新值部署好。
  3. 新账户送 $0.50 试用额度,7 天内有效,不需要填任何支付信息。
  4. 试用到期或用完后,请求会返回 402,错误码 no_credit,充值预付费余额即可继续用,不是订阅,余额不会过期。

把 key 放进环境变量:macOS / Linux 执行 export API_KEY=你的密钥,Windows PowerShell 用 $env:API_KEY="你的密钥"。后面所有示例都从 API_KEY 读取。

第一步:用 /v1/models 验证连通性

别急着发对话。先打一个零成本的 GET,确认地址、网络、key 三件事都没问题:

curl https://api.wushenchaapi.com/v1/models \
  -H "Authorization: Bearer $API_KEY"

返回 200 和模型列表(只有一个 uncensored)就说明通了。返回 401 是 key 有误或没带;超时则检查本机网络和代理。把连通性和请求体问题拆开,是接入阶段最省时间的习惯。

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 是本次的 token 用量。三处都读,才算接入完整。

另外两条硬限制记一下:请求体不超过 8 MB,每把 key 每分钟 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,是接口层问题,要读 error.code。

首次调用常见的坑

  • 401:Header 写成了 Authorization: 密钥,漏了 Bearer 前缀;或环境变量在新开的终端里没生效。
  • 404:路径少了 /v1,或把 chat/completions 拼错。
  • 400:JSON 不合法,或 prompt 加 max_tokens 超过 100,000 token 的上限。
  • 402:余额用完或试用过期。
  • 输出被截断:max_tokens 默认 2048,单次最大 16,000,写长文要显式调大。
  • 想要流式:请求体加 "stream": true,响应是 SSE,最后会自动追加一个带 usage 的数据块。

跑通之后,下一步看 Prompt 写法 调输出质量,遇到报错查 错误码排障手册。参数完整说明在 文档,价格见 价格页。

跑通之后,上线前补三样东西

教程里的示例是最小可用版本,真要放进服务里,至少补这三项。

  1. 超时。示例里统一给了 120 秒,因为长文本生成确实慢。如果你的业务是同步等待,就按页面容忍度缩短,并配合流式输出,用户能先看到字。
  2. 错误分流。401、402、403 属于重试也没用的错误,要报警或提示用户;429 和 503 才值得退避重试。具体写法放在排障手册里,这里不展开。
  3. 用量记录。每次响应的 usage 落一条日志,只记数字,不要把用户内容写进日志。月底对账、查异常消耗都靠它。

再提一句密钥管理:key 只有一把,泄露后只能重新生成,而重新生成会让所有在用的服务同时掉线。所以别把它散落在多个脚本和多台机器的配置里,集中放在一个密钥配置处,换起来才不会漏。

最后是内容边界:合法的成人向内容、小说虚构和有争议的话题不会被拒绝,但涉及未成年人的性内容一律拦截,返回 403,虚构和角色扮演也不例外。你的应用面向成年用户时,建议在自己的注册流程里也做年龄确认。

最后给一个自检顺序,贴在显示器边上也行:密钥在不在环境变量里;models 通不通;请求体是不是合法 JSON;model 是不是 uncensored;max_tokens 够不够;响应里 finish_reason 是 stop 还是 length;usage 有没有记录。七项全绿,接入就算完成。

常见问题

必须用官方 SDK 才能调用吗?

不需要。它就是标准的 HTTPS POST 加 JSON,任何能发 HTTP 请求的语言都行,SDK 只是帮你包了一层。

model 字段该填什么?

固定填 uncensored。目前只有这一个模型,可以用 GET /v1/models 确认。

试用额度用完后会怎样?

请求返回 402,错误码 no_credit。充值预付费余额后即可继续使用,余额不会过期,也没有订阅。

重新生成 key 会影响旧 key 吗?

会。旧 key 立即失效,所以要先在服务里换上新 key 再点重新生成,或接受短暂中断。

只需填写表单即可获取密钥

创建账户,复制密钥,修改 Base URL。配置就是这么简单。