Tutorial Semantic Router: Routing Cerdas untuk Aplikasi LLM

# Tutorial Semantic Router: Routing Cerdas untuk Aplikasi LLM Semantic Router adalah library Python yang memungkinkan Anda membuat keputusan routing berbasis makna (semantic) secara cepat dan efisien...

By Ruby Abdullah · · tutorial
Semantic RouterLLMNLPPythonAI Agents

Tutorial Semantic Router: Routing Cerdas untuk Aplikasi LLM

Semantic Router adalah library Python yang memungkinkan Anda membuat keputusan routing berbasis makna (semantic) secara cepat dan efisien. Alih-alih mengandalkan LLM untuk setiap keputusan klasifikasi, Semantic Router menggunakan embedding vectors untuk menentukan intent pengguna dalam hitungan milidetik.

Library ini sangat berguna untuk membangun chatbot, virtual assistant, dan aplikasi AI yang memerlukan respons cepat terhadap berbagai jenis pertanyaan pengguna. Dengan Semantic Router, Anda bisa mengarahkan query ke handler yang tepat tanpa overhead pemanggilan LLM setiap saat.

Mengapa Semantic Router?

Dalam pengembangan aplikasi berbasis LLM, salah satu tantangan umum adalah menentukan bagaimana merespons input pengguna. Pendekatan tradisional menggunakan keyword matching yang rigid, atau mengirim semua query ke LLM yang mahal dan lambat.

Semantic Router menawarkan pendekatan tengah yang optimal:

  • Kecepatan: Routing dilakukan dalam milidetik, bukan detik
  • Akurasi: Menggunakan semantic similarity, bukan keyword matching
  • Efisiensi biaya: Mengurangi pemanggilan LLM yang tidak perlu
  • Fleksibilitas: Mendukung routing statis maupun routing yang memanggil fungsi

Contoh kasus penggunaan:

  • Memfilter pertanyaan yang tidak relevan sebelum dikirim ke LLM
  • Mengarahkan pertanyaan teknis ke knowledge base tertentu
  • Mengaktifkan guardrails untuk topik sensitif
  • Memicu fungsi tertentu berdasarkan intent pengguna

Instalasi

Semantic Router dapat diinstal menggunakan pip. Tersedia beberapa variasi instalasi tergantung encoder yang ingin Anda gunakan.

# Instalasi dasar

pip install semantic-router

Dengan dukungan OpenAI encoder

pip install "semantic-router[openai]"

Dengan dukungan Cohere encoder

pip install "semantic-router[cohere]"

Dengan dukungan encoder lokal (HuggingFace)

pip install "semantic-router[local]"

Instalasi lengkap

pip install "semantic-router[all]"

Untuk tutorial ini, kita akan menggunakan encoder lokal agar bisa berjalan tanpa API key:

pip install "semantic-router[local]"

Verifikasi instalasi:

import semanticrouter

print(semanticrouter.version)

Konsep Dasar

Sebelum masuk ke kode, penting untuk memahami konsep inti dalam Semantic Router.

Route

Route adalah aturan yang mendefinisikan sebuah intent atau kategori. Setiap route terdiri dari nama dan beberapa contoh utterance yang merepresentasikan intent tersebut.

from semanticrouter import Route

Mendefinisikan route untuk pertanyaan tentang cuaca

weatherroute = Route(

name="weather",

utterances=[

"bagaimana cuaca hari ini?",

"apakah akan hujan besok?",

"berapa suhu di Jakarta?",

"prakiraan cuaca minggu ini",

"cuaca hari ini cerah atau mendung?",

],

)

Encoder

Encoder bertanggung jawab mengubah teks menjadi embedding vector. Semantic Router mendukung berbagai encoder:

# Encoder lokal (gratis, tidak perlu API key)

from semanticrouter.encoders import HuggingFaceEncoder

encoder = HuggingFaceEncoder()

Encoder OpenAI

from semanticrouter.encoders import OpenAIEncoder

encoder = OpenAIEncoder(apikey="sk-...")

Encoder Cohere

from semanticrouter.encoders import CohereEncoder

encoder = CohereEncoder(apikey="...")

RouteLayer

RouteLayer menggabungkan routes dan encoder menjadi satu sistem routing yang siap digunakan.

from semanticrouter.layer import RouteLayer

routelayer = RouteLayer(

encoder=encoder,

routes=[weatherroute, greetingroute],

)

Penggunaan Dasar

Mari kita bangun sistem routing sederhana yang bisa membedakan beberapa jenis intent pengguna.

