SSD Nodes Learn
Panduan Matt ConnorOleh Matt Connor · Dikemas kini 2026-07-24

Tutorial Claude API pada VPS Ubuntu 24.04

Bina aplikasi Python untuk analisis log menggunakan Claude API. Pelajari cara simpan kunci API dengan selamat dan kawal kos token pada Ubuntu 24.04.

Apa yang anda bina

Sebuah alat baris perintah pada VPS Ubuntu 24.04 yang baharu. Anda masukkan mesej ralat atau cebisan log, dan anda akan menerima diagnosis dalam bahasa Inggeris yang mudah: journalctl -u nginx -n 50 | explain. Ia mungkin hanya enam puluh baris kod Python, tetapi ia merangkumi semua keperluan aplikasi Claude API yang sebenar — kunci yang disimpan dengan betul, virtualenv, bentuk respons SDK, penstriman, rantaian pengecualian bertipe, dan unit systemd supaya ia boleh berjalan secara automatik.

Saya memilih projek ini dengan sengaja. Kebanyakan tutorial "aplikasi API pertama" meminta anda membina chatbot yang tidak akan anda buka lagi. Alat penerang log memberikan nilai kegunaan pada pelayan dari hari pertama, dan ia melatih anda dalam dua perkara yang sering dilakukan silap oleh pemula: membaca objek respons dengan betul, dan mengawal perbelanjaan. Bil API dikira mengikut token tanpa had selain daripada had yang anda tetapkan sendiri. Oleh itu, kawalan kos adalah input reka bentuk di sini, bukan sekadar perkara sampingan — disiplin yang sama penting apabila anda beralih kepada menjalankan Claude Code pada VPS yang sama ini dalam tmux.

Dapatkan kunci API daripada Console

Akses API diuruskan dalam Anthropic Console di platform.claude.com — daftar akaun, kemudian cipta kunci di bawah Settings → API Keys (pautan dokumentasi akan terus ke platform.claude.com/settings/keys). Kunci tersebut hanya dipaparkan sekali, bermula dengan sk-ant-, dan tidak boleh dilihat semula — salin segera atau padam dan keluarkan semula.

Mengenai kos: setakat Julai 2026, tiada pelan percuma berterusan untuk API. Dokumentasi harga Anthropic menyatakan pengguna baharu menerima sedikit kredit percuma untuk ujian; jumlah tepat adalah apa yang dipaparkan oleh Console semasa pendaftaran, dan setelah kredit habis, anda perlu menambah dana ke akaun sebelum permintaan berjaya. Ini adalah berbeza daripada langganan claude.ai — pelan Pro atau Max tidak termasuk kredit API, dan kunci API tidak memberikan akses kepada aplikasi sembang. Jika anda sedang mempertimbangkan antara langganan atau API, perbandingan tersebut adalah topik tersendiri: pelan Claude mana yang anda sebenarnya perlukan.

Cipta kunci yang dihadkan kepada satu projek atau pelayan sahaja. Apabila kunci bocor — dan dalam jangka masa panjang, ia pasti akan berlaku — anda perlu membatalkannya tanpa menjejaskan semua sistem lain yang anda miliki.

Jangan simpan kunci dalam .bashrc

Tindakan refleksif ini adalah export ANTHROPIC_API_KEY=sk-ant-... dalam ~/.bashrc. Jangan lakukan. Terdapat tiga masalah berasingan:

  • Setiap proses mewarisinya. Pemboleh ubah persekitaran yang dieksport dalam shell log masuk anda akan tersebar ke semua perkara yang anda mulakan — aplikasi web, pelapor ralat yang memasukkan persekitaran ke dalam laporan pepijat, atau halaman phpinfo() yang dibiarkan aktif. Permukaan pendedahan kunci menjadi "semua perkara yang dijalankan oleh pengguna ini."
  • Mengetiknya akan disimpan dalam ~/.bash_history. Jalankan arahan export secara manual sekali dan kunci anda akan tersimpan dalam fail teks biasa selama-lamanya, serta diselaraskan ke dalam setiap sandaran direktori home anda.
  • Ia tidak tersedia apabila systemd memerlukannya. Perkhidmatan tidak membaca .bashrc anda, jadi corak ini akan gagal tepat apabila anda menukar skrip tersebut kepada unit — biasanya sebagai ralat 401 yang misteri pada jam 6 pagi.

Corak yang betul pada pelayan adalah fail persekitaran khusus dengan keizinan 600, yang hanya dimuatkan 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/null

