繁中 ▾
取得 API 金鑰

NsfwAiApi指南

Python 版 NSFW LLM API:串流輸出、JSON 與工具

若要採用 Python 風格的 nsfw llm api 呼叫方式,你只需要標準的 openai 套件以及兩項變更:base URL 與金鑰。本指南將展示首次請求、串流輸出、JSON 模式、工具呼叫以及速率限制的清晰處理方式。

更新

終端機視窗顯示由光線螺旋環繞的發光 token 串流

設定:安裝並進行首次呼叫

你需要當前的 Python 3、openai 套件(pip install openai)以及 API 金鑰。新帳戶可在註冊後一鍵於 API 金鑰頁面 領取 $0.50 試用額度;該試用無需付款資訊。請將金鑰存放在環境變數中,而非原始碼內。

該服務採用 OpenAI 聊天完成協定:POST /v1/chat/completions 用於生成,GET /v1/models 用於取得模型列表。驗證方式為 bearer token,模型 ID 為 uncensored。這是能運行的最小腳本:

import os
from openai import OpenAI

client = OpenAI(
    base_url="https://api.nsfwaiapi.com/v1",
    api_key=os.environ["NSFWAIAPI_KEY"],
)

resp = client.chat.completions.create(
    model="uncensored",
    messages=[
        {"role": "system", "content": "You are a fiction co-writer for adult readers. Write vivid, non-explicit scenes."},
        {"role": "user", "content": "Open a noir story in a rainy harbor town, three sentences."},
    ],
    temperature=0.8,
)

print(resp.choices[0].message.content)
print(resp.usage)

如果你希望先從 Shell 檢查連線,相同的請求也可使用 curl:

curl https://api.nsfwaiapi.com/v1/chat/completions \
  -H "Authorization: Bearer $NSFWAIAPI_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model": "uncensored", "messages": [{"role": "user", "content": "Say hello in five words."}]}'

該模型經過調整,在合法成人用途下不會拒絕內容(即不會拒絕回答)。這會影響其撰寫的語氣,但不會改變 API 的結構,因此你的程式碼看起來與其他 OpenAI 整合並無二致。請保留用於小說、角色聊天及其他合法成人專案的提示詞,並維持每個角色都是成年人的狀態。

從第一天開始養成好習慣。將永不變更的指示放在系統訊息中,並將使用者訊息保留給每次輪替時會變化的部分。為特定任務選擇一個 temperature 值,並在比較提示詞時保持不變,因為同時變更兩件事無法讓你學到東西。記錄每次呼叫的請求 ID 與 resp.usage 中的 token 計數,這樣當帳單或輸出令你驚訝時,就有記錄可供查核。

使用 SSE 串流回覆

設定 stream=True,伺服器會以伺服器發送的事件(SSE)傳送 token。對於聊天應用程式而言這很重要,因為讀者能很快看到第一個字,而不必等待完整回覆。總用量會在串流結束時到達,因此串流請求仍可準確計費與記錄。

import os
from openai import OpenAI

client = OpenAI(
    base_url="https://api.nsfwaiapi.com/v1",
    api_key=os.environ["NSFWAIAPI_KEY"],
)

stream = client.chat.completions.create(
    model="uncensored",
    messages=[{"role": "user", "content": "Write a short scene: two rival smugglers share a lantern during a storm."}],
    stream=True,
)

text = ""
for chunk in stream:
    if chunk.choices and chunk.choices[0].delta.content:
        piece = chunk.choices[0].delta.content
        text += piece
        print(piece, end="", flush=True)
    usage = getattr(chunk, "usage", None)
    if usage:
        print("\n[usage]", usage)

兩個細節可節省除錯時間。首先,最後一個區塊可能包含空的 choices 列表,這就是迴圈在索引前檢查它的原因。其次,串流請求會佔用其並行槽位直到串流結束,因此如果你的程式碼在未關閉的情況下放棄串流,該槽位仍會保持忙碌。使用 with client.chat.completions.create(..., stream=True) as stream: 或在提早停止讀取時呼叫 stream.close()。

用於結構化輸出的 JSON 模式

當你的程式需要資料而非散文時,例如角色表、場景節奏列表或故事標籤,請使用 JSON 模式並設定 response_format={"type": "json_object"}。同時在提示詞中說明「JSON」並描述你需要的鍵。此設定要求 JSON 物件,但無法保證你的鍵會存在,因此請檢查它們。

import json
import os
from openai import OpenAI

client = OpenAI(
    base_url="https://api.nsfwaiapi.com/v1",
    api_key=os.environ["NSFWAIAPI_KEY"],
)

