中文 ▾
立即开始

ChatGPT 无审查 API:流式输出、工具与 JSON

ChatGPT 无审查 API 只有在支持真实应用所需功能时才有用:流式文本、工具调用和结构化输出。该接口支持这三项,并采用 OpenAI 格式。下面是每项功能的可用代码,以及不支持功能的清晰列表。

最后更新于

传送带上光粒子流,机械臂拾取结构化块,用于流式工具与 JSON

总结

  1. 支持:SSE 流式输出、带流式 tool_calls 的工具调用、JSON 模式以及常规采样设置。
  2. 不支持:图像、音频或视频生成、嵌入、微调。
  3. 流式连接会占用并发槽位直到结束:付费密钥占用 8 个槽位,试用密钥占用 2 个。
  4. 请防御性地解析工具参数和 JSON 回复;模型可能返回格式错误的输出。

支持与不支持的功能

项目状态备注
聊天补全是POST /v1/chat/completions
响应是POST /v1/responses
流式输出 (SSE)是stream: true,末尾包含使用情况
函数调用是tools、tool_choice、流式输出 tool_calls、结果以 role: "tool" 形式返回
JSON 模式是response_format: {"type":"json_object"}
采样控制是temperature、top_p、stop、seed、penalties
图像、音频、视频否仅文本
嵌入、微调否不提供

该模型是一个开放权重文本模型,ID 为 uncensored,由独立提供商运营。它针对合法成人用途提供无内容拒绝的回答,并非 OpenAI 或其他供应商的官方 API。以下所有示例均使用基础 URL https://api.chatgptunfiltered.com/v1。

列表中未提及的功能应视为不可用,除非 文档另有说明。这包括供应商特定的托管工具,它们与下面展示的函数调用不同。

流式输出

设置 stream: true 并遍历分片。在文本分片到达时打印它们,并从最后一个分片中读取使用情况。

from openai import OpenAI

client = OpenAI(
    base_url="https://api.chatgptunfiltered.com/v1",
    api_key="YOUR_KEY",
)

stream = client.chat.completions.create(
    model="uncensored",
    messages=[{"role": "user", "content": "Write a four-line poem about a night train."}],
    stream=True,
)

for chunk in stream:
    if chunk.choices and chunk.choices[0].delta.content:
        print(chunk.choices[0].delta.content, end="", flush=True)
    if chunk.usage:
        print("\nusage:", chunk.usage)

记住两点。首先,流式请求会占用并发槽位直到流结束,因此废弃的流会占用槽位;用户离开时请关闭它。其次,最后一个分片可能包含使用情况但没有文本,因此请像上面那样保护对 choices 的访问。

在 Web 应用中,将分片转发到浏览器,例如通过你自己的 SSE 路由,并让页面将每个文本片段追加到消息中。在流关闭后在服务器上进行使用情况记账,此时最后一个分片会告诉你请求的成本。

端到端工具调用

声明一个函数,让模型请求调用它,你自己运行它,然后通过 role: "tool" 发送结果。

import json

tools = [{
    "type": "function",
    "function": {
        "name": "get_order_status",
        "description": "Look up the status of an order by its ID.",
        "parameters": {
            "type": "object",
            "properties": {"order_id": {"type": "string"}},
            "required": ["order_id"],
        },
    },
}]

def get_order_status(order_id):
    return {"order_id": order_id, "status": "shipped"}

messages = [{"role": "user", "content": "Where is order A-1042?"}]
r = client.chat.completions.create(
    model="uncensored", messages=messages, tools=tools, tool_choice="auto"
)
msg = r.choices[0].message

if msg.tool_calls:
    messages.append(msg.model_dump(exclude_none=True))
    for call in msg.tool_calls:
        args = json.loads(call.function.arguments)
        result = get_order_status(**args)
        messages.append({
            "role": "tool",
            "tool_call_id": call.id,
            "content": json.dumps(result),
        })
    final = client.chat.completions.create(model="uncensored", messages=messages, tools=tools)
    print(final.choices[0].message.content)
else:
    print(msg.content)

模型决定是否调用函数;tool_choice 让你可以控制这一点。函数本身在你的代码中运行,而不是在服务器上,因此你控制它可以访问的资源。在执行操作之前验证参数,因为模型可能会发送错误的类型或缺失字段。

流式工具调用

当您将 stream: true 与 tools 结合使用时,调用会分片到达。函数名最先到达,参数字符串以片段形式到达,您必须通过 index 将它们连接起来。

calls = {}

stream = client.chat.completions.create(
    model="uncensored",
    messages=[{"role": "user", "content": "Where is order A-1042?"}],
    tools=tools,
    stream=True,
)

for chunk in stream:
    if not chunk.choices:
        continue
    for tc in chunk.choices[0].delta.tool_calls or []:
        slot = calls.setdefault(tc.index, {"id": "", "name": "", "args": ""})
        if tc.id:
            slot["id"] = tc.id
        if tc.function and tc.function.name:
            slot["name"] = tc.function.name
        if tc.function and tc.function.arguments:
            slot["args"] += tc.function.arguments

