Python untuk AI Engineer
Ini bukan kursus βbelajar programmingβ. Ini kursus belajar Python-nya β ditulis untuk software engineer yang sudah paham logika, struktur data, dan HTTP, tapi belum pernah menyentuh Python. Delapan fase, berurutan, tiap fase punya checkpoint konkret.
- Durasi
- ~9,5 minggu
- Beban
- ~8 jam/minggu
- Prasyarat
- Bisa programming (bahasa apa pun)
- Target akhir
- AWS GenAI Developer β Pro
Prinsip: jangan belajar semua Python
Python itu luas, dan sebagian besar isinya tidak relevan untuk AI engineering. Waktu terbesar hilang bukan karena materinya susah, tapi karena belajar bagian yang tidak akan pernah dipakai. Daftar ini sama pentingnya dengan daftar materi:
Lewati β jangan buang waktu
| Topik | Alasan |
|---|---|
Metaclass, descriptor, __slots__ | Hampir tidak pernah muncul di kode aplikasi |
| Hierarki OOP dalam, multiple inheritance | Kode AI cenderung flat dan fungsional |
| Django | FastAPI jauh lebih relevan untuk serve model |
| Tkinter / PyQt / GUI | Tidak relevan sama sekali |
Threading manual, multiprocessing | Beban kerja LLM itu I/O-bound β yang dipakai asyncio |
setup.py, virtualenv, pipenv, poetry | Sudah digantikan uv |
| Training model dari nol (PyTorch) | Itu ranah ML engineer, bukan AI engineer |
Yang tersisa justru sedikit dan tajam: idiom Python, type hints, Pydantic, async, SDK LLM, FastAPI, testing, packaging. Itulah isi delapan fase di bawah.
Setup Toolchain
Tujuan: punya lingkungan kerja Python modern dan tidak pernah lagi berurusan dengan venv/pip manual.
Perhatian: toolchain Python berubah total dalam 2β3 tahun terakhir. Banyak tutorial masih mengajarkan
virtualenv + pip + requirements.txt. Jangan ikuti. Mulai langsung dari uv.
Instalasi & alur kerja harian
# uv β package manager + version manager, ditulis dengan Rust (10β100x lebih cepat)
curl -LsSf https://astral.sh/uv/install.sh | sh
uv python install 3.13 # pasang interpreter Python
uv init proyek-pertama # bikin proyek (pyproject.toml)
cd proyek-pertama
uv add anthropic httpx # tambah dependency + kunci versi
uv run main.py # jalankan (venv dibuat otomatis, tanpa activate)
uv sync # samakan venv dengan lockfile
Yang membedakan uv dari pip: ia mengelola interpreter, virtual environment,
dependency, dan lockfile sekaligus. Tidak ada lagi langkah source .venv/bin/activate β
uv run yang mengurus itu.
Empat tool wajib
| Tool | Fungsi | Perintah |
|---|---|---|
uv | Package, venv, versi Python | uv add, uv run, uv sync |
ruff | Linter + formatter β pengganti black, flake8, isort sekaligus | uvx ruff check --fix, uvx ruff format |
mypy | Type checker statis | uvx mypy . |
pytest | Framework testing | uv run pytest |
Editor: VS Code + extension Python dan Ruff. Aktifkan format-on-save sejak hari pertama.
Materi
-
Dokumentasi uvResmiSumber utama. Mulai dari βGetting startedβ, lalu βGuides β Working on projectsβ.docs.astral.sh/uv
-
uv β InstallationResmiCara pasang di Linux, macOS, Windows, plus opsi update mandiri.docs.astral.sh/uv
-
uv β Working on projectsResmiAnatomi
pyproject.toml, lockfile, dan aluradd/run/sync.docs.astral.sh/uv -
Ruff β Linter & FormatterResmiKonfigurasi aturan lint di
pyproject.toml; baca juga bagian Formatter.docs.astral.sh/ruff -
pytestResmiSekarang cukup baca βGet Startedβ. Bagian fixtures dipakai lagi di Fase 6.docs.pytest.org
-
mypyResmiPasang sekarang, pakai serius di Fase 2.mypy.readthedocs.io
Kamu bisa uv init proyek baru, tambah dependency, jalankan, dan format kodenya β tanpa googling.
Sintaks & Idiom Python
Tujuan: menulis Python yang terasa seperti Python β bukan Java atau PHP yang kebetulan pakai sintaks Python.
Kamu sudah paham konsepnya. Yang perlu dipelajari adalah cara Python mengungkapkannya. Bagian ini padat contoh β ketik ulang semuanya, jangan copy-paste.
Idiom yang wajib lancar
# ββ f-string
f"Halo {nama}, umur {umur + 1}"
f"{harga:,.2f}" # format angka: 1,234.50
f"{nilai=}" # debug: mencetak "nilai=42"
# ββ Unpacking
a, b = b, a # swap tanpa variabel bantu
first, *rest = [1, 2, 3, 4] # first=1, rest=[2,3,4]
config = {**default, **override} # merge dict
def f(*args, **kwargs): ...
# ββ Comprehension β paling idiomatik, harus refleks
[x * 2 for x in items if x > 0] # list
{k: v for k, v in pairs} # dict
{x.id for x in items} # set
(x for x in big_list) # generator: lazy, hemat memori
# ββ enumerate & zip
# Jangan pernah tulis `for i in range(len(xs))`
for i, item in enumerate(items, start=1): ...
for nama, umur in zip(nama_list, umur_list): ...
# ββ Context manager
with open("f.txt") as f: ... # file otomatis ditutup
# ββ Truthiness
nilai = mungkin_none or "default"
hasil = a if kondisi else b
if not items: ... # bukan `if len(items) == 0`
pathlib β jangan pakai os.path lagi
from pathlib import Path
Path("data/file.json").read_text()
(Path.home() / "roadmap" / "catatan.md").exists()
for f in Path("docs").glob("**/*.md"): ...
Path("out").mkdir(parents=True, exist_ok=True)
Struktur data: pilih yang mana?
| Kebutuhan | Pakai |
|---|---|
| Kumpulan data internal | @dataclass atau NamedTuple |
| Validasi data dari luar (API, JSON, env) | Pydantic BaseModel β Fase 2 |
| Enum | enum.StrEnum |
| Hitung frekuensi, grouping | collections.Counter, defaultdict |
| Cache hasil fungsi | functools.lru_cache |
from dataclasses import dataclass, field
@dataclass
class Dokumen:
id: str
isi: str
skor: float = 0.0
tag: list[str] = field(default_factory=list) # jangan `= []`
Jebakan klasik: mutable default argument. def f(items=[]) membuat list yang sama
dipakai ulang di setiap pemanggilan. Pakai def f(items=None) lalu items = items or [],
atau field(default_factory=list) di dataclass.
Error handling
class RetrievalError(Exception):
"""Gagal mengambil dokumen dari vector store."""
try:
hasil = ambil(query)
except (ValueError, KeyError) as e:
logger.warning("gagal parse: %s", e)
raise RetrievalError("query tidak valid") from e # jaga rantai penyebab
finally:
cleanup()
Materi
-
The Python TutorialResmiBaca cepat bab 3β9. Kamu sudah paham konsepnya, jadi fokus ke sintaksnya saja.docs.python.org
-
Data StructuresResmiBab paling penting di fase ini β list, dict, set, dan semua bentuk comprehension.docs.python.org
-
pathlib β Object-oriented filesystem pathsResmiReferensi lengkap. Perhatikan tabel perbandingan dengan
os.pathdi bagian bawah.docs.python.org -
dataclassesResmi
field(),frozen=True, dan kenapa default mutable berbahaya.docs.python.org -
collectionsResmi
Counter,defaultdict,dequeβ cukup baca sekilas, pakai saat butuh.docs.python.org -
PEP 8 β Style GuideResmiBaca sekali untuk paham konvensi penamaan. Sisanya ditegakkan otomatis oleh Ruff.peps.python.org
-
Google Python Style GuideReferensiLebih opinionated dari PEP 8, dengan alasan di balik tiap aturan. Bagus untuk paham βkenapaβ.google.github.io
-
Functional Programming HOWTOResmiComprehension, generator, dan iterator dijelaskan berikut alasannya β termasuk kapan comprehension justru jadi kurang terbaca.docs.python.org
-
Input and Output β Fancier Output FormattingResmiFormat spec f-string selengkapnya: presisi desimal, padding, perataan, dan trik debug
{x=}.docs.python.org
Tulis ulang satu script utility dari bahasa lamamu ke Python. Kalau hasilnya masih terasa seperti βmenulis Java dengan sintaks Pythonβ, ulangi bagian comprehension dan unpacking.
Type Hints & Pydantic
Tujuan: kode yang lolos mypy, dan menguasai Pydantic β pondasi yang dipakai FastAPI,
structured output LLM, dan definisi tool untuk agent.
Ini pembeda kode Python amatir dengan profesional. Seluruh ekosistem AI modern β FastAPI, SDK Anthropic, SDK OpenAI β dibangun di atas type hints.
Sintaks modern (Python 3.10+)
from typing import Literal, Any
from collections.abc import Sequence, Iterator, Callable
def cari(query: str, top_k: int = 5) -> list[Dokumen]: ...
def proses(
data: dict[str, Any],
mode: Literal["fast", "accurate"] = "fast",
callback: Callable[[str], None] | None = None,
) -> Iterator[str]: ...
Jangan ikuti tutorial lama: sejak Python 3.9/3.10 pakai list[str], dict[str, int],
dan str | None β bukan List[str], Dict[str, int], atau Optional[str].
Impor koleksi abstrak dari collections.abc, bukan typing.
Pydantic β kuasai ini serius
Pydantic adalah lingua franca Python di dunia AI: validasi request API, parsing output LLM, konfigurasi aplikasi, dan skema tool. Investasi waktu di sini terbayar di semua fase berikutnya.
from typing import Literal
from pydantic import BaseModel, Field, field_validator
class Tiket(BaseModel):
judul: str = Field(min_length=1, max_length=200)
prioritas: Literal["low", "medium", "high"] = "medium"
tag: list[str] = []
email: str
@field_validator("email")
@classmethod
def cek_email(cls, v: str) -> str:
if "@" not in v:
raise ValueError("format email tidak valid")
return v
t = Tiket.model_validate(json_dari_api) # parse + validasi
t.model_dump_json() # serialize ke JSON
Tiket.model_json_schema() # β JSON Schema
Baris terakhir itu kuncinya. model_json_schema() menghasilkan JSON Schema,
dan JSON Schema itulah format yang dipakai untuk mendefinisikan tool pada LLM.
Inilah jembatan antara Python biasa dan GenAI engineering β dan alasan fase ini tidak boleh dilewati.
Konfigurasi aplikasi
from pydantic_settings import BaseSettings, SettingsConfigDict
class Settings(BaseSettings):
model_config = SettingsConfigDict(env_file=".env")
anthropic_api_key: str # wajib β error saat start kalau kosong
aws_region: str = "us-east-1"
max_tokens: int = 4096
settings = Settings() # otomatis baca env var, tervalidasi
Pola ini menggantikan os.getenv() yang tersebar: semua config divalidasi sekali, saat aplikasi start.
Materi
-
Python Typing DocumentationResmiRumah baru dokumentasi typing. Ada bagian βType System Guidesβ yang ditulis untuk pemula typing.typing.python.org
-
mypy β Type Hints Cheat SheetResmiSatu halaman berisi hampir semua pola anotasi yang akan kamu butuhkan. Bookmark ini.mypy.readthedocs.io
-
typing β Support for type hintsResmiReferensi lengkap. Untuk lookup, bukan untuk dibaca berurutan.docs.python.org
-
Pydantic β Getting StartedResmiTitik masuk utama. Pastikan kamu membaca versi v2, bukan v1 β API-nya berbeda jauh.pydantic.dev
-
Pydantic β ModelsResmiInti Pydantic:
model_validate,model_dump, nested model, model dinamis.pydantic.dev -
Pydantic β ValidatorsResmi
field_validatorvsmodel_validator, modebefore/after.pydantic.dev -
Pydantic β JSON SchemaResmiBaca ini sebelum Fase 4. Dari sinilah skema tool dan structured output LLM dibentuk.pydantic.dev
-
Pydantic SettingsResmiManajemen konfigurasi dari env var dan file
.env, dengan validasi.pydantic.dev
Semua fungsi publik di kodemu punya type hint, dan uvx mypy . lolos tanpa error.
Kamu bisa menjelaskan kenapa model_json_schema() penting untuk LLM.
Async & HTTP
Tujuan: memanggil puluhan API secara paralel dengan batas concurrency, timeout, dan retry yang benar.
Panggilan LLM itu I/O-bound dan lambat β bisa puluhan detik. Tanpa async, aplikasimu memblokir dan tidak akan pernah scalable. Ini bagian yang tidak bisa ditawar untuk AI engineer.
Pola dasar
import asyncio
import httpx
async def ambil(client: httpx.AsyncClient, url: str) -> dict:
r = await client.get(url, timeout=30)
r.raise_for_status()
return r.json()
async def main() -> None:
async with httpx.AsyncClient() as client:
# gather = jalankan bersamaan, bukan berurutan
hasil = await asyncio.gather(
*(ambil(client, u) for u in urls),
return_exceptions=True, # satu gagal tidak menjatuhkan semua
)
asyncio.run(main())
Batasi concurrency β wajib untuk API berbayar
sem = asyncio.Semaphore(5) # maksimal 5 request bersamaan
async def ambil_terbatas(client, url):
async with sem:
return await ambil(client, url)
Tanpa ini, gather atas 500 URL akan menembak 500 request sekaligus dan langsung kena rate limit.
Retry dengan exponential backoff
from tenacity import retry, stop_after_attempt, wait_exponential, retry_if_exception_type
@retry(
stop=stop_after_attempt(5),
wait=wait_exponential(multiplier=1, min=1, max=30),
retry=retry_if_exception_type(httpx.HTTPStatusError),
)
async def call_api(): ...
Yang harus dipahami
async def/await/asyncio.run()β dasarasyncio.gather()β fan-out paralel (banyak dokumen, banyak LLM call)asyncio.Semaphoreβ pembatas concurrencyasyncio.wait_for()/ parametertimeoutβ jangan pernah panggil API tanpa timeoutasync for/async withβ dipakai langsung untuk streaming LLM di Fase 4- Kapan TIDAK pakai async: pekerjaan CPU-bound (justru melambat), atau script sekali jalan
Soal HTTP client: pakai httpx, bukan requests. httpx punya API sync dan async
dalam satu library dengan bentuk yang hampir identik; requests tidak mendukung async sama sekali.
Materi
-
asyncio β Coroutines and TasksResmiHalaman paling penting di modul asyncio: coroutine, task,
gather,TaskGroup, timeout.docs.python.org -
asyncio β Asynchronous I/OResmiHalaman induk. Bagian βSynchronization Primitivesβ memuat
Semaphore.docs.python.org -
Developing with asyncioResmiDaftar jebakan async yang paling sering menjerat pemula: debug mode, coroutine yang lupa di-
await, dan blocking call yang menyumbat event loop.docs.python.org -
Python Asyncio: The Complete GuideTutorialPenjelasan naratif panjang soal kenapa async berbeda dari threading. Baca ini kalau dokumentasi resmi terasa terlalu kering.superfastpython.com
-
HTTPXResmiQuickstart, lalu bagian βClientsβ β reuse client, jangan bikin baru tiap request.python-httpx.org
-
HTTPX β Async SupportResmi
AsyncClient, streaming response, dan cara membatalkan request.python-httpx.org -
TenacityResmiLibrary retry. Perhatikan kombinasi
stop,wait, danretrypredicate.tenacity.readthedocs.io
Buat script yang fetch 20 URL paralel dengan batas concurrency 5, timeout, dan retry otomatis. Ukur waktunya, bandingkan dengan versi sequential β kamu harus bisa menjelaskan selisihnya.
Bicara dengan LLM
Tujuan: menguasai empat pilar aplikasi LLM β panggilan dasar, streaming, tool use, dan structured output β lalu memindahkannya ke AWS Bedrock tanpa mengubah logika aplikasi.
4.1 Β· Panggilan dasar
uv add anthropic
export ANTHROPIC_API_KEY=sk-ant-...
import anthropic
client = anthropic.Anthropic() # membaca ANTHROPIC_API_KEY dari environment
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."}],
)
# response.content adalah LIST of block, bukan string. Selalu cek .type
for block in response.content:
if block.type == "text":
print(block.text)
Empat hal yang harus benar-benar kamu internalisasi di sini:
- API-nya stateless. Riwayat percakapan kamu yang kirim ulang setiap kali, lewat array
messages. Tidak ada session di sisi server. response.contentitu list berisi content block (text,thinking,tool_use) β bukan string.response.usage(input_tokens,output_tokens) adalah dasar perhitungan biaya.response.stop_reasonβend_turn,max_tokens,tool_use,refusal. Cek ini sebelum membaca content.
4.2 Β· Streaming
Wajib untuk UX chat, dan wajib saat max_tokens besar β tanpa streaming, koneksi HTTP bisa timeout.
with client.messages.stream(
model="claude-opus-5",
max_tokens=64000,
messages=[{"role": "user", "content": "Tulis artikel panjang"}],
) as stream:
for teks in stream.text_stream:
print(teks, end="", flush=True)
final = stream.get_final_message() # objek lengkap setelah selesai
print(f"\n\nToken keluar: {final.usage.output_tokens}")
Versi async tinggal ganti jadi async with + async for β inilah gunanya Fase 3.
4.3 Β· Tool use β fondasi agent
Ini konsep terpenting di GenAI engineering. LLM tidak mengeksekusi apa pun. Ia hanya meminta kamu menjalankan sebuah fungsi; kamu jalankan, lalu kirim hasilnya kembali. Perulangan inilah yang disebut agentic loop.
from anthropic import beta_tool
@beta_tool
def cari_tiket(status: str, limit: int = 10) -> str:
"""Cari tiket support berdasarkan status.
Args:
status: Status tiket, misal "open" atau "closed".
limit: Jumlah maksimal hasil yang dikembalikan.
"""
return db.query(status=status, limit=limit)
# SDK mengurus loop-nya: panggil API β eksekusi tool β kirim hasil β ulangi
runner = client.beta.messages.tool_runner(
model="claude-opus-5",
max_tokens=16000,
tools=[cari_tiket],
messages=[{"role": "user", "content": "Ada berapa tiket yang masih open?"}],
)
for message in runner:
print(message)
Skema tool dibuat otomatis dari type hint dan docstring. Sekarang jelas kenapa Fase 2 tidak boleh dilewati.
Setelah nyaman dengan tool_runner, pelajari juga manual loop-nya: cek
stop_reason == "tool_use", ambil block tool_use, kirim balik tool_result dengan
tool_use_id yang cocok. Tujuannya supaya kamu paham apa yang sebenarnya terjadi β bukan sekadar memakai
abstraksi yang terasa ajaib.
4.4 Β· Structured output
Memaksa LLM mengeluarkan JSON yang tervalidasi β inilah yang membuat LLM layak dipakai di dalam pipeline.
from pydantic import BaseModel
class Ekstraksi(BaseModel):
nama: str
email: str
minat: list[str]
response = client.messages.parse(
model="claude-opus-5",
max_tokens=4096,
messages=[{"role": "user", "content": "Ekstrak: Budi ([email protected]), tertarik API dan SDK."}],
output_format=Ekstraksi,
)
data = response.parsed_output # instance Ekstraksi, sudah tervalidasi
print(data.nama, data.minat)
4.5 Β· Jembatan ke AWS Bedrock
Bagian yang langsung nyambung ke target sertifikasi. Kode aplikasinya sama persis β yang berbeda hanya client dan prefix model ID.
uv add "anthropic[bedrock]"
from anthropic import AnthropicBedrockMantle
client = AnthropicBedrockMantle(aws_region="us-east-1") # kredensial dari AWS profile/env
response = client.messages.create(
model="anthropic.claude-opus-5", # β prefix "anthropic." khusus Bedrock
max_tokens=16000,
messages=[{"role": "user", "content": "Halo"}],
)
Setelah client dibuat, messages.create, .stream, dan tool use semuanya identik.
Jadi semua yang kamu pelajari di 4.1β4.4 langsung terpakai di Bedrock.
Sebagai pembanding, pelajari juga Converse API milik AWS lewat boto3 β API netral-vendor
yang bentuknya seragam untuk semua model di Bedrock. Ini yang paling sering muncul di materi ujian AWS.
4.6 Β· Yang juga harus dipahami
| Konsep | Kenapa penting |
|---|---|
| Prompt caching | Hemat biaya besar untuk konteks berulang. Cache bekerja secara prefix match β satu byte berubah di depan, seluruh cache setelahnya hangus. |
| Token counting | client.messages.count_tokens() untuk estimasi biaya sebelum kirim. Jangan pakai tiktoken β itu tokenizer OpenAI dan hasilnya salah untuk Claude. |
| Adaptive thinking | thinking={"type": "adaptive"} plus output_config={"effort": ...} untuk tugas yang butuh penalaran dalam. |
| Error handling | Tangkap RateLimitError, APIStatusError, APIConnectionError secara terpisah β jangan satu except Exception. Yang retryable dan tidak harus dibedakan. |
| Pemilihan model | Pilih per-rute, bukan satu model untuk semua: yang paling capable untuk reasoning berat, yang lebih ringan untuk klasifikasi dan tugas sederhana. |
Materi
-
Claude API β Get StartedResmiPanggilan pertama sampai jalan. Mulai dari sini sebelum apa pun.platform.claude.com
-
anthropic-sdk-pythonResmiREADME-nya adalah referensi SDK terlengkap. Folder
examples/berisi program yang bisa langsung dijalankan.github.com -
Streaming MessagesResmiJenis-jenis event pada stream dan cara menanganinya β termasuk saat ada thinking dan tool use.platform.claude.com
-
Tool Use OverviewResmiKonsep terpenting di fase ini. Baca sampai paham alur
tool_useβtool_result.platform.claude.com -
Structured OutputsResmiCara memaksa output sesuai JSON Schema β pasangan langsung dari Pydantic di Fase 2.platform.claude.com
-
Prompt CachingResmiOptimasi biaya paling berdampak. Perhatikan aturan prefix match dan apa saja yang membatalkan cache.platform.claude.com
-
Token CountingResmiHitung token sebelum mengirim request, untuk estimasi biaya dan cek batas context.platform.claude.com
-
Models OverviewResmiDaftar model, context window, dan harga per juta token. Rujukan saat memilih model per-rute.platform.claude.com
-
Claude Platform on AWSResmiCara memakai Claude lewat infrastruktur AWS: setup client, autentikasi, dan perbedaannya dengan Bedrock.platform.claude.com
-
What is Amazon Bedrock?ResmiTitik masuk dokumentasi Bedrock. Wajib untuk sertifikasi AIP-C01.docs.aws.amazon.com
-
Bedrock β Converse APIResmiAPI percakapan seragam lintas model di Bedrock, termasuk tool use dan streaming.docs.aws.amazon.com
-
boto3 β
bedrock-runtime.converse()ResmiReferensi parameter lengkap versi Python. Untuk lookup saat menulis kode.docs.aws.amazon.com -
Claude CookbooksResmiNotebook siap jalan: tool use, RAG, evaluasi, sub-agent. Sumber belajar paling praktis yang ada.github.com
Buat CLI chatbot yang: streaming, mengingat riwayat percakapan, punya 2 tool (misal kalkulator dan pencarian file lokal), memakai structured output untuk satu perintah, dan mencetak total biaya di akhir sesi.
Bangun API dengan FastAPI
Tujuan: membungkus aplikasi LLM-mu jadi HTTP API yang bisa dipakai frontend, lengkap dengan streaming token.
FastAPI adalah standar de facto untuk men-serve model di Python. Ia dibangun di atas Pydantic dan async β dua hal yang sudah kamu kuasai di Fase 2 dan 3, jadi fase ini akan terasa cepat.
from fastapi import FastAPI, Depends, HTTPException
from pydantic import BaseModel
app = FastAPI()
class ChatRequest(BaseModel):
pesan: str
session_id: str
class ChatResponse(BaseModel):
balasan: str
token_terpakai: int
@app.post("/chat")
async def chat(req: ChatRequest) -> ChatResponse:
... # validasi request & serialisasi response otomatis dari type hint
Streaming ke browser (SSE)
FastAPI punya dukungan Server-Sent Events bawaan lewat EventSourceResponse. Cukup yield
dari path operation β keep-alive ping, header anti-cache, dan pencegahan buffering proxy diurus otomatis.
from collections.abc import AsyncIterable
from fastapi.sse import EventSourceResponse
@app.post("/chat/stream", response_class=EventSourceResponse)
async def chat_stream(req: ChatRequest) -> AsyncIterable[str]:
async with async_client.messages.stream(
model="claude-opus-5",
max_tokens=16000,
messages=[{"role": "user", "content": req.pesan}],
) as stream:
async for teks in stream.text_stream:
yield teks
Yang perlu dikuasai
- Request/response model Pydantic β validasi otomatis, plus dokumentasi interaktif gratis di
/docs Depends()β dependency injection untuk auth, koneksi DB, dan client LLMEventSourceResponseβ streaming token ke browserlifespanβ buat client LLM sekali saat startup, bukan tiap requestBackgroundTasksβ pekerjaan yang tidak perlu ditunggu klien- Exception handler global β ubah error internal jadi respons HTTP yang rapi
- Jalankan dengan
uv run uvicorn main:app --reload
Jebakan async di FastAPI: menaruh kode blocking (misal requests.get() atau query DB sync)
di dalam async def akan memblokir seluruh event loop dan menjatuhkan throughput semua request lain.
Kalau fungsimu blocking, deklarasikan sebagai def biasa β FastAPI otomatis menjalankannya di threadpool.
Materi
-
FastAPI β Tutorial User GuideResmiSalah satu dokumentasi terbaik di ekosistem Python. Bertahap dan penuh contoh yang bisa dijalankan.fastapi.tiangolo.com
-
Concurrency and async / awaitResmiKapan pakai
async def, kapandefbiasa. Baca ini untuk menghindari jebakan blocking di atas.fastapi.tiangolo.com -
DependenciesResmiSistem DI FastAPI β cara bersih menyuntik client LLM, session DB, dan user terautentikasi.fastapi.tiangolo.com
-
Server-Sent Events (SSE)ResmiCara resmi streaming di FastAPI, termasuk
ServerSentEventdan resume viaLast-Event-ID.fastapi.tiangolo.com -
Lifespan EventsResmiSetup dan teardown resource aplikasi β tempat yang benar untuk membuat client LLM.fastapi.tiangolo.com
-
Run a Server ManuallyResmiUvicorn, worker, dan opsi menjalankan di production.fastapi.tiangolo.com
Endpoint chat streaming yang berjalan dan bisa dicoba dari browser, dengan client LLM dibuat sekali di lifespan.
Data, Testing, Deploy
Tujuan: proyek yang punya struktur benar, ada testnya, dan bisa dijalankan orang lain lewat satu perintah Docker.
Data β secukupnya saja
| Library | Sejauh apa perlu |
|---|---|
json | Wajib lancar. json.dumps(d, sort_keys=True) untuk output deterministik β penting agar prompt caching tidak batal. |
numpy | Secukupnya: array, dot product, cosine similarity β untuk bekerja dengan embedding. |
pandas | Dasar saja: read_csv, filter, groupby. Jangan habiskan seminggu di sini. |
sqlite3 / SQLAlchemy | Menyimpan riwayat percakapan dan metadata dokumen. |
| ChromaDB | Vector store lokal untuk belajar RAG. Di AWS nanti: OpenSearch atau pgvector. |
import numpy as np
def cosine_similarity(a: np.ndarray, b: np.ndarray) -> float:
return float(np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b)))
Testing
import pytest
from myapp import ekstrak
def test_ekstrak_email():
assert ekstrak("Hubungi [email protected]").email == "[email protected]"
@pytest.mark.parametrize("teks,jumlah", [("a b", 2), ("satu", 1), ("", 0)])
def test_hitung_kata(teks, jumlah):
assert hitung_kata(teks) == jumlah
@pytest.fixture
def fake_llm(monkeypatch):
... # mock LLM β JANGAN panggil API asli di unit test
Prinsip testing aplikasi LLM: mock panggilan LLM di unit test supaya deterministik, gratis, dan cepat. Untuk menilai kualitas output LLM, itu bukan unit test β itu eval, dijalankan terpisah dengan dataset dan rubrik penilaian sendiri. Mencampur keduanya membuat CI-mu lambat sekaligus flaky.
Struktur proyek & deploy
proyek/
βββ pyproject.toml
βββ Dockerfile
βββ src/myapp/
β βββ __init__.py
β βββ main.py # entrypoint FastAPI
β βββ llm.py # semua interaksi dengan LLM
β βββ models.py # model Pydantic
β βββ settings.py # config
βββ tests/
- Docker: base
python:3.13-slim, multi-stage build, pakaiuv sync --frozen - Logging: modul
loggingbawaan, dikonfigurasi sekali di entrypoint β bukanprint() - Secret dari environment variable lewat
pydantic-settingsβ jangan pernah hardcode API key
Materi
-
NumPy: the absolute basics for beginnersResmiCukup sampai bagian operasi array dan broadcasting. Tidak perlu lebih jauh untuk sekarang.numpy.org
-
10 minutes to pandasResmiPersis sebanyak yang kamu butuhkan. Jangan tergoda mendalami pandas sekarang.pandas.pydata.org
-
pytest β How to use fixturesResmiFixture adalah cara pytest melakukan setup/teardown dan mocking. Konsep inti.docs.pytest.org
-
pytest β Parametrizing testsResmiSatu fungsi test, banyak kasus. Menghemat banyak duplikasi.docs.pytest.org
-
Logging HOWTOResmiLevel, handler, formatter. Baca bagian βBasicβ dan βAdvancedβ, lalu berhentilah pakai
print().docs.python.org -
uv β Using uv in DockerResmiDockerfile yang benar dengan uv, termasuk cache mount dan build multi-stage.docs.astral.sh
-
Docker β Python language guideResmiContainerize aplikasi Python dari nol sampai jalan, termasuk compose untuk dependensi.docs.docker.com
Proyek dengan struktur src/ di atas, test lolos, ter-Dockerize, dan berjalan dengan satu docker run.
Capstone: RAG Chatbot
Tujuan: satu aplikasi utuh yang menggabungkan seluruh fase β dan kebetulan persis arsitektur yang diuji di sertifikasi.
Teori tanpa proyek akan hilang dalam sebulan. Kerjakan satu ini sampai tuntas: RAG chatbot atas dokumenmu sendiri.
Requirement
- Ingest β baca folder PDF/Markdown β chunking β embedding β simpan ke ChromaDB
- Retrieval β cari chunk paling relevan dengan cosine similarity
- Generation β kirim chunk + pertanyaan ke LLM, streaming jawaban
- Sitasi β sebutkan chunk mana yang dipakai; jangan biarkan model mengarang sumber
- API β FastAPI dengan endpoint streaming SSE
- Riwayat β percakapan tersimpan di SQLite
- Tool β LLM bisa memanggil
cari_dokumen()sendiri, bukan retrieval yang selalu dipaksa di depan - Biaya β tracking token per-request dari
response.usage - Test β untuk chunking dan retrieval, dengan LLM di-mock
- Docker β satu perintah untuk menjalankan semuanya
Kenapa proyek ini: arsitekturnya persis yang diuji di AWS Certified Generative AI Developer β Professional, di Domain 1 dan 2 yang menyumbang 57% bobot ujian. Nanti tinggal ganti komponennya ke versi AWS: ChromaDB β Bedrock Knowledge Bases, tool manual β Bedrock Agents, filter β Bedrock Guardrails.
Bonus kalau masih semangat
- Guardrails β filter input/output, deteksi PII sebelum masuk prompt
- Evaluation β dataset 20 pertanyaan + penilaian jawaban dengan LLM-as-judge
- Contextual retrieval β teknik menambahkan konteks ke tiap chunk sebelum embedding, mengurangi kegagalan retrieval secara signifikan
- Deploy ke AWS Lambda dengan container image
Materi
-
Chroma β IntroductionResmiVector database paling mudah untuk belajar. Bisa jalan in-process tanpa server terpisah.docs.trychroma.com
-
Claude CookbooksResmiCari notebook RAG dan evaluasi. Ini contoh implementasi paling dekat dengan capstone-mu.github.com
-
Introducing Contextual RetrievalArtikelKenapa RAG naif sering gagal, dan teknik chunking yang memperbaikinya. Bacaan wajib sebelum menulis ingest pipeline.anthropic.com
-
Bedrock Knowledge BasesResmiVersi terkelola dari yang kamu bangun manual. Baca setelah capstone selesai β supaya paham apa yang di-abstraksi.docs.aws.amazon.com
-
Amazon Bedrock SamplesResmiNotebook resmi AWS: Converse API, Knowledge Bases, Agents, Guardrails. Jembatan ke persiapan ujian.aws-samples.github.io
RAG chatbot berjalan end-to-end: ingest dokumen, jawab dengan sitasi yang benar, streaming ke browser, dan laporkan biaya per percakapan.
Aturan main
- Ketik ulang setiap contoh kode. Copy-paste tidak menghasilkan pembelajaran apa pun.
- Baca error message sampai habis. Traceback Python sangat informatif β baris paling bawah yang paling penting.
- Macet lebih dari 30 menit? Lanjut dulu. Sering kali paham belakangan setelah melihat konteks lain.
- Type hint sejak hari pertama. βNanti sajaβ berarti tidak pernah.
- Satu proyek nyata mengalahkan sepuluh tutorial. Kerjakan checkpoint-nya, jangan dilewati.
- Jangan sentuh LangChain dulu. Pelajari SDK mentahnya supaya paham apa yang sebenarnya terjadi. Framework adalah abstraksi di atas hal yang harus kamu pahami lebih dulu.
Setelah ini
Lanjut ke roadmap AWS: menutup gap serverless, IAM, IaC, dan observability, lalu masuk ke Bedrock secara mendalam menuju AWS Certified Generative AI Developer β Professional (AIP-C01). Python yang kamu bangun di sini akan jadi bahasa kerja untuk semuanya.