SSD Nodes Learn Hosting plans →
指南 Matt Connor作者: Matt Connor · 已更新 2026-08-07

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)。key 只會顯示一次,以 sk-ant- 開頭,之後無法再次取回。請立即複製;若遺失,請刪除後重新建立。

費用方面,截至 July 2026,API 沒有持續提供的免費方案。Anthropic 的定價文件表示,新使用者會獲得少量免費額度供測試;確切額度以註冊時 Console 顯示的內容為準。額度用完後,必須先為帳戶加值,請求才會成功。這與 claude.ai 訂閱分開計算。Pro 或 Max plan 不包含 API 額度,而 API key 也不會提供 chat app。若要比較訂閱與 API,這項取捨屬於另一個主題:你實際需要哪個 Claude plan

請將 key 的權限範圍限定在單一 project 或 server。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-4-8",
    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。第一天就加入這個迴圈,可以避免整類「列印出垃圾」的困惑。

請使用確切的模型 ID claude-opus-4-8。目前世代的 ID 不含日期。請不要依照習慣,或舊部落格文章的說法,在 ID 後方加上日期後綴;這會產生 404,詳情如下。

實際工具:說明

以下是完整程式:從 stdin 讀取輸入,串流輸出診斷結果,並處理錯誤:

#!/usr/bin/env python3
"""explain: pipe an error or log excerpt in, get a diagnosis out."""
import sys
import anthropic

MODEL = "claude-opus-4-8"

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=1500,
            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 必須設定為你的管理員使用者所屬的群組。請明確選擇其中一種方式,不要直接將檔案權限放寬為 644。)

為什麼使用串流。 client.messages.stream 會在 tokens 到達時立即輸出,而不是等到完整生成結束才顯示內容。這也能避免長篇輸出造成 HTTP timeout;基於相同原因,SDK 在非串流呼叫中會拒絕過大的 max_tokens 值。如果之後需要取得組合完成的物件,請在 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 是每次呼叫的支出上限。 在 Opus 4.8 中,輸出 token 的價格是輸入 token 的 5 倍,而 max_tokens 會限制模型最多能產生的 token 數量。失控的 prompt 不會產生超過你允許上限的輸出成本。請依工作需求設定:診斷日誌時,1,500 已經足夠;分類工作則需要 100。若回應在句子中途因 stop_reason: "max_tokens" 停止,表示上限設定過低。請有意識地提高上限,不要直接改成過大的值。

傳送前先計算 token 數量。 輸入也會產生成本,而日誌通常很龐大。API 提供免費的計數端點,但它有獨立於訊息建立端點的速率限制:

count = client.messages.count_tokens(
    model="claude-opus-4-8",
    messages=[{"role": "user", "content": big_log_text}],
)
print(count.input_tokens)

請用它避免意外將 2 GB 的日誌串流給工具。不要使用 tiktoken,因為那是 OpenAI 的 tokenizer;對一般文字而言,它低估 Claude token 數量約 15–20%,對程式碼的低估幅度更大。

依工作選擇模型,不要因為偏好而固定使用同一個模型。 截至 2026 年 7 月,Opus 4.8(claude-opus-4-8)每 1 million 個輸入 token 收費 $5,每 1 million 個輸出 token 收費 $25;Haiku 4.5(claude-haiku-4-5)的價格為 $1/$5,並提供 200K context;Sonnet 5(claude-sonnet-5)介於兩者之間,價格為 $3/$15,且在 2026 年 8 月 31 日前提供 $2/$10 的導入價格。具體而言,包含 2,000 個 token 的日誌摘錄和 500 個 token 回應,在 Opus 上的成本約為 $0.0225,在 Haiku 上約為 $0.0045。評估輸出品質時,先使用 Opus;接著以相同 prompt 測試 Haiku。對於大量且簡單的轉換工作,Haiku 的結果通常難以與 Opus 區分,但價格只有五分之一。將任何價格硬編入預算前,請先在定價頁面確認目前數值。

凡是可以延後的工作,都使用 Batches。 Batches API 會以標準價格的 50% 非同步處理請求,而且大多數批次會在 1 小時內完成。夜間摘要、歷史資料回填、大量分類,以及所有不需要人工等待的工作,都適合使用 Batches。

對重複使用的 context 啟用 prompt caching。 如果每次呼叫都重新傳送相同的大型 system prompt 或 runbook,請將其標記為可快取:

