Tutorial Claude API: Bina Aplikasi Pertama di VPS
Pelajari cara mendapatkan kunci Claude API, melindunginya di Ubuntu 24.04 dan membina alat Python sekitar 60 baris dengan penstriman serta kawalan kos.
Perkara yang anda bina
Alat baris perintah pada VPS Ubuntu 24.04 yang baharu. Anda menyalurkan mesej ralat atau sebahagian log kepadanya, lalu menerima diagnosis dalam bahasa Inggeris mudah: journalctl -u nginx -n 50 | explain. Alat ini mungkin hanya mengandungi kira-kira enam puluh baris Python. Ia merangkumi semua perkara yang diperlukan oleh aplikasi Claude API sebenar: key yang disimpan dengan betul, virtualenv, bentuk respons SDK, penstriman, rantaian pengecualian bertip, serta unit systemd supaya alat ini berjalan sendiri.
Saya memilih projek ini dengan sengaja. Kebanyakan tutorial "aplikasi API pertama" membina chatbot yang tidak akan anda buka lagi. Alat penerang log berguna pada pelayan sejak hari pertama. Alat ini juga memaksa anda memahami dua perkara yang sering tersilap dilakukan oleh pemula: membaca objek respons dengan betul dan mengawal perbelanjaan. API mengenakan bayaran berdasarkan token tanpa had selain had yang anda tetapkan. Oleh itu, kawalan kos ialah input reka bentuk dalam projek ini, bukan perkara yang difikirkan kemudian. Disiplin yang sama penting apabila anda mula menjalankan Claude Code pada VPS yang sama dalam tmux.
Dapatkan kunci API daripada Console
Akses API diuruskan dalam Anthropic Console di platform.claude.com. Daftar, kemudian cipta kunci di bawah Settings → API Keys (pautan dokumentasi terus ke platform.claude.com/settings/keys). Kunci itu dipaparkan sekali sahaja, bermula dengan sk-ant-, dan tidak boleh diperoleh semula. Salin kunci itu dengan segera atau padamkan dan keluarkan kunci baharu.
Mengenai kos: setakat July 2026, tiada free tier berterusan untuk API. Dokumentasi harga Anthropic menyatakan bahawa pengguna baharu menerima sejumlah kecil kredit percuma untuk ujian. Jumlah tepat ialah jumlah yang dipaparkan oleh Console semasa pendaftaran. Selepas kredit itu habis, anda perlu menambah dana ke akaun sebelum permintaan berjaya. Ini berasingan daripada langganan claude.ai. Pelan Pro atau Max tidak termasuk kredit API, dan kunci API tidak memberi anda akses kepada aplikasi chat. Jika anda sedang mempertimbangkan langganan berbanding API, pertukaran itu ialah topik yang berasingan: pelan Claude yang sebenarnya anda perlukan.
Cipta kunci yang dihadkan kepada satu projek atau pelayan. Jika kunci bocor, dan lambat laun perkara itu akan berlaku, anda perlu membatalkannya tanpa menjejaskan semua perkara lain yang anda miliki.
Simpan key di luar .bashrc
Tindakan spontan yang biasa dilakukan ialah export ANTHROPIC_API_KEY=sk-ant-... dalam ~/.bashrc. Jangan lakukan demikian. Terdapat tiga masalah berasingan:
- Setiap proses mewarisinya. Pemboleh ubah persekitaran yang dieksport dalam shell log masuk anda tersebar kepada semua yang anda mulakan, termasuk aplikasi web, pelapor ranap yang menyertakan persekitarannya dalam laporan pepijat, dan halaman
phpinfo()yang dibiarkan aktif. Permukaan pendedahan key menjadi "semua perkara yang pernah dijalankan oleh pengguna ini." - Menaipnya menulis ke
~/.bash_history. Jalankan perintah export secara manual sekali, lalu key anda tersimpan dalam fail teks biasa selama-lamanya dan disegerakkan ke setiap sandaran direktori rumah anda. - Key itu tiada apabila systemd memerlukannya. Perkhidmatan tidak membaca
.bashrcanda. Oleh itu, corak ini gagal apabila skrip dinaik taraf menjadi unit, biasanya sebagai ralat 401 yang tidak jelas pada pukul 6 pagi.
Corak yang betul pada pelayan ialah menggunakan fail persekitaran khusus dengan keizinan 600, yang dimuatkan hanya oleh proses yang memerlukannya:
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/nullGunakan tee daripada printf dan bukannya editor jika anda mahu mengelakkan key daripada fail swap editor. Dalam kedua-dua keadaan, sahkan dengan ls -l /etc/claude-explain.env bahawa fail itu membaca -rw------- dan dimiliki oleh root. Shell interaktif menerima key bagi setiap penggunaan melalui wrapper (di bawah), manakala systemd menerimanya melalui EnvironmentFile=. root membaca fail tersebut sebelum menggugurkan keistimewaan, jadi pengguna perkhidmatan tidak perlu mempunyai akses baca kepadanya. Key itu tidak pernah muncul dalam kod, git, output ps atau sejarah shell.
Pasang SDK dalam venv
Ubuntu 24.04 menyediakan Python 3.12 dengan penguatkuasaan PEP 668. Oleh itu, pip install anthropic terus terhadap penterjemah sistem gagal dengan error: externally-managed-environment. Ralat itu menunjukkan OS berfungsi seperti yang ditetapkan. Gunakan virtualenv:
sudo apt update && sudo apt install -y python3-venv
sudo python3 -m venv /opt/explain/venv
sudo /opt/explain/venv/bin/pip install anthropicPengaktifan tidak diperlukan pada pelayan. Panggil /opt/explain/venv/bin/python secara terus untuk sentiasa menggunakan pakej venv.
Panggilan pertama dan cara membaca respons dengan betul
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)Dua perkara dalam dua belas baris itu menerangkan sebahagian besar model mental API. Pertama, anthropic.Anthropic() tanpa argumen membaca kunci daripada persekitaran. Jangan sekali-kali menghantarnya sebagai rentetan literal. Kedua, response.content ialah senarai blok kandungan, bukan rentetan. Jika anda mencetaknya secara terus, anda akan mendapat output klasik pengguna kali pertama:
[TextBlock(citations=None, text='A systemd unit file is...', type='text')]Itu bukan pepijat; itu ialah repr objek. Respons boleh mengandungi beberapa jenis blok (teks, panggilan alat, pemikiran). Oleh itu, lakukan iterasi dan semak block.type == "text" sebelum mengakses .text. Laksanakan gelung itu sejak hari pertama supaya kekeliruan "outputnya bercelaru" tidak berlaku lagi.
Gunakan ID model tepat claude-opus-4-8. ID generasi semasa tidak mengandungi tarikh. Jangan mengikut kebiasaan lama atau catatan blog lama yang menyuruh anda menambah akhiran tarikh; tindakan itu menghasilkan 404, seperti yang diterangkan di bawah.
Alat sebenar: penjelasan
Berikut ialah program penuh: input daripada stdin, diagnosis distrim, dan ralat dikendalikan:
#!/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())Simpan sebagai /opt/explain/explain.py, kemudian tambahkan pembungkus yang memuatkan kunci untuk penggunaan interaktif:
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(Pembungkus itu perlu dijalankan melalui sudo atau fail env perlu mempunyai kumpulan yang disertai oleh pengguna pentadbir anda. Pilih salah satu dengan sengaja dan jangan melonggarkan keizinan fail kepada 644.)
Sebab penstriman. client.messages.stream mencetak token apabila token itu tiba, bukannya berdiam diri sehingga penjanaan penuh selesai. Cara ini juga mengelakkan tamat masa HTTP untuk output yang panjang. SDK sebenarnya akan menolak nilai max_tokens yang sangat besar pada panggilan bukan penstriman atas sebab yang sama. Jika anda memerlukan objek yang telah dihimpunkan selepas itu, panggil stream.get_final_message() dalam blok with.
Sebab susunan pengecualian itu. SDK menjana pengecualian berjenis, daripada yang paling khusus dahulu: RateLimitError ialah 429 dan mengandungi pengepala retry-after yang memberitahu tempoh menunggu; APIStatusError meliputi respons bukan-2xx yang lain (semak e.status_code >= 500 untuk masalah pada pihak pelayan); APIConnectionError bermaksud permintaan itu langsung tidak menerima respons. Sebelum anda membina gelung cuba semula: SDK sudah mencuba semula ralat 429 dan 5xx secara automatik, dua kali secara lalai dengan backoff eksponen (max_retries pada klien). Apabila except anda dijalankan, semua percubaan semula itu telah selesai. Oleh itu, tindakan yang betul dalam CLI ialah melaporkan ralat dan keluar, bukan tidur seketika lalu menghantar permintaan berulang kali.
Kos kawalan
Bahagian ini wajar mempunyai seksyen tersendiri kerana API tidak mempunyai had bulanan terbina dalam selain had yang anda konfigurasikan, dan setiap kesilapan di sini akan terkumpul secara senyap.
max_tokens ialah had perbelanjaan bagi setiap panggilan. Token output ialah komponen yang lebih mahal. Pada Opus 4.8, harganya lima kali ganda daripada harga input, dan max_tokens ialah had mutlak bagi jumlah token yang boleh dihasilkan oleh model. Prompt yang tidak terkawal tidak boleh menghasilkan kos output yang melebihi had yang anda tetapkan. Tetapkan saiz mengikut tugas: 1,500 token sudah mencukupi untuk diagnosis log; tugas pengelasan memerlukan 100 token. Jika respons berhenti di tengah ayat dengan stop_reason: "max_tokens", had itu terlalu rendah. Naikkannya secara sedar dan jangan terus menggunakan nilai yang terlalu besar sebagai lalai.
Kira sebelum menghantar. Input juga dikenakan bayaran, dan log biasanya besar. API mempunyai endpoint pengiraan yang boleh digunakan secara percuma. Endpoint ini mempunyai had kadar tersendiri yang berasingan daripada penciptaan mesej:
count = client.messages.count_tokens(
model="claude-opus-4-8",
messages=[{"role": "user", "content": big_log_text}],
)
print(count.input_tokens)Gunakannya untuk mengelakkan penghantaran log bersaiz 2 GB secara tidak sengaja melalui alat tersebut. Jangan gunakan tiktoken untuk tujuan ini. Itu ialah tokenizer OpenAI, dan biasanya mengira token Claude kira-kira 15–20% lebih rendah bagi teks biasa, serta lebih rendah lagi bagi kod.
Pilih model mengikut tugas, bukan kesetiaan kepada model tertentu. Setakat July 2026, Opus 4.8 (claude-opus-4-8) berharga $5 bagi setiap juta token input dan $25 bagi setiap juta token output; Haiku 4.5 (claude-haiku-4-5) berharga $1/$5 dengan konteks 200K; Sonnet 5 (claude-sonnet-5) berada di antara kedua-duanya pada harga $3/$15, dengan harga pengenalan $2/$10 sehingga August 31, 2026. Secara khusus, petikan log 2,000 token dengan jawapan 500 token berharga kira-kira $0.0225 pada Opus dan $0.0045 pada Haiku. Mulakan dengan Opus semasa menilai kualiti output. Kemudian cuba prompt yang sama pada Haiku. Untuk transformasi mudah bervolum tinggi, hasilnya sering tidak dapat dibezakan, dengan kos satu perlima daripada harga tersebut. Semak angka semasa di halaman harga sebelum menetapkan mana-mana angka ini secara kekal dalam belanjawan.
Gunakan Batches untuk perkara yang boleh ditangguhkan. Batches API memproses permintaan secara tak segerak pada 50% daripada harga standard, dan kebanyakan batch selesai dalam masa sejam. Ringkasan harian, pengisian semula data lama, pengelasan pukal dan apa-apa tugas yang tidak memerlukan manusia menunggu hendaklah menggunakan kaedah ini.
Gunakan caching prompt untuk konteks yang berulang. Jika setiap panggilan menghantar semula system prompt atau runbook besar yang sama, tandakannya supaya boleh dicache:
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 onPenulisan cache berharga kira-kira 1.25x harga input, manakala pembacaan cache berharga kira-kira 0.1x, dengan TTL 5-minute. Oleh itu, panggilan kedua dalam tempoh tersebut sudah menampung kos panggilan pertama. Terdapat 2 perkara yang perlu diberi perhatian. Awalan yang dicache mesti melepasi minimum bagi setiap model, iaitu beberapa ribu token pada Opus. Oleh itu, system prompt yang pendek tidak akan dicache langsung tanpa sebarang petunjuk. Selain itu, jika cache_read_input_tokens kekal sifar bagi panggilan yang sama, ada sesuatu dalam awalan anda berubah pada setiap permintaan. Timestamp ialah punca yang biasa.
Fahami perkara yang dikira sebagai input. System prompt, definisi alat dan, dalam perbualan berbilang giliran, seluruh sejarah yang dihantar semula pada setiap giliran semuanya dibilkan sebagai token input. Gelung chat yang tidak pernah memendekkan sejarah akan meningkatkan kos secara kuadratik. Anda wajar memahami perakaunan penuh sebelum membina sesuatu yang bersifat perbualan: cara penggunaan dan pengebilan token Claude sebenarnya dikira.
Jalankan di bawah systemd
Faedah penggunaan fail persekitaran yang teratur ialah pemasa yang meringkaskan ralat semalam setiap pagi.
# /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 nowPerhatikan manfaat EnvironmentFile=: systemd membaca fail milik root dengan mod-600 sebelum menurunkan keistimewaan kepada pengguna tanpa keistimewaan explain. Oleh itu, proses menerima pemboleh ubah tersebut, manakala pengguna tidak dapat membaca fail kunci. Kumpulan systemd-journal memberikan akses log. Uji dengan systemctl start secara manual dan baca journalctl -u log-digest.service. Jangan tunggu sehingga 06:15 untuk menemukan kesilapan taip. Apabila corak ini tidak lagi sesuai untuk saluran paip shell, pendekatan kunci-dalam-fail-persekitaran yang sama boleh terus digunakan dalam aliran kerja n8n berkuasa Claude pada mesin yang sama.
Kegagalan, dengan rentetan yang akan anda lihat
401 pada key yang berfungsi. Pengecualian memaparkan:
anthropic.AuthenticationError: Error code: 401 - {'type': 'error', 'error': {'type': 'authentication_error', 'message': 'invalid x-api-key'}, 'request_id': 'req_011CSHoEeqs5C35K2UUqR7Fy'}Jika key berfungsi dalam shell anda tetapi perkhidmatan mengembalikan 401, perkhidmatan itu tidak pernah menerimanya. Ingat bahawa systemd tidak membaca .bashrc; semak sama ada EnvironmentFile= menunjuk ke laluan yang betul. Punca lain termasuk tanda petikan yang ditampal ke dalam fail env (ANTHROPIC_API_KEY="sk-ant-...", systemd membuang tanda petikan itu, tetapi . file pembalut shell anda mengekalkannya dalam nilai jika anda menggunakan tanda petikan dengan cara yang tidak betul), ruang kosong di hujung, atau key yang anda batalkan dalam Console minggu lalu.
404 kerana kesilapan taip model. Kes yang paling lazim ialah menambah akhiran tarikh pada ID model semasa:
anthropic.NotFoundError: Error code: 404 - {'type': 'error', 'error': {'type': 'not_found_error', 'message': 'model: claude-opus-4-8-20260115'}, 'request_id': 'req_011CSJqymAvNw4bT3qmDdMbA'}ID generasi semasa mesti tepat seperti yang ditulis, claude-opus-4-8, claude-haiku-4-5, claude-sonnet-5. Salin ID tersebut daripada dokumentasi model, bukan daripada ingatan atau tutorial lama.
429 rate_limit_error. Rentetan jenis ralat ialah rate_limit_error dan respons mengandungi pengepala retry-after dengan bilangan saat untuk menunggu. SDK telah mencuba semula sebanyak dua kali dengan backoff sebelum anda melihat pengecualian itu. Oleh itu, 429 yang berterusan bermaksud kadar berterusan anda benar-benar melebihi peringkat anda. Kelompokkan kerja atau sebarkan pelaksanaannya. Jangan mengetatkan gelung percubaan semula.
Ia mencetak objek, bukan teks. Output kelihatan seperti [TextBlock(citations=None, text='...', type='text')]. Anda mencetak response.content dan bukannya mengulangi blok serta membaca .text daripada blok yang mempunyai block.type == "text". Setiap contoh SDK di atas melakukannya dengan betul; salin gelung tersebut.
error: externally-managed-environment. Anda menjalankan pip install terhadap Python sistem Ubuntu 24.04. Gunakan venv. Jangan gunakan --break-system-packages pada pelayan yang penting.
Jawapan terpotong. response.stop_reason == "max_tokens" bermaksud model mencapai had output semasa masih menghasilkan jawapan. Ini berfungsi seperti yang direka; tingkatkan had tersebut dengan sengaja.
Selepas aplikasi pertama anda berfungsi, membina ejen AI dengan Claude menukar panggilan API yang sama menjadi ejen yang menggunakan alat.
FAQ
Berapakah kos untuk mencuba Claude API?
Kosnya sememangnya rendah untuk alat seperti ini. Setakat Julai 2026, Opus 4.8 berharga $5 bagi setiap juta token input dan $25 bagi setiap juta token output. Oleh itu, diagnosis log biasa, dengan beberapa ribu token input dan beberapa ratus token output, berharga kira-kira dua sen. Dengan Haiku 4.5 ($1/$5), kosnya kurang daripada setengah sen. Penghantaran ringkasan harian selama sebulan berharga kurang daripada secawan kopi. Risikonya bukan harga bagi setiap panggilan. Risikonya ialah gelung tanpa had dan max_tokens tanpa had. Oleh itu, kedua-duanya ditetapkan secara jelas dalam panduan ini.
Adakah Claude API mempunyai peringkat percuma?
Tiada peringkat percuma berterusan setakat Julai 2026. Dokumentasi harga Anthropic menyatakan bahawa pengguna baharu menerima sejumlah kecil kredit percuma untuk menguji API. Ini ialah percubaan sekali sahaja. Jumlah tepat dipaparkan dalam Console semasa pendaftaran. Selepas itu, anda perlu membiayai akaun tersebut. Jika matlamat anda ialah kos marginal sifar bagi setiap permintaan, bukannya kualiti model termaju, alternatifnya ialah mengehos sendiri model dengan pemberat terbuka menggunakan Ollama dan membayar dalam bentuk RAM, bukan token.
Bagaimanakah saya boleh memastikan API key saya selamat pada pelayan?
Jangan simpan API key dalam kod atau git. Jangan eksportnya daripada .bashrc. Jangan taipkannya ke dalam shell yang akan menyimpannya dalam sejarah arahan. Simpan API key dalam fail milik root dengan permission 600. Muatkannya bagi setiap proses. Gunakan skrip pembungkus untuk penggunaan interaktif dan EnvironmentFile= untuk systemd. Hadkan satu key bagi setiap pelayan atau projek supaya key yang terdedah boleh dibatalkan dengan mudah, bukan memerlukan perubahan besar. Jika key tersebut pernah dimasukkan ke tapak perkongsian teks atau commit git, batalkannya dalam Console dengan segera. Memadam commit tidak menghapuskan kebocoran tersebut.
Model Claude yang manakah patut saya mulakan?
Mulakan dengan claude-opus-4-8 semasa anda menilai sama ada outputnya cukup baik untuk dijadikan asas. Anda juga dapat menilai idea tersebut pada kualiti penuh. Pada jumlah penggunaan hobi, perbezaan kos hanya beberapa sen. Selepas prompt dimuktamadkan, jalankan semula input sebenar anda pada claude-haiku-4-5. Untuk tugasan seperti membuat ringkasan, pengelasan, dan triage log, model ini kerap memberikan prestasi yang sama baik pada harga satu perlima. Beralih kepada Haiku atau Sonnet berdasarkan pengukuran, bukan secara lalai.