Menyajikan LLM di Produksi dengan Text Generation Inference (TGI)
Text Generation Inference (TGI) adalah toolkit buatan Hugging Face yang dirancang khusus untuk menyajikan large language model di balik API HTTP produksi. TGI memadukan lapisan web Rust dengan backend inferensi Python, didistribusikan sebagai image Docker siap pakai, dan menyediakan Messages API yang kompatibel dengan OpenAI sehingga klien yang sudah ada bisa dipakai dengan perubahan minimal. Tutorial ini membahas cara men-deploy TGI, menyetel launcher-nya, dan memanggilnya dari curl, klien OpenAI, serta klien Hugging Face Hub.
Apa Itu TGI
TGI adalah server inferensi yang dikelola Hugging Face dan menjadi penggerak layanan Inference Endpoints mereka. Secara arsitektur, tanggung jawabnya terbagi:
- Sebuah router/webserver Rust menangani HTTP, validasi request, keputusan batching, dan streaming token. Rust menjaga jalur penanganan request tetap cepat dan aman memori di bawah konkurensi.
- Sebuah model server Python (satu proses per shard) menjalankan forward pass model di GPU, memakai kernel attention dan batching yang teroptimasi.
Pemisahan ini membuat lapisan jaringan yang sibuk tetap ringan, sementara pekerjaan numerik berat berada di kode Python/CUDA yang sudah teruji. Karena TGI dibuat oleh tim yang sama di balik library Transformers dan Hub, pemuatan model, penanganan tokenizer, dan autentikasi model gated terhubung secara alami dengan ekosistem Hugging Face lainnya.
Fitur Utama
- Continuous batching. Request yang masuk bergabung ke batch yang sedang berjalan begitu slot tersedia, bukan menunggu jendela batch tetap. Ini menjaga GPU tetap sibuk dan meningkatkan throughput pada beban campuran.
- Tensor parallelism (sharding). Model dapat dibagi ke beberapa GPU dengan
--num-shard, memungkinkan model yang tidak muat di satu kartu. - Attention teroptimasi. TGI memakai kernel Flash Attention dan Paged Attention untuk mengurangi pemakaian memori dan mempercepat prefill maupun decode.
- Streaming token. Server-Sent Events (SSE) mengalirkan token saat diproduksi, sehingga menurunkan latensi yang dirasakan pada antarmuka chat.
- Kuantisasi. Dukungan bawaan untuk
bitsandbytes, GPTQ, AWQ, dan skema lain agar model besar muat di VRAM yang lebih kecil. - Messages API kompatibel OpenAI. Endpoint
/v1/chat/completionsyang meniru bentuk request/response OpenAI.
Jika Anda sudah membaca tutorial vLLM kami: kedua server melakukan continuous batching dan paged attention, serta sama-sama menyediakan API gaya OpenAI. Perbedaan praktisnya ada pada pengemasan dan ekosistem. TGI mengutamakan Docker, terintegrasi erat dengan Hub dan Inference Endpoints, serta digerakkan oleh satu binary launcher dengan flag yang eksplisit. Perbandingan lebih konkret ada di bagian akhir.
Prasyarat
- Mesin dengan satu atau beberapa GPU NVIDIA dan driver terbaru.
- Docker dengan NVIDIA Container Toolkit terpasang, agar
--gpus allberfungsi. - Akun Hugging Face dan access token jika Anda berencana menyajikan model gated seperti keluarga Llama. Buat token di Settings → Access Tokens.
Pastikan akses GPU di dalam Docker sebelum melanjutkan:
docker run --rm --gpus all nvidia/cuda:12.4.0-base-ubuntu22.04 nvidia-smi
Jika tabel GPU tercetak, runtime container dapat melihat perangkat keras Anda.
Jalur Tercepat: Menjalankan TGI dengan Docker
TGI didistribusikan sebagai image container di ghcr.io/huggingface/text-generation-inference. Yang minimum Anda butuhkan adalah ID model dan akses GPU. Kita akan memakai model Mistral instruct, yang terbuka dan cukup kecil untuk berjalan di satu GPU kelas menengah.
# Gunakan kembali direktori host untuk cache model agar pengulangan tidak mengunduh ulang
mkdir -p $HOME/.cache/huggingface
docker run --gpus all --shm-size 1g -p 8080:80 \
-v $HOME/.cache/huggingface:/data \
ghcr.io/huggingface/text-generation-inference:latest \
--model-id mistralai/Mistral-7B-Instruct-v0.3
Beberapa detail penting di sini:
--gpus allmengekspos GPU ke container.-p 8080:80memetakan port 80 container ke port 8080 host. Secara default TGI mendengarkan di port 80 di dalam container.-v $HOME/.cache/huggingface:/datame-mount cache persisten. Bobot diunduh sekali ke/datadan dipakai ulang antar restart container, sehingga menghemat waktu dan bandwidth.--shm-size 1gmenaikkan shared memory; model server memakainya untuk komunikasi antar-proses, dan nilai default bisa terlalu kecil untuk setup sharded.- Semua argumen setelah nama image diteruskan ke launcher TGI, bukan ke Docker.
--model-idadalah argumen wajib launcher.
Menyajikan Model Gated
Model seperti meta-llama/Llama-3.1-8B-Instruct mengharuskan persetujuan lisensi dan autentikasi. Teruskan token Anda melalui variabel lingkungan HFTOKEN:
docker run --gpus all --shm-size 1g -p 8080:80 \
-v $HOME/.cache/huggingface:/data \
-e HFTOKEN=$HFTOKEN \
ghcr.io/huggingface/text-generation-inference:latest \
--model-id meta-llama/Llama-3.1-8B-Instruct
Set token di shell terlebih dahulu dengan export HFTOKEN=hfxxx. Jangan pernah menanamkan token ke dalam image atau menyimpannya di kontrol versi.
Memastikan Server Sudah Aktif
TGI mencatat Connected dan pesan siap setelah bobot dimuat dan warmup selesai. Anda dapat menguji endpoint health:
curl http://localhost:8080/health
Respons 200 OK dengan body kosong berarti server siap menerima request.
Flag Launcher yang Penting
Launcher menyediakan banyak flag; yang di bawah ini paling berdampak pada memori dan throughput. Anda bisa melihat semuanya dengan docker run ... --help.
Anggaran Token
docker run --gpus all --shm-size 1g -p 8080:80 \
-v $HOME/.cache/huggingface:/data \
ghcr.io/huggingface/text-generation-inference:latest \
--model-id mistralai/Mistral-7B-Instruct-v0.3 \
--max-input-tokens 4096 \
--max-total-tokens 8192 \
--max-batch-prefill-tokens 8192
--max-input-tokensmembatasi panjang prompt yang boleh dikirim satu request. Request di atas batas ini ditolak lebih awal.--max-total-tokensmembatasi prompt ditambah token yang dihasilkan. Selisih antara nilai ini dan--max-input-tokensadalah ruang yang tersisa untuk generasi.--max-batch-prefill-tokensmembatasi berapa banyak token prompt yang diproses TGI dalam satu langkah prefill di seluruh batch. Ini adalah tombol utama untuk tekanan memori prefill; setel sama atau sedikit di atas--max-input-tokensuntuk prompt panjang tunggal.
Ketiga nilai ini bersama-sama mendefinisikan working set yang dicadangkan TGI di GPU. Menyetelnya lebih rendah dari maksimum teoritis model adalah cara umum untuk memuat model dan menyisakan ruang untuk konkurensi.
Tensor Parallelism
docker run --gpus all --shm-size 1g -p 8080:80 \
-v $HOME/.cache/huggingface:/data \
ghcr.io/huggingface/text-generation-inference:latest \
--model-id meta-llama/Llama-3.1-70B-Instruct \
--num-shard 4
--num-shard 4 membagi model ke empat GPU memakai tensor parallelism. Gunakan ini saat model tidak muat di satu kartu. Jumlah shard biasanya harus membagi habis jumlah attention head model, dan semua shard harus terlihat oleh container.
Kuantisasi dan Presisi
docker run --gpus all --shm-size 1g -p 8080:80 \
-v $HOME/.cache/huggingface:/data \
ghcr.io/huggingface/text-generation-inference:latest \
--model-id mistralai/Mistral-7B-Instruct-v0.3 \
--quantize bitsandbytes \
--dtype float16
--quantizemenerimabitsandbytes(8-bit/4-bit on-the-fly),gptq,awq,eetq, dan lainnya. GPTQ dan AWQ membutuhkan model yang sudah memiliki bobot terkuantisasi; bitsandbytes dapat mengkuantisasi checkpoint standar saat dimuat tetapi lebih lambat.--dtypemenetapkan presisi komputasi, biasanyafloat16ataubfloat16. Biarkan pada default kecuali ada alasan spesifik, dan jangan menggabungkan--dtypedengan checkpoint GPTQ/AWQ yang sudah terkuantisasi.
Panduan praktis: utamakan checkpoint AWQ atau GPTQ bila tersedia untuk model Anda, karena keduanya disetel untuk inferensi. Pakai bitsandbytes saat Anda hanya punya checkpoint presisi penuh dan perlu mengecilkannya dengan cepat.
Memanggil Server
TGI menyediakan dua keluarga endpoint: API native /generate dan Messages API kompatibel OpenAI di /v1/chat/completions.
Native /generate dan /generatestream
Endpoint native menerima teks input mentah dan parameter generasi. Endpoint ini tidak menerapkan chat template, jadi Anda mengontrol prompt secara persis.
curl http://localhost:8080/generate \
-H 'Content-Type: application/json' \
-d '{
"inputs": "[INST] Jelaskan continuous batching dalam satu paragraf. [/INST]",
"parameters": {
"maxnewtokens": 200,
"temperature": 0.7,
"topp": 0.95
}
}'
Responsnya adalah objek JSON dengan field generatedtext. Untuk streaming, pakai /generatestream, yang mengembalikan Server-Sent Events:
curl http://localhost:8080/generatestream \
-H 'Content-Type: application/json' \
-d '{
"inputs": "[INST] Sebutkan tiga kegunaan streaming token. [/INST]",
"parameters": { "maxnewtokens": 150 }
}'
Setiap event membawa objek token saat dihasilkan, dan event terakhir menyertakan generatedtext serta detail waktu.
Messages API (Kompatibel OpenAI) dengan curl
Endpoint /v1/chat/completions menerima request gaya OpenAI. TGI menerapkan chat template model secara otomatis berdasarkan array messages, jadi Anda tidak perlu menulis tanda [INST] secara manual.
curl http://localhost:8080/v1/chat/completions \
-H 'Content-Type: application/json' \
-d '{
"model": "tgi",
"messages": [
{"role": "system", "content": "Anda asisten yang ringkas."},
{"role": "user", "content": "Apa itu tensor parallelism?"}
],
"maxtokens": 200,
"temperature": 0.7
}'
Field model diterima tetapi tidak dipakai untuk routing; TGI menyajikan model apa pun yang dijalankan saat startup. Isi dengan placeholder apa saja seperti "tgi".
Messages API dengan Klien Python OpenAI
Karena endpoint kompatibel OpenAI, library resmi openai bekerja dengan mengarahkan baseurl ke server TGI Anda. Ini jalur migrasi paling sederhana untuk kode yang sudah ditulis untuk OpenAI.
from openai import OpenAI
client = OpenAI(
baseurl="http://localhost:8080/v1",
apikey="not-needed", # TGI mengabaikan key kecuali Anda menambahkan auth di depannya
)
resp = client.chat.completions.create(
model="tgi",
messages=[
{"role": "system", "content": "Anda asisten yang ringkas."},
{"role": "user", "content": "Ringkas apa yang dilakukan TGI dalam dua kalimat."},
],
maxtokens=200,
temperature=0.7,
)
print(resp.choices[0].message.content)
Streaming memakai pola stream=True yang sama seperti OpenAI:
stream = client.chat.completions.create(
model="tgi",
messages=[{"role": "user", "content": "Hitung dari 1 sampai 5 perlahan."}],
maxtokens=100,
stream=True,
)
for chunk in stream:
delta = chunk.choices[0].delta.content
if delta:
print(delta, end="", flush=True)
print()
Memakai huggingfacehub.InferenceClient
Library huggingfacehub menyediakan InferenceClient yang berbicara langsung dengan TGI. Ia menawarkan metode tingkat rendah textgeneration yang cocok dengan API native dan metode chatcompletion yang cocok dengan Messages API.
from huggingfacehub import InferenceClient
client = InferenceClient(baseurl="http://localhost:8080")
Generasi teks native
out = client.textgeneration(
"[INST] Berikan satu manfaat paged attention. [/INST]",
maxnewtokens=120,
temperature=0.7,
)
print(out)
Chat completion dengan klien yang sama:
completion = client.chatcompletion(
messages=[
{"role": "user", "content": "Jelaskan kuantisasi dalam dua kalimat."},
],
max
tokens=150,
)
print(completion.choices[0].message.content)
Kedua metode mendukung streaming. Untuk generasi teks, teruskan stream=True dan iterasi token:
for token in client.textgeneration(
"[INST] Sebutkan dua flag launcher TGI. [/INST]",
max
newtokens=80,
stream=True,
):
print(token, end="", flush=True)
print()
Untuk chat, chatcompletion(..., stream=True) menghasilkan chunk yang choices[0].delta.content-nya berisi setiap potongan inkremental, meniru bentuk OpenAI.
Output Terstruktur dengan JSON Grammar
TGI dapat membatasi generasi sehingga model menghasilkan teks yang sesuai dengan skema JSON. Dengan Messages API Anda memakai responseformat, yang dipetakan ke grammar secara internal dan menjamin output dapat di-parse.
from openai import OpenAI
client = OpenAI(baseurl="http://localhost:8080/v1", apikey="not-needed")
schema = {
"type": "object",
"properties": {
"kota": {"type": "string"},
"populasi": {"type": "integer"},
},
"required": ["kota", "populasi"],
}
resp = client.chat.completions.create(
model="tgi",
messages=[{"role": "user", "content": "Berikan kota dan populasi Jakarta."}],
responseformat={"type": "jsonobject", "value": schema},
maxtokens=100,
)
print(resp.choices[0].message.content)
Pada endpoint native /generate, padanannya adalah field grammar di dalam parameters dengan {"type": "json", "value": . Decoding terbatas berguna untuk pipeline ekstraksi di mana kode hilir harus mem-parse hasil tanpa pembersihan defensif.
Men-deploy di Kubernetes
TGI berjalan baik sebagai Deployment Kubernetes standar ditambah Service. Container membutuhkan permintaan resource GPU, cache yang di-mount sebagai volume, dan flag launcher diteruskan sebagai args. Contoh di bawah mengasumsikan NVIDIA device plugin terpasang sehingga nvidia.com/gpu dapat dijadwalkan.
apiVersion: apps/v1
kind: Deployment
metadata:
name: tgi-mistral
labels:
app: tgi-mistral
spec:
replicas: 1
selector:
matchLabels:
app: tgi-mistral
template:
metadata:
labels:
app: tgi-mistral
spec:
containers:
- name: tgi
image: ghcr.io/huggingface/text-generation-inference:latest
args:
- "--model-id"
- "mistralai/Mistral-7B-Instruct-v0.3"
- "--max-input-tokens"
- "4096"
- "--max-total-tokens"
- "8192"
ports:
- containerPort: 80
env:
- name: HFTOKEN
valueFrom:
secretKeyRef:
name: hf-secret
key: token
resources:
limits:
nvidia.com/gpu: 1
volumeMounts:
- name: model-cache
mountPath: /data
- name: dshm
mountPath: /dev/shm
volumes:
- name: model-cache
persistentVolumeClaim:
claimName: tgi-cache-pvc
- name: dshm
emptyDir:
medium: Memory
sizeLimit: 1Gi
Service yang menyertainya mengekspos pod di dalam cluster:
apiVersion: v1
kind: Service
metadata:
name: tgi-mistral
spec:
selector:
app: tgi-mistral
ports:
- port: 8080
targetPort: 80
Perhatikan volume dshm yang di-mount di /dev/shm; ini padanan Kubernetes dari --shm-size dan mencegah error shared memory saat startup sharded. Simpan token dalam Secret bernama hf-secret dan PersistentVolumeClaim bernama tgi-cache-pvc agar bobot bertahan antar restart pod.
Catatan tentang Hugging Face Inference Endpoints
Jika Anda lebih memilih tidak menjalankan infrastruktur sendiri, Hugging Face Inference Endpoints men-deploy model di perangkat keras terkelola dengan TGI di baliknya. Anda memilih model dan tipe instance, lalu memperoleh endpoint HTTPS yang berbicara dengan API /generate dan /v1/chat/completions yang sama seperti dijelaskan di atas. Kompromi-nya adalah kenyamanan versus kontrol: endpoint terkelola menghapus beban operasional, sedangkan self-hosting memberi kontrol penuh atas perangkat keras, jaringan, dan biaya.
Observabilitas dan Benchmark
Metrik Prometheus
TGI menyediakan endpoint metrik Prometheus di /metrics:
curl http://localhost:8080/metrics
Endpoint ini melaporkan jumlah request, durasi antrian, durasi inferensi, ukuran batch, dan throughput token. Konfigurasi scrape umum di Prometheus:
scrapeconfigs:
- jobname: tgi
staticconfigs:
- targets: ["tgi-mistral:8080"]
Pantau durasi antrian dan pengisian batch: waktu antrian yang naik pada beban tetap menandakan Anda sudah jenuh dan perlu menambah instance atau menaikkan anggaran token.
Benchmark dengan text-generation-benchmark
Image menyertakan alat benchmark yang membebani server yang sedang berjalan dan melaporkan latensi serta throughput. Jalankan di dalam container yang sama:
docker exec -it \
text-generation-benchmark \
--tokenizer-name mistralai/Mistral-7B-Instruct-v0.3 \
--sequence-length 512 \
--decode-length 128 \
--batch-size 1 --batch-size 8 --batch-size 32
Alat ini menyapu ukuran batch yang terdaftar dan mencetak waktu prefill serta decode per batch, yang membantu Anda memilih anggaran token dan memahami bagaimana throughput berskala dengan konkurensi sebelum menetapkan setelan produksi.
Memilih TGI atau vLLM
Keduanya server inferensi yang kuat dan aktif dikembangkan dengan teknik inti yang tumpang tindih. Pandangan yang seimbang:
- Pilih TGI saat Anda sudah berada di ekosistem Hugging Face, ingin satu image Docker yang didukung resmi, menghargai integrasi erat dengan Hub dan Inference Endpoints, atau lebih suka launcher dengan flag yang eksplisit dan terdokumentasi baik. Router Rust andal di bawah konkurensi, dan jalur endpoint terkelola adalah jalan keluar yang rapi.
- Pilih vLLM saat Anda ingin dukungan terluas dan sering paling awal untuk model dan format kuantisasi baru, membutuhkan fitur penjadwalannya yang spesifik, atau membangun di atas stack Python-native di mana API library vLLM lebih pas.
Pada praktiknya keduanya konvergen pada throughput untuk model umum, jadi keputusan biasanya bergantung pada kecocokan ekosistem dan preferensi operasional, bukan kecepatan mentah. Lakukan benchmark keduanya pada model dan pola trafik Anda sendiri sebelum memutuskan.
Praktik Terbaik
- Mount cache. Selalu ikatkan volume host atau PVC ke
/dataagar bobot diunduh sekali saja. - Setel anggaran token secara sengaja. Setel
--max-input-tokens,--max-total-tokens, dan--max-batch-prefill-tokenssesuai panjang prompt nyata, bukan membiarkan default; ini mengembalikan VRAM untuk konkurensi. - Jauhkan rahasia dari image. Suntikkan
HFTOKENmelalui variabel lingkungan atau Kubernetes Secret, jangan pernah di dalam image atau repo. - Utamakan checkpoint terkuantisasi. Bobot AWQ atau GPTQ umumnya lebih unggul dibanding kuantisasi bitsandbytes on-the-fly untuk penyajian.
- Atur ukuran
/dev/shm. Deployment sharded membutuhkan shared memory yang memadai; setel--shm-sizedi Docker atauemptyDirmemori di Kubernetes. - Stream untuk chat. Pakai
/generatestreamataustream=Trueuntuk memangkas latensi yang dirasakan pada antarmuka interaktif. - Ukur sebelum scaling. Pakai
text-generation-benchmarkdan/metricsuntuk menemukan bottleneck nyata alih-alih menebak. - Kunci tag image. Pakai tag versi spesifik alih-alih
latestdi produksi agar deployment dapat direproduksi.
Kesimpulan dan Poin Penting
TGI memberi Anda server LLM kelas produksi dengan setup sangat sedikit: satu perintah Docker, sebuah ID model, dan cache yang di-mount sudah cukup untuk membuat endpoint berjalan dengan continuous batching dan attention teroptimasi. Messages API yang kompatibel OpenAI berarti kode klien OpenAI yang sudah ada bekerja hanya dengan mengubah baseurl, sedangkan endpoint native /generate dan huggingfacehub.InferenceClient memberi kontrol lebih halus serta integrasi langsung dengan Hub.
Poin penting:
- TGI adalah router Rust ditambah model server Python, didistribusikan sebagai image Docker dan terintegrasi erat dengan Hugging Face Hub.
- Flag launcher untuk anggaran token, sharding, dan kuantisasi adalah tuas utama Anda untuk memuat model dan menyetel throughput.
- Anda dapat memanggilnya dengan tiga cara: native
/generate,/v1/chat/completionsyang kompatibel OpenAI, danInferenceClient— semuanya dengan dukungan streaming dan output terstruktur. - TGI ter-deploy rapi di Kubernetes dan tersedia sepenuhnya terkelola melalui Inference Endpoints.
- Dibanding vLLM, pilihan biasanya bergantung pada kecocokan ekosistem; benchmark keduanya pada beban kerja Anda sebelum memutuskan.
Dengan perintah dan konfigurasi pada panduan ini, Anda dapat menjalankan model Mistral atau Llama instruct, memanggilnya dari berbagai klien, dan memindahkannya ke Kubernetes saat siap untuk trafik produksi.