resp = client.chat.completions.create(
    model="uncensored",
    response_format={"type": "json_object"},
    messages=[
        {"role": "system", "content": "Reply with a JSON object with keys: name, age, goal, secret. All characters are adults."},
        {"role": "user", "content": "Create a ship's cook for a pirate adventure."},
    ],
    temperature=0.7,
)

sheet = json.loads(resp.choices[0].message.content)
missing = [k for k in ("name", "age", "goal", "secret") if k not in sheet]
if missing:
    raise ValueError(f"model skipped keys: {missing}")
print(sheet["name"], "-", sheet["goal"])

如果長回答被 max_tokens 截斷,JSON 將不完整且 json.loads 會失敗。將 max_tokens 保持未設定狀態,因為它是可選的,且完成生成可以使用剩餘的視窗,或者將其設為較大的值。

函式呼叫

工具呼叫讓模型要求你的程式執行某些動作,例如擲骰子、查詢角色備註或取得價格。你傳入 tools,如果需要也可傳入 tool_choice。回覆包含 tool_calls;你執行它們並將結果以 role: "tool" 訊息傳回。串流回應也在增量中攜帶 tool_calls。

import json
import os
import random
from openai import OpenAI

client = OpenAI(
    base_url="https://api.nsfwaiapi.com/v1",
    api_key=os.environ["NSFWAIAPI_KEY"],
)

tools = [{
    "type": "function",
    "function": {
        "name": "roll_die",
        "description": "Roll one die with the given number of sides",
        "parameters": {
            "type": "object",
            "properties": {"sides": {"type": "integer", "minimum": 2}},
            "required": ["sides"],
        },
    },
}]

messages = [
    {"role": "system", "content": "You run a tabletop fiction game. Use roll_die for any chance-based outcome."},
    {"role": "user", "content": "I try to pick the lock on the captain's cabin. Roll a d20."},
]

first = client.chat.completions.create(
    model="uncensored", messages=messages, tools=tools, tool_choice="auto"
)
msg = first.choices[0].message

if msg.tool_calls:
    messages.append(msg)
    for call in msg.tool_calls:
        args = json.loads(call.function.arguments)
        result = random.randint(1, args["sides"])
        messages.append({"role": "tool", "tool_call_id": call.id, "content": str(result)})
    final = client.chat.completions.create(
        model="uncensored", messages=messages, tools=tools
    )
    print(final.choices[0].message.content)
else:
    print(msg.content)

將引數視為不受信任的輸入。在根據它們執行動作之前先進行驗證,就像處理網頁表單一樣。模型有時會遺漏欄位或傳送錯誤的類型,而在 json.loads 周圍加上小保護措施,可防止一次錯誤呼叫導致你的會話結束。

速率限制、重試與你的餘額

限制保護服務並提供可預測的行為。完整金鑰允許 8 個並行請求和每分鐘 300 個請求。試用金鑰允許 2 個和 60 個。最大主體為 8 MB。兩種限制錯誤以 HTTP 429 回傳:程式碼 rate_limited 表示每分鐘請求過多,concurrency 表示同時請求過多。暫時過載也會回傳 429,並帶有 Retry-After: 5 標頭。

OpenAI SDK 預設會重試一些錯誤。為了控制,請關閉該功能並撰寫一個小迴圈以尊重 Retry-After:

import os
import time
from openai import OpenAI, RateLimitError

client = OpenAI(
    base_url="https://api.nsfwaiapi.com/v1",
    api_key=os.environ["NSFWAIAPI_KEY"],
    max_retries=0,
)

def ask(messages, tries=5):
    for attempt in range(tries):
        try:
            raw = client.chat.completions.with_raw_response.create(
                model="uncensored", messages=messages
            )
            print("balance:", raw.headers.get("X-Balance-USD"), "request id:", raw.headers.get("X-Request-Id"))
            return raw.parse()
        except RateLimitError as err:
            wait = float(err.response.headers.get("Retry-After", 2 ** attempt))
            time.sleep(wait)
    raise RuntimeError("still rate limited after retries")

reply = ask([{"role": "user", "content": "Describe a market at dawn in two sentences."}])
print(reply.choices[0].message.content)

每個回應都帶有 X-Request-Id,這是你在聯絡支援時引用的內容,以及 X-Balance-USD,顯示你剩餘的額度。X-RateLimit-Limit-Requests 和 X-RateLimit-Limit-Concurrency 標頭告訴你哪些限制適用於你的金鑰。要同時執行許多工作,請在你的程式碼中使用訊號量來限制並行度,其大小應對應你的金鑰限制(完整金鑰為 8,試用金鑰為 2),這樣你幾乎不會看到 429。

並行執行許多請求

批次工作(例如為幾百個故事片段生成標籤)是並行限制發揮作用的地方。完整金鑰一次接受 8 個請求,因此請透過非同步客戶端和該大小的訊號量來執行工作。如果你使用的是試用金鑰,請使用 2。

import asyncio
import os
from openai import AsyncOpenAI

client = AsyncOpenAI(
    base_url="https://api.nsfwaiapi.com/v1",
    api_key=os.environ["NSFWAIAPI_KEY"],
)
gate = asyncio.Semaphore(8)

async def summarize(fragment):
    async with gate:
        resp = await client.chat.completions.create(
            model="uncensored",
            messages=[
                {"role": "system", "content": "Summarize the passage in one sentence."},
                {"role": "user", "content": fragment},
            ],
            temperature=0.3,
        )
    return resp.choices[0].message.content

async def main(fragments):
    return await asyncio.gather(*(summarize(f) for f in fragments))

results = asyncio.run(main(["The tide came in early.", "Marta hid the ledger under the floor."]))
print(results)

訊號量是整個訣竅。沒有它,200 個片段的列表會同時發出 200 個請求,其中大多數會以程式碼為 concurrency 的 429 錯誤回傳。有了它,工作會以你的金鑰允許的速度流動,且不會浪費。如果你還執行每分鐘的速率限制,完整金鑰每分鐘 300 個請求相當於每秒五個,因此非常短的請求可能會在達到並行限制之前觸及每分鐘限制。

常見問題與解決方案

  • 401 或驗證錯誤。 金鑰遺失、截斷或傳送至錯誤的主機。列印 client.base_url 並檢查環境變數。標頭必須讀取 Authorization: Bearer 後接你的金鑰。
  • 找不到模型。 唯一的模型 ID 是 uncensored。複製的範例如果指定其他名稱會失敗,因此如果你不確定,請呼叫 GET /v1/models。
  • 故事迴圈中的空回應或短回應。 檢查你是否在下一輪之前將助手回覆附加到訊息列表中。沒有它,模型只能看到你的最後一條訊息。
  • 重複的回覆。 稍微提高 frequency_penalty,例如設為 0.3,或在文字漂移時降低 temperature。懲罰值 top_p、stop 和 seed 都會通過。
  • 每次執行輸出不同。 設定 seed 和低 temperature,以便在除錯時獲得盡可能可重複的結果。
  • 請求太大。 主體限制為 8 MB,提示詞加上完成必須符合 100,000 token。在達到任一限制之前,請修剪或摘要舊的上下文。

當伺服器端看起來有問題時,請儲存回應中的 X-Request-Id 標頭,並將其與簡短描述一起發送到 支援頁面 聯絡方式。這讓操作員可以找到你的確切請求。

費用與限制

定價為每 1M 輸入 token $0.15,每 1M 輸出 token $0.50,從預付額度扣除,無訂閱。失敗或被拒絕的請求不會收費,且額度永不過期。作為一個實例,一個發送 3,000 token 並接收 800 token 的腳本,輸入需支付 $0.00045,輸出需支付 $0.0004,每次呼叫共 $0.00085,因此 1,000 次呼叫成本為 $0.85。儲值範圍從 $20 到 $500,紅利為:$50 起 +5%,$100 起 +10%,$200 起 +15%。本站僅接受加密貨幣,即 TRC20 上的 USDT 或 Base 上的 USDC。請參閱 定價頁面 查看完整表格,並參閱 文件 查看端點參考。

界限很明確。這是一個單一開放權重模型,由獨立供應商運行,並非任何模型廠商的官方 API。上下文視窗為 100,000 token(包含提示詞與完成)。它不生成圖像、音訊或影片,不提供嵌入,也不支援微調。僅用於合法成人用途,並注意硬性限制:不含涉及未成年人的性內容。提示詞不用於訓練。

問答

從 Python 呼叫此 API 需要特殊 SDK 嗎?

不需要。官方 openai 套件即可運作。將 base_url 設為 https://api.nsfwaiapi.com/v1,傳入你的金鑰,並使用模型 ID uncensored。

串流運作方式與 OpenAI 相同嗎?

是的。傳入 stream=True 並逐區塊讀取伺服器發送的事件。用量會在串流結束時回報。

收到 429 錯誤時該怎麼辦?

等待並重試。如果回應包含 Retry-After 標頭,請遵守該指示。錯誤程式碼 rate_limited 表示每分鐘請求過多,concurrency 表示同時請求過多。

我可以免費測試嗎?

是的。完成註冊後,你可以在 API 金鑰頁面領取 $0.50 的試用額度。無需提供付款資訊,有效期為 7 天,每人限領一次。

只差一張表單,即可取得金鑰

建立帳號、複製金鑰、更改基礎 URL。這就是整個設定過程。

取得 API 金鑰

NsfwAiApi用於 NSFW 文字產生的無審查 LLM API