中文 ▾
https://api.unrestrictedaiapi.com/v1uncensored2026-10-06
获取 API 密钥

Unrestricted AI API 快速入门:Python、JavaScript、Go、PHP 和 Ruby

使用 Unrestricted AI API 不需要 SDK。它使用标准的 HTTP 和 JSON,因此任何带有 HTTP 客户端的语言都可以使用。本页面为 Python、JavaScript、Go、PHP 和 Ruby 各提供一个经过测试的请求示例,以及需要处理的 HTTP 状态码和防止脚本崩溃的重试规则。

更新于

关键点

  1. 一个接口,一个模型 ID(无审查),一个 Bearer 令牌:相同的请求体适用于所有语言。
  2. 设置明确的超时时间。长时间的生成过程可能会超过大多数默认客户端的超时时间。
  3. 在解析之前检查状态码;402 和 403 的响应体是有效的 JSON,但不包含 choices 数组。
  4. 仅重试 429 和 503,并使用短暂的指数退避策略。

一个 curl 搞定整个 API

先忘掉 SDK。下面的每个示例都发送相同的内容:向 POST /v1/chat/completions 发送 JSON 主体和 Bearer 令牌。如果你能发送这个,你就完成了。从 注册页面获取密钥(试用额度无需支付信息),将其导出为 API_KEY,然后运行此代码。

curl https://api.unrestrictedaiapi.com/v1/chat/completions \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "uncensored",
    "messages": [{"role": "user", "content": "Write a two-line noir opening set in a laundromat."}],
    "max_tokens": 120
  }'

响应是一个 OpenAI 风格的对象。文本位于 choices[0].message.content,usage 块会告诉你该调用消耗的 token 数量。只有一个模型 uncensored,因此 model 字段不会改变。你可以通过 GET /v1/models 进行确认。

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

在编写任何代码之前,有两个限制值得记住:上下文窗口为 100,000 个 token,提示词和补全内容共享该窗口;max_tokens 默认为 2048,除非你将其调高(最高至 32,000)。如果你的输出总是在句子中间停止,这个默认值通常是罪魁祸首。

Python 使用 httpx

httpx 提供具有合理超时设置的同步客户端,以及你需要的异步版本。显式设置超时。长生成可能需要一段时间,默认的 5 秒超时会将其截断。

import os
import httpx

resp = httpx.post(
    "https://api.unrestrictedaiapi.com/v1/chat/completions",
    headers={"Authorization": f"Bearer {os.environ['API_KEY']}"},
    json={
        "model": "uncensored",
        "messages": [
            {"role": "system", "content": "You are a blunt, vivid fiction writer."},
            {"role": "user", "content": "Pitch a heist where the vault is a night market."},
        ],
        "temperature": 0.9,
        "max_tokens": 300,
    },
    timeout=60.0,
)
resp.raise_for_status()
print(resp.json()["choices"][0]["message"]["content"])

raise_for_status() 将任何 4xx 或 5xx 状态码转换为异常,这对于脚本来说没问题。对于任何长时间运行的任务,请包装调用,以便让两个状态码获得重试机会:429(你达到了每个密钥每分钟 300 次请求的限制)和 503(upstream_busy,几秒后会自动恢复)。其他所有状态码,包括 401、402 和 403,在重试时不会自动修复。

import os
import time
import httpx

def chat(messages, retries=3):
    for attempt in range(retries + 1):
        r = httpx.post(
            "https://api.unrestrictedaiapi.com/v1/chat/completions",
            headers={"Authorization": f"Bearer {os.environ['API_KEY']}"},
            json={"model": "uncensored", "messages": messages, "max_tokens": 400},
            timeout=60.0,
        )
        if r.status_code in (429, 503) and attempt < retries:
            time.sleep(2 ** attempt)
            continue
        r.raise_for_status()
        return r.json()["choices"][0]["message"]["content"]

print(chat([{"role": "user", "content": "Name five cursed objects found in a thrift store."}]))

在 async def 中将 httpx.post 替换为 httpx.AsyncClient().post,即可得到具有相同负载的异步版本。

JavaScript 使用 fetch

Node 18 及更高版本内置了 fetch,无需安装。将文件保存为 .mjs(或设置 "type": "module")以支持顶层 await。浏览器也提供相同的 API,但请勿将密钥放在前端代码中。请通过你自己的后端代理该请求。

const res = await fetch("https://api.unrestrictedaiapi.com/v1/chat/completions", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    model: "uncensored",
    messages: [{ role: "user", content: "Describe a villain's morning routine in four bullets." }],
    max_tokens: 250,
  }),
});

