繁中 ▾
取得 API 金鑰

從 LLM API 建立聊天機器人:Python 教學

Abliterated 模型是大型語言模型,其中執行安全拒絕的機制已被移除,使模型能夠回答爭議性、成人或利基問題而不觸發內容過濾器。這種方法讓開發者完全控制模型的語氣和知識截止點,對於程式碼編寫、角色扮演和創意寫作特別有價值,因為標準防護措施可能會阻止有用的輸出。

聊天訊息區塊在迴圈中移動並進入中央立方體,說明聊天機器人的對話迴圈

重點摘要

  • API 是無狀態的,因此你的程式碼擁有對話歷史,並在每個請求時傳送它。
  • 串流輸出、函式呼叫與 JSON 模式皆使用標準的 OpenAI 參數。
  • 在接近 100,000 token 的上下文視窗之前,請截斷或摘要歷史紀錄。
  • 1,000 次聊天,每次包含 2,000 個輸入 token 與 400 個輸出 token,成本約為 $0.50。

核心概念:聊天機器人是一個迴圈與一個列表

語言模型在請求之間不會記住任何內容。每次呼叫 POST /v1/chat/completions 都是獨立的。感覺像是記憶,其實是你的程式再次傳送先前的訊息,每則訊息都標註了角色:system 用於固定指示,user 用於使用者輸入的內容,assistant 用於先前的模型回覆。

因此整體架構很小。保持一個列表。附加使用者訊息。傳送列表。附加回覆。重複。本教學中的其餘內容,從串流輸出到工具,都是該迴圈的變體。

此 API 與 OpenAI 相容,因此你可以使用一般的 openai 套件。將 Base URL 設為 https://api.abliterated.cc/v1,使用你的金鑰,並將模型設為 uncensored。前往 API 金鑰頁面取得金鑰;$0.50 的試用額度已足夠進行數百則短測試訊息的測試。

步驟 1:建立可運作的主控台聊天機器人

使用 pip install openai 安裝 SDK 並執行此程式。

from openai import OpenAI

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

messages = [
    {"role": "system", "content": "You are a concise, friendly support assistant for a bike shop."}
]

while True:
    text = input("you: ")
    if text.strip() in {"quit", "exit"}:
        break
    messages.append({"role": "user", "content": text})
    resp = client.chat.completions.create(
        model="uncensored",
        messages=messages,
        temperature=0.7,
    )
    answer = resp.choices[0].message.content
    messages.append({"role": "assistant", "content": answer})
    print("bot:", answer)

這是一個完整的聊天機器人。系統訊息設定其任務,列表儲存記憶,而 temperature 控制回覆的多樣性。針對需要事實準確的客服型機器人,請將其調低至接近 0.2;針對創意型機器人,請將其調高至接近 1.0。

撰寫設定任務的系統提示詞

系統提示詞是改善聊天機器人最便宜的方式。保持簡短且具體。說明角色、受眾、回覆的長度與語氣,以及當機器人不知道答案時該怎麼辦。一個類似「你為自行車店回答問題。回覆最多三句話。如果問題關於維修價格,請表示必須由技師檢查自行車」的提示詞,比一頁泛泛而談的美德更有效。

兩個習慣會帶來回報。首先,以動作形式放置規則,而非態度:「當請求含糊時,請提出一個澄清問題」,而非「保持樂於助人」。其次,使用惡意輸入進行測試,例如空訊息、非常長的貼上內容以及與你的產品無關的請求。根據觀察結果修正提示詞,然後將這些輸入保留為回歸測試列表。

由於系統訊息會在每個回合中重新發送,其中的每個字都會在每次請求時計費。一個 400 token 的提示詞,經過 1,000 次每次 5 個回合的對話,會增加 2,000,000 個輸入 token,或 2 x $0.15 = $0.30。這筆金額很小,但這說明了冗長的提示詞在大量使用時會累積。

步驟 2:串流輸出回覆

在聊天視窗中等待完整答案感覺很慢。設定 stream: true,並在資料到達時逐段列印。串流使用伺服器發送的事件,並以包含用量資訊的區塊結束,因此你可以記錄 token 數量。

from openai import OpenAI

client = OpenAI(base_url="https://api.abliterated.cc/v1", api_key="YOUR_KEY")
messages = [{"role": "user", "content": "Explain tire pressure in two sentences."}]

stream = client.chat.completions.create(
    model="uncensored",
    messages=messages,
    stream=True,
)
reply = ""
for chunk in stream:
    if chunk.choices and chunk.choices[0].delta.content:
        part = chunk.choices[0].delta.content
        reply += part
        print(part, end="", flush=True)
    if getattr(chunk, "usage", None):
        print("\ntokens:", chunk.usage.prompt_tokens, chunk.usage.completion_tokens)

請記得將組合好的 reply 附加到對話歷史中,否則下一輪對話將不知道機器人說了什麼。

步驟 3:在上下文膨脹前進行管理