Gunakan tee daripada printf dan bukannya editor jika anda ingin mengelakkan kunci daripada tersimpan dalam fail swap editor; dalam apa jua cara sekalipun, sahkan dengan ls -l /etc/claude-explain.env bahawa ia membaca -rw------- dan dimiliki oleh root. Shell interaktif menerima kunci bagi setiap panggilan melalui pembungkus (di bawah), dan systemd menerimanya melalui EnvironmentFile= — root membaca fail tersebut sebelum menurunkan keistimewaan, jadi pengguna perkhidmatan tidak perlu mempunyai akses baca kepadanya. Kunci tersebut tidak akan muncul dalam kod, dalam git, dalam output ps, atau dalam sejarah shell.

Pasang SDK dalam venv

Ubuntu 24.04 menyertakan Python 3.12 dengan penguatkuasaan PEP 668, jadi pemasangan pip install anthropic terus pada interpreter sistem akan gagal dengan error: externally-managed-environment. Ralat tersebut 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 anthropic

Tiada proses pengaktifan diperlukan pada pelayan: memanggil /opt/explain/venv/bin/python secara terus akan sentiasa menggunakan pakej venv.

Panggilan pertama, dan 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 tersebut merangkumi sebahagian besar model mental API ini. Pertama, anthropic.Anthropic() tanpa argumen akan membaca kunci daripada persekitaran (environment) — jangan sesekali hantarkannya sebagai string literal. Kedua, response.content adalah senarai blok kandungan, bukan string. Jika anda mencetaknya secara terus, anda akan mendapat output biasa bagi pengguna baharu:

[TextBlock(citations=None, text='A systemd unit file is...', type='text')]

Itu bukan pepijat; itu adalah repr objek tersebut. Respons boleh mengandungi pelbagai jenis blok (teks, panggilan alatan, pemikiran), jadi anda perlu melakukan iterasi dan menyemak block.type == "text" sebelum mengakses .text. Gunakan gelung (loop) tersebut sejak hari pertama untuk mengelakkan kekeliruan "output sampah".

Gunakan ID model yang tepat iaitu claude-opus-4-8. ID generasi semasa tidak mempunyai tarikh — jangan ikut tabiat lama (atau catatan blog lama) yang menyuruh anda menambah akhiran tarikh; tindakan itu akan menghasilkan ralat 404, seperti yang dijelaskan di bawah.

Alat sebenar: penjelasan

Berikut adalah program lengkap — input melalui stdin, diagnosis dialirkan keluar, 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 tambah pembungkus (wrapper) 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 tersebut perlu dijalankan melalui sudo atau fail persekitaran (env file) perlu mempunyai kumpulan yang disertai oleh pengguna admin anda — pilih salah satu secara sengaja daripada melonggarkan keizinan fail kepada 644.)

Mengapa penstriman (streaming). client.messages.stream mencetak token sebaik sahaja ia tiba berbanding menunggu keseluruhan penjanaan selesai, dan ia mengelakkan masalah masa tamat (timeout) HTTP pada output yang panjang — SDK akan menolak nilai max_tokens yang sangat besar pada panggilan bukan penstriman atas sebab tersebut. Jika anda memerlukan objek yang lengkap kemudian, panggil stream.get_final_message() di dalam blok with.

Mengapa urutan pengecualian tersebut. SDK melontarkan pengecualian bertipe, yang paling spesifik didahulukan: RateLimitError adalah ralat 429 dan mengandungi pengepala retry-after yang memberitahu tempoh menunggu; APIStatusError merangkumi respons bukan-2xx yang lain (rujuk e.status_code >= 500 untuk masalah sebelah pelayan); APIConnectionError bermaksud permintaan tidak menerima sebarang respons. Sebelum anda membina gelung cubaan semula (retry loop): SDK sudah melakukan cubaan semula bagi ralat 429 dan 5xx secara automatik, sebanyak dua kali secara lalai dengan sandaran eksponen (max_retries pada klien). Menjelang masa except anda dijalankan, semua cubaan semula telah habis digunakan — jadi tindakan yang betul dalam CLI adalah melaporkan ralat dan keluar, bukan tidur dan terus mencuba.

Kawalan kos

Bahagian ini memerlukan seksyen khas kerana API tidak mempunyai had bulanan terbina dalam selain daripada apa yang anda tetapkan, dan setiap kesilapan di sini akan bertambah secara senyap.

max_tokens adalah had perbelanjaan setiap panggilan anda. Token output adalah bahagian yang mahal — pada Opus 4.8, harganya lima kali ganda harga input — dan max_tokens adalah had tetap bagi jumlah token yang boleh dihasilkan oleh model. Prompt yang tidak terkawal tidak akan menelan kos output melebihi had yang anda tetapkan. Tetapkan saiz mengikut keperluan tugas: 1,500 sudah memadai untuk diagnosis log; tugas klasifikasi memerlukan 100. Jika respons terhenti di tengah ayat dengan stop_reason: "max_tokens", bermakna had anda terlalu kecil — tingkatkan had tersebut secara sedar daripada menetapkannya terlalu besar secara lalai.

