繁中 ▾
取得 API 金鑰

GLM API Python:聊天、串流與工具範例

進行 glm api python 開發只需標準 openai 套件:將其指向 https://api.glmapi.cc/v1,使用模型 ID uncensored,即可使用一般的聊天呼叫。本頁將透過可執行的程式碼,逐步說明從首次請求到非同步批次與速率限制處理的各種模式。

重點摘要

  • 安裝 openai,將 base_url 設為 https://api.glmapi.cc/v1,並使用模型 uncensored。
  • 串流輸出、JSON 模式與函式呼叫使用與 OpenAI 聊天 API 相同的參數。
  • 完整金鑰允許 8 個並行請求與每分鐘 300 個,因此請將非同步工作程序上限設為 8。
  • 處理 429 錯誤時,請讀取錯誤程式碼與 Retry-After 標頭。
從筆記型電腦終端機到雲端伺服器的光帶串流資料區塊,代表 Python API 呼叫

安裝與首次請求

建立虛擬環境並安裝 SDK。全文假設使用 openai 套件版本 1 或更高。

python -m venv .venv
source .venv/bin/activate
pip install --upgrade openai

從 API 金鑰 頁面取得金鑰;新用戶可一鍵領取 7 天有效的 $0.50 試用額度,無需信用卡。將金鑰設為環境變數,然後進行首次呼叫:

import os
from openai import OpenAI

client = OpenAI(
    base_url="https://api.glmapi.cc/v1",
    api_key=os.environ["GLM_API_KEY"],
)

resp = client.chat.completions.create(
    model="uncensored",
    messages=[
        {"role": "system", "content": "You are a concise writing assistant."},
        {"role": "user", "content": "Suggest five titles for a space-western novel."},
    ],
    temperature=0.8,
)

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

這就是完整的整合方式。該服務是一個獨立的 OpenAI 相容端點,僅提供單一 open-weight 模型,因此並非 GLM 背後廠商或其他任何人的官方 API。僅存在 POST /v1/chat/completions 與 GET /v1/models。快速入門列出了支援的請求欄位。

兩個小習慣能從一開始就派上用場。首先,在煙霧測試中呼叫一次 client.models.list():它會觸發 GET /v1/models,藉此證明金鑰、base URL 與網路路徑均能運作,然後才在補全請求中消耗 token。其次,在開發期間列印 resp.usage。提示詞與補全的 token 計數能讓你早期發現系統提示詞是否比預期大,且每 1M 輸入 token 為 $0.15、每 1M 輸出 token 為 $0.50,你可以心算呼叫成本。

多輪聊天與取樣設定

API 是無狀態的,因此你需要自行維護對話列表並每次傳送。一個小型類別即可應付:

class Chat:
    def __init__(self, client, system, max_turns=12):
        self.client = client
        self.system = system
        self.max_turns = max_turns
        self.history = []

    def say(self, text):
        self.history.append({"role": "user", "content": text})
        window = self.history[-self.max_turns * 2:]
        resp = self.client.chat.completions.create(
            model="uncensored",
            messages=[{"role": "system", "content": self.system}] + window,
            temperature=0.9,
            top_p=0.95,
            frequency_penalty=0.3,
        )
        reply = resp.choices[0].message.content
        self.history.append({"role": "assistant", "content": reply})
        return reply

切片 self.history[-self.max_turns * 2:] 保留最後 12 組使用者與助手的配對。實際應用程式可能會固定幾則早期訊息(如角色設定或關鍵事實),並摘要中間內容。將輸入限制為最後 12 輪可讓對話增長時輸入成本保持固定。上下文視窗為 100,000 token(提示詞與完成內容合計),因此這是成本考量而非必要。參數 temperature、top_p、stop、seed 及懲罰參數會原樣傳遞。測試提示詞時設定 seed 以獲得可重複結果,除非要限制長度,否則不要設定 max_tokens。

串流回應

串流輸出使用伺服器傳送事件,並在產生時提供 token,這對任何互動式工具都很重要。傳入 stream=True 並遍歷:

stream = client.chat.completions.create(
    model="uncensored",
    messages=[{"role": "user", "content": "Describe a harbour at dawn in 120 words."}],
    stream=True,
)