if (!res.ok) {
  const err = await res.json().catch(() => ({}));
  throw new Error(`HTTP ${res.status}: ${err?.error?.message ?? "unknown error"}`);
}

const data = await res.json();
console.log(data.choices[0].message.content);

注意检查顺序。fetch 仅在网络失败时拒绝,因此 402 或 403 会作为正常响应到达。自行测试 res.ok 并读取错误 JSON,其结构始终为 {"error":{"code":...,"message":...}}。

Go 使用 net/http

Go 需要更多的代码行,但无需依赖项。仅定义你读取的结构体字段;encoding/json 会忽略其余部分。在检查状态之前将正文读取为字节,以便在出错时打印服务器的错误消息。

package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"os"
)

type reply struct {
	Choices []struct {
		Message struct {
			Content string `json:"content"`
		} `json:"message"`
	} `json:"choices"`
}

func main() {
	payload, _ := json.Marshal(map[string]any{
		"model": "uncensored",
		"messages": []map[string]string{
			{"role": "user", "content": "Give me a ghost story in exactly three sentences."},
		},
		"max_tokens": 200,
	})

	req, _ := http.NewRequest("POST", "https://api.unrestrictedaiapi.com/v1/chat/completions", bytes.NewReader(payload))
	req.Header.Set("Authorization", "Bearer "+os.Getenv("API_KEY"))
	req.Header.Set("Content-Type", "application/json")

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()

	body, _ := io.ReadAll(resp.Body)
	if resp.StatusCode != http.StatusOK {
		panic(fmt.Sprintf("HTTP %d: %s", resp.StatusCode, body))
	}

	var out reply
	if err := json.Unmarshal(body, &out); err != nil {
		panic(err)
	}
	fmt.Println(out.Choices[0].Message.Content)
}

对于生产环境,构建一个 http.Client{Timeout: 60 * time.Second} 并重复使用它。默认客户端没有任何超时,这就是卡住的请求变成卡住的 goroutine 的原因。

PHP 使用 cURL 和 Ruby 使用 Net::HTTP

PHP 的 cURL 扩展已在大多数主机上启用。使用 json_encode 构建请求体,将传输作为字符串返回,然后使用 curl_getinfo 读取状态。跳过状态检查是经典错误:402 响应体可以顺利解码为 JSON,然后你的代码会因缺少 choices 键而失败。

<?php
$payload = json_encode([
    "model" => "uncensored",
    "messages" => [
        ["role" => "user", "content" => "Write a villanelle opening about a broken vending machine."],
    ],
    "max_tokens" => 200,
]);

$ch = curl_init("https://api.unrestrictedaiapi.com/v1/chat/completions");
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 60,
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer " . getenv("API_KEY"),
        "Content-Type: application/json",
    ],
    CURLOPT_POSTFIELDS => $payload,
]);

$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if ($body === false || $status !== 200) {
    fwrite(STDERR, "HTTP $status: $body\n");
    exit(1);
}

$data = json_decode($body, true);
echo $data["choices"][0]["message"]["content"], "\n";

在具有低 max_execution_time 的共享主机上,保持 max_tokens 适中,或将调用移至队列工作者。

标准库也足够了。ENV.fetch 如果变量缺失会立即抛出异常,这比发送空的 Bearer 令牌并调试 10 分钟的 401 错误要好得多。

require "net/http"
require "json"
require "uri"

uri = URI("https://api.unrestrictedaiapi.com/v1/chat/completions")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer #{ENV.fetch('API_KEY')}"
req["Content-Type"] = "application/json"
req.body = JSON.generate(
  model: "uncensored",
  messages: [{ role: "user", content: "Invent a tavern rumor that sounds too specific to be fake." }],
  max_tokens: 200
)

res = Net::HTTP.start(uri.host, uri.port, use_ssl: true, read_timeout: 60) { |http| http.request(req) }
abort("HTTP #{res.code}: #{res.body}") unless res.is_a?(Net::HTTPSuccess)

puts JSON.parse(res.body).dig("choices", 0, "message", "content")

如果你后来迁移到 Rails,相同的请求体也适用于后台作业。将调用保持在请求周期之外;生成过程比数据库查询慢。

这两个代码片段发送的正文与 Python 代码发送的完全相同,这正是重点:如果一种语言有效而另一种无效,请比较 JSON 而不是客户端。打印一次原始请求正文并按字节进行比较。十有八九的原因是缺少 Content-Type 标头或模型名称输入时使用了大写字母。

无库流式输出