for slot in calls.values():
    print(slot["name"], json.loads(slot["args"]))

只有在流结束后才解析 args。接收了一半的字符串不是有效的 JSON。之后,运行函数并按非流式示例中的方式发送结果。

JSON 模式

对于结构化回复,开启 JSON 模式并在提示词中描述你需要的形状。

r = client.chat.completions.create(
    model="uncensored",
    temperature=0.2,
    response_format={"type": "json_object"},
    messages=[
        {"role": "system", "content": "Reply with JSON only: {\"mood\": string, \"intensity\": integer from 1 to 5}."},
        {"role": "user", "content": "Rate this line: The door slammed and nobody spoke for an hour."},
    ],
)

try:
    data = json.loads(r.choices[0].message.content)
except json.JSONDecodeError:
    data = None  # retry once, or fall back
print(data)

JSON 模式使生成有效 JSON 的可能性大大增加,但它不会强制执行你的 schema。请自行检查键和类型,并保留重试路径。低 temperature 有助于提取。采样设置如 temperature、top_p、stop、seed 和 penalties 会透传。

一个有用的模式是将 JSON 模式与小型验证函数结合,该函数返回清晰的错误消息,然后将该消息反馈给模型进行一次重试:“你的上次回复缺少 intensity 键。请再次回复有效的 JSON。”模型通常在第二次尝试时自行纠正,额外的请求成本不到一分钱。

处理流式传输期间的故障

流式传输以普通请求不会遇到的方式失败:连接可能在文本传输一半时断开。请为此做好准备。

import time
from openai import RateLimitError, APIConnectionError

def stream_reply(messages):
    for attempt in range(3):
        parts = []
        try:
            stream = client.chat.completions.create(
                model="uncensored", messages=messages, stream=True
            )
            for chunk in stream:
                if chunk.choices and chunk.choices[0].delta.content:
                    parts.append(chunk.choices[0].delta.content)
            return "".join(parts)
        except RateLimitError:
            time.sleep(5)
        except APIConnectionError:
            time.sleep(1)
    raise RuntimeError("stream failed after retries")

这里的 429 表示达到限制或暂时过载,正确的做法是等待 5 秒,这与 API 发送的 Retry-After: 5 一致。如果流在中间断开,您会得到一个部分答案。决定是丢弃并重试,还是保留它并让模型继续。对于聊天界面,丢弃并重试通常对用户来说更不容易混淆。

需规划的速率限制和成本

  • 速率: 完整密钥每分钟 300 个请求,试用密钥每分钟 60 个。
  • 并发: 完整密钥 8 个,试用密钥 2 个。记住每个打开的流都会计入。
  • 大小: 请求体最大 8 MB;100,000 token 的上下文窗口,包括提示词和补全。
  • 429 处理: 代码 rate_limited 和 concurrency 表示您超出了限制;暂时过载返回 429 并附带 Retry-After: 5。

成本示例:涉及两个请求的工具调用交互,第一个请求输入 1,200 token,输出 80;第二个请求输入 1,400 token,输出 150。输入成本为 2,600 x $0.15 / 1M = $0.00039。输出成本为 230 x $0.50 / 1M = $0.000115。总计 $0.000505。失败或被拒绝的请求不收费。费率见 定价,完整方法列表在 文档中。从 API 密钥页面获取 $0.50 试用额度。有关模型的背景信息,请参阅 了解无审查 ChatGPT 模型。硬性限制适用于所有模式:禁止涉及未成年人的性内容。

发布前检查清单

  • 工具参数在 try 块中使用 json.loads 进行解析,并在运行任何操作之前检查预期的键和类型。
  • 你暴露的函数只能执行你允许匿名用户执行的操作。由模型决定何时调用它们,而不是你。
  • JSON 回复经过验证,失败时重试一次。
  • 当用户离开页面时,流会被关闭,因此它们不会占用并发槽位。
  • 代码中的并发限制等于或低于密钥的限制:完整密钥为 8。
  • X-Request-Id 的请求 ID 已记录。
  • 密钥存储在服务器上且可重新生成;旧密钥立即失效。

服务仅限文本,因此需要图像或嵌入的功能必须来自其他提供商。

常见问题

接口是否支持流式响应?

支持。发送 stream: true 即可接收 Server-Sent Events,并在流结束时获取用量报告。

支持函数调用吗?

支持。使用 tools 和 tool_choice,从回复中读取 tool_calls,并以 role: tool 的消息形式将结果发回。也支持流式输出的 tool_calls。

JSON 模式是否总是返回有效的 JSON?

它能显著提高返回有效 JSON 的概率,但并非保证,且不强制执行 schema。请在 try 块中解析,并在失败时重试。

我可以在同一个请求中流式传输并使用工具吗?

是的。工具调用名称和参数以片段形式到达,因此请按索引将它们连接起来,并在流结束后解析参数。

获取 API 密钥

注册,复制 token,更新你的 Base URL。就这样。

立即开始