နားလည်ထားရမယ့် အချက်
RAG (Retrieval-Augmented Generation) ဆိုသည်မှာ local LLM တစ်ခုကို ၎င်း train လုပ်စဉ်က မသိခဲ့သော အချက်အလက်များ — သင့်ရဲ့ note များ၊ codebase၊ internal documentation များကို — retrain ပြန်လုပ်စရာမလိုဘဲ သုံးနိုင်စေတဲ့ standard architecture တစ်ခုဖြစ်သည်။
Indexing lane (offline)
Documents များကို chunk များအဖြစ် ခွဲပြီး၊ chunk တစ်ခုစီကို embedding model တစ်ခုဖြင့် vector အဖြစ် ပြောင်းကာ၊ vector database တွင် မူရင်း text နှင့်အတူ သိမ်းထားသည် — တစ်ကြိမ်တည်း run သည်။
Query lane (မေးခွန်းတိုင်း)
User မေးခွန်းကိုလည်း embedding model တူတူဖြင့် vector အဖြစ်ပြောင်းပြီး၊ vector store က အနီးဆုံးဖြစ်သော chunk များကို ပြန်ပေးကာ၊ ထို chunk များကို LLM ထံပို့မည့် prompt ထဲသို့ context အဖြစ် ထည့်သွင်းသည်။ ထို့နောက် model က ထို context ပေါ်အခြေခံပြီး အဖြေထုတ်ပေးသည်။
RAG အကြောင်း အလွဲအထင်ဆုံး အချက်မှာ 'သင့် documents များပေါ် model ကို train လုပ်ပေးသည်' ဆိုတာပါ။ ဒါဟာ မှားနေပါတယ်။ RAG system ထဲ document တစ်ခု ထပ်ထည့်လိုက်ရုံနဲ့ LLM ရဲ့ weight တွေ ဘာမှ ပြောင်းသွားခြင်း မရှိပါ — gradient descent မရှိ၊ backpropagation မရှိ၊ fine-tuning လည်း မဖြစ်ပေါ်ပါ။ တကယ်ဖြစ်နေတာက ပိုရိုးရှင်းပြီး ပိုမြန်ပါတယ် — relevant စာသားကို request အချိန်တိုင်း prompt ထဲကို copy ထည့်ပေးလိုက်တာပါပဲ။ ဒါကြောင့် RAG update က ချက်ချင်းဖြစ်ပါတယ် — document အသစ်တစ်ခု ထည့်လိုက်တာနဲ့ နောက် query တစ်ခု ချက်ချင်း retrieve လုပ်နိုင်ပါတယ်၊ retrain cost လည်း လုံးဝမရှိပါ။
RAG ရဲ့ အမှန်တကယ် ကန့်သတ်ချက်
RAG ရဲ့ ကန့်သတ်ချက်လည်း ရှိပါတယ် — model က request တစ်ခုအတွက် retrieve လုပ်ရရှိတဲ့ context ထဲက အချက်အလက်ကိုပဲ 'သိ' ပါတယ်၊ retrieval က chunk မှားယွင်းရွေးချယ်ရင် model ကလည်း data မှားပေါ်မှာ reasoning လုပ်ရပါလိမ့်မယ်။ Operationally ပြောရရင် RAG ရဲ့ အရည်အသွေးက LLM ကိုယ်တိုင်ထက် chunking နဲ့ retrieval accuracy ပေါ်မှာ ပိုမူတည်ပါတယ်။
- RAG
- Retrieval-Augmented Generation — relevant text ကို external store တစ်ခုကနေ retrieve လုပ်ပြီး request time မှာ prompt ထဲ ထည့်ပေးတဲ့ architecture တစ်ခုပါ၊ model ရဲ့ weight ထဲ ထည့်သိမ်းထားတာ မဟုတ်ပါ။
- Chunking
- Document တစ်ခုကို အပိုင်းသေးသေးလေးတွေအဖြစ် ခွဲတာပါ၊ ဘေးချင်းကပ်နေတဲ့ အပိုင်းတွေကြား overlap အနည်းငယ်ပါလေ့ရှိပါတယ်၊ အပိုင်းတစ်ခုစီက embed လုပ်ပြီး အဓိပ္ပာယ်ရှိရှိ retrieve လုပ်နိုင်လောက်အောင် သေးငယ်အောင်ပါ။
- Retrieval
- Query time မှာ run တဲ့ step တစ်ခုပါ၊ မေးခွန်းရဲ့ embedding နှင့် အနီးစပ်ဆုံး ဖြစ်တဲ့ chunk တွေကို vector store ထဲက ရှာဖွေတာပါ။
LOCAL RAG: TWO LANES
--------------------
LOCAL RAG: TWO LANES
---------------------
INDEXING LANE (offline, runs once per document)
documents -> chunker -> embedding model -> vector store
QUERY LANE (runs on every user question)
question -> embed -> search vector store -> top chunks
|
v
chunks + question -> LLM -> answerလက်တွေ့ scenario နဲ့ ချိတ်ကြည့်မယ်
Local RAG pipeline တစ်ခု တည်ဆောက်ဖို့ အလုပ်လုပ်ရမယ့် piece လေးခု လိုအပ်ပါတယ်၊ ပထမနှစ်ခုကို မှန်ကန်အောင်လုပ်တာက fancy LLM တစ်ခု ရွေးချယ်တာထက် ပိုအရေးကြီးပါတယ်။
Chunking
Documents တွေကို overlapping pieces (token အနည်းငယ်ရာစီ၊ 10-20% overlap) အဖြစ်ခွဲပါ၊ chunk boundary အနီးက fact တစ်ခု အထီးကျန်မသွားစေဖို့ပါ။
Embeddings
Chunk တစ်ခုစီအပေါ် local embedding model (sentence-transformers ကနေ all-MiniLM/BGE variant, ဒါမှမဟုတ် llama.cpp ကတဆင့် GGUF embedding model) run ပြီး fixed-length vector ရယူပါ။
Vector store
SQLite table with vector extension လို ပေါ့ပေါ့ပါးပါး တစ်ခုမှသည် Chroma, Qdrant, FAISS လို dedicated store အထိ စက်ပေါ်မှာပဲ အလုံးစုံ run နိုင်ပါတယ်။
Retrieval at query time
Embedding model တူတူနဲ့ မေးခွန်းကို embed လုပ်ပြီး၊ nearest-neighbor search (cosine similarity က common default) run ပြီး top-k chunks ရယူကာ၊ မေးခွန်းရှေ့မှာ prompt template ထဲ ကူးထည့်ပါ။
- Chunk size ကြီးလွန်းခြင်း (relevance ပျို့ဖျက်စေ) ဒါမှမဟုတ် သေးလွန်းခြင်း (context ဆုံးရှုံးစေ)
- Indexing အတွက်သုံးတဲ့ embedding model နဲ့ query အတွက်သုံးတဲ့ embedding model မကိုက်ညီခြင်း — model တူတူဖြစ်ရမယ်၊ မဟုတ်ရင် vector space တွေ မကိုက်ညီတော့ဘဲ retrieval quality က တိတ်တဆိတ် ပျက်သွားပါလိမ့်မယ်
အတူတူ စမ်းရေးကြည့်မယ်
def chunk_text(text, chunk_size=60, overlap=20):
chunks = []
start = 0
while start < len(text):
end = start + chunk_size
chunks.append(text[start:end])
if end >= len(text):
break
start = end - overlap
return chunks
document = (
"Local AI lets you run models on your own hardware. "
"This means no data leaves your machine during inference. "
"RAG adds a retrieval step before generation. "
"It does not change the model's weights at all."
)
chunks = chunk_text(document, chunk_size=60, overlap=20)
for i, c in enumerate(chunks):
print(f"chunk {i} (len={len(c)}): {c!r}")
print(f"total chunks: {len(chunks)}")Sample document ကို chunk_size=60, overlap=20 ဖြင့် run လိုက်တဲ့အခါ overlapping chunk 5 ခု ရရှိပါတယ် -
chunk 0 (len=60): 'Local AI lets you run models on your own hardware. This mean'
chunk 1 (len=60): ' hardware. This means no data leaves your machine during inf'
chunk 2 (len=60): 'r machine during inference. RAG adds a retrieval step before'
chunk 3 (len=60): 'etrieval step before generation. It does not change the mode'
chunk 4 (len=39): " not change the model's weights at all."
total chunks: 5
ပထမဆုံး chunk အပြီးက chunk တိုင်းက အရင် chunk ရဲ့ နောက်ဆုံး character 20 လုံးကို (overlap ကို) ထပ်ပြပါတယ်၊ ဒါကြောင့် 'hardware' နဲ့ 'inference' တို့က boundary မှာ ပျောက်မသွားဘဲ chunk နှစ်ခုကြားမှာ ခွဲပြီး ပေါ်လာတာပါ။၅ မိနစ် စမ်းကြည့်
စာသားဖိုင်တိုတို (paragraph အနည်းငယ်) တစ်ခုကို ယူပြီး code ဥပမာလုပ်သလို overlapping chunks အဖြစ် ခွဲမယ့် script ရေးပါ။ ပြီးရင် function ဒုတိယတစ်ခု ရေးပါ — မေးခွန်းတစ်ခု ပေးလိုက်ရင်၊ မေးခွန်းနှင့် chunk တစ်ခုစီကြား share လုပ်ထားတဲ့ စကားလုံးအရေအတွက် ရေတွက်ပြီး naive 'search' လုပ်ကာ overlap အများဆုံးရှိတဲ့ chunk ကို ပြန်ပေးပါ။ ဒါက real embedding-based search မဟုတ်ပါဘူး၊ ဒါပေမယ့် proper vector embeddings နဲ့ RAG သုံးတဲ့ retrieve-then-inject pattern တူတူကို ပြသပေးပါတယ်။
သတိလေးတစ်ချက်
Indexing အတွက်နဲ့ query အတွက် embedding model ကွဲပြား (ဒါမှမဟုတ် version ကွဲပြား) သုံးခြင်း — vector space တွေက compatible မဖြစ်တော့ဘဲ retrieval quality က error မပြဘဲ တိတ်တဆိတ် ပျက်သွားနိုင်ပါတယ်။
'Model ကို train မလုပ်ဘူးဆိုတော့' ဆိုပြီး data governance ကို ကျော်လွှားနိုင်တယ်လို့ ထင်ခြင်း — retrieve ရလာတဲ့ chunk တွေက plaintext context အနေနဲ့ LLM ဆီကို ပို့ပြီး output ဒါမှမဟုတ် log ထဲမှာ ပေါ်လာနိုင်ပါတယ်။
အမြန် စစ်ဆေးမှု
LangChain — RAG Concepts — Local AI / Local LLM