← Semua pembelajaran / Python untuk AI Engineer
Fase 4 · Bicara dengan LLM

Claude API — Get Started

Panggilan API Claude pertama: setup kredensial, struktur request, dan cara membaca respons dengan benar.

Intisari

  • Semuanya lewat satu endpoint: POST /v1/messages. Tool use dan structured output adalah fitur di endpoint yang sama.
  • API-nya stateless — riwayat percakapan kamu yang kirim ulang tiap kali, lewat array messages.
  • response.content adalah list of block, bukan string. Selalu cek .type.
  • Cek response.stop_reason sebelum membaca isi — bisa end_turn, max_tokens, tool_use, atau refusal.
  • response.usage berisi jumlah token masuk dan keluar — dasar semua perhitungan biaya.

Setup

uv add anthropic
export ANTHROPIC_API_KEY=sk-ant-...
import anthropic

client = anthropic.Anthropic()      # membaca ANTHROPIC_API_KEY dari environment

Jangan hardcode API key. Baca dari environment (lewat pydantic-settings seperti di Fase 2). Key yang ter-commit ke git harus dianggap bocor dan wajib dicabut, meskipun commit-nya sudah dihapus.

Panggilan pertama

response = client.messages.create(
    model="claude-opus-5",
    max_tokens=16000,
    system="Kamu asisten yang menjawab ringkas dalam bahasa Indonesia.",
    messages=[{"role": "user", "content": "Jelaskan apa itu RAG dalam 3 kalimat."}],
)

for block in response.content:
    if block.type == "text":
        print(block.text)

Anatomi request

ParameterWajibKeterangan
model✅ID model, misal claude-opus-5
max_tokens✅Batas keras token keluar. Bukan target, tapi plafon.
messages✅Riwayat percakapan, berselang-seling user/assistant
system—Instruksi tingkat sistem. Parameter terpisah, bukan anggota messages.
tools—Daftar tool yang boleh dipanggil model
thinking—{"type": "adaptive"} — model menentukan sendiri kedalaman berpikirnya
output_config—{"effort": "high"} dan/atau format keluaran terstruktur
stream—Streaming; lebih enak lewat client.messages.stream()

Empat hal yang harus benar-benar kamu internalisasi

1. API-nya stateless

messages = []

def kirim(teks: str) -> str:
    messages.append({"role": "user", "content": teks})
    r = client.messages.create(
        model="claude-opus-5", max_tokens=16000, messages=messages,
    )
    jawaban = next(b.text for b in r.content if b.type == "text")
    messages.append({"role": "assistant", "content": jawaban})
    return jawaban

Tidak ada session di sisi server. Setiap request mengirim ulang seluruh percakapan. Konsekuensinya: biaya input tumbuh seiring panjangnya percakapan, dan kamulah yang bertanggung jawab memangkas riwayat sebelum menabrak batas context window. Ini juga alasan prompt caching begitu berdampak.

2. content adalah list of block

for block in response.content:
    if block.type == "text":
        print(block.text)
    elif block.type == "thinking":
        print("[berpikir]", block.thinking)
    elif block.type == "tool_use":
        print("minta tool:", block.name, block.input)

response.content[0].text akan pecah begitu kamu menyalakan thinking atau tool use — blok pertamanya bukan teks lagi. Biasakan menelusuri list dan memeriksa .type sejak awal.

3. stop_reason — periksa dulu

NilaiArtinyaYang harus kamu lakukan
end_turnSelesai wajarBaca teksnya
max_tokensKena plafonNaikkan max_tokens atau pakai streaming
tool_useModel minta tool dijalankanJalankan, kirim hasilnya kembali
refusalDitolak oleh pengamanCek stop_details.category; jangan diulang begitu saja
pause_turnTool sisi server berhenti sementaraKirim ulang untuk melanjutkan
if response.stop_reason == "refusal":
    tangani_penolakan(response.stop_details)
elif response.stop_reason == "max_tokens":
    logger.warning("respons terpotong")
else:
    tampilkan(response.content)

4. usage — dasar perhitungan biaya

u = response.usage
u.input_tokens                  # token masuk yang dibayar penuh
u.output_tokens                 # token keluar
u.cache_read_input_tokens       # dari cache — jauh lebih murah
u.cache_creation_input_tokens   # ditulis ke cache
HARGA_IN, HARGA_OUT = 5.0, 25.0   # USD per juta token (Claude Opus 5)

biaya = (u.input_tokens * HARGA_IN + u.output_tokens * HARGA_OUT) / 1_000_000
print(f"${biaya:.6f}")

Adaptive thinking dan effort

response = client.messages.create(
    model="claude-opus-5",
    max_tokens=16000,
    thinking={"type": "adaptive", "display": "summarized"},
    output_config={"effort": "high"},     # low | medium | high | xhigh | max
    messages=[{"role": "user", "content": "..."}],
)
effortUntuk
lowKlasifikasi, ekstraksi sederhana, tugas yang sensitif latensi
mediumBeban kerja rutin yang perlu hemat token
highDefault — keseimbangan yang baik untuk sebagian besar tugas
xhighCoding dan pekerjaan agentic — biasanya pilihan terbaik di sana
maxSaat kebenaran lebih penting daripada biaya

Pada Claude Opus 5, thinking aktif secara default — menghilangkan parameter thinking tetap membuat model berpikir. Karena max_tokens membatasi thinking + teks jawaban sekaligus, sediakan ruang yang cukup atau jawabanmu bisa terpotong di tengah.

Menangani error

import anthropic

try:
    r = client.messages.create(...)
except anthropic.RateLimitError as e:
    tunggu = int(e.response.headers.get("retry-after", "60"))
except anthropic.APIStatusError as e:
    if e.status_code >= 500:
        ...       # layak diulang
    else:
        raise     # request-mu yang salah
except anthropic.APIConnectionError:
    ...           # masalah jaringan

SDK sudah mengulang otomatis untuk 408, 409, 429, dan 5xx — default 2 kali. Ubah dengan anthropic.Anthropic(max_retries=5).

Versi async

client = anthropic.AsyncAnthropic()

async def tanya(prompt: str) -> str:
    r = await client.messages.create(
        model="claude-opus-5", max_tokens=16000,
        messages=[{"role": "user", "content": prompt}],
    )
    return next(b.text for b in r.content if b.type == "text")

Inilah gunanya Fase 3 — asyncio.gather atas puluhan panggilan seperti ini.

Rangkuman ini sengaja dipangkas ke bagian yang dipakai di roadmap. Buka sumber aslinya saat kamu butuh detail lengkap atau referensi parameter.