parts = []
for chunk in stream:
    if not chunk.choices:
        continue
    delta = chunk.choices[0].delta.content
    if delta:
        parts.append(delta)
        print(delta, end="", flush=True)

text = "".join(parts)

對 chunk.choices 的檢查很重要,因為最後一個 chunk 包含用量資訊,且可能為空的 choices 列表。一個運作重點:串流請求會佔用並行請求槽位直到串流結束。將迴圈包裹在 try 區塊中,並在 finally 子句中關閉串流,以防程式碼中途拋出異常(例如用戶端斷線時)。務必結束或關閉串流,否則放棄串流的迴圈會觸發並行限制卻未執行任何有用工作。

JSON 模式

當輸出結果供其他程式碼使用時,請要求 JSON 物件。在提示詞中提及 JSON,讓模型知道你預期的格式:

import json

resp = client.chat.completions.create(
    model="uncensored",
    response_format={"type": "json_object"},
    messages=[
        {"role": "system", "content": "Reply with a JSON object only."},
        {"role": "user", "content": "Give a character with keys name, age, motto."},
    ],
)

data = json.loads(resp.choices[0].message.content)
print(data["name"])

在生產環境程式碼中,仍應將 json.loads 包裹在 try 區塊中。JSON 模式提高產生有效輸出的機率,但若因停止序列或自訂限制導致請求被截斷,仍可能留下截斷的物件。使用相同輸入重試一次是廉價的修正方式,且失敗請求不計費,因此重試的成本僅為成功的那次呼叫。

函式呼叫

函式呼叫遵循 OpenAI 的格式:你在 tools 中描述函式,模型會回傳 tool_calls,你執行它們並使用 role tool 回傳結果。完整的往返流程:

import json

tools = [{
    "type": "function",
    "function": {
        "name": "roll_dice",
        "description": "Roll a die with the given number of sides.",
        "parameters": {
            "type": "object",
            "properties": {"sides": {"type": "integer"}},
            "required": ["sides"],
        },
    },
}]

messages = [{"role": "user", "content": "Roll a twenty-sided die for me."}]
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 = {"value": 17, "sides": args["sides"]}  # replace with real logic
        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_call_id 將無處匹配,這是導致第二次回覆混亂的常見原因。當 tool_choice 設定為 auto 時,模型會自行決定是否呼叫工具,因此務必處理它直接回覆的分支(如上方的程式碼所示)。串流輸出也可包含 tool_calls,以片段形式傳遞,需在解析參數前依索引將其拼接。

在執行動作前請驗證參數。模型可能會產生格式錯誤的呼叫,你的程式碼應將參數視為不可信的輸入,就像來自使用者的任何資料一樣。

限制內的非同步批次

對於一次處理許多提示詞的情況,請使用 AsyncOpenAI 並搭配與你的並行請求限制相符的訊號量。完整金鑰允許 8 個並行請求,試用金鑰允許 2 個:

import asyncio, os
from openai import AsyncOpenAI

client = AsyncOpenAI(
    base_url="https://api.glmapi.cc/v1",
    api_key=os.environ["GLM_API_KEY"],
)
gate = asyncio.Semaphore(8)  # use 2 on a trial key

async def one(prompt):
    async with gate:
        r = await client.chat.completions.create(
            model="uncensored",
            messages=[{"role": "user", "content": prompt}],
        )
        return r.choices[0].message.content

async def main():
    prompts = [f"Write a one-line tagline for product {i}." for i in range(40)]
    results = await asyncio.gather(*(one(p) for p in prompts))
    print(len(results))

asyncio.run(main())

訊號量可處理並行請求,但無法處理每分鐘 300 次請求的上限。對於長時間批次,請加入少量延遲或 token 桶限制器。輸入 token 每 1M 為 $0.15,輸出 token 每 1M 為 $0.50,40 則標語請求(輸入約 60 token,輸出 25 token)總計費用為 $0.00036 + $0.0005 = $0.00086,因此限制條件而非價格決定了批次設計。請見 定價頁面以進行儲值。

速率限制、重試與標頭

超過限制時,API 會回傳 HTTP 429。錯誤程式碼為 rate_limited(每分鐘請求過多)與 concurrency(同時請求過多)。暫時過載也會回傳 429 並帶有 Retry-After: 5 標頭。SDK 會自行重試某些失敗,你可以在客戶端設定 max_retries,但明確處理更清晰:

