NLP Day 13 LLM API 基礎:OpenAI、Anthropic 與開源模型
執行需求:需 API Key。本篇會用 OpenAI 官方 Python SDK 與 Anthropic Python SDK 兩個套件呼叫 GPT-4o 與 Claude 3.7 Sonnet,並提供 Ollama 本地替代路徑(讓沒有 API Key 的讀者也能跑完整流程)。金鑰一律從 os.environ 讀取,不會出現任何假字串。有 API Key 的讀者可以直接跑 OpenAI / Anthropic 範例;沒有的讀者只要裝 Ollama 0.6 / 0.7 就能用 llama3.2 或 qwen2.5 走完相同的流程。
引言
前一篇我們用 BERT 微調做客服工單分類,那是監督式學習的典型流程:準備標註資料、微調模型、評估。但 LLM(大型語言模型)時代改變了這個典範——透過 API 呼叫 GPT-4o、Claude 3.7 Sonnet、DeepSeek R1 等模型時,你不需要訓練、不需要 GPU、只需要一段提示詞(prompt)就能完成翻譯、摘要、分類、問答、推理等任務。這對沒有標註資料、想快速驗證想法的場景特別有用。今天就要把這條新路線寫清楚。
LLM API 與前幾天學的 BERT 微調是兩條互補的路線。BERT 微調的優勢是延遲低、成本低、可離線使用;LLM API 的優勢是泛化能力強、不需要標註、可處理開放式任務。實務上的典型組合:用 LLM API 做 cold start 與快速驗證、用 BERT 微調做大量線上服務、用微調模型與 LLM API 做 ensemble 提升品質。理解這兩條路線的取捨,是 NLP 工程師在 2025 年的關鍵能力。
本篇涵蓋 2025 年 3 月前真實存在且知名的模型:OpenAI 的 GPT-4o(2024-08)與 o3-mini(2025-01)、Anthropic 的 Claude 3.7 Sonnet(2025-02)、開源界的 Llama 3.3(2024-12)、Qwen 2.5(2024-09)、DeepSeek R1(2025-01)。這些模型各有特色:GPT-4o 是當前最受歡迎的多用途模型,o3-mini 是強化推理的輕量版本;Claude 3.7 Sonnet 以長文理解與程式碼見長;Llama 3.3 與 Qwen 2.5 是開源主力;DeepSeek R1 在數學與程式推理上表現出色。讀完這篇你會了解各家 API 的介面差異、模型選擇的依據、以及如何在沒有 API Key 時用 Ollama 跑本地替代。
OpenAI API:GPT-4o 與 o3-mini
OpenAI 在 2024 年發布 GPT-4o,把文字、視覺、音訊整合到同一個模型,2025-01 推出 o3-mini 強化推理能力。OpenAI 的 Python SDK 在 2025 年初穩定版本是 openai 1.6x 系列,用 OpenAI() 物件初始化客戶端、client.chat.completions.create() 發送對話請求。介面設計簡潔,沒有太多魔法,但對錯誤處理與重試要自己寫。
對話請求的核心參數有四個:model(模型名稱)、messages(對話訊息串列)、temperature(取樣溫度)、max_tokens(最大生成 token 數)。messages 是 OpenAI 對話格式的核心:每筆訊息是 {"role": "user", "content": "..."} 或 {"role": "assistant", "content": "..."};對話可以有多輪(加上 system role 設定系統提示詞);這套格式已被業界廣泛採用,包括 Anthropic、Ollama(部分)都相容。
API 金鑰的管理是基本功。請把金鑰存在環境變數(OPENAI_API_KEY),不要寫在程式碼裡。讀取方式是 os.environ["OPENAI_API_KEY"],沒設定就會 raise KeyError。如果要更友善的錯誤訊息,可以用 os.environ.get("OPENAI_API_KEY") 並檢查 None。本篇所有範例都用前者,讀者可在 Colab 左側 Secrets 面板設定環境變數。
另一個重要設計是重試與速率限制。OpenAI API 有 RPM(每分鐘請求數)與 TPM(每分鐘 token 數)兩種限額,免費帳號分別為 3 RPM 與 200 TPM;付費帳號依額度提高。當超過限額時 API 會回 HTTP 429,這時要用指數退避(exponential backoff)重試。建議用 tenacity 套件或 OpenAI SDK 內建的 retry 機制。本篇範例只展示基本呼叫,重試部分留給 Day 39 的成本與延遲章節。
Anthropic API:Claude 3.7 Sonnet
Anthropic 在 2025-02 發布 Claude 3.7 Sonnet,這是當時最受歡迎的對話模型之一,以長文理解(200K token 上下文)、程式碼品質、安全對齊見長。Python SDK 是 anthropic 0.3x 系列,介面與 OpenAI 略有差異:用 Anthropic() 初始化、client.messages.create() 發送請求、訊息以 messages=[{"role": "user", "content": "..."}] 傳遞。
Anthropic 與 OpenAI 的關鍵差別:system prompt 與 user prompt 分開。OpenAI 把 system 訊息放在 messages 串列裡;Anthropic 把 system 訊息當作頂層參數 system="..." 傳入,messages 串列只放 user 與 assistant。這對提示工程有實際影響:Anthropic 的 system 提示詞不會被算進對話長度限制,長度可以更長(雖然太大會稀釋效果)。
另一個差異是 max_tokens 是必填。OpenAI 的 max_tokens 預設是 4096、可省略;Anthropic 的 max_tokens 是必填,建議根據對話性質設 256 到 4096。Claude 3.7 Sonnet 的定價比 GPT-4o 略低,長文處理特別划算。實際選擇依據:對話短、需要快速回應 → GPT-4o;對話長、需要細緻推理 → Claude 3.7 Sonnet;需要本地或成本敏感 → Llama 3.3 / Qwen 2.5 / DeepSeek R1。
Ollama 本地替代
對於沒有 API Key 的讀者,Ollama 是最佳的本地替代方案。Ollama 在 2025 年初穩定版本是 0.6 與 0.7,提供類似 OpenAI API 的 HTTP 介面(http://localhost:11434/v1/chat/completions),可以用 OpenAI SDK 直接呼叫,無需修改程式碼。本篇會用 llama3.2(Meta 2024-09 發布的輕量模型,3B 與 1B 兩種)與 qwen2.5(阿里 2024-09 發布,0.5B 到 72B)作為示範。
Ollama 的安裝很簡單:macOS / Linux 直接 curl -fsSL https://ollama.com/install.sh | sh,Windows 從官網下載安裝檔。安裝後執行 ollama serve 啟動服務(背景常駐),再 ollama pull llama3.2 下載模型(首次約 2 GB)。模型下載後會保留,後續重啟 Ollama 不需重拉。用 ollama list 可以看到已下載的模型與版本。
用 OpenAI SDK 連 Ollama 時,要把 base_url 設成 http://localhost:11434/v1、api_key 設成任意字串(Ollama 不驗證)。這樣同一支程式可以同時跑雲端(OpenAI)與本地(Ollama),只要改兩個參數。本篇會把這個設計做成 build_client() 函式,呼叫端用 backend="openai" 或 backend="ollama" 切換。
完整實作:GPT-4o、Claude 3.7 Sonnet、Llama 3.2
以下範例涵蓋三個 API 的基本呼叫,並把 Ollama 包成與 OpenAI 相容的形式。執行前請先 pip install openai==1.61.0 anthropic==0.40.0 httpx。有 API Key 的讀者請先在環境變數設定 OPENAI_API_KEY 與 ANTHROPIC_API_KEY;沒有的讀者請裝 Ollama 並 pull llama3.2。
# 1. 讀取環境變數,並設計後端切換層
import os
from openai import OpenAI
from anthropic import Anthropic
def build_client(backend: str):
"""根據 backend 回傳對應的 LLM 客戶端。"""
if backend == "openai":
api_key = os.environ["OPENAI_API_KEY"] # 從環境變數讀取
return OpenAI(api_key=api_key), "openai", "gpt-4o"
if backend == "anthropic":
api_key = os.environ["ANTHROPIC_API_KEY"]
return Anthropic(api_key=api_key), "anthropic", "claude-3-7-sonnet-latest"
if backend == "ollama":
# Ollama 的 OpenAI 相容介面;api_key 任意填(Ollama 不驗證)
return OpenAI(base_url="http://localhost:11434/v1", api_key="ollama"), "openai", "llama3.2"
raise ValueError(f"未知後端:{backend}")
# 範例:用 ollama(不需 API key)
client, kind, model = build_client("ollama")
print(f"使用 {model}(介面類型:{kind})")
# 輸出:使用 llama3.2(介面類型:openai)
build_client() 是這篇的核心設計:把三家 API 統一包成「OpenAI 介面」與「Anthropic 介面」兩種;Ollama 因為相容 OpenAI API,所以可以直接用 OpenAI 客戶端呼叫。讀者只要改 backend 參數,就能在三個後端間切換。這對企業內部部署特別有用——研發環境用 OpenAI API 快速驗證、生產環境用 Ollama 本地部署保證資料不外流。
# 2. OpenAI 呼叫範例:GPT-4o 做客服工單分類
def chat_openai(client, model, system: str, user: str, temperature=0.0) -> str:
resp = client.chat.completions.create(
model=model,
messages=[
{"role": "system", "content": system},
{"role": "user", "content": user},
],
temperature=temperature,
max_tokens=512,
)
return resp.choices[0].message.content
# 注意:實際執行請先用 build_client("openai") 取得 client
# 這裡示範介面呼叫,實際輸出會略有不同
system_prompt = "你是客服工單分類助手。請從以下類別中選出最合適的一個:帳務、物流、帳號、技術、產品、其他。回答只用類別名稱,不要解釋。"
user_prompt = "您好,我昨天申請退款到今天還沒到帳,想查詢退款進度。"
# 假裝有 client(讀者實測時用 build_client("openai"))
# print(chat_openai(client, "gpt-4o", system_prompt, user_prompt))
# 輸出(實際數字會略有不同):
# 帳務
這個範例展示 GPT-4o 的零樣本客服分類能力。temperature 設 0 讓結果可重現;max_tokens 設 512(雖然分類只要 1–2 個字,留點 buffer)。實際執行請先把註解拿掉,並用 build_client("openai") 取得 client。我們在所有範例中保留 # print(...) 的形式,是為了讓程式碼即使沒有 API Key 也能匯入與檢查(不會在 import 時 raise KeyError)。
# 3. Anthropic 呼叫範例:Claude 3.7 Sonnet,system prompt 當頂層參數
def chat_anthropic(client, model, system: str, user: str, temperature=0.0) -> str:
resp = client.messages.create(
model=model,
system=system,
messages=[{"role": "user", "content": user}],
temperature=temperature,
max_tokens=512,
)
return resp.content[0].text
# 讀者實測範例:
# anth_client = Anthropic(api_key=os.environ["ANTHROPIC_API_KEY"])
# result = chat_anthropic(anth_client, "claude-3-7-sonnet-latest", system_prompt, user_prompt)
# print(result)
# 輸出(實際數字會略有不同):
# 帳務
Anthropic SDK 的 messages.create() 把 system 訊息當作頂層參數傳入,這是與 OpenAI SDK 的關鍵差異。回傳結構也不同:resp.content 是 [ContentBlock] 串列,每個 block 是 {type: "text", text: "..."},所以取文字要 resp.content[0].text。這個介面在 2024 年底到 2025 年初相當穩定,0.3x 與 0.4x SDK 之間也保持向下相容。
# 4. Ollama 本地替代:完整跑通的範例(不需 API Key)
def chat_ollama(prompt: str, model: str = "llama3.2") -> str:
client = OpenAI(base_url="http://localhost:11434/v1", api_key="ollama")
resp = client.chat.completions.create(
model=model,
messages=[{"role": "user", "content": prompt}],
temperature=0.0,
max_tokens=512,
)
return resp.choices[0].message.content
# 實際執行(需先 ollama serve && ollama pull llama3.2):
# result = chat_ollama(f"{system_prompt}\n\n{user_prompt}")
# print(result)
# 輸出(實際數字會略有不同):
# 帳務
Ollama 的 HTTP API 路徑是 /v1/chat/completions,與 OpenAI 完全相容;OpenAI SDK 只要把 base_url 改成 http://localhost:11434/v1 就能直接用。這是 Ollama 在 2024 年的關鍵設計選擇——走 OpenAI 相容 API 讓生態系的 SDK、工具、框架都能直接接上,大幅降低使用門檻。本篇範例把 Ollama 包成單獨函式,方便讀者直接測試;接下來我們會展示統一的幾條直線(用 build_client())。
# 5. 統一介面:把三家 API 包成同一個函式
def chat(backend: str, system: str, user: str, temperature=0.0) -> str:
client, kind, model = build_client(backend)
if kind == "openai":
return chat_openai(client, model, system, user, temperature)
return chat_anthropic(client, model, system, user, temperature)
# 完整跑通:使用 Ollama(不需 API Key)
result = chat("ollama", system_prompt, user_prompt)
print(f"[Ollama llama3.2] {result}")
# 完整跑通:使用 OpenAI(需 OPENAI_API_KEY)
# result = chat("openai", system_prompt, user_prompt)
# print(f"[OpenAI gpt-4o] {result}")
# 完整跑通:使用 Anthropic(需 ANTHROPIC_API_KEY)
# result = chat("anthropic", system_prompt, user_prompt)
# print(f"[Anthropic claude-3-7-sonnet] {result}")
# 輸出(實際數字會略有不同):
# [Ollama llama3.2] 帳務
這段把三個後端包成同一個 chat() 函式。讀者只要改 backend 參數就能切換模型,這對 A/B 測試、成本比較、品質評估很有用。實務上建議先用 Ollama 跑 baseline(無成本)、再用 OpenAI / Anthropic 跑品質比較,這樣能用最低成本決定要走哪條路線。llama3.2 在客服分類任務上表現不如 GPT-4o,但差距通常在 5–10 個百分點以內;如果差距可以接受,就可以用 Ollama 大幅壓低成本。
# 6. 多輪對話與訊息歷史
def chat_with_history(backend: str, history: list, user: str, temperature=0.0) -> tuple:
"""history 是 [{"role": "user"|"assistant", "content": "..."}] 串列。"""
messages = history + [{"role": "user", "content": user}]
client, kind, model = build_client(backend)
resp = client.chat.completions.create(
model=model,
messages=messages,
temperature=temperature,
max_tokens=512,
)
reply = resp.choices[0].message.content
return reply, messages + [{"role": "assistant", "content": reply}]
# 範例:建立一個 3 輪對話
history = [
{"role": "user", "content": "請幫我查詢訂單 12345 的物流狀態"},
{"role": "assistant", "content": "訂單 12345 目前正在配送中,預計明天送達。"},
]
# reply, history = chat_with_history("ollama", history, "請問可以指定送達時間嗎?")
# print(reply)
# 輸出(實際數字會略有不同):
# 您好,可以指定送達時間喔!我們支援上午、下午、晚上三個時段。
多輪對話的關鍵是把歷史訊息放在 messages 串列裡。隨著對話輪數增加,訊息串會越來越長,token 數也快速增加。實務上的控制:(1)每輪對話上限:客服場景通常 5–10 輪就足夠;(2)歷史訊息摘要:超過 10 輪時把前幾輪摘要成一句話;(3)token 預算:設定總 token 上限(例如 4K),超過就丟棄最舊訊息。Day 14 的提示工程會展開這些技巧。
# 7. 串流輸出(streaming):對長回應可以分塊顯示
def chat_stream(backend: str, system: str, user: str):
client, kind, model = build_client(backend)
if kind == "openai":
stream = client.chat.completions.create(
model=model,
messages=[{"role": "system", "content": system},
{"role": "user", "content": user}],
temperature=0.0,
max_tokens=1024,
stream=True,
)
for chunk in stream:
delta = chunk.choices[0].delta.content
if delta:
yield delta
# Anthropic 的串流介面類似但用 stream=True,請參考 anthropic SDK
# 使用範例(用 Ollama):
# for piece in chat_stream("ollama", "你是一個 helpful assistant", "請用 100 字介紹台灣"):
# print(piece, end="", flush=True)
# 輸出(實際數字會略有不同):
# 台灣是位於東亞的島嶼,面積約 3.6 萬平方公里,...
串流輸出是 LLM 應用的關鍵 UX 設計。沒有串流時,使用者要等模型完整生成(10–30 秒)才看到結果;有串流時,第一個 token 約 0.5 秒就出現,後續每 50–100 ms 一塊文字,使用者感覺「模型在思考、回應即時出現」。OpenAI 與 Anthropic 都用 SSE(Server-Sent Events)實作串流,Python SDK 把 SSE 包裝成 generator,直接 for 迴圈就能拿到每塊文字。Ollama 也支援串流,介面相同。
常見錯誤與踩雷
錯誤一:在程式碼裡硬寫 API Key。這是 LLM 應用最常見的安全漏洞。不管是寫在字串常數、寫在 .env 但 commit 到 git、還是寫在 config 檔,都會讓金鑰外洩。修正方式:永遠用 os.environ["..."] 讀取;Colab 用 Secrets 面板設定;本機開發用 .env 檔但加進 .gitignore;生產環境用雲端 Secrets 管理(AWS Secrets Manager、GCP Secret Manager)。
錯誤二:忘記處理 rate limit。OpenAI 免費帳號有 3 RPM 的限制,短時間大量請求會被 HTTP 429 拒絕。修正方式:用 tenacity 套件做指數退避重試,或在迴圈裡加入 time.sleep() 控制節奏。production 等級建議用佇列(queue)做節流,Day 39 會展開。
錯誤三:把整本小說丟給模型。GPT-4o 與 Claude 3.7 Sonnet 的 context window 都是 128K–200K tokens,但「塞滿」與「有效使用」是兩回事。實務上的建議:保持在 4K–32K tokens 以內,模型的注意力最穩定;超過 64K 後品質明顯下降。對長文件請用 RAG(檢索增強生成),Day 25–32 會專門展開。
錯誤四:以為 temperature=0 就能完全重現。GPT-4o 與 Claude 3.7 Sonnet 在 temperature=0 時「大部分情況」會輸出相同結果,但因為底層是 GPU 並行計算、加上內部隨機性(例如 top-p 採樣的順序),偶爾會有微小差異。對要求 bit-perfect 重現的場景(例如單元測試),需要 mock LLM 客戶端;對一般應用,temperature=0 已足夠穩定。
錯誤五:用 ollama 時忘了啟動服務。Ollama 安裝後預設不會自動啟動(macOS 例外),需要手動執行 ollama serve 或用系統服務管理器啟動。Linux 系統可用 systemctl enable ollama 設為開機啟動;macOS 用 brew services start ollama。第一次執行忘記啟動會看到 connection refused 錯誤。
錯誤六:Anthropic SDK 的 max_tokens 沒填。OpenAI 的 max_tokens 預設 4096,Anthropic 是必填。忘了傳會 raise TypeError。修正方式:永遠帶上 max_tokens,根據對話性質設 256–4096。
錯誤七:以為 ollama 的模型下載是一次性的。ollama pull 會下載模型並保留版本。模型更新時(例如 llama3.2 之後的修補版),需要重新 pull;舊版本會保留為 tag(例如 llama3.2:3b-instruct-q4_K_M)。如果想強制更新,可以 ollama pull llama3.2 --update。
效能與實務提醒
三家 API 的延遲比較:OpenAI GPT-4o 在亞太地區約 0.5–2 秒(第一個 token)、後續 50–100 ms 一個 token;Anthropic Claude 3.7 Sonnet 約 0.7–2.5 秒、50–80 ms 一個 token;Ollama 本地推論依硬體而定,llama3.2 3B 在 M1 Mac 約 1 秒(第一個 token)、後續 30–50 ms 一個 token;在 RTX 3090 上約 0.3 秒、20–40 ms 一個 token。CPU 推論約比 GPU 慢 5–10 倍,llama3.2 1B 是較好選擇。
成本比較(2025-03 行情,僅供參考):GPT-4o 約 2.5 USD / 1M input tokens、10 USD / 1M output tokens;Claude 3.7 Sonnet 約 3 USD / 1M input、15 USD / 1M output;Ollama 本地推論是免費的(電費 + 硬體折舊)。一般客服對話(輸入 200 token、輸出 100 token)單次成本約 0.0006 USD(GPT-4o)、0.0008 USD(Claude)、0 USD(Ollama)。規模化時 Ollama 的成本優勢巨大。
模型的選擇建議:預算充足、需要最高品質 → GPT-4o 或 Claude 3.7 Sonnet;需要處理長文(> 32K tokens)→ Claude 3.7 Sonnet;需要即時回應、預算敏感 → Ollama 本地 Llama 3.2 / Qwen 2.5;需要數學與程式推理 → DeepSeek R1 或 o3-mini。實務上的折衷:核心任務用 OpenAI / Anthropic、邊緣任務用 Ollama,這樣能兼顧品質與成本。
另一個重要考量是資料合規。GPT-4o 與 Claude 3.7 Sonnet 的請求會被送到 OpenAI / Anthropic 的伺服器,這對處理個資、財務資料、醫療紀錄的應用是個問題。Ollama 完全本地推論,沒有資料外流風險。對企業內部應用,建議先用 Ollama 驗證流程,再考慮是否升級到付費 API。OpenAI 也提供「Zero Data Retention」選項(API 請求不保留),但成本更高。
小結
本篇把 LLM API 的基礎建立完成:我們看了 OpenAI GPT-4o、Anthropic Claude 3.7 Sonnet、Ollama 本地替代三條路線的介面差異,並把三家包成同一個 chat() 函式方便切換。讀完這篇你應該能回答:OpenAI 與 Anthropic SDK 的關鍵差異?Ollama 怎麼提供 OpenAI 相容介面?客服分類場景怎麼選模型?API Key 要怎麼管理才安全?這些答案都藏在本篇的程式與觀念裡。明天 Day 14 我們會進入提示工程:系統提示的設計、few-shot 範例、結構化輸出、Chain-of-Thought 等技巧,把 LLM 的輸出品質推到極限。
結語
今天的重點是「打開 LLM API 的世界」。我們從單一 API 呼叫開始,到三個後端的統一介面,到多輪對話與串流輸出,建立了完整的 LLM API 工具鏈。從前幾天的 BERT 微調到今天的 LLM API,NLP 的開發模式有了本質改變:從「訓練模型」變成「設計提示」。明天,我們會深入提示工程的世界:如何用系統提示控制模型行為、如何用 few-shot 提升特定任務的表現、如何用結構化輸出讓模型回應可被程式解析。
在工業界,LLM API 與 BERT 微調不是替代關係而是互補。GPT-4o 與 Claude 3.7 Sonnet 在零樣本場景特別強(cold start),BERT 微調在大量穩定請求時成本更低(hot path)。Ollama 是另一條重要路線——完全本地、成本最低、資料不外流。下一篇進入提示工程時,會用 GPT-4o 與 Ollama 兩條路徑展示具體做法。
延伸資源
- OpenAI 官方文件(2025-03 擷取):Chat Completions API、
openaiPython SDK 1.61.x 版本(platform.openai.com/docs/api-reference/chat)。 - Anthropic 官方文件(2025-03 擷取):Messages API、
anthropicPython SDK 0.40.x 版本(docs.anthropic.com/en/api/messages)。 - Ollama 官方文件(2025-03 擷取):OpenAI 相容 API、模型清單、
ollama serve啟動指令(github.com/ollama/ollama,版本對應 Ollama 0.6 / 0.7)。 - Meta 官方發布(2024-12):Llama 3.3 模型卡,授權 Llama 3 Community License。
- 阿里官方發布(2024-09):Qwen 2.5 模型卡,授權 Apache 2.0(部分版本)。
- DeepSeek 官方發布(2025-01):DeepSeek R1 模型卡,授權 MIT。
留言
張貼留言