from semanticrouter import Route, RouteLayer

from semanticrouter.encoders import HuggingFaceEncoder

1. Definisikan routes

greetingroute = Route(

name="greeting",

utterances=[

"halo",

"hai, apa kabar?",

"selamat pagi",

"hey, salam kenal",

"halo, senang bertemu denganmu",

],

)

farewellroute = Route(

name="farewell",

utterances=[

"sampai jumpa",

"selamat tinggal",

"bye bye",

"dadah, sampai ketemu lagi",

"saya pergi dulu ya",

],

)

technicalroute = Route(

name="technicalsupport",

utterances=[

"aplikasi saya error",

"bagaimana cara reset password?",

"tidak bisa login ke akun saya",

"website loading lama sekali",

"ada bug di fitur pembayaran",

],

)

billingroute = Route(

name="billing",

utterances=[

"berapa tagihan bulan ini?",

"saya mau bayar invoice",

"status pembayaran saya bagaimana?",

"cara upgrade paket langganan",

"mau cancel subscription",

],

)

2. Inisialisasi encoder

encoder = HuggingFaceEncoder()

3. Buat RouteLayer

routes = [greetingroute, farewellroute, technicalroute, billingroute]

routelayer = RouteLayer(encoder=encoder, routes=routes)

4. Test routing

testqueries = [

"hai, saya butuh bantuan",

"saya tidak bisa masuk ke akun",

"mau tanya soal tagihan",

"ok terima kasih, bye",

"cuaca hari ini bagaimana?", # tidak cocok dengan route manapun

]

for query in testqueries:

result = routelayer(query)

print(f"Query: '{query}'")

print(f"Route: {result.name}")

print(f"Similarity: {result.similarityscore:.4f}")

print()

Output yang diharapkan:

Query: 'hai, saya butuh bantuan'

Route: greeting

Similarity: 0.8234

Query: 'saya tidak bisa masuk ke akun'

Route: technicalsupport

Similarity: 0.8567

Query: 'mau tanya soal tagihan'

Route: billing

Similarity: 0.8901

Query: 'ok terima kasih, bye'

Route: farewell

Similarity: 0.8123

Query: 'cuaca hari ini bagaimana?'

Route: None

Similarity: 0.0000

Perhatikan bahwa query terakhir tentang cuaca tidak cocok dengan route manapun dan mengembalikan None. Ini adalah fitur penting karena Semantic Router bisa mengenali ketika suatu query tidak masuk ke kategori yang telah didefinisikan.

Penggunaan Lanjutan

Dynamic Routes dengan Function Calling

Semantic Router mendukung dynamic routes yang bisa memanggil fungsi Python saat route tertentu terpicu. Ini sangat berguna untuk membangun agent yang bisa melakukan aksi tertentu.

from semanticrouter import Route, RouteLayer

from semanticrouter.encoders import HuggingFaceEncoder

from datetime import datetime

Definisikan fungsi-fungsi yang akan dipanggil

def getcurrenttime(timezone: str = "Asia/Jakarta"):

"""Mendapatkan waktu saat ini."""

from zoneinfo import ZoneInfo

now = datetime.now(ZoneInfo(timezone))

return f"Waktu saat ini di {timezone}: {now.strftime('%H:%M:%S %d-%m-%Y')}"

def calculateprice(item: str, quantity: int = 1):

"""Menghitung harga item."""

prices = {

"kopi": 25000,

"teh": 15000,

"roti": 20000,

"nasi goreng": 35000,

}

price = prices.get(item.lower(), 0)

total = price * quantity

return f"{item} x{quantity} = Rp{total:,}"

Definisikan route dengan function schema

timeroute = Route(

name="gettime",

utterances=[

"jam berapa sekarang?",

"waktu saat ini",

"sekarang pukul berapa?",

"kasih tahu saya waktu sekarang",

],

functionschemas=[

{

"name": "getcurrenttime",

"description": "Mendapatkan waktu saat ini",

"parameters": {

"type": "object",

"properties": {

"timezone": {

"type": "string",

"description": "Timezone, default Asia/Jakarta",

}

},

"required": [],

},

}

],

)

priceroute = Route(

name="checkprice",

utterances=[

"berapa harga kopi?",

"hitung total belanjaan saya",

"mau pesan 3 nasi goreng, berapa totalnya?",

"price list menu",

],

functionschemas=[

{

"name": "calculateprice",

"description": "Menghitung harga item",

"parameters": {

"type": "object",

"properties": {

"item": {

"type": "string",

"description": "Nama item",

},

"quantity": {

"type": "integer",

"description": "Jumlah item",

"default": 1,

},

},

"required": ["item"],

},

}

],

)