response = client.messages.create(
    model="claude-opus-4-8",
    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

快取寫入的成本約為輸入價格的 1.25 倍,快取讀取約為輸入價格的 0.1 倍,TTL 為 5 分鐘。因此,在此期間的第 2 次呼叫就能開始抵銷第 1 次呼叫的成本。這裡有兩個注意事項。可快取的前置內容必須達到各模型的最低長度;Opus 的最低長度為數千個 token,因此較短的 system prompt 可能完全不會建立快取。如果 cache_read_input_tokens 在內容完全相同的呼叫中仍為 0,表示前置內容在每次請求中都有變動,最常見的原因是包含 timestamp。

記住哪些內容會計入輸入。 System prompt、tool 定義,以及多輪對話中每次重新傳送的完整歷史記錄,都會按輸入 token 計費。從不裁剪歷史記錄的 chat loop,成本會以平方級增長。在建立任何對話式功能前,請先了解完整的計費方式: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.target
sudo 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。

模型名稱拼寫錯誤導致 404。 最常見的情況,是在目前的 model ID 後面加上日期尾碼:

anthropic.NotFoundError: Error code: 404 - {'type': 'error', 'error': {'type': 'not_found_error', 'message': 'model: claude-opus-4-8-20260115'}, 'request_id': 'req_011CSJqymAvNw4bT3qmDdMbA'}

目前世代的 ID 必須完全依照原文使用,即 claude-opus-4-8claude-haiku-4-5claude-sonnet-5。請從 models documentation 複製,不要憑記憶輸入,也不要使用舊 tutorial 中的值。

429 rate_limit_error。 錯誤類型字串是 rate_limit_error,回應會帶有 retry-after header,其中包含需要等待的秒數。在你看到例外之前,SDK 已經使用 backoff 重試 2 次,因此持續收到 429 表示你的持續速率確實超過目前 tier。請分批處理或分散請求,不要縮短 retry loop 的間隔。

輸出的是物件,而不是文字。 輸出看起來像 [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" 表示模型在輸出上限處到達回答中段。這是預期行為;請審慎提高上限。

第一個應用程式運作後,使用 Claude 建立 AI agent 可將相同的 API 呼叫轉換為能使用工具的 agent。

FAQ

試用 Claude API 需要多少費用?

對這類工具而言,實際費用很低。截至 2026 年 7 月,Opus 4.8 的費用為每 100 萬個輸入 token $5、每 100 萬個輸出 token $25。因此,一次典型的日誌診斷可能使用幾千個輸入 token 和幾百個輸出 token,費用約為兩美分;使用 Haiku 4.5($1/$5)則低於半美分。每天產生摘要一個月的費用低於一杯咖啡。真正的風險不在單次呼叫費用,而在無上限的迴圈與無上限的 max_tokens,因此本指南會明確設定這兩者。

Claude API 是否提供免費方案?

截至 2026 年 7 月,沒有持續提供的免費方案。Anthropic 的定價文件表示,新使用者會取得少量免費額度,用於測試 API;這是一次性的試用額度,確切金額會在註冊時顯示於 Console,之後則需要為帳戶儲值。如果你的目標是讓每次請求的邊際成本為零,而不是追求前沿模型的品質,另一個選擇是 使用 Ollama 自行託管開放權重模型,以 RAM 取代 token 支付費用。

如何在伺服器上保護 API key?

絕不要將 API key 放在程式碼或 git 中,也不要從 .bashrc 匯出,更不要直接輸入到會保留歷史紀錄的 shell。請將它放在 root 擁有且具備 600 權限的檔案中,並依程序載入;互動式使用時採用包裝指令碼,systemd 則使用 EnvironmentFile=。每台伺服器或每個專案使用一組 key,這樣洩漏時只需撤銷該 key,不必大規模處理。如果 key 曾經出現在貼文網站或 git commit 中,請立即在 Console 撤銷;刪除 commit 並不能解除洩漏。

應該從哪個 Claude 模型開始?

在評估輸出是否足以作為後續基礎時,請先從 claude-opus-4-8 開始。你需要先以完整品質評估這個想法,而在業餘使用量下,費用差異只有幾美分。提示詞確定後,請使用 claude-haiku-4-5 重新處理實際輸入;在摘要、分類與日誌初步分析方面,它的效果通常相當於前者,但價格只有五分之一。請依據測量結果在 Haiku 或 Sonnet 之間選擇,不要預設採用其中一個。