import time
from openai import RateLimitError

def ask(prompt, tries=4):
    for attempt in range(tries):
        try:
            raw = client.chat.completions.with_raw_response.create(
                model="uncensored",
                messages=[{"role": "user", "content": prompt}],
            )
            print("balance:", raw.headers.get("X-Balance-USD"))
            return raw.parse().choices[0].message.content
        except RateLimitError as e:
            wait = float(e.response.headers.get("Retry-After", 2 ** attempt))
            time.sleep(wait)
    raise RuntimeError("still rate limited")

此處 with_raw_response 可存取 X-Balance-USD、X-Request-Id 與速率限制標頭。記錄任何欲回報錯誤的請求 ID。切勿將金鑰放入會提交至版本控制的 Notebook 或前端程式碼中。

不消耗額度的測試與常見錯誤

Python 整合的大部分是基礎建設,而基礎建設不需要活躍的模型。將網路呼叫封裝在一個函式中,你的測試就可以替換它。僅使用標準函式庫:

from unittest.mock import MagicMock

def reply_text(client, prompt):
    r = client.chat.completions.create(
        model="uncensored",
        messages=[{"role": "user", "content": prompt}],
    )
    return r.choices[0].message.content.strip()

def test_reply_text_strips_whitespace():
    fake = MagicMock()
    fake.chat.completions.create.return_value.choices = [
        MagicMock(message=MagicMock(content="  hello  "))
    ]
    assert reply_text(fake, "hi") == "hello"

僅在邊緣處執行少量真實呼叫:每次部署執行一次冒煙測試,並偶爾執行已儲存的提示詞集。一次約 100 token 輸入、20 token 輸出的冒煙測試成本為 $0.000015 + $0.00001 = $0.000025,這微乎其微,且失敗請求完全不計費。$0.50 試用額度遠超過測試套件所需。

進行提示詞工作時,固定seed和temperature,以便在同等條件下比較系統提示詞的兩個版本。如果在每次執行之間同時更改提示詞和取樣設定,將導致結果難以解讀。請儲存每次執行的輸出結果,並附上來自X-Request-Id標頭的請求 ID,以便稍後追蹤令人驚訝的回答。

常見 Python 錯誤

這些是導致 Python 使用者提出支援問題的主要原因:

  • 僅傳遞金鑰作為 OPENAI_API_KEY。 若在程式碼中設定了 base_url 但遺漏金鑰變數,SDK 會發送空值或錯誤的金鑰。請明確傳遞 api_key。
  • 遺漏 /v1。 base URL 以 /v1 結尾。SDK 會自行新增 /chat/completions。
  • 使用來自其他服務的模型名稱。 這裡僅 uncensored 有效。
  • 無限制的並行請求。 對超過一千個協同程式使用 asyncio.gather 且沒有訊號量,會產生一堆 concurrency 錯誤。
  • 將串流回覆視為單一字串。 請連接資料片段,並跳過具有空 choices 列表的區塊。
  • 忽略上下文限制。 歷史記錄加上補全必須符合 100,000 token 的限制。在達到限制前請截斷舊的輪次。

如需儲值與當前費率,請見 定價頁面。此服務僅支援文字,因此無需設定圖片、音訊或嵌入呼叫,且提示詞不會用於訓練。

問答

我需要哪個 Python 套件?

標準 openai 套件,版本 1 或更高。將 base_url 設定為 https://api.glmapi.cc/v1,並將模型設定為 uncensored。

串流輸出有效嗎?

是的。傳遞 stream=True 並遍歷 chunks。串流結束時會包含用量資訊,且在完成前會佔用一個並行槽位。

我可以同時執行多少個請求?

完整金鑰允許 8 個並行請求與每分鐘 300 次。試用金鑰允許 2 個並行請求與每分鐘 60 次。

我可以改用 LangChain 或 LiteLLM 嗎?

兩者都可以連接到 OpenAI 相容的端點,只要提供 base URL、金鑰與模型名稱 uncensored。請查看各專案的文件以取得確切的參數名稱。

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

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

取得 API 金鑰閱讀文件