Retrieval Augmented Generation

Retrieval Augmented Generation (RAG) adalah salah satu cara untuk membuat sebuah Large Language Model (LLM) agar bisa menjawab dengan akurat berbasis fakta. Ada banyak variasi detail implementasi RAG, tapi intinya sederhana: kita memberikan informasi berupa teks tambahan kepada LLM untuk menjawab sebuah pertanyaan.

Sebagai catatan: sudah ada banyak sekali produk RAG baik open source maupun komersial. Tulisan ini hanya sekedar memperkenalkan cara kerjanya, supaya tahu bagaimana mengevaluasi produk yang ada atau memodifikasi produknya.

Mari kita bahas beberapa konsep mengenai LLM, embedding, database vektor, dan bagaimana bisa menyusun ini untuk RAG.

Di teks ini saya akan memakai OpenAI API karena saat ini merupakan yang paling mudah dipakai, reliable dan murah. Tapi kita bisa memanfaatkan LLM apapun juga. untuk RAG ini, walau hasilnya bisa bervariasi.

Lanjutkan membaca Retrieval Augmented Generation

Mengenal dan memakai instruksi SIMD

Instruksi SIMD (Single Instruction Multiple Data) adalah jenis instruksi pada prosesor modern yang bisa melakukan operasi terhadap banyak data sekaligus (biasanya bentuknya adalah array/vector). Instruksi assembly dalam sebuah ISA biasanya hanya melakukan hal dasar berikut:

  • Menyalin data dari memori/register ke memori/register
  • Melakukan operasi terhadap satu atau lebih register dan menyimpan hasilnya di memori atau register (contoh: penjumlahan, perkalian, operasi bit, dsb). Beberapa operasi akan mempengaruhi flag pada CPU.
  • Memindahkan alur eksekusi ke alamat tertentu dalam kondisi tertentu (biasanya berdasarkan flag)
  • Melakukan manipulasi hardware spesifik (misalnya mengakses I/O, enable interrupt, enable paging, dsb)

Instruksi SIMD bisa melakukan load/save register dari/ke memori, melakukan manipulasi pada register, tapi satu instruksi bisa memproses banyak data sekaligus. Jika dilakukan dengan benar, ini bisa mempercepat program cukup signifikan. Instruksi SIMD tidak bisa melakukan branching ke banyak alamat sekaligus.

Sejarah SIMD ini cukup panjang: singkatnya tahun 1970an sudah dipikirkan ide ini dan sudah diimplementasikan di berbagai komputer besar, tapi baru masuk ke CPU untuk consumer di akhir abad lalu. Data yang diproses semuanya perlu berurutan (seperti array) dan biasanya disebut sebagai vector (tidak berhubungan dengan istilah vektor di matematika).

Lanjutkan membaca Mengenal dan memakai instruksi SIMD

Mengenal algoritma kompresi Zstandard

Zstandard, atau lebih dikenal dengan nama implementasinya: zstd, adalah algoritma kompresi lossless yang sangat cepat dan fleksibel. Algoritma kompresi ini sudah disupport di banyak software, sampai sudah masuk di kernel Linux. Salah satu keunikan kompresi dengan zstandard adalah adanya fitur custom dictionary dan waktu kompresi dan dekompresi yang cepat. Kita bisa membuat custom dictionary untuk aplikasi kita sendiri. Bagian dictionary ini yang akan saya bahas lebih dalam pemanfaatnya di tulisan ini.

Lengkapnya bisa dilihat di: https://facebook.github.io/zstd/
Lanjutkan membaca Mengenal algoritma kompresi Zstandard

Membuat Telegram Bot memakai API ChatGPT di AWS Lambda

Saat ini OpenAI sudah meluncurkan API ChatGPT resmi. Di tulisan ini saya akan memandu bagaimana membuat ChatBot telegram dengan API ChatGPT, dan bagaimana menghosting ini di AWS Lambda. Dengan AWS Lamba, kita bisa menghosting bot telegram secara gratis (sampai setidaknya ratusan ribu pesan per bulan).