上下文視窗為 100,000 個 token,提示詞與補全內容共用此視窗。大多數聊天機器人從未接近此限制,但由於每一輪都要為整個提示詞付費,成本會隨歷史紀錄增長。一個簡單的策略可以同時控制兩者:

  • 始終保留系統提示詞。
  • 保留最後 10 到 20 則訊息的完整內容。
  • 當列表超過你設定的大小限制(例如 8,000 個預估 token)時,將最舊的區塊傳送至模型,並附上指示「在 150 字以內總結這段對話」,然後以系統訊息的形式將該區塊替換為摘要。

一個 token 約等於四個英文字元的粗略估算已足以作為觸發條件。每個回應中的用量數字會提供精確數據,讓你在事後進行限制調整。

如果你透過刪除最舊的訊息來截斷,請以使用者與助手配對的方式刪除。沒有問題的回覆或沒有回覆的問題,會讓模型感到困惑的程度超出你的預期。

步驟 4:提供機器人工具

函式呼叫讓模型可以要求你的程式碼執行某些動作,例如查詢訂單。你使用 tools 描述函式,模型會回傳 tool_calls 項目,你執行該函式,並將結果以 role: "tool" 訊息回傳。

import json
from openai import OpenAI

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

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 A1042?"}]
resp = client.chat.completions.create(
    model="uncensored", messages=messages, tools=tools, tool_choice="auto"
)
msg = resp.choices[0].message

if msg.tool_calls:
    messages.append(msg)
    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)

在執行任何具有副作用的操作前,請始終驗證參數。模型提出呼叫;你的程式決定是否執行它。

步驟 5:使用 JSON 模式進行結構化輸出

當程式的下一步需要資料而非文字時(例如將訊息分類),請使用 JSON 模式並設定 response_format。在提示詞中也請提及 JSON 以及預期的鍵名。

curl https://api.abliterated.cc/v1/chat/completions \
  -H "Authorization: Bearer YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "uncensored",
    "response_format": {"type": "json_object"},
    "messages": [
      {"role": "system", "content": "Reply with JSON: {\"intent\": string, \"urgent\": boolean}"},
      {"role": "user", "content": "My brakes squeal and I ride tomorrow morning."}
    ]
  }'

請務必將 json.loads 包裹在 try 區塊中。如果解析失敗,請附加錯誤文字後重試一次;失敗的請求不會計費。

錯誤、成本與部署注意事項

處理錯誤、重試與速率限制

真實使用者會在不合適的時刻發送請求,且網路可能會失敗。將呼叫包裝起來,以免單一不良回應導致對話崩潰。

import time
from openai import OpenAI, APIError, RateLimitError

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

def chat(messages, tries=3):
    for attempt in range(tries):
        try:
            resp = client.chat.completions.create(
                model="uncensored", messages=messages, temperature=0.7
            )
            return resp.choices[0].message.content
        except RateLimitError:
            time.sleep(2 ** attempt)
        except APIError as exc:
            if attempt == tries - 1:
                raise
            time.sleep(1)
    return "Sorry, the assistant is busy. Please try again in a moment."

完整金鑰允許 8 個並行請求與每分鐘 300 個請求;試用金鑰允許 2 個與每分鐘 60 個。如果你的機器人同時服務許多使用者,請將請求放入佇列,並將worker 並行限制設為低於 8,而不是依賴重試。由於失敗的請求不會計費,重試不會產生 token 成本。保持較小的重試次數,以便在真正停機時快速失敗。

也請在每次對話輪次中記錄 X-Request-Id 標頭。當回覆看起來有誤時,該 ID 可讓你在日後找到確切的請求。

成本與部署

價格為每 1M 輸入 token $0.15,每 1M 輸出 token $0.50。假設支援聊天總共使用 2,000 個輸入 token 與 400 個輸出 token。

  • 輸入:0.002M x $0.15 = $0.0003
  • 輸出:0.0004M x $0.50 = $0.0002
  • 一次聊天:$0.0005,因此 1,000 次聊天成本為 $0.50

請在 定價頁面 查看目前的費率與儲值贈額。用於生產環境時,請將金鑰保留在伺服器上,切勿放在瀏覽器程式碼中,並監控 X-Balance-USD 回應標頭,以便在額度耗盡前收到警報。完整金鑰允許 8 個並行請求和每分鐘 300 個請求,因此請對突發流量進行排隊,而不是一次性全部發出。文件 列出了所有支援的參數。

問答

我需要框架來建立聊天機器人嗎?

不需要。OpenAI SDK 和訊息列表就足以讓機器人運作。只有在需要額外的功能時,才建議稍後加入框架。

API 會記住之前的訊息嗎?

不會。每個請求都是獨立的,因此你的程式碼必須在每次請求時重新傳送歷史紀錄。

我該如何防止歷史紀錄變得太長?

保留系統訊息和最近的對話輪次,並在列表超過你設定的大小時,將較舊的內容摘要為簡短備註。

機器人可以呼叫我自己的函式嗎?

可以。傳遞 tools 和 tool_choice,當回覆包含 tool_calls 時執行該函式,並將結果以 tool message 的形式回傳。

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

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