Kira sebelum anda menghantar. Input juga memerlukan kos, dan log adalah besar. API mempunyai endpoint pengiraan yang percuma untuk digunakan (ia mempunyai had kadar tersendiri, 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)

Gunakan ia untuk mengelakkan penghantaran log sebesar 2 GB melalui alat ini secara tidak sengaja. Jangan gunakan tiktoken untuk tujuan ini — itu adalah tokenizer OpenAI, dan ia mengira token Claude kurang daripada 15–20% bagi teks biasa, dan lebih rendah bagi kod.

Pilih model mengikut tugas, bukan mengikut kesetiaan. Setakat Julai 2026, Opus 4.8 (claude-opus-4-8) beroperasi pada $5 per satu juta token input dan $25 per satu juta output; Haiku 4.5 (claude-haiku-4-5) adalah $1/$5 dengan konteks 200K; Sonnet 5 (claude-sonnet-5) berada di tengah-tengah pada $3/$15, dengan harga pengenalan $2/$10 sehingga 31 Ogos 2026. Secara konkrit: petikan log 2,000-token dengan jawapan 500-token menelan kos kira-kira $0.0225 pada Opus dan $0.0045 pada Haiku. Mulakan dengan Opus semasa anda menilai kualiti output, kemudian cuba prompt yang sama pada Haiku — untuk transformasi ringkas volum tinggi, hasilnya sering kali tidak dapat dibezakan pada harga satu per lima. Sahkan angka semasa di halaman harga sebelum menetapkan mana-mana angka ini ke dalam bajet.

Gunakan Batches untuk apa sahaja yang boleh menunggu. Batches API memproses permintaan secara asinkronus pada 50% daripada harga standard, dan kebanyakan batch selesai dalam masa satu jam. Ringkasan harian, pengisian semula data (backfills), klasifikasi pukal — apa sahaja yang tidak memerlukan menunggu manusia harus menggunakan kaedah ini.

Prompt caching untuk konteks berulang. Jika setiap panggilan menghantar semula sistem prompt atau runbook besar yang sama, tandakan ia sebagai boleh disimpan dalam cache:

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

Kos penulisan cache adalah kira-kira 1.25x harga input, manakala bacaan cache adalah kira-kira 0.1x, dengan TTL 5 minit — jadi panggilan kedua dalam tempoh tersebut sudah membayar kos panggilan pertama. Terdapat dua perkara penting. Awalan (prefix) yang disimpan dalam cache mesti melepasi minimum setiap model — beberapa ribu token pada Opus — jadi sistem prompt yang pendek tidak akan disimpan dalam cache secara senyap. Dan jika cache_read_input_tokens kekal sifar bagi panggilan yang serupa, bermakna terdapat sesuatu dalam awalan anda yang berubah pada setiap permintaan (cap masa adalah punca biasa).

Ingat apa yang dikira sebagai input. Sistem prompt, definisi alat, dan — dalam perbualan pelbagai pusingan — keseluruhan sejarah yang anda hantar semula pada setiap pusingan semuanya dibilkan sebagai token input. Gelung sembang yang tidak pernah memotong sejarah akan menyebabkan kos meningkat secara kuadratik. Perincian penuh perlu difahami sebelum anda membina apa-apa sistem perbualan: bagaimana penggunaan token dan bil Claude sebenarnya dikira.

Jalankan di bawah systemd

Hasil daripada penggunaan fail-environment: satu timer yang merumuskan ralat semalam pada 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.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

Perhatikan kelebihan EnvironmentFile=: systemd membaca fail milik root dengan mode-600 sebelum bertukar kepada pengguna explain yang tidak mempunyai keistimewaan, jadi proses tersebut menerima pemboleh ubah manakala pengguna tidak boleh membaca fail kunci tersebut. Kumpulan systemd-journal memberikan akses log. Uji dengan systemctl start secara manual dan baca journalctl -u log-digest.service — jangan tunggu sehingga jam 06:15 untuk mengesan kesilapan taip. Apabila corak ini melampaui keupayaan shell pipeline, pendekatan kunci-dalam-fail-environment yang sama boleh digunakan terus ke dalam aliran kerja n8n berkuasa Claude pada mesin yang sama.

Mod kegagalan, bersama string yang akan anda lihat

401 pada kunci yang berfungsi. Pengecualian tersebut berbunyi:

anthropic.AuthenticationError: Error code: 401 - {'type': 'error', 'error': {'type': 'authentication_error', 'message': 'invalid x-api-key'}, 'request_id': 'req_011CSHoEeqs5C35K2UUqR7Fy'}