encoder = HuggingFaceEncoder()

routelayer = RouteLayer(

encoder=encoder,

routes=[timeroute, priceroute],

)

Test dynamic routing

result = routelayer("jam berapa sekarang di Tokyo?")

print(f"Route: {result.name}")

print(f"Function call: {result.functioncall}")

Threshold Tuning

Anda bisa mengatur threshold untuk setiap route agar lebih ketat atau longgar dalam mencocokkan query.

# Route dengan threshold tinggi - hanya cocok jika sangat mirip

strictroute = Route(

name="passwordreset",

utterances=[

"reset password saya",

"lupa password",

"ganti password akun",

"tidak ingat password",

],

scorethreshold=0.85, # threshold tinggi

)

Route dengan threshold rendah - lebih longgar

generalroute = Route(

name="generalinquiry",

utterances=[

"saya punya pertanyaan",

"bisa bantu saya?",

"info dong",

"mau tanya",

],

scorethreshold=0.5, # threshold rendah

)

Menggunakan Multiple Encoders

Untuk kasus penggunaan tertentu, Anda mungkin perlu menggunakan encoder yang berbeda untuk routes yang berbeda.

from semanticrouter.encoders import HuggingFaceEncoder

Encoder untuk bahasa Indonesia

idencoder = HuggingFaceEncoder(

name="sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2"

)

Encoder dengan model yang lebih besar untuk akurasi lebih tinggi

largeencoder = HuggingFaceEncoder(

name="sentence-transformers/all-mpnet-base-v2"

)

Hybrid Route Layer

Semantic Router juga mendukung hybrid approach yang menggabungkan semantic routing dengan sparse retrieval (BM25).

from semanticrouter import Route, HybridRouteLayer

from semanticrouter.encoders import HuggingFaceEncoder

encoder = HuggingFaceEncoder()

routes = [greetingroute, technicalroute, billingroute]

Hybrid layer menggabungkan dense dan sparse matching

hybridlayer = HybridRouteLayer(

encoder=encoder,

routes=routes,

alpha=0.5, # bobot antara dense (1.0) dan sparse (0.0)

)

result = hybridlayer("mau bayar tagihan internet bulan lalu")

print(f"Route: {result.name}")

Guardrails dengan Semantic Router

Salah satu use case paling populer adalah menggunakan Semantic Router sebagai guardrails untuk memfilter input yang tidak diinginkan sebelum dikirim ke LLM.

from semanticrouter import Route, RouteLayer

from semanticrouter.encoders import HuggingFaceEncoder

Route untuk konten yang harus diblokir

harmfulcontent = Route(

name="harmful",

utterances=[

"bagaimana cara meretas website",

"cara membuat virus komputer",

"cara bypass keamanan",

"tutorial hacking ilegal",

"cara mencuri data orang lain",

],

scorethreshold=0.75,

)

offtopic = Route(

name="offtopic",

utterances=[

"siapa presiden Indonesia?",

"berapa jarak bumi ke matahari?",

"resep masak rendang",

"jadwal liga sepakbola",

"rekomendasi film bagus",

],

scorethreshold=0.70,

)

Route untuk konten yang diizinkan

allowedtopics = Route(

name="allowed",

utterances=[

"bagaimana cara menggunakan API ini?",

"jelaskan fitur produk",

"bantuan pengaturan akun",

"cara integrasi dengan sistem lain",

"dokumentasi endpoint REST API",

],

scorethreshold=0.60,

)

encoder = HuggingFaceEncoder()

guardrail = RouteLayer(

encoder=encoder,

routes=[harmfulcontent, offtopic, allowedtopics],

)

def processquery(query: str):

"""Memproses query dengan guardrails."""

result = guardrail(query)

if result.name == "harmful":

return "Maaf, saya tidak bisa membantu dengan permintaan tersebut."

elif result.name == "offtopic":

return "Pertanyaan ini di luar cakupan layanan kami. Silakan tanyakan tentang produk kami."

elif result.name == "allowed":

return f"[Diteruskan ke LLM] Memproses: {query}"

else:

return "Maaf, saya tidak memahami pertanyaan Anda. Bisa diperjelas?"

Test guardrails

testinputs = [

"cara menggunakan API payment gateway",

"bagaimana cara hack akun orang",

"siapa juara piala dunia 2022?",

"cara setup webhook untuk notifikasi",

]

for q in testinputs:

response = processquery(q)

