Claude API 教學:在 VPS 建立第一個 Python 應用程式
學會取得 Claude API key,並在 Ubuntu 24.04 安全設定。用約 60 行 Python 建立支援 streaming、型別錯誤處理與成本控制的日誌診斷工具。
建置內容
在全新的 Ubuntu 24.04 VPS 上建立一個命令列工具。將錯誤訊息或一段日誌透過 pipe 傳入後,工具會回傳 plain-English 診斷結果:journalctl -u nginx -n 50 | explain。程式大約只有 60 行 Python,卻涵蓋實際 Claude API 應用程式需要的所有要素,包括妥善儲存的 key、virtualenv、SDK 的回應結構、streaming、具型別的例外鏈結,以及讓程式自動執行的 systemd unit。
我刻意選擇這個專案。多數「第一個 API 應用程式」教學都會讓你建立一個之後不會再開啟的 chatbot。Log explainer 從第一天起就能在伺服器上發揮作用,也會迫使你處理初學者最常犯錯的兩件事:正確讀取回應物件,以及控制支出。API 按 token 計費,除了你自行設定的限制外沒有其他上限。因此,成本控制不是事後補上的措施,而是這裡的設計條件。當你進一步在同一台 VPS 的 tmux 中 執行 Claude Code 時,也需要遵循相同的規範。
從 Console 取得 API key
API 存取權在 Anthropic Console 的 platform.claude.com 中管理。先註冊,再前往 Settings → API Keys 建立 key(文件會直接連到 platform.claude.com/settings/keys)。Console 會要求你為 key 命名、設定到期時間,並將它連結至自己或 service account。Anthropic 建議正式環境服務及任何需要共用的情境使用 service account key。key 只會顯示一次,開頭為 sk-ant-,之後無法再次取回。請立即複製,或刪除後重新簽發。
費用方面,截至 October 2026,API 沒有持續提供的免費方案。Anthropic 的定價文件表示,新使用者會獲得少量免費額度以供測試;確切金額以註冊時 Console 顯示的內容為準。額度用完後,必須先為帳戶儲值,請求才會成功。這與 claude.ai 訂閱分開,API key 也不會提供聊天應用程式的存取權。Pro 方案不包含 API 額度,但 Max 與 Team 方案包含:截至 October 2026,Max 5x 每月提供 $100,Max 20x 每月提供 $200;Team 則為每個 Standard seat $20、每個 Premium seat $100,最高 $500。使用者必須從 claude.ai 的帳單設定連結 Console 組織,才能領取額度。未使用的額度會在每個計費週期結束時到期,且不適用於 Claude Code;詳細說明請參閱 Max 與 Team 每月 API 額度的運作方式。如果你正在評估訂閱方案與 API,這項取捨屬於另一個主題:你實際需要哪個 Claude 方案。
請將 key 的權限範圍限制在單一專案或伺服器。當 key 外洩時,長期來看這種情況一定會發生;你應能撤銷該 key,而不影響自己擁有的其他資源。
不要將金鑰放在 .bashrc
直覺做法是在 ~/.bashrc 中設定 export ANTHROPIC_API_KEY=sk-ant-...。不要這樣做。這會造成 3 個獨立問題:
- 所有程序都會繼承它。 在登入 shell 中匯出的環境變數會傳遞給你啟動的所有程序,包括 Web 應用程式、會將環境變數傾印到錯誤報告中的 crash reporter,以及有人忘記停用的
phpinfo()頁面。金鑰的暴露範圍會變成「此使用者曾執行過的所有程式」。 - 輸入內容會寫入
~/.bash_history。 手動執行一次 export 後,金鑰就會永久留在純文字檔案中,並同步到家目錄的每個備份。 - systemd 需要時找不到它。 服務不會讀取你的
.bashrc,因此當你將指令稿提升為 unit 時,這種做法會失效,通常在早上 6 點以神秘的 401 錯誤呈現。
伺服器上的正確做法,是建立具備 600 權限的專用環境檔案,只由需要它的程序載入:
sudo mkdir -p /opt/explain
sudo install -m 600 -o root -g root /dev/null /etc/claude-explain.env
printf 'ANTHROPIC_API_KEY=sk-ant-YOUR-KEY-HERE\n' | sudo tee /etc/claude-explain.env >/dev/null如果要避免金鑰出現在編輯器的暫存檔中,請使用 printf 的輸出搭配 tee,不要使用編輯器;無論採用哪種方式,都應使用 ls -l /etc/claude-explain.env 驗證它會讀取 -rw-------,且檔案擁有者為 root。互動式 shell 會透過包裝指令稿在每次執行時取得金鑰(如下),systemd 則透過 EnvironmentFile= 取得金鑰;root 會在降權前讀取檔案,因此服務使用者不需要具備該檔案的讀取權限。金鑰不會出現在程式碼、git、ps 輸出或 shell 歷史紀錄中。
在 venv 中安裝 SDK
Ubuntu 24.04 隨附的 Python 3.12 啟用了 PEP 668 強制機制,因此直接對系統直譯器執行 pip install anthropic 會因 error: externally-managed-environment 而失敗。這是作業系統的預期行為,請使用 virtualenv:
sudo apt update && sudo apt install -y python3-venv
sudo python3 -m venv /opt/explain/venv
sudo /opt/explain/venv/bin/pip install anthropic伺服器不需要啟用 venv:直接呼叫 /opt/explain/venv/bin/python 一律會使用 venv 中的套件。
首次呼叫並正確讀取回應
import anthropic
client = anthropic.Anthropic() # reads ANTHROPIC_API_KEY from the environment
response = client.messages.create(
model="claude-opus-5-5",
max_tokens=1000,
messages=[{"role": "user", "content": "Explain what a systemd unit file is in three sentences."}],
)
for block in response.content:
if block.type == "text":
print(block.text)這 12 行中有兩點最能說明 API 的運作模型。第一,anthropic.Anthropic() 不帶引數時會從環境變數讀取金鑰,絕對不要將金鑰直接寫成字串常值。第二,response.content 是內容區塊清單,不是字串。直接列印時,會得到初學者最常見的輸出:
[TextBlock(citations=None, text='A systemd unit file is...', type='text')]這不是錯誤,而是物件的 repr。回應可能包含多種區塊類型(文字、工具呼叫、思考內容),因此應逐一迭代,先檢查 block.type == "text",再存取 .text。在 Opus 5.5 上,這從第一次呼叫就很重要:思考功能一律啟用,因此除非模型在簡單請求上略過思考,清單開頭會是 thinking 區塊,其文字預設為空,而 response.content[0].text 並不是你的答案。從第一天就加入這段迴圈,便能避免一整類「怎麼印出垃圾內容」的混淆。
請使用確切的模型 ID claude-opus-5-5。從 4.6 世代開始,模型 ID 不含日期,而不含日期的 ID 就是固定的 snapshot,因此不要沿用在目前模型 ID 後方加上日期後綴的習慣(或舊部落格文章中的做法);這會產生 404,詳情如下。較舊的模型則相反:Haiku 4.5 的 canonical ID 是帶日期的 claude-haiku-4-5-20251001。
實際工具:說明
以下是完整程式:從 stdin 讀取輸入,串流輸出診斷結果,並處理錯誤:
#!/usr/bin/env python3
"""explain: pipe an error or log excerpt in, get a diagnosis out."""
import sys
import anthropic
MODEL = "claude-opus-5-5"
def main() -> int:
text = sys.stdin.read().strip()
if not text:
print("usage: journalctl -u nginx -n 50 | explain", file=sys.stderr)
return 1
client = anthropic.Anthropic()
try:
with client.messages.stream(
model=MODEL,
max_tokens=4096,
system=(
"You are a senior Linux sysadmin. The user pipes you server "
"logs or error output. Name the most likely cause outright, "
"then give the commands to confirm and fix it. Be terse."
),
messages=[{"role": "user", "content": text}],
) as stream:
for chunk in stream.text_stream:
print(chunk, end="", flush=True)
print()
except anthropic.RateLimitError as e:
retry_after = e.response.headers.get("retry-after", "60")
print(f"rate limited; retry in {retry_after}s", file=sys.stderr)
return 2
except anthropic.APIStatusError as e:
print(f"API error {e.status_code}: {e.message}", file=sys.stderr)
return 2
except anthropic.APIConnectionError:
print("network error reaching the API", file=sys.stderr)
return 2
return 0
if __name__ == "__main__":
sys.exit(main())將它儲存為 /opt/explain/explain.py,然後加入一個 wrapper,在互動式使用時載入 key:
sudo tee /usr/local/bin/explain >/dev/null <<'EOF'
#!/bin/sh
set -a; . /etc/claude-explain.env; set +a
exec /opt/explain/venv/bin/python /opt/explain/explain.py "$@"
EOF
sudo chmod 755 /usr/local/bin/explain(wrapper 必須透過 sudo 執行,或將 env file 設定為 admin user 所屬群組可讀取。請明確選擇其中一種,不要將檔案權限放寬為 644。)
為何使用串流。 client.messages.stream 會在 tokens 到達時立即列印,而不是在完整生成結果前保持無輸出狀態。這也能避開長輸出的 HTTP timeout;SDK 在非串流呼叫中,基於相同原因,會拒絕過大的 max_tokens 值。text_stream 只會產生回答文字;在 Opus 5.5 的預設 thinking 顯示設定下,不會串流任何 thinking 文字,因此輸出能保持乾淨。如果之後需要組合完成的物件,請在 with 區塊內呼叫 stream.get_final_message()。
為何採用這個例外順序。 SDK 會依特定程度由高至低擲出具型別的例外:RateLimitError 表示 429,並包含 retry-after header,指出需要等待多久;APIStatusError 涵蓋其他非 2xx 回應(請檢查 e.status_code >= 500 是否為伺服器端問題);APIConnectionError 表示請求完全沒有取得回應。在建立 retry loop 前,請先注意:SDK 已自行重試 429 與 5xx 錯誤,預設會使用 exponential backoff 重試 2 次(client 上的 max_retries)。執行 except 時,重試已經用盡,因此 CLI 的正確做法是回報錯誤並結束,而不是休眠後持續發送請求。
成本控制
這一節需要獨立說明,因為 API 沒有內建的每月上限,能否控制支出完全取決於你的設定;而且這裡的每個錯誤都會在不易察覺的情況下持續累積。
max_tokens 是每次呼叫的支出上限。 輸出 token 的費用較高;在 Opus 5.5 上,輸入價格的 5 倍,而 max_tokens 會硬性限制模型最多可產生的 token 數量。失控的提示內容不會讓輸出費用超過你允許的上限。在 5.5 模型上,這個上限也包含 thinking:thinking token 會計入 max_tokens,並按照輸出計費,即使 thinking 文字不會回傳給你。應依工作內容設定上限:4,096 足以讓簡短的日誌診斷完成必要的思考;分類工作需要的上限則低得多。如果回應以 stop_reason: "max_tokens" 提前結束,表示上限設得太低。此時應有意識地調高上限,或降低 effort 設定,讓模型減少思考;不要直接改用過大的值。
傳送前先計算。 輸入也需要付費,而且日誌通常很大。API 提供免費的計算 endpoint,但它有獨立於訊息建立功能的 rate limit:
count = client.messages.count_tokens(
model="claude-opus-5-5",
messages=[{"role": "user", "content": big_log_text}],
)
print(count.input_tokens)請用它避免意外透過工具傳送 2 GB 的日誌,並傳入實際要呼叫的模型:Claude 4.7 及後續模型使用較新的 tokenizer;對相同文字產生的 token 數量約比較早期的 Claude 模型多 30%。不要使用 tiktoken 進行計算,因為那是 OpenAI 的 tokenizer,不是 Claude 的 tokenizer,因此計算結果不會符合實際計費數量。
依工作選擇模型,不要只因偏好而固定使用同一個模型。 截至 October 2026,Opus 5.5(claude-opus-5-5)每 1 million 個輸入 token 收費 $4,每 1 million 個輸出 token 收費 $20;Haiku 5.5(claude-haiku-5-5)在不超過 100,000 個 token 的提示中,價格為 $0.10/$0.50,超過該數量則為 $0.50/$2.50,並提供 1M context;Sonnet 5.5(claude-sonnet-5-5)介於兩者之間,價格為 $2/$10。具體而言,包含 2,000 個 token 的日誌摘錄和 500 個 token 回答,在 Opus 上的費用約為 $0.018,在 Haiku 上約為 $0.00045,另加模型進行 thinking 的費用;thinking 按輸出計費。評估輸出品質時先使用 Opus,再以相同提示測試 Haiku。對於高流量、簡單的轉換工作,Haiku 通常難以分辨品質差異,但每個 token 的價格只有 Opus 的四十分之一。在將這些數字硬編碼到預算前,請先到 pricing page 確認目前價格。
任何可以延後的工作都使用 Batches。 Batches API 會以標準價格的 50% 非同步處理請求,而且大多數 batch 能在 1 小時內完成。每日摘要、backfill、大量分類,以及任何不需要人員等待結果的工作,都適合使用 Batches。
對重複的 context 使用 prompt caching。 如果每次呼叫都會重新傳送相同的大型 system prompt 或 runbook,請將它標記為可快取:
response = client.messages.create(
model="claude-opus-5-5",
max_tokens=1000,
system=[{
"type": "text",
"text": RUNBOOK_TEXT, # the same 30K tokens on every call
"cache_control": {"type": "ephemeral"},
}],
messages=[{"role": "user", "content": question}],
)
print(response.usage.cache_read_input_tokens) # non-zero from the second call on在 5 分鐘的 TTL 內,cache write 的費用是輸入價格的 1.25 倍;在 Opus 5.5 和 Sonnet 5.5 上,cache read 的費用是輸入價格的 0.05 倍,在大多數其他模型上則為 0.1 倍。因此,快取有效期間的第二次呼叫就已足以抵銷第一次呼叫的快取成本。這裡有兩點需要注意。快取的 prefix 必須達到每個模型的最低 token 數量;Opus 5.5 的最低值為 512 個 token,因此過短的 system prompt 會在沒有明確提示的情況下完全不進行快取。此外,如果相同呼叫中的 cache_read_input_tokens 持續為零,表示你的 prefix 在每次請求中都有變更,最常見的原因是包含 timestamp。
記住哪些內容會計入輸入。 System prompt、tool definition,以及多輪對話中每一輪重新傳送的完整歷史紀錄,都會按照輸入 token 計費。從不刪減歷史紀錄的 chat loop 會讓成本以二次方成長。在建立任何 conversational 功能前,值得先了解完整的計費方式:Claude token 使用量與實際計費方式。
以 systemd 執行
遵循環境檔案的規範後,就能設定一個 timer,每天早上摘要前一天的錯誤。
# /etc/systemd/system/log-digest.service
[Unit]
Description=Daily error-log digest via the Claude API
[Service]
Type=oneshot
User=explain
Group=systemd-journal
EnvironmentFile=/etc/claude-explain.env
ExecStart=/bin/sh -c 'journalctl -p err --since yesterday | /opt/explain/venv/bin/python /opt/explain/explain.py >> /var/log/log-digest.txt'# /etc/systemd/system/log-digest.timer
[Unit]
Description=Run the log digest every morning
[Timer]
OnCalendar=06:15
Persistent=true
[Install]
WantedBy=timers.targetsudo useradd -r -s /usr/sbin/nologin explain
sudo touch /var/log/log-digest.txt && sudo chown explain /var/log/log-digest.txt
sudo systemctl daemon-reload
sudo systemctl enable --now log-digest.timer
sudo systemctl start log-digest.service # test it once, right now請注意 EnvironmentFile= 的作用:systemd 會在切換至非特權 explain 使用者前,先讀取由 root 擁有且模式為 600 的檔案,因此程序可以取得該變數,而該使用者無法讀取金鑰檔案。systemd-journal 群組則授予日誌存取權。請先手動測試 systemctl start 並讀取 journalctl -u log-digest.service,不要等到 06:15 才發現拼字錯誤。當這種模式不再適合以 shell pipeline 處理時,同樣的金鑰置於環境檔案的方法,也能直接套用至同一台主機上的 由 Claude 驅動的 n8n 工作流程。
會看到的錯誤情況與訊息
使用中的 key 卻回傳 401。 例外訊息如下:
anthropic.AuthenticationError: Error code: 401 - {'type': 'error', 'error': {'type': 'authentication_error', 'message': 'invalid x-api-key'}, 'request_id': 'req_011CSHoEeqs5C35K2UUqR7Fy'}如果 key 在 shell 中可正常使用,但服務回傳 401,表示服務根本沒有收到該 key。請記住,systemd 不會讀取 .bashrc;請確認 EnvironmentFile= 指向正確路徑。其他原因包括:將引號貼入環境檔(ANTHROPIC_API_KEY="sk-ant-...";systemd 會移除引號,但如果 shell wrapper 的 . file 使用了不正確的引號,則引號會保留在值中)、尾端空白、上週在 Console 撤銷的 key,或 key 已到達建立時指定的到期時間。
模型名稱拼寫錯誤而回傳 404。 最常見的情況,是對沒有日期版本的 model ID 加上日期尾碼:
anthropic.NotFoundError: Error code: 404 - {'type': 'error', 'error': {'type': 'not_found_error', 'message': 'model: claude-opus-5-5-20260922'}, 'request_id': 'req_011CSJqymAvNw4bT3qmDdMbA'}目前世代的 ID 必須完全依照文件書寫,包括 claude-opus-5-5、claude-sonnet-5-5、claude-haiku-5-5、claude-fable-5-1。4.6 世代以前的模型是例外:claude-haiku-4-5 是日期版 ID claude-haiku-4-5-20251001 的便利別名,兩種寫法都能使用。請從 models 文件複製 ID,不要憑記憶輸入,也不要從舊教學複製。
429 rate_limit_error。 錯誤類型字串是 rate_limit_error,回應會帶有 retry-after header,其中包含需要等待的秒數。在你看到例外之前,SDK 已使用 backoff 重試 2 次,因此持續出現 429 表示你的持續請求速率確實超過所屬 tier。請將工作分批或分散處理,不要縮短重試間隔。
輸出的是物件,不是文字。 輸出看起來像 [TextBlock(citations=None, text='...', type='text')]。你輸出了 response.content,而不是逐一處理 blocks,並從 block.type == "text" 的項目讀取 .text。上方的每個 SDK 範例都已正確處理,請直接複製該迴圈。
error: externally-managed-environment。 你在 Ubuntu 24.04 的 system Python 上執行了 pip install。請使用 venv;在重要的伺服器上不要執行 --break-system-packages。
回答遭截斷。 response.stop_reason == "max_tokens" 表示模型在輸出上限用盡時仍處於產生內容的過程中。這是預期行為;請視需要提高上限。另請注意,在 5.5 models 上,思考內容也會佔用相同的上限。
第一個應用程式運作後,使用 Claude 建立 AI agent 可將相同的 API 呼叫轉換成會使用工具的 agent。
FAQ
試用 Claude API 需要多少費用?
對這類工具而言,實際費用非常低。截至 2026 年 10 月,Opus 5.5 每 1 百萬個輸入 token 收費 $4,每 1 百萬個輸出 token 收費 $20。因此,一般的日誌診斷會輸入幾千個 token、輸出幾百個 token,在計入作為輸出計費的 thinking token 前,費用約為兩美分;使用 Haiku 5.5($0.10/$0.50)時,則遠低於十分之一美分。每天產生摘要一個月的費用不到一杯咖啡。真正的風險不是單次呼叫費用,而是無限制的迴圈與無限制的 max_tokens,因此本指南會明確設定這兩項限制。
Claude API 有免費方案嗎?
截至 2026 年 10 月,沒有持續提供的免費方案。Anthropic 的定價文件指出,新使用者會獲得少量免費額度來測試 API,這是一次性的試用額度;確切金額會在註冊 Console 時顯示,之後需要自行為帳戶儲值。Max 與 Team 訂閱者例外:其方案包含每月 API 額度,前文已有說明。如果你的目標是讓每次請求都不產生額外費用,而不是追求最先進的品質,另一個選擇是使用 Ollama 自行託管開放權重模型,以 RAM 取代 token 費用。
如何在伺服器上保護 API key?
絕對不要將 API key 放在程式碼或 git 中,也不要從 .bashrc 匯出,更不要直接輸入會被 shell 歷史記錄保存的命令列。請將它放在由 root 擁有且具備 600 權限的檔案中,並依程序載入;互動式使用時可透過包裝腳本,systemd 則使用 EnvironmentFile=。每台伺服器或每個專案使用一組獨立的 key,這樣洩漏後即可撤銷單一 key,而不必影響其他環境。如果 key 曾出現在貼文網站或 git commit 中,請立即在 Console 撤銷;刪除 commit 並不會消除已洩漏的 key。
應該從哪個 Claude 模型開始?
在評估輸出是否足以作為後續建置基礎時,先從 claude-opus-5-5 開始。此時你需要以完整品質判斷這個構想,而在業餘使用量下,費用差異只有幾美分。提示詞確定後,使用實際輸入重新執行 claude-haiku-5-5;對摘要、分類與日誌分流而言,它通常已具備足夠品質,且每個 token 的價格只有前者的四十分之一。應根據實際測量結果切換至 Haiku 或 Sonnet,不要預設選用其中之一。