Claude API tutorial: unang Python app sa Ubuntu VPS
Gumawa ng Claude log explainer sa Ubuntu 24.04 gamit ang Python, streaming, typed errors, secure API key, systemd, at limitasyon sa token cost.
Ang bubuuin mo
Isang command-line tool sa bagong Ubuntu 24.04 VPS na tatanggap ng error message o bahagi ng log sa pamamagitan ng pipe at magbabalik ng diagnosis sa payak na English: journalctl -u nginx -n 50 | explain. Humigit-kumulang 60 linya lamang ito ng Python, at ginagamit nito ang lahat ng mahalagang bahagi ng isang totoong Claude API application: wastong pag-store ng key, virtualenv, mga anyo ng response ng SDK, streaming, typed exception chain, at isang systemd unit para awtomatiko itong tumakbo.
Sinadya kong piliin ang proyektong ito. Sa karamihan ng tutorial para sa “first API app,” bubuo ka ng chatbot na malamang ay hindi mo na muling bubuksan. Kapaki-pakinabang ang log explainer sa isang server mula pa sa unang araw, at pinagdaraanan nito ang dalawang bagay na karaniwang nagiging mali sa mga beginner: tamang pagbasa sa response object at pagkontrol sa gastusin. Sinisingil ng API ang bawat token, at walang ibang ceiling maliban sa mga itatakda mo. Kaya bahagi ng disenyo rito ang pagkontrol sa gastos, hindi ito idinadagdag sa huli. Ito rin ang parehong disiplina na kakailanganin mo kapag umabot ka na sa pagpapatakbo ng Claude Code sa parehong VPS na ito gamit ang tmux.
Kumuha ng API key mula sa Console
Pinamamahalaan ang API access sa Anthropic Console sa platform.claude.com. Mag-sign up, pagkatapos ay gumawa ng key sa Settings → API Keys. Direktang nagli-link ang docs sa platform.claude.com/settings/keys. Isang beses lang ipinapakita ang key, nagsisimula ito sa sk-ant-, at hindi na ito maaaring makuha muli. Kopyahin ito kaagad, o i-delete at gumawa ng bagong key.
Tungkol sa gastos: noong July 2026, walang patuloy na libreng tier para sa API. Ayon sa pricing docs ng Anthropic, tumatanggap ang mga bagong user ng maliit na halaga ng libreng credits para sa testing. Ang eksaktong halaga ay kung ano ang ipinapakita ng Console kapag nag-sign up ka. Kapag naubos ito, kailangan mong lagyan ng pondo ang account bago magtagumpay ang mga request. Hiwalay ito sa subscription sa claude.ai. Hindi kasama sa Pro o Max plan ang API credit, at hindi nagbibigay ng chat app ang isang API key. Kung pinag-iisipan mo ang subscription kumpara sa API, hiwalay na paksa ang trade-off na iyon: kung aling Claude plan ang talagang kailangan mo.
Gumawa ng key na naka-scope sa isang project o server lamang. Kapag nag-leak ang isang key, at sa paglipas ng sapat na panahon ay mangyayari ito, dapat mo itong ma-revoke nang hindi naaapektuhan ang lahat ng iba pang pagmamay-ari mo.
Ilayo ang key sa .bashrc
Ang karaniwang unang hakbang ay export ANTHROPIC_API_KEY=sk-ant-... sa ~/.bashrc. Huwag itong gawin. Tatlong magkakahiwalay na problema ang dulot nito:
- Namamana ito ng bawat process. Ang environment variable na ini-export sa iyong login shell ay naipapasa sa lahat ng sinisimulan mo—sa web app, sa crash reporter na awtomatikong nagda-dump ng environment nito sa bug report, at sa
phpinfo()page na naiwan mong naka-enable. Ang exposure surface ng key ay nagiging “lahat ng pinapatakbo ng user na ito.” - Napupunta ito sa
~/.bash_historykapag tina-type mo. Kapag isang beses mong manu-manong pinatakbo ang export, mananatili ang key sa isang plaintext file at maisasama sa bawat backup ng iyong home directory. - Wala ito kapag kailangan na ito ng systemd. Hindi binabasa ng mga service ang iyong
.bashrc, kaya eksaktong pumapalya ang pattern kapag ginawa mong unit ang script. Karaniwang lumalabas ito bilang misteryosong 401 sa ganap na 6 a.m.
Ang tamang pattern sa server ay isang dedicated environment file na may 600 permissions. Ilo-load lamang ito ng process na nangangailangan nito:
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/nullGamitin ang tee mula sa isang printf sa halip na editor kung gusto mong hindi mapunta ang key sa editor swap files. Alinmang paraan ang gamitin mo, i-verify gamit ang ls -l /etc/claude-explain.env na binabasa nito ang -rw------- at pagmamay-ari ito ng root. Tinatanggap ng interactive shells ang key sa bawat invocation sa pamamagitan ng wrapper (sa ibaba). Tinatanggap naman ito ng systemd sa pamamagitan ng EnvironmentFile=. Binabasa ng root ang file bago mag-drop ng privileges, kaya hindi kailangang magkaroon ng read access dito ang service user. Hindi kailanman lumalabas ang key sa code, sa git, sa ps output, o sa shell history.
I-install ang SDK sa isang venv
May Python 3.12 ang Ubuntu 24.04 at ipinapatupad nito ang PEP 668, kaya mabibigo ang direktang pip install anthropic gamit ang system interpreter at lalabas ang error: externally-managed-environment. Inaasahan ang error na ito dahil gumagana ang OS ayon sa disenyo nito. Gumamit ng virtualenv:
sudo apt update && sudo apt install -y python3-venv
sudo python3 -m venv /opt/explain/venv
sudo /opt/explain/venv/bin/pip install anthropicHindi kailangang i-activate ang venv sa server. Kapag direktang tinawag ang /opt/explain/venv/bin/python, palaging gagamitin nito ang mga package ng venv.
Unang tawag at tamang pagbasa ng response
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)Dalawang bagay sa labindalawang linyang iyon ang bumubuo sa malaking bahagi ng mental model ng API. Una, binabasa ng anthropic.Anthropic() na walang arguments ang key mula sa environment; huwag itong ipasa bilang string literal. Ikalawa, ang response.content ay isang listahan ng mga content block, hindi isang string. Kapag direktang ni-print mo ito, makukuha mo ang karaniwang output ng mga unang beses pa lamang gumamit:
[TextBlock(citations=None, text='A systemd unit file is...', type='text')]Hindi ito bug; ito ang repr ng object. Maaaring maglaman ang mga response ng maraming uri ng block, gaya ng text, tool calls, at thinking. Kaya i-iterate ang mga ito at suriin ang block.type == "text" bago gamitin ang .text. I-wire ang loop na ito sa unang araw pa lang upang maiwasan ang isang buong klase ng kalituhan na “garbage ang pini-print nito.”
Gamitin ang eksaktong model ID na claude-opus-4-8. Walang petsa ang mga ID ng kasalukuyang generation. Huwag sundin ang nakasanayan o ang sinasabi ng lumang blog post na magdagdag ng date suffix; magreresulta ito sa 404, na tatalakayin sa ibaba.
Ang aktuwal na tool: paliwanag
Narito ang buong program: tumatanggap ng input mula sa stdin, naglalabas ng diagnosis habang nagpo-process, at humahawak ng mga error:
#!/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())I-save ito bilang /opt/explain/explain.py, pagkatapos ay magdagdag ng wrapper na naglo-load ng key para sa interactive use:
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(Kailangang tumakbo ang wrapper sa pamamagitan ng sudo, o kailangang may group ang env file na kinabibilangan ng iyong admin user. Pumili nang sinadya; huwag basta luwagan ang permission ng file sa 644.)
Bakit streaming. Ang client.messages.stream ay nagpi-print ng mga token habang dumarating ang mga ito sa halip na manatiling walang output hanggang matapos ang buong generation. Nalalampasan din nito ang HTTP timeouts sa mahahabang output. Sa non-streaming calls, talagang tatanggihan ng SDK ang napakalalaking value ng max_tokens dahil mismo sa kadahilanang iyon. Kung kailangan mo ang nabuong object pagkatapos, tawagin ang stream.get_final_message() sa loob ng with block.
Bakit ganoon ang pagkakasunod-sunod ng mga exception. Typed exceptions ang ibinabato ng SDK, mula sa pinakaespesipiko: ang RateLimitError ay 429 at may dalang retry-after header na nagsasabi kung gaano katagal maghintay; ang APIStatusError ay para sa iba pang non-2xx response (tingnan ang e.status_code >= 500 kapag server-side ang problema); ang APIConnectionError ay nangangahulugang walang response na natanggap ang request. At bago ka gumawa ng retry loop: awtomatikong nagre-retry na ang SDK ng 429 at 5xx errors, dalawang beses bilang default gamit ang exponential backoff (max_retries sa client). Kapag tumakbo na ang iyong except, nagamit na ang lahat ng retry. Kaya sa isang CLI, ang tamang gawin ay mag-report at mag-exit, hindi maghintay at paulit-ulit na magpadala ng request.
Kontrol sa gastos
Nararapat itong magkaroon ng sariling seksyon dahil walang built-in na buwanang cap ang API bukod sa iko-configure mo, at ang bawat pagkakamali rito ay tahimik na naiipon.
max_tokens ang iyong maximum na gastos sa bawat call. Mas mahal ang output tokens kaysa input tokens—limang beses ng input price sa Opus 4.8—at ang max_tokens ang hard cap sa dami ng output tokens na maaaring gawin ng model. Hindi maaaring lumampas ang gastos sa output ng runaway prompt sa limit na itinakda mo. Iakma ito sa task: sapat na ang 1,500 para sa pag-diagnose ng log; 100 naman para sa classification task. Kung humihinto sa gitna ng pangungusap ang mga response na may stop_reason: "max_tokens", masyadong mababa ang itinakda mong limit; itaas ito nang sinasadya sa halip na gumamit agad ng napakalaking value.
Magbilang muna bago magpadala. May gastos din ang input, at malalaki ang mga log. May counting endpoint ang API na libre gamitin, pero mayroon itong sariling rate limits na hiwalay sa message creation:
count = client.messages.count_tokens(
model="claude-opus-4-8",
messages=[{"role": "user", "content": big_log_text}],
)
print(count.input_tokens)Gamitin ito upang maiwasan ang aksidenteng pag-pipe ng 2 GB na log sa tool. Huwag gamitin ang tiktoken para rito. Tokenizer ito ng OpenAI, at karaniwan nitong minamaliit nang humigit-kumulang 15–20% ang bilang ng Claude tokens sa ordinaryong text, at mas malaki pa ang diperensya sa code.
Piliin ang model ayon sa task, hindi dahil nakasanayan mo na ito. Noong July 2026, ang Opus 4.8 (claude-opus-4-8) ay nagkakahalaga ng $5 bawat million input tokens at $25 bawat million output tokens; ang Haiku 4.5 (claude-haiku-4-5) ay $1/$5 na may 200K context; nasa pagitan ang Sonnet 5 (claude-sonnet-5) sa $3/$15, na may introductory pricing na $2/$10 hanggang August 31, 2026. Sa aktuwal na paggamit, ang 2,000-token na log excerpt na may 500-token na sagot ay nagkakahalaga ng humigit-kumulang $0.0225 sa Opus at $0.0045 sa Haiku. Magsimula sa Opus habang sinusuri mo ang kalidad ng output, pagkatapos ay subukan ang parehong prompts sa Haiku. Para sa high-volume at simpleng transformations, madalas ay hindi mapapansin ang pagkakaiba sa ikalimang bahagi ng presyo. I-verify ang kasalukuyang mga halaga sa pricing page bago ilagay ang alinman dito bilang hard-coded na bahagi ng budget.
Gumamit ng Batches para sa mga task na maaaring maghintay. Pinoproseso ng Batches API ang mga request nang asynchronous sa 50% ng standard prices, at karaniwang natatapos ang karamihan ng batches sa loob ng isang oras. Dito dapat ilagay ang nightly digests, backfills, bulk classification, at anumang task na hindi hinihintay ng tao habang tumatakbo.
Gamitin ang prompt caching para sa paulit-ulit na context. Kung ipinapadala sa bawat call ang parehong malaking system prompt o runbook, markahan itong cacheable:
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 onAng cache writes ay nagkakahalaga ng humigit-kumulang 1.25x ng input price, habang ang cache reads ay humigit-kumulang 0.1x, na may 5-minute TTL. Dahil dito, nababawi na ng ikalawang call sa loob ng window ang gastos ng una. May dalawang dapat tandaan. Kailangang lumampas sa per-model minimum ang cached prefix, na ilang libong tokens sa Opus, kaya maaaring hindi talaga ma-cache ang maikling system prompt. At kung nananatiling zero ang cache_read_input_tokens sa magkakaparehong call, may bahagi ng prefix na nagbabago sa bawat request; karaniwang sanhi nito ang timestamp.
Tandaan kung ano ang binibilang bilang input. Kasama sa sinisingil na input tokens ang system prompts, tool definitions, at, sa multi-turn conversations, ang buong history na ipinapadala mo sa bawat turn. Ang chat loop na hindi nagta-trim ng history ay lumalaki ang gastos nang quadratically. Mahalagang maunawaan ang buong accounting bago gumawa ng conversational system: kung paano aktuwal na nabibilang at sinisingil ang Claude token usage.
Patakbuhin ito sa ilalim ng systemd
Ang pakinabang ng maayos na pamamahala ng environment file: isang timer na nagbubuod ng mga error kahapon tuwing umaga.
# /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 nowTandaan kung ano ang naibibigay sa iyo ng EnvironmentFile=: binabasa ng systemd ang file na pagmamay-ari ng root at may mode na 600 bago bumaba sa walang-pribilehiyong user na explain, kaya natatanggap ng proseso ang variable habang hindi mababasa ng user ang key file. Nagbibigay ang group na systemd-journal ng access sa logs. Subukan gamit ang manual na systemctl start at basahin ang journalctl -u log-digest.service; huwag maghintay hanggang 06:15 para matuklasan ang typo. Kapag lumampas na sa kakayahan ng shell pipeline ang pattern na ito, magagamit din ang parehong approach na key-in-env-file sa mga n8n workflow na pinapagana ng Claude sa parehong server.
Mga failure mode at mga string na makikita mo
401 sa gumaganang key. Ganito ang exception:
anthropic.AuthenticationError: Error code: 401 - {'type': 'error', 'error': {'type': 'authentication_error', 'message': 'invalid x-api-key'}, 'request_id': 'req_011CSHoEeqs5C35K2UUqR7Fy'}Kung gumagana ang key sa shell mo pero nagbabalik ng 401 ang service, hindi ito kailanman natanggap ng service. Tandaan na hindi binabasa ng systemd ang .bashrc; tingnan kung ang EnvironmentFile= ay nakaturo sa tamang path. Iba pang posibleng sanhi: may mga quote na nakopya sa env file (ANTHROPIC_API_KEY="sk-ant-..."; inaalis ng systemd ang mga quote, pero pinananatili ng . file ng shell wrapper mo ang mga ito sa value kung kakaiba ang pagkaka-quote mo), may trailing whitespace, o na-revoke mo noong nakaraang linggo sa Console ang key.
404 dahil sa maling model ID. Ang pinakakaraniwang bersyon nito ay ang pagdaragdag ng date suffix sa kasalukuyang 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'}Dapat eksakto ang pagkakasulat ng mga ID ng kasalukuyang generation: claude-opus-4-8, claude-haiku-4-5, claude-sonnet-5. Kopyahin ang mga ito mula sa models documentation, hindi mula sa memorya o lumang tutorial.
429 rate_limit_error. Ang error type string ay rate_limit_error, at may retry-after header ang response na naglalaman ng mga segundong dapat hintayin. Dalawang beses nang nag-retry ang SDK na may backoff bago mo makita ang exception. Kaya kung tuloy-tuloy ang 429, tunay na lumalampas ang sustained rate mo sa limit ng tier mo. I-batch ang work o hatiin ito sa mas mahabang panahon. Huwag pabilisin ang retry loop.
Ang object ang pini-print nito, hindi ang text. Ganito ang hitsura ng output: [TextBlock(citations=None, text='...', type='text')]. Na-print mo ang response.content sa halip na i-iterate ang blocks at basahin ang .text mula sa mga block kung saan block.type == "text". Tama itong ginagawa ng bawat SDK example sa itaas; kopyahin ang loop.
error: externally-managed-environment. Pinatakbo mo ang pip install gamit ang system Python ng Ubuntu 24.04. Gamitin ang venv. Huwag gamitin ang --break-system-packages sa server na mahalaga sa iyo.
Napuputol na mga sagot. Ibig sabihin ng response.stop_reason == "max_tokens" ay naabot ng model ang output cap habang hindi pa tapos ang sagot. Inaasahan itong behavior. Itaas ang cap nang sinasadya.
Kapag gumagana na ang una mong app, ang pagbuo ng AI agent gamit ang Claude ay ginagawang agent ang parehong API call na gumagamit ng tools.
FAQ
Magkano ang gastos para subukan ang Claude API?
Talagang mababa ito para sa ganitong tool. Noong July 2026, nagkakahalaga ang Opus 4.8 ng $5 bawat milyong input token at $25 bawat milyong output token. Kaya ang karaniwang log diagnosis na may ilang libong token na input at ilang daang token na output ay humigit-kumulang dalawang sentimo. Sa Haiku 4.5 ($1/$5), wala pang kalahating sentimo ang gastos. Mas mababa sa halaga ng isang kape ang gastos sa isang buwang daily digest. Hindi ang presyo bawat request ang pangunahing panganib. Ang panganib ay walang limitasyong loop at walang limitasyong max_tokens. Kaya parehong tahasang sine-set ang mga ito sa guide na ito.
May libreng tier ba para sa Claude API?
Walang patuloy na libreng tier noong July 2026. Ayon sa pricing documentation ng Anthropic, nakakatanggap ang mga bagong user ng maliit na halaga ng libreng credits para subukan ang API. One-time trial ito, at ipinapakita sa Console ang eksaktong halaga kapag nag-sign up. Pagkatapos nito, kailangan mong pondohan ang account. Kung ang layunin mo ay zero marginal cost bawat request sa halip na frontier quality, ang alternatibo ay mag-self-host ng open-weight model gamit ang Ollama at gumamit ng RAM sa halip na tokens.
Paano ko mapapanatiling ligtas ang API key ko sa server?
Huwag itong ilagay sa code, sa git, o i-export mula sa .bashrc. Huwag din itong i-type sa shell kung saan mase-save ito sa history. Ilagay ito sa file na pagmamay-ari ng root at may 600 permissions. I-load ito bawat process. Para sa interactive use, gumamit ng wrapper script. Para sa systemd, gumamit ng EnvironmentFile=. Gumamit ng isang key bawat server o project upang madaling ma-revoke ang na-leak na key. Kung napunta ang key sa paste site o git commit, agad itong i-revoke sa Console. Hindi sapat ang pagbura sa commit para maalis ang leak.
Aling Claude model ang dapat kong simulan?
Magsimula sa claude-opus-4-8 habang sinusuri mo kung sapat ang kalidad ng output para gamitin bilang basehan. Sa ganitong paraan, masusuri mo ang ideya gamit ang pinakamataas na kalidad. Sa hobby-level na volume, sentimo lamang ang diperensya sa gastos. Kapag maayos na ang prompt, patakbuhin muli ang aktuwal mong inputs sa claude-haiku-4-5. Para sa summarization, classification, at log triage, madalas ay kasinghusay nito ang resulta sa ikalimang bahagi ng presyo. Pumili sa Haiku o Sonnet batay sa measurement, hindi bilang default.