print(f"Input: {q}")

print(f"Response: {response}\n")

Integrasi dengan LangChain

Semantic Router dapat diintegrasikan dengan framework populer seperti LangChain untuk membangun aplikasi yang lebih kompleks.

from semanticrouter import Route, RouteLayer

from semanticrouter.encoders import HuggingFaceEncoder

from langchainopenai import ChatOpenAI

from langchaincore.prompts import ChatPromptTemplate

Setup routes

coderoute = Route(

name="codehelp",

utterances=[

"bantu saya debug kode Python ini",

"bagaimana cara menulis unit test?",

"jelaskan error ini",

"review kode saya",

],

)

dataroute = Route(

name="dataanalysis",

utterances=[

"analisis data penjualan",

"buat visualisasi dari dataset ini",

"query SQL untuk laporan bulanan",

"cara cleaning data yang efektif",

],

)

encoder = HuggingFaceEncoder()

router = RouteLayer(encoder=encoder, routes=[coderoute, dataroute])

Setup LLM chains per route

codellm = ChatOpenAI(model="gpt-4o", temperature=0)

datallm = ChatOpenAI(model="gpt-4o", temperature=0.3)

codeprompt = ChatPromptTemplate.frommessages([

("system", "Kamu adalah expert Python developer. Bantu user dengan kode mereka."),

("human", "{query}"),

])

dataprompt = ChatPromptTemplate.frommessages([

("system", "Kamu adalah data analyst expert. Bantu user menganalisis data."),

("human", "{query}"),

])

codechain = codeprompt | codellm

datachain = dataprompt | datallm

def smartroute(query: str):

"""Route query ke chain yang tepat."""

result = router(query)

if result.name == "codehelp":

return codechain.invoke({"query": query})

elif result.name == "dataanalysis":

return datachain.invoke({"query": query})

else:

return "Pertanyaan di luar cakupan. Silakan tanyakan tentang coding atau analisis data."

response = smartroute("tolong review kode sorting algorithm saya")

print(response.content)

Menyimpan dan Memuat Routes

Untuk production, Anda bisa menyimpan konfigurasi route dan memuatnya kembali tanpa perlu mendefinisikan ulang.

import json

Simpan konfigurasi routes ke JSON

def saveroutes(routes, filepath):

config = []

for route in routes:

config.append({

"name": route.name,

"utterances": route.utterances,

"scorethreshold": route.scorethreshold,

})

with open(filepath, "w") as f:

json.dump(config, f, indent=2, ensureascii=False)

print(f"Routes saved to {filepath}")

Muat routes dari JSON

def loadroutes(filepath):

with open(filepath) as f:

config = json.load(f)

routes = []

for item in config:

routes.append(Route(

name=item["name"],

utterances=item["utterances"],

scorethreshold=item.get("scorethreshold", 0.5),

))

return routes

Simpan

saveroutes(routes, "routesconfig.json")

Muat kembali

loadedroutes = loadroutes("routesconfig.json")

routelayer = RouteLayer(encoder=encoder, routes=loadedroutes)

Best Practices

1. Sediakan Utterances yang Beragam

Setiap route sebaiknya memiliki minimal 5-10 utterances yang beragam. Semakin beragam contohnya, semakin baik akurasi routing.

# Kurang baik - terlalu mirip

badroute = Route(

name="greeting",

utterances=["halo", "hai", "hey"], # terlalu sedikit dan mirip

)

Lebih baik - beragam dan representatif

goodroute = Route(

name="greeting",

utterances=[

"halo, apa kabar?",

"selamat pagi, bisa bantu saya?",

"hai, saya pengguna baru",

"good morning, need help",

"hey, ada yang bisa dibantu?",

"permisi, saya mau tanya",

"salam, butuh informasi",

],

)

2. Gunakan Threshold yang Tepat

Threshold terlalu tinggi menyebabkan banyak query tidak ter-route. Threshold terlalu rendah menyebabkan false positive. Mulai dari 0.5 dan sesuaikan berdasarkan testing.

# Mulai dengan threshold default, lalu tune

route = Route(

name="specificintent",

utterances=[...],

scorethreshold=0.5, # mulai dari sini

)

Test dengan berbagai query dan adjust

Jika terlalu banyak false positive: naikkan ke 0.6-0.7

Jika terlalu banyak miss: turunkan ke 0.4-0.45

3. Pisahkan Route Berdasarkan Aksi

Jangan membuat route yang terlalu luas. Pisahkan berdasarkan aksi atau respons yang berbeda.