流式输出是纯 HTTP 需要你多做一点的地方。使用 stream: true,服务器通过服务器发送事件(SSE)响应:每行以 data: 开头,携带一个 JSON 块,流以 data: [DONE] 结束。会自动添加最终的 usage 块,因此即使进行流式输出也能获得 token 计数。该块没有 choices 条目,这就是下面的循环在索引之前进行检查的原因。

import json
import os
import httpx

body = {
    "model": "uncensored",
    "messages": [{"role": "user", "content": "Tell a campfire story about a lighthouse keeper."}],
    "stream": True,
    "max_tokens": 400,
}
headers = {"Authorization": f"Bearer {os.environ['API_KEY']}"}

with httpx.stream("POST", "https://api.unrestrictedaiapi.com/v1/chat/completions",
                  headers=headers, json=body, timeout=60.0) as r:
    r.raise_for_status()
    for line in r.iter_lines():
        if not line.startswith("data: "):
            continue
        data = line[6:]
        if data == "[DONE]":
            break
        chunk = json.loads(data)
        if chunk.get("choices"):
            print(chunk["choices"][0]["delta"].get("content") or "", end="", flush=True)
print()

相同模式可直接移植。在 JavaScript 中,使用读取器读取 res.body 并按换行符分割。在 Go 中,将 resp.Body 包装在 bufio.Scanner 中。在 Ruby 中,向 http.request 传递一个块并使用 read_body。在 PHP 中,设置一个 CURLOPT_WRITEFUNCTION 回调。逻辑永远不会改变:剥离前缀,在哨兵处停止,解析 JSON,打印差异。

五分钟冒烟测试与预算检查

在任何这些代码片段之上构建之前,先运行一次快速检查。首先,使用你的密钥调用 /v1/models;200 状态码证明密钥和网络路径有效。其次,发送你能发送的最小聊天请求,并将 max_tokens 设置为 20。第三,故意破坏某些内容,例如空的 Bearer 令牌,并确认你的代码清晰地显示 401 错误,而不是因缺少字段而崩溃。

然后做一次算术计算,以免出现意外。价格为每百万输入 token 0.25 美元,每百万输出 token 1.00 美元。作为说明性假设,假设一个请求发送 600 个提示词 token 并接收 400 个 token。即 600 x $0.25 / 1,000,000 = $0.00015 输入,加上 400 x $1.00 / 1,000,000 = $0.0004 输出,每次调用约 $0.00055。0.50 美元的免费试用额度大约可以覆盖 900 次该规模的调用。你的实际提示词会有所不同,因此请读取一些响应中的 usage 块并据此进行计算。

试用额度有效期为七天,无需提供支付信息,足以测试所有五种语言。如果你需要一个用例作为目标,NSFW 内容指南 提供了一个完整的示例。请记住,一个密钥对应一个账户;如果重新生成密钥,请同时更新所有脚本,因为旧密钥会立即失效。

所有语言中相同的错误

由于 API 是纯 HTTP,无论你选择哪种语言,故障处理都是相同的。记住这个表,你就可以移植上面的任何代码片段。

状态含义操作
400请求错误,例如提示词加 max_tokens 超过 10 万缩短提示词或降低 max_tokens
401密钥缺失或无效检查 API_KEY;重新生成的密钥会立即使旧密钥失效
402no_credit:余额已耗尽或试用已过期为预付额度充值
403content_blocked不要重试;涉及未成年人的色情内容始终会被拦截
429每分钟超过 300 次请求退避并重试
503upstream_busy等待几秒后重试

基础功能就绪后,设置 stream: true 以实现逐 token 流式输出,并逐行读取服务器发送的事件。使用 提示词指南 优化提示词,或通过 机器人指南 将调用接入聊天平台。费率详见 定价页面。

问答

调用此 API 需要 OpenAI SDK 吗?

不是。这里的示例仅使用每种语言的标准 HTTP 工具。如果你将 OpenAI SDK 的基础 URL 指向 https://api.unrestrictedaiapi.com/v1.,它们也能正常工作。

我应该发送哪个模型 ID?

始终使用 "uncensored"。只有一个模型,可通过 GET /v1/models 列出。

为什么我的响应在句子中间停止?

默认的 max_tokens 为 2048。您可以按请求提高该值,最高可达 32,000,只要提示词加补全内容的 token 总数不超过 100,000-token 上下文窗口即可。

我的代码应该重试哪些错误?

在短暂延迟后重试 429(速率限制)和 503(upstream_busy)。400、401、402 和 403 错误需要您在客户端进行更改,重试这些错误会浪费请求。

只差一张表单,即可获得密钥

创建账户,复制密钥,更改 Base URL。这就是全部设置。

获取 API 密钥