Untuk apa menghosting bot sendiri? bukankah sudah ada banyak yang menyediakan gratis di telegram dan WhatsApp? Apakah Anda pernah bertanya: siapa pemilik botnya? apa kebijakan privasi datanya? apakah chat Anda akan direkam selamanya? Sementara versi ChatGPT gratis sekarang sering down ketika dibutuhkan (atau error di tengah percakapan).

Saat ini OpenAI sudah menyatakan bahwa API ChatGPT tidak akan menggunakan data yang kita kirimkan untuk melatih sistem mereka, dan data akan dihapus dalam sebulan. Saya percaya OpenAI bukan karena mereka pasti bisa dipercaya, tapi karena jika mereka tidak patuh, bisa kena denda yang sangat besar. Dengan mengakses API ChatGPT langsung, saya yakin yang memegang data hanya saya dan OpenAI, bukan pihak lain.

Selain itu kita bisa meng-customize bot kita dengan kepribadian sesuai yang kita mau. Bahkan kita bisa membuat banyak bot dengan kepribadian masing-masing. Kita juga bisa menghubungkan output ChatGPT dengan program kita untuk melakukan aksi tertentu.

Contoh bot telegram

Sebelum API resmi diluncurkan, sudah ada yang berusaha membuat API ChatGPT dengan emulasi browser, tapi cara ini kurang stabil dan ChatGPT gratisan sering tidak tersedia (tidak reliable) dan kadang library perlu diupdate tiap kali ada perubahan di sisi OpenAI. Dengan API resmi, kita bisa mendapatkan jawaban dengan cepat dan API-nya tidak akan tiba-tiba berubah tanpa peringatan.

ChatGPT through the lens of The Dunning-Kruger effect

Harga API ChatGPT sangat murah, hanya 0.002 USD per 1000 token. Apa itu token? token adalah pembagian kata yang dilakukan untuk pemrosesan bahasa alami, untuk memahami token, mudahnya bisa langsung mencoba di URL ini. Untuk pemakaian pribadi, ratusan sampai ribuan pertanyaan bisa ditanyakan dengan biaya total puluhan ribu rupiah saja.

Memahami token dengan Tokenizer OpenAI
Lanjutkan membaca Membuat Telegram Bot memakai API ChatGPT di AWS Lambda

Coding dengan TabNine, Copilot, dan ChatGPT

Saat ini ada beberapa tool pembantu coding berbasis AI. Sejak ada Tabnine yang menyediakan autocomplete dengan AI, saya langsung berlangganan, dan ketika Github meluncurkan Copilot, saya juga langsung memakainya. Saat ini saya sudah menggunakan Tabnine lebih dari setahun dan Copilot selama beberapa bulan, dan ingin menceritakan pengalaman serta tips menggunakan tool-tool ini.

Meme (sumber asli tidak diketahui)

Penggunaan tool asisten programmer berbasis AI tentunya juga menimbulkan pertanyaan: apakah di masa depan programmer akan tergantikan oleh AI? Saya akan membahasnya sedikit di akhir tulisan ini.

Coding di HP dengan NeoVIM dan plugin Copilot
Lanjutkan membaca Coding dengan TabNine, Copilot, dan ChatGPT

Calling convention pada AMD64, ARM64, dan RISCV64

Artikel ini merupakan lanjutan dari artikel Hello, World! sebelumnya yang akan memperkenalkan calling convention pada arsitektur AMD64, ARM64 dan RISCV64. Program assembly pada artikel sebelumnya sangat sederhana: tidak ada percabangan, tidak ada pemanggilan fungsi, hanya memakai syscall. Kali ini saya ingin membahas mengenai: pembuatan fungsi, percabangan, dan pemanggilan fungsi.