# Kurang baik - satu route untuk semua

supportroute = Route(

name="support",

utterances=[

"reset password",

"berapa tagihan saya",

"cara upgrade paket",

],

)

Lebih baik - route terpisah per aksi

passwordroute = Route(name="passwordreset", utterances=[...])

billingroute = Route(name="billinginquiry", utterances=[...])

upgraderoute = Route(name="planupgrade", utterances=[...])

4. Monitor dan Iterasi

Implementasikan logging untuk memantau performa routing di production.

import logging

from datetime import datetime

logger = logging.getLogger("semanticrouter")

def routewithlogging(routelayer, query: str):

"""Route query dengan logging untuk monitoring."""

result = routelayer(query)

logentry = {

"timestamp": datetime.now().isoformat(),

"query": query,

"route": result.name,

"score": result.similarityscore,

}

if result.name is None:

logger.warning(f"Unrouted query: {query}")

elif result.similarityscore < 0.6:

logger.info(f"Low confidence route: {logentry}")

return result

5. Gunakan Encoder yang Sesuai

Untuk production dengan traffic tinggi, pertimbangkan trade-off antara kecepatan dan akurasi:

  • HuggingFace encoder lokal: Gratis, cepat, cocok untuk prototyping dan low-latency requirement
  • OpenAI encoder: Akurasi tinggi, memerlukan API call, ada biaya per request
  • Cohere encoder: Alternatif cloud encoder dengan performa baik untuk multilingual

6. Handling Edge Cases

Selalu tangani kasus ketika tidak ada route yang cocok:

def handlequery(routelayer, query):

result = routelayer(query)

if result.name is None:

# Fallback: kirim ke LLM general

return fallbackllm(query)

return route_handlersresult.name

Perbandingan dengan Pendekatan Lain

| Aspek | Semantic Router | Keyword Matching | LLM Classification |

|-------|----------------|------------------|---------------------|

| Kecepatan | ~5ms | ~1ms | ~500ms-2s |

| Akurasi | Tinggi | Rendah | Sangat Tinggi |

| Biaya | Rendah/Gratis | Gratis | Mahal |

| Setup | Mudah | Mudah | Kompleks |

| Fleksibilitas | Tinggi | Rendah | Sangat Tinggi |

| Skalabilitas | Baik | Baik | Terbatas oleh rate limit |

Kesimpulan

Semantic Router adalah solusi yang elegan untuk permasalahan routing di aplikasi LLM. Dengan menggabungkan kecepatan embedding-based classification dengan fleksibilitas function calling, library ini menjembatani gap antara pendekatan keyword matching yang kaku dan LLM classification yang mahal.

Poin-poin utama yang perlu diingat:

  • Gunakan untuk keputusan cepat: Semantic Router ideal untuk klasifikasi intent yang perlu respons instan
  • Sediakan contoh yang beragam: Kualitas routing sangat bergantung pada kualitas utterances
  • Tuning threshold: Mulai dari default dan sesuaikan berdasarkan data real
  • Guardrails: Manfaatkan sebagai lapisan keamanan sebelum query mencapai LLM
  • Kombinasikan dengan LLM: Gunakan Semantic Router untuk routing cepat, LLM untuk pemrosesan mendalam
  • Semantic Router terus berkembang dengan komunitas yang aktif. Untuk informasi terbaru, kunjungi repository GitHub resmi dari Aurelio AI.

    Artikel Terkait

    Tutorial Lengkap Llama Stack: Framework Resmi Meta untuk Membangun Aplikasi AI dengan Model Llama

    Tutorial Lengkap Llama Stack: Framework Resmi Meta untuk Membangun Aplikasi AI dengan Model Llama Llama Stack adalah fra...

    Tutorial CAMEL-AI: Framework Multi-Agent Communication untuk Membangun Sistem AI Kolaboratif

    Tutorial Lengkap CAMEL-AI: Framework Multi-Agent Communication untuk Membangun Sistem AI Kolaboratif Penulis: Ruby Abdul...

    Tutorial Semantic Kernel: Framework AI Orchestration dari Microsoft untuk Membangun Aplikasi Cerdas

    Tutorial Semantic Kernel: Framework AI Orchestration dari Microsoft untuk Membangun Aplikasi Cerdas Semantic Kernel adal...

    Tutorial Zep: Memori Jangka Panjang untuk AI Agent dengan Temporal Knowledge Graph

    Zep: Bikin AI Agent Punya Memori Jangka Panjang dengan Temporal Knowledge Graph Temen-temen, pernah ngobrol sama chatbot...