Jika kunci berfungsi dalam shell anda tetapi perkhidmatan memulangkan 401, perkhidmatan tersebut tidak pernah menerimanya — ingat bahawa systemd tidak membaca .bashrc; pastikan EnvironmentFile= merujuk ke laluan yang betul. Punca lain: tanda petik yang ditampal ke dalam fail env (ANTHROPIC_API_KEY="sk-ant-..." — systemd membuang tanda petik, tetapi . file pada pembungkus shell anda mengekalkannya dalam nilai jika anda menggunakan tanda petik secara tidak betul), ruang kosong di hujung baris, atau kunci yang telah anda nyahaktifkan dalam Console minggu lepas.

404 akibat kesilapan taip model. Versi yang paling kerap berlaku adalah 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 adalah tepat seperti yang ditulis — claude-opus-4-8, claude-haiku-4-5, claude-sonnet-5. Salin ID tersebut daripada dokumentasi model, jangan sesekali bergantung pada ingatan atau tutorial lama.

429 rate_limit_error. String jenis ralat ialah rate_limit_error dan respons mengandungi pengepala retry-after dengan jumlah saat yang perlu ditunggu. SDK telah mencuba semula sebanyak dua kali dengan backoff sebelum anda melihat pengecualian tersebut, jadi 429 yang berterusan bermaksud kadar penggunaan anda benar-benar melebihi tahap anda — lakukan kerja secara berkelompok atau selang-selikan, jangan rapatkan kitaran cubaan semula.

Ia mencetak objek, bukan teks. Output kelihatan seperti [TextBlock(citations=None, text='...', type='text')]. Anda mencetak response.content sebaliknya melakukan iterasi pada blok dan 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 sesekali gunakan --break-system-packages pada pelayan yang penting bagi anda.

Jawapan terpotong. response.stop_reason == "max_tokens" bermaksud model telah mencapai had output anda semasa proses berfikir. Ini adalah fungsi yang direka; tingkatkan had tersebut secara sengaja.

Setelah aplikasi pertama anda berfungsi, membina ejen AI dengan Claude menukarkan panggilan API yang sama itu kepada ejen yang menggunakan alatan.

FAQ

Berapakah kos untuk mencuba Claude API?

Sangat rendah untuk alatan seperti ini. Setakat Julai 2026, Opus 4.8 berharga $5 bagi setiap sejuta token input dan $25 bagi setiap sejuta token output. Diagnosis log tipikal — beberapa ribu token input dan beberapa ratus token output — hanya menelan kos sekitar dua sen. Bagi Haiku 4.5 ($1/$5), kosnya kurang daripada setengah sen. Kos untuk ringkasan harian selama sebulan adalah lebih murah daripada harga secawan kopi. Risiko utama bukan pada harga setiap panggilan; risiko sebenar adalah gelung tanpa had dan max_tokens tanpa had, sebab itulah kedua-duanya perlu ditetapkan secara eksplisit dalam panduan ini.

Adakah terdapat pelan percuma untuk Claude API?

Tiada pelan percuma berterusan setakat Julai 2026. Dokumentasi harga Anthropic menyatakan pengguna baharu menerima jumlah kredit percuma yang kecil untuk menguji API — percubaan sekali sahaja, dengan jumlah tepat dipaparkan di Console semasa pendaftaran — selepas itu anda perlu menambah dana ke akaun. Jika matlamat anda adalah kos marginal sifar bagi setiap permintaan berbanding kualiti tahap tinggi, alternatifnya adalah untuk hos sendiri model open-weight dengan Ollama dan membayar menggunakan RAM berbanding token.

Bagaimanakah cara untuk menjaga keselamatan kunci API saya pada pelayan?

Jangan sesekali letakkannya di dalam kod, jangan dalam git, jangan eksport dari .bashrc, dan jangan taip ke dalam shell yang menyimpan sejarah (history). Letakkannya dalam fail milik root dengan kebenaran 600. Muatkannya mengikut proses — skrip pembungkus (wrapper script) untuk penggunaan interaktif, atau EnvironmentFile= untuk systemd. Hadkan satu kunci bagi setiap pelayan atau projek supaya proses membatalkan kunci yang bocor adalah mudah dan tidak menjejaskan keseluruhan sistem. Jika kunci tersebut pernah terdedah di laman paste atau komit git, batalkan kunci tersebut di Console dengan segera; memadam komit tidak akan membatalkan kebocoran tersebut.

Model Claude manakah yang patut saya mulakan?

Mulakan dengan claude-opus-4-8 semasa anda menilai sama ada output yang dihasilkan cukup baik untuk pembangunan — anda perlu menilai idea tersebut pada kualiti penuh, dan pada volum hobi, perbezaan kos hanyalah beberapa sen. Setelah prompt ditetapkan, jalankan semula input sebenar anda pada claude-haiku-4-5; untuk ringkasan, klasifikasi, dan triaj log, ia sering kali sama baik dengan harga satu per lima daripada harga asal. Beralih ke Haiku atau Sonnet berdasarkan ukuran prestasi, bukan secara lalai.