Calling Convention

Jika kita membuat seluruh program sendiri, tidak memanggil fungsi apapun yang lain, maka kita punya kebebasan memakai register manapun juga untuk kebutuhkan apapun. Misalnya kita ingin memanggil fungsi, parameter pertama bisa di register r0, parameter kedua di r1, dst. Atau terserah kalau mau mulai dari r5 juga boleh.

Tapi ketika kita ingin memakai library atau kode orang lain, maka kita perlu memiliki semacam standard/konvensi agar berbagai program bisa berinteroperasi. Istilah untuk ini adalah calling convention, sebuah calling convention biasanya menyatakan:

  • Bagaimana passing parameter, register mana yang dipakai (atau apakah langsung dipassing menggunakan stack)
  • Di register mana hasil kembalian fungsinya
  • Register-register mana saja yang boleh diubah di dalam subrutin/fungsi (scratch registers), atau disebut juga caller saved registers
  • Register-register mana saja yang harus disimpan (must be preserved) dalam subrutin/fungsi, atau callee saved registers

Untuk register yang harus disimpan, maksudnya: ketika keluar dari subrutin, maka nilai register tersebut harus sama dengan ketika masuk. Artinya kita boleh saja mengubah register tersebut di dalam fungsi, asalkan kita simpan dulu, entah di stack atau di tempat lain, dan sebelum kembali (return), nilai registernya dikembalikan lagi.

Lanjutkan membaca Calling convention pada AMD64, ARM64, dan RISCV64

Hello, World! di Linux dalam Assembly AMD64, ARM64, dan RISCV64

Tadinya saya ingin menulis tentang arsitektur RISC-V, dan memulai dengan membuat Hello, World!, tapi setelah diingat lagi, saya belum pernah membahas assembly di berbagai arsitektur lain. Jadi di tulisan ini saya ingin membuat program Hello World di Linux untuk arsitektur 64 bit: x86/64 disebut juga AMD64, ARM64 dan RISCV64.

Dulu waktu mulai mengenal assembly, saya menganggap ini susah. Tapi setelah diingat lagi, semuanya karena keterbatasan teknologi yang saya pakai saat itu:

  • Saya memakai DOS, jika salah memprogram assembly maka komputer bisa restart atau hang dengan mudah, bahkan ketika masuk ke Windows 95/98, masih sangat mudah membuat crash dengan program DOS sederhana
  • Tool yang ada juga terbatas, misalnya saya membuat program assembly mode grafik di DOS, maka debugger tidak bisa jalan ketika program berjalan
  • Arsitektur x86 memang lebih rumit dibandingkan arsitektur lain, karena masalah sejarah (arsitektur ini berusaha kompatibel dengan versi sebelumnya)

Dengan sistem operasi modern seperti Linux dan tools yang ada saat ini, belajar assembly berbagai arsitektur sudah semakin mudah:

  • Hardware dan sistem operasi mendukung memory protection, tidak mudah membuat crash
  • Sistem multi window memudahkan memprogram grafik dan menjalankan debugger di Window lain. Selain itu jika ingin memprogram grafik fullscreen juga bisa dilakukan via remote SSH
  • Ternyata berbagai arsitektur lain lebih sederhana daripada x86

Saya memakai HoneyComb LX untuk target ARM dan Nezha SBC untuk target RISCV64.

Lanjutkan membaca Hello, World! di Linux dalam Assembly AMD64, ARM64, dan RISCV64

Kesan pertama memakai Rust

Bahasa Rust digadangkan sebagai bahasa untuk pemrograman sistem dengan performansi yang tinggi dan memiliki jaminan memory safety. Performansi yang tinggi ini didapatkan dengan menggunakan abstraksi yang tidak menambah overhead pada runtime (zero cost abstraction, bandingkan misalnya dengan PHP yang overheadnya sangat tinggi). Memory safety artinya bebas dari berbagai bug yang berhubungan dengan managemen memori (contoh bug memori yang umum: menimpa memori yang masih dipakai, tidak menginisialisasi memori, memakai pointer null, melakukan double free, dsb).

Logo Rust

Bahasa Rust mulai diumumkan ke publik pada 2010, dan baru masuk versi 1.0 pada 2015. Setelah itu masih ada banyak perubahan pada bahasa ini, saat artikel ini ditulis Rust versi stabil adalah 1.56. Dibandingkan banyak bahasa lain, Rust ini masih cukup muda, dan banyak hal masih belum stabil.

Saat ini saya belum memiliki proyek besar yang memakai Rust, tapi selama 25 hari terakhir saya menyelesaikan Advent Of Code (AoC) 2021 menggunakan Rust. Soal AoC ini sangat bervariasi, jadi bisa digunakan untuk menguji banyak fitur bahasa Rust. Kadang soalnya sangat sederhana, jadi bisa diselesaikan dengan cepat dan saya punya waktu mencoba-coba berbagai pendekatan untuk mencoba-coba fitur Rust tertentu.

Lanjutkan membaca Kesan pertama memakai Rust

Logging

Di tulisan ini saya ingin membahas mengenai kenapa kita butuh logging dalam aplikasi, dan bagaimana praktik terbaik untuk melakukan logging.

Kenapa butuh logging

Kita memerlukan log supaya tahu apa kesalahan yang mungkin terjadi ketika program berjalan. Meskipun program dirancang sempurna, tetap ada banyak hal kemungkinan error yang bisa terjadi ketika aplikasi berjalan. Error ini bisa karena banyak hal, tapi bisa dibagi menjadi dua yang utama:

  • karena masalah pada runtime environment (lingkungan eksekusi program), misalnya: disk space habis, jaringan putus, disk error, dsb
  • karena logika program yang salah, atau ada library yang memiliki bug tertentu

Sering kali kita tidak bisa mengakses sistem di mana software kita berjalan, jadi tidak bisa langsung menginspeksi masalahnya apa. Contoh kasusnya:

  • Pada aplikasi desktop/game yang berjalan di komputer client
  • Pada aplikasi server yang berjalan di sistem production

Log level

Mencatat semua aktivitas program di log akan membuang banyak CPU dan disk space. Jadi kita perlu memberi tag level ketika melakukan logging.

Sistem log yang baik dapat diset agar hanya log pada level tertentu yang disimpan atau ditampilkan. Tergantung kebutuhan, level log bisa diset saat aplikasi berjalan (runtime) jika ada masalah.

Lanjutkan membaca Logging

Kisah Quick Fix Aplikasi Web PHP 5

Belum lama ini saya diminta tolong memperbaiki aplikasi lama dalam PHP 5. Aplikasi ini sudah lama dan masih dipakai sampai development aplikasi baru selesai. Aplikasi ditulis dalam PHP dengan framework Code Igniter dengan database MySQL. Deskripsi masalahnya begini: di aplikasi ini setiap hari ada satu halaman yang semakin lambat sampai suatu hari error, tidak bisa diakses lagi.

Pesan popup itu muncul dari komponen datatables.net di browser. Setelah diselidiki: penyebabnya adalah error di sisi server, tepatnya lagi ternyata out of memory di sisi server.

Allowed memory size of 134217728 bytes exhausted (tried to allocate 7077931 bytes) /var/www/html/application/XXX.php

Aplikasi ini meload data dari database menjadi satu file JSON berisi beberapa belas ribu baris. Dari hasil membaca dokumentasi komponen datatables ini, seharusnya mudah membuat paging dengan pemrosesan di sisi server cukup dengan menambah OFFSET dan LIMIT pada query SQL. Tapi ternyata tidak mudah di aplikasi ini.

Lanjutkan membaca Kisah Quick Fix Aplikasi Web PHP 5