开工前的检查清单
先过一遍,省得半路回头。
- 一个能收信的邮箱,用来注册。
- 本机有任意一种运行环境:Python 3、JDK 15 及以上(示例用到文本块)、Go、或带 curl 扩展的 PHP。
- 确认自己是 18 岁以上的成年人,服务只面向成年用户。
- 知道自己要的是纯文本对话:这里只有一个模型,没有向量、图片、语音、微调。
- 准备好用环境变量保存密钥,不要写进源码,更不要提交到仓库。
接口约定很少:地址 https://api.wushenchaapi.com/v1,格式与 OpenAI 的聊天补全兼容,所以你以前写过的请求体基本可以原样搬过来。
耗时预估:注册一分钟,装环境视你本机情况,第一次请求本身不超过三十秒。如果超过这个时间还没出结果,多半是网络或密钥问题,直接跳到文末的排错清单。顺序别乱:先 models,后 chat,先同步,后流式,每一步确认再往下走。
注册并拿到 key
打开 /get-api-key/,用邮箱加密码注册。注册完成后密钥立即显示,复制下来即可。几个细节:
- 每个账户只有一把 key。
- 可以重新生成,但旧 key 会立刻失效,线上服务换 key 前要先把新值部署好。
- 新账户送 $0.50 试用额度,7 天内有效,不需要填任何支付信息。
- 试用到期或用完后,请求会返回 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 写法 调输出质量,遇到报错查 错误码排障手册。参数完整说明在 文档,价格见 价格页。
跑通之后,上线前补三样东西
教程里的示例是最小可用版本,真要放进服务里,至少补这三项。
- 超时。示例里统一给了 120 秒,因为长文本生成确实慢。如果你的业务是同步等待,就按页面容忍度缩短,并配合流式输出,用户能先看到字。
- 错误分流。401、402、403 属于重试也没用的错误,要报警或提示用户;429 和 503 才值得退避重试。具体写法放在排障手册里,这里不展开。
- 用量记录。每次响应的 usage 落一条日志,只记数字,不要把用户内容写进日志。月底对账、查异常消耗都靠它。
再提一句密钥管理:key 只有一把,泄露后只能重新生成,而重新生成会让所有在用的服务同时掉线。所以别把它散落在多个脚本和多台机器的配置里,集中放在一个密钥配置处,换起来才不会漏。
最后是内容边界:合法的成人向内容、小说虚构和有争议的话题不会被拒绝,但涉及未成年人的性内容一律拦截,返回 403,虚构和角色扮演也不例外。你的应用面向成年用户时,建议在自己的注册流程里也做年龄确认。
最后给一个自检顺序,贴在显示器边上也行:密钥在不在环境变量里;models 通不通;请求体是不是合法 JSON;model 是不是 uncensored;max_tokens 够不够;响应里 finish_reason 是 stop 还是 length;usage 有没有记录。七项全绿,接入就算完成。