兩種將免費 LLM 引入 Python 腳本的方法
當人們搜尋 Python 免費 LLM 時,通常指兩種情況。第一種是你下載並自行運行的開放權重模型,使用 Ollama、llama.cpp 或 Hugging Face transformers 庫等工具。第二種是託管端點,其成本極低或提供足夠的試用額度,使其在原型開發時感覺免費。兩者皆具價值,適用於不同任務。
在本機運行意味著沒有每個 token 的計費,且資料不會離開您的機器。這也代表您需要足夠的記憶體或 GPU 記憶體來運行所選模型,必須等待下載,且適合筆記型電腦的小型模型表現不如大型模型。託管式 API 消除了硬體需求,但一旦試用額度用完,您需按 token 付費。本頁面誠實地介紹這兩種方式,接著展示本站託管選項的 Python 程式碼,該選項與 OpenAI 相容,並可使用標準 openai 套件。
本地模型與託管 API 並列比較
| 問題 | 自行運行 | 託管預付 API |
|---|---|---|
| 每個 token 的成本 | 無,但需支付硬體和電力費用 | 每 1M 輸入 $0.15,每 1M 輸出 $0.50 |
| 設定時間 | 安裝運行時、下載權重、調整設定 | 安裝一個套件,貼上金鑰 |
| 上下文長度 | 受你的上下文長度限制 | 100,000 token,含提示詞與補全 |
| 並行請求 | 取決於你的機器能處理的程度 | 完整金鑰可同時處理 8 個請求,試用金鑰為 2 個 |
| 拒絕回應 | 取決於你選擇的權重 | 經過調整,可在合法成人用途下無內容拒絕地回答 |
| 離線使用 | 是 | 否 |
如果你有強大的 GPU 且工作涉及隱私或離線,本地運行是個好選擇,你可以到此為止。如果你想要更大的模型而不擁有硬體,或希望腳本在筆記型電腦、伺服器和本機 CI 執行器上表現一致,託管方案更簡單。許多專案同時使用兩者:開發時使用小型本地模型,生產環境使用託管模型,只需更改一個 base URL 即可切換。
五分鐘內設定託管端點
你需要先取得金鑰。使用 Google 或電子郵件與密碼註冊,然後在 API 金鑰頁面 點擊一次領取 $0.50 試用額度。試用期為 7 天,每人限領一次,無需付款。然後安裝 SDK 並將金鑰保留在原始碼之外。
pip install openai
export NOTRACK_API_KEY="sk-your-key-here"
客戶端需要從標準 OpenAI 設定進行兩項更改:Base URL 和金鑰。模型 ID 為 uncensored,且僅提供一種模型。
import os
from openai import OpenAI
client = OpenAI(
base_url="https://api.nsfwvideogenerator.cc/v1",
api_key=os.environ["NOTRACK_API_KEY"],
)
resp = client.chat.completions.create(
model="uncensored",
messages=[
{"role": "system", "content": "You are a concise writing assistant."},
{"role": "user", "content": "Give me three title ideas for a noir short story."},
],
temperature=0.8,
)
print(resp.choices[0].message.content)
print(resp.usage)
驗證為標準的 Authorization: Bearer 標頭,SDK 會自動為您加入。提供兩種方法:POST /v1/chat/completions 與 GET /v1/models。您可以透過 client.models.list() 確認連線,該方法會回傳可用的模型 ID。完整參數列表請見 文件頁面。
串流回應
對於任何人類使用者會觀看的內容,請使用串流輸出。設定 stream=True 並在伺服器發送事件 (SSE) 到達時逐區塊迭代。使用情況會在串流結束時報告,因此你仍然可以記錄 token 計數。
stream = client.chat.completions.create(
model="uncensored",
messages=[{"role": "user", "content": "Write a four-line poem about rain on a tin roof."}],
stream=True,
)
for chunk in stream:
if chunk.choices and chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="", flush=True)
usage = getattr(chunk, "usage", None)
if usage:
print("\n", usage)
一個容易讓人忽略的細節是:串流請求會佔用其並行槽位,直到串流結束為止。在具有 2 個槽位的試用金鑰上,兩個開啟的串流會導致第三次呼叫收到 429 錯誤,並帶有程式碼 concurrency。請務必讀取或關閉串流。
工具呼叫與 JSON 模式
端點支援 tools、tool_choice、串流的 tool_calls 以及以 role: "tool" 形式返回的結果。以下是一個包含一個函式的完整請求週期範例。
import json
tools = [{
"type": "function",
"function": {
"name": "word_count",
"description": "Count the words in a piece of text.",
"parameters": {
"type": "object",
"properties": {"text": {"type": "string"}},
"required": ["text"],
},
},
}]
messages = [{"role": "user", "content": "How many words are in: the quick brown fox jumps"}]
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 = len(args["text"].split())
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)
請謹慎解析 arguments;模型會將其作為 JSON 字串返回,且任何模型偶爾都可能產生格式錯誤的 JSON。若需不使用工具的結構化輸出,請使用 JSON 模式。
resp = client.chat.completions.create(
model="uncensored",
messages=[
{"role": "system", "content": "Reply with a JSON object with keys title and tags (list of strings)."},
{"role": "user", "content": "Describe a lighthouse keeper's diary."},
],
response_format={"type": "json_object"},
temperature=0.2,
)
data = json.loads(resp.choices[0].message.content)
print(data["title"], data["tags"])
在提示詞中提及 JSON 並指定鍵名,並將 temperature 設低。在生產環境程式碼中,請將 json.loads 包裹在 try 區塊中。
速率限制、錯誤與重試
完整金鑰允許 8 個並行請求和每分鐘 300 個請求。試用金鑰允許 2 個和 60 個。超出限制會收到 HTTP 429,代碼為 rate_limited(每分鐘過多)或 concurrency(同時過多)。在臨時超載時,API 也會返回 429,並帶有 Retry-After: 5 標頭。SDK 會自動重試某些錯誤;對於扇出腳本,使用小型明確包裝器更清晰。
import time
from concurrent.futures import ThreadPoolExecutor
from openai import RateLimitError
def ask(prompt, tries=4):
for attempt in range(tries):
try:
r = client.chat.completions.create(
model="uncensored",
messages=[{"role": "user", "content": prompt}],
max_tokens=300,
)
return r.choices[0].message.content
except RateLimitError:
time.sleep(5 * (attempt + 1))
raise RuntimeError("still rate limited")
prompts = [f"Summarize idea number {i} in one sentence." for i in range(20)]
with ThreadPoolExecutor(max_workers=2) as pool: # 8 on a full key
results = list(pool.map(ask, prompts))
將 max_workers 設定為與金鑰的並行限制相符,可避免大多數 429 錯誤發生。每個回應也會包含 X-Request-Id、X-Balance-USD 以及兩個速率限制標頭,當您需要它們進行除錯或支援時,可透過 client.chat.completions.with_raw_response.create(...) 讀取這些標頭。
如何選擇本地與託管方案
拋開意識形態,回答關於專案的四個問題。
- 資料必須留在你的機器上嗎? 如果合約或習慣要求如此,請在本機執行。在此處託管的提示詞不會用於訓練,但它們確實會經過網路傳輸。
- 你有多少記憶體? 模型大小決定品質。沒有專用 GPU 的筆記型電腦會限制你只能使用小型模型,且回答品質會受影響。託管模型可讓你獲得擁有 100,000 token 上下文視窗的大型模型,這在家裡很難達到。
- 你會發送多少請求? 每週幾百個請求在任何一方都微不足道。每月數十萬個請求會使託管帳單成為實際數字,如果本地機器閒置,它看起來會更具吸引力。計算一下:100,000 個請求,每個請求包含 1,000 個輸入 token 和 500 個輸出 token,成本為 100,000 x $0.0004 = $40。
- 您需要以特定方式處理拒絕回應嗎? 許多開放權重模型內建拒絕行為,而其他模型則已調整以消除該行為。本站的託管模型已調整為在合法成人用途下無內容拒絕地提供回答,因此您無需費心尋找合適的權重。
如果你的答案指向兩方面,請先從託管開始試用一週。試用免費,你將了解提示詞的需求,然後再購買硬體或下載另一個多 GB 檔案。
Python 腳本中的常見錯誤
人們遇到的大多數問題都是小問題且可修復。
- Base URL 錯誤。 它必須以
/v1結尾。缺少後綴會導致 404 錯誤,而非有用的訊息。如有疑問,請列印client.base_url。 - 金鑰在程式碼中。 從環境變數讀取,如上所述,並將你的
.env檔案添加到.gitignore。 - 模型名稱錯誤。 唯一的模型 ID 是
uncensored。來自其他供應商的名称將無法運作,因此在移植程式碼時請更改它們。 - 無界循環。 永不結束的函式呼叫循環是一個昂貴的錯誤。將其限制在例如五輪以內。
- 忽略上下文預算。 提示詞和完成內容共享 100,000 個 token。如果你永遠追加每次對話,最終會達到限制。請修剪或總結舊訊息。
- 假設 JSON 總是有效的。 即使在 JSON 模式下,在使用之前也請檢查所需的鍵。
當伺服器端出現異常時,請在致信 支援 時引用回應中的 X-Request-Id 值。這能讓作業人員找到您的精確呼叫。
託管選項在 Python 工作中的成本
一般腳本呼叫包含 1,000 個輸入 token 和 500 個輸出 token 的成本為 $0.00015 加上 $0.00025,即 $0.0004。$0.50 的試用額度約可涵蓋 1,250 次呼叫。$20 的儲值(最低金額)可涵蓋 50,000 次呼叫。額度永不過期,失敗或遭拒絕的請求不會計費,且提示詞不會用於訓練。儲值最高可達 $500,從 $50 起享有贈額,付款方式為加密貨幣,包括 TRC20 上的 USDT 或 Base 上的 USDC。詳見 定價頁面。
僅限文本:無圖像、音訊、影片、嵌入或微調。唯一的硬性規定是不涉及未成年人的色情內容。對於需要更少拒絕的文本生成的 Python 專案,這就是全部功能範圍。
