Embedding Chuqur (Embedding Deep Dive)
Embedding — RAG tizimining yuragi. Agar embedding sifatsiz bo'lsa, qidiruv noto'g'ri natija beradi, LLM noto'g'ri ma'lumot asosida javob beradi, butun tizim ishlamaydi. Bu bobda embedding nima ekanini chuqur tushuntiramiz.
Vektor nima?
2D analogiya — eng oddiy tushuntirish
Maktabda koordinata tekisligini o'rgangansiz. Har bir nuqta ikki son bilan ifodalanadi: (x, y).
y
^
4 | * (3, 4) = "mushuk"
|
3 | * (2, 3) = "koshka" (ruscha)
|
2 | * (1, 2) = "it"
|
1 | * (5, 1) = "mashina"
|
+---+---+---+---+---+---> x
0 1 2 3 4 5
E'tibor bering: "mushuk" va "koshka" bir-biriga yaqin (ikkalasi ham mushuk degani, turli tillarda), "it" ham hayvon sifatida yaqinroq, lekin "mashina" uzoqda.
Bu analogiya oddiy, lekin g'oya aynan shu: ma'nosi yaqin so'zlar — vektor fazoda ham yaqin.
3D ga o'tish
Endi uchinchi o'lcham qo'shamiz — masalan, "jonlilik darajasi":
jonlilik (z)
^
| * mushuk (3, 4, 9) <- jonli, hayvon
| * koshka (2, 3, 9) <- jonli, hayvon
| * it (1, 2, 8) <- jonli, hayvon
|
|
| * mashina (5, 1, 1) <- jonsiz
+-----------------------------------> x
/
/
v y
Har bir o'lcham ma'noning biror jihatini ifodalaydi. 3 ta o'lcham bilan biz uchta jihatni saqlashimiz mumkin.
1536D va 4096D — haqiqiy embedding lar
Haqiqiy embedding modellar 1536 yoki 4096 ta o'lchamda ishlaydi. Har bir o'lcham ma'noning biror nozik jihatini saqlaydi:
- O'lcham 47: "texnik atama darajasi" (0.2 = oddiy so'z, 0.9 = tor ixtisoslik)
- O'lcham 128: "ijobiylik darajasi" (-0.8 = salbiy, 0.7 = ijobiy)
- O'lcham 891: "vaqt bilan bog'liqlik" (0.1 = vaqtsiz, 0.9 = vaqtga bog'liq)
- ... va hokazo 4096 ta o'lcham
Biz bu o'lchamlarni alohida interpret qila olmaymiz — ular model o'qitilganda avtomatik shakllanadi. Lekin natija shuki: har bir gap 4096 ta sonli vektor sifatida ifodalanadi va bu vektor gapning to'liq ma'nosini saqlaydi.
# Nihol loyihasidan haqiqiy misol from app.config import get_settings import httpx settings = get_settings() # "Nihol kompaniyasi server yetkazib beradi" gapini embedding qilish resp = httpx.post( f"{settings.OLLAMA_URL}/api/embed", json={ "model": "qwen3-embedding:8b", # Bizning model "input": "Nihol kompaniyasi server yetkazib beradi" }, ) vector = resp.json()["embeddings"][0] print(f"O'lchamlar soni: {len(vector)}") # 4096 print(f"Birinchi 5 ta son: {vector[:5]}") # Misol natija: [0.0234, -0.0891, 0.1456, -0.0023, 0.0678]
Embedding modellar qanday o'qitiladi?
Contrastive Learning — qarama-qarshi o'rganish
Embedding modellar contrastive learning usulida o'qitiladi. G'oya oddiy: modelga juft gaplar beriladi — ba'zilari ma'nosi yaqin (positive pair), ba'zilari uzoq (negative pair).
Positive pairs (yaqin bo'lishi kerak): "mushuk uyda o'tirdi" <--> "koshka sidela doma" (tarjima) "server yetkazib berish" <--> "equipment delivery" (tarjima) "IBM Power modullari" <--> "server uskunalari" (sinonim) Negative pairs (uzoq bo'lishi kerak): "mushuk uyda o'tirdi" <--> "bugun ob-havo yaxshi" (aloqasiz) "server yetkazib berish" <--> "bolalar bog'chasi" (aloqasiz)
O'qitish jarayoni
1-qadam: Model ikkala gapni vektor ga aylantiradi
2-qadam: Positive pair vektorlari orasidagi masofa hisoblanadi
3-qadam: Agar masofa katta bo'lsa -> model parametrlari o'zgartiriladi
(yaqinlashtirish uchun)
4-qadam: Negative pair uchun teskari — uzoqlashtirish uchun o'zgartiriladi
5-qadam: Millionlab juftliklar bilan takrorlanadi
Natija: Model ma'nosi yaqin gaplarni yaqin vektorlarga,
uzoq gaplarni uzoq vektorlarga aylantiradi
Bu jarayon milliardlab gap juftliklari ustida amalga oshadi. Shuning uchun embedding modellar ma'noni shunchalik yaxshi tushunadi.
Bi-encoder vs Cross-encoder
Bu ikki arxitektura embedding dunyosida eng muhim farqlardan biri.
Bi-encoder: Ikki alohida encoding
Savol Hujjat
| |
v v
+----------+ +----------+
| Encoder | | Encoder |
| (bir xil | | (bir xil |
| model) | | model) |
+----+-----+ +----+-----+
| |
v v
Vector_Q Vector_D
[0.02, -0.08, ...] [0.03, -0.07, ...]
| |
+--------> Taqqoslash <-----+
cosine similarity
|
v
Score: 0.87
Qanday ishlaydi: Savol va hujjat alohida-alohida embedding qilinadi. Keyin ikki vektor orasidagi cosine similarity hisoblanadi.
Afzalligi: Hujjat vektorlari oldindan hisoblab qo'yiladi (bazaga saqlanadi). Qidiruv vaqtida faqat savol embedding qilinadi. Shuning uchun juda tez — millionlab hujjatlar orasida millisekund larda qidirish mumkin.
Kamchiligi: Savol va hujjat bir-birini "ko'rmaydi". Nozik kontekstual aloqalarni topa olmaydi.
Bizning Nihol tizimimizda: pgvector dagi barcha chunk embedding lari oldindan hisoblab qo'yilgan. Bu bi-encoder yondashuvi.
Cross-encoder: Birgalikda encoding
Savol + Hujjat
(birlashtirilgan)
|
v
+----------+
| Encoder |
| (bitta |
| model) |
+----+-----+
|
v
Relevance Score: 0.92
Qanday ishlaydi: Savol va hujjat birgalikda bitta modelga beriladi. Model ikkalasini bir vaqtda ko'radi va bevosita relevantlik bahosini beradi.
Afzalligi: Sifat yuqori — chunki model savolning har bir so'zini hujjatning har bir so'zi bilan solishtiradi. Nozik kontekstni tushunadi.
Kamchiligi: Juda sekin — har bir savol-hujjat juftligi uchun alohida hisoblash kerak. 10,000 hujjatni tekshirish uchun 10,000 marta model ishga tushiriladi.
Qanday birlashtiriladi?
Production tizimda ikkalasi birgalikda ishlatiladi:
Savol keldi
|
v
Bi-encoder: Top 100 chunk ni tez topish (millisekundlar)
|
v
Cross-encoder (yoki Reranker): 100 dan top 5 ni sifatli tanlash (1-2 soniya)
|
v
LLM ga berish
Nihol loyihasida alohida cross-encoder yoki LLM-reranker ishlatilmaydi -- bi-encoder (vector search) natijasi ustidan tez heuristik tanlash qo'llanadi (select_context_chunks: top-3 + kalit so'z mosliklari). Cross-encoder sifatliroq natija berishi mumkin, lekin lokal serverda har savolga qo'shimcha soniyalar qo'shadi -- shu sababli undan voz kechilgan.
Sparse vs Dense Embeddings
Sparse embedding: BM25 (so'z chastotasi)
BM25 — bu klassik information retrieval usuli. U so'z chastotasiga asoslangan.
Hujjat: "Nihol kompaniyasi IBM Power server yetkazib berdi" Sparse vektor (soddalashtirilgan): "nihol": 0.82 "kompaniya": 0.15 (ko'p hujjatlarda bor -> past qiymat) "ibm": 0.91 "power": 0.67 "server": 0.73 "yetkazib": 0.58 "berdi": 0.12 Qolgan 50,000 so'z: 0.0 (shuning uchun "sparse" — siyrak)
Qanday ishlaydi: Har bir so'z uchun uning shu hujjatdagi muhimligi hisoblanadi. Kamdan-kam uchraydigan so'zlar (masalan, "IBM") yuqori ball oladi, ko'p uchraydigan so'zlar ("kompaniya") past ball oladi.
Kuchi: Aniq so'zlarni topishda kuchli. "IBM Power VRM" desangiz, aynan shu so'zlar bo'lgan hujjatni topadi.
Zaif tomoni: Ma'noni tushunmaydi. "server uskunalari" va "серверное оборудование" — bir xil narsa, lekin BM25 uchun bular mutlaqo turli so'zlar.
Dense embedding: Neyron tarmoq (ma'no)
Hujjat: "Nihol kompaniyasi IBM Power server yetkazib berdi" Dense vektor: [0.0234, -0.0891, 0.1456, -0.0023, 0.0678, 0.0912, ...] # 4096 ta son HAR BIR son noldan farqli (shuning uchun "dense" — zich)
Kuchi: Ma'noni tushunadi. "server uskunalari" = "серверное оборудование" = "equipment delivery" — barchasi yaqin vektorlarga aylanadi.
Zaif tomoni: Aniq, noyob so'zlarni "yo'qotishi" mumkin. "VRM" kabi tor texnik atama dense embedding da "yo'qolishi" mumkin.
Hybrid Search — eng yaxshi natija
Eng yaxshi yondashuv — ikkalasini birlashtirish:
Savol: "IBM Power VRM modullari" BM25 natijasi (aniq so'z topish): 1. "IBM Power CPU VRM modullarini yetkazib berish" -> Score: 0.95 2. "IBM Power Systems serverlari" -> Score: 0.61 Dense natijasi (ma'no bo'yicha topish): 1. "Server uskunalari yetkazib berish loyihasi" -> Score: 0.88 2. "IBM Power CPU VRM modullarini yetkazib berish" -> Score: 0.85 Hybrid (birlashtirilgan): 1. "IBM Power CPU VRM modullarini yetkazib berish" -> Score: 0.95 (ikkala tizimda yuqori) 2. "Server uskunalari yetkazib berish loyihasi" -> Score: 0.74 3. "IBM Power Systems serverlari" -> Score: 0.68
Cosine Similarity — vektorlarni taqqoslash
Cosine similarity — ikki vektor orasidagi burchak kosinusini hisoblash. Bu embedding lar qanchalik o'xshash ekanini aniqlashning standart usuli.
Formula
A . B a1*b1 + a2*b2 + ... + an*bn
cos(theta) = --------------- = -----------------------------------
||A|| * ||B|| sqrt(a1^2+...+an^2) * sqrt(b1^2+...+bn^2)
Sodda qilib aytganda: ikki vektor orasidagi burchakning kosinusi.
Vizual tushuntirish (2D misol)
^ A = "mushuk uyda"
/|
/ |
/ | B = "koshka doma"
/ 10| /
/ deg| /
/ | / cos(10) = 0.98 (juda o'xshash!)
+-------+-------->
^ A = "mushuk uyda"
/|
/ |
/ |
/ |
/ 80 |
/ deg |
+------+--------> C = "mashina tez yurar"
cos(80) = 0.17 (o'xshash emas)
Qiymatlar ma'nosi
| Cosine Similarity | Ma'nosi | Misol |
|---|---|---|
| 1.0 | Bir xil ma'no | "mushuk" va "mushuk" |
| 0.85 - 0.99 | Juda o'xshash | "mushuk uyda" va "koshka sidela doma" |
| 0.70 - 0.85 | O'xshash | "mushuk uyda" va "it hovlida" |
| 0.50 - 0.70 | Biroz aloqador | "mushuk uyda" va "hayvonlar dunyosi" |
| 0.30 - 0.50 | Zaif aloqa | "mushuk uyda" va "bugungi yangiliklar" |
| 0.0 - 0.30 | Aloqasiz | "mushuk uyda" va "kvant fizikasi" |
Nihol loyihasida RAG_SIMILARITY_THRESHOLD admin paneldan sozlanadi (default 0.0 — filtrsiz). Chegara qo'yilsa (masalan 0.3), undan past similarity li chunk lar olib tashlanadi. Amalda default 0.0 qoldirilgan: top_k=15 va heuristik tanlash shovqinni o'zi yetarlicha kamaytiradi.
Python da hisoblash
import numpy as np def cosine_similarity(vec_a: list[float], vec_b: list[float]) -> float: a = np.array(vec_a) b = np.array(vec_b) return float(np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b))) # Misol: OpenAI API bilan from openai import OpenAI client = OpenAI() def embed(text: str) -> list[float]: response = client.embeddings.create( model="text-embedding-3-small", input=text ) return response.data[0].embedding # Ikki gapni embedding qilish vec_server = embed("Nihol kompaniyasi server yetkazib beradi") vec_deliver = embed("Nihol provides server equipment delivery") vec_weather = embed("Bugun ob-havo yaxshi, harorat 25 daraja") # Taqqoslash sim_1 = cosine_similarity(vec_server, vec_deliver) sim_2 = cosine_similarity(vec_server, vec_weather) print(f"server <-> delivery: {sim_1:.4f}") # ~0.85 (o'xshash ma'no) print(f"server <-> weather: {sim_2:.4f}") # ~0.15 (aloqasiz)
pgvector da cosine distance
Nihol loyihasida biz PostgreSQL + pgvector ishlatamiz. pgvector da cosine distance <=> operatori bilan hisoblanadi:
-- Cosine distance = 1 - cosine_similarity -- Shuning uchun similarity olish uchun: 1 - distance SELECT chunk_text, 1 - (embedding_local <=> :query_vector) AS similarity FROM wde.lv_content_chunks WHERE embedding_local IS NOT NULL ORDER BY embedding_local <=> :query_vector -- eng yaqindan boshlab LIMIT 10;
Multilingual Embeddings — ko'p tilli embedding lar
Zamonaviy embedding modellar bir nechta tilni bitta vektor fazoda ifodalay oladi. Bu degani turli tillardagi bir xil ma'noli gaplar yaqin vektorlarga aylanadi.
Qanday ishlaydi?
"server uskunalari" -> [0.23, -0.08, 0.14, ...] (UZ) "серверное оборудование" -> [0.22, -0.09, 0.15, ...] (RU) "server equipment" -> [0.24, -0.07, 0.13, ...] (EN) Uchala vektor bir-biriga juda yaqin! Cosine similarity > 0.90
Bu Nihol loyihamiz uchun juda muhim. nihol.uz saytida ma'lumotlar ruscha va o'zbekcha mavjud. Multilingual embedding tufayli: - O'zbekcha savol berilsa -> ruscha chunk ham topilishi mumkin (agar o'zbekcha mavjud bo'lmasa) - Ruscha savol berilsa -> o'zbekcha chunk ham topilishi mumkin
Lekin biz detect_lang() bilan til filtratsiyasini ham qo'shganmiz — chunki foydalanuvchi o'zbekcha so'rasa, ruscha javob olishni xohlamaydi.
Qwen3-embedding ning multilingual qobiliyati
Bizning loyihamizda Qwen3-embedding:8b ishlatamiz. Bu model 100 dan ortiq tilni qo'llab-quvvatlaydi, shu jumladan: - O'zbek tili (lotin va kirill) - Rus tili - Ingliz tili
Bu bizning ikki tilli (UZ/RU) bilim bazamiz uchun ideal tanlov.
Mashhur Embedding Modellar Taqqoslashi
| Model | O'lcham (Dimensions) | Multilingual | Narx | Xususiyat |
|---|---|---|---|---|
| OpenAI text-embedding-3-small | 1536 | 100+ til | $0.02/1M token | Eng mashhur cloud model. Yaxshi sifat, arzon narx. |
| OpenAI text-embedding-3-large | 3072 | 100+ til | $0.13/1M token | Yuqori sifat, qimmatlroq. Dimension qisqartirilishi mumkin. |
| Cohere embed-v3 | 1024 | 100+ til | $0.10/1M token | Search va classification uchun alohida rejimlar. |
| BGE-M3 | 1024 | 100+ til | Bepul (open-source) | Dense + sparse + multi-vector. Eng ko'p qirrali. |
| Qwen3-embedding | 4096 | 100+ til | Bepul (open-source) | Bizning loyihamizda ishlatamiz. Ollama bilan local. |
| Jina embeddings-v3 | 1024 | 89 til | Bepul / API | Task-specific: retrieval, classification, separation. |
| Voyage-3 | 1024 | Ko'p tillik | $0.06/1M token | Code va texnik matnlar uchun kuchli. |
Qwen3-embedding ni tanlash sabablari (Nihol loyihasi)
- Local ishlaydi — Ollama orqali serverda, internet kerak emas. Ma'lumotlar tashqariga chiqmaydi.
- Bepul — API narxi yo'q. Serverda GPU bor — bas.
- 4096 dimension — ko'proq dimension = ko'proq ma'no saqlanadi.
- Multilingual — o'zbek va rus tillarini yaxshi tushunadi.
- Maxfiylik — kompaniya ma'lumotlari cloud ga yuborilmaydi.
MTEB Leaderboard — Embedding modellarni baholash
MTEB (Massive Text Embedding Benchmark) — bu embedding modellarni 8 ta turli vazifa bo'yicha baholovchi benchmark.
MTEB vazifalari
| Vazifa | Nima tekshiriladi | Misol |
|---|---|---|
| Retrieval | Savol bo'yicha hujjat topish | "IBM Power haqida" -> tegishli chunk |
| STS (Semantic Textual Similarity) | Ikki gapning o'xshashligini aniqlash | "mushuk" <-> "koshka" = 0.95 |
| Classification | Matnni kategoriyaga ajratish | "yaxshi mahsulot" -> ijobiy |
| Clustering | O'xshash matnlarni guruhlash | Loyihalarni soha bo'yicha guruhlash |
| PairClassification | Juft gaplar orasidagi munosabat | Parafraz mi yoki yo'qmi |
| Reranking | Qidiruv natijalarini qayta tartiblash | Eng tegishli hujjatni birinchi qilish |
| Summarization | Qisqartma sifatini baholash | Matn va uning summarysining o'xshashligi |
| BitextMining | Turli tillardagi juft gaplarni topish | UZ-RU parallel gaplar |
MTEB ni qanday o'qish kerak?
Hugging Face MTEB Leaderboard: https://huggingface.co/spaces/mteb/leaderboard Ko'rsatkich: Model nomi | Avg | Retrieval | STS | Classification | ... ---------------+------+-----------+------+----------------+---- Qwen3-emb | 72.1 | 68.5 | 85.2 | 78.4 | ... BGE-M3 | 70.8 | 67.2 | 83.1 | 76.9 | ... text-emb-3-sm | 69.4 | 65.8 | 82.7 | 74.3 | ...
RAG tizim qurish uchun eng muhim ko'rsatkich — Retrieval ustuni. Chunki bizning asosiy vazifamiz savol bo'yicha eng tegishli chunk ni topish.
Qaysi metrikalar muhim?
- nDCG@10 (Normalized Discounted Cumulative Gain) — top 10 natijaning sifati. Birinchi o'rindagi natija muhimroq.
- MAP (Mean Average Precision) — o'rtacha aniqlik. Barcha tegishli hujjatlar topildimi?
- Recall@100 — top 100 natijada barcha tegishli hujjatlar bormi? Bu reranking dan oldingi bosqich uchun muhim.
Haqiqiy kod misoli: Embedding va Cosine Similarity
Keling, to'liq ishlaydigan misol ko'raylik — ikkita gapni embedding qilib, o'xshashligini hisoblaymiz.
OpenAI bilan
from openai import OpenAI import numpy as np client = OpenAI() # OPENAI_API_KEY environment variable dan oladi def embed_text(text: str) -> list[float]: """Matnni vektor ga aylantirish.""" response = client.embeddings.create( model="text-embedding-3-small", input=text, ) return response.data[0].embedding def cosine_sim(a: list[float], b: list[float]) -> float: """Ikki vektor orasidagi cosine similarity.""" a, b = np.array(a), np.array(b) return float(np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b))) # Uchta gapni embedding qilish gap_1 = "Nihol kompaniyasi Ucell uchun server yetkazib bergan" gap_2 = "Nihol поставила серверное оборудование для Ucell" gap_3 = "Bugun Toshkentda ob-havo bulutli" vec_1 = embed_text(gap_1) vec_2 = embed_text(gap_2) vec_3 = embed_text(gap_3) print(f"Dimension: {len(vec_1)}") # 1536 # O'xshashlik hisoblash print(f"UZ <-> RU (bir xil ma'no): {cosine_sim(vec_1, vec_2):.4f}") # ~0.88 print(f"UZ <-> Ob-havo (boshqa mavzu): {cosine_sim(vec_1, vec_3):.4f}") # ~0.12 print(f"RU <-> Ob-havo (boshqa mavzu): {cosine_sim(vec_2, vec_3):.4f}") # ~0.10
Nihol loyihasidagi Qwen3-embedding bilan (Ollama)
import httpx import numpy as np OLLAMA_URL = "http://127.0.0.1:11434" MODEL = "qwen3-embedding:8b" def embed_local(text: str) -> list[float]: """Qwen3-embedding bilan local embedding.""" resp = httpx.post( f"{OLLAMA_URL}/api/embed", json={"model": MODEL, "input": text}, timeout=60, ) resp.raise_for_status() return resp.json()["embeddings"][0] def cosine_sim(a: list[float], b: list[float]) -> float: a, b = np.array(a), np.array(b) return float(np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b))) # Test chunks = [ "Nihol kompaniyasi Ucell uchun IBM Power CPU VRM modullarini yetkazib bergan", "Нихол поставила модули IBM Power CPU VRM для Ucell", "Dell PowerEdge billing modernizatsiyasi loyihasi", "Bugun Toshkentda harorat 35 daraja", ] query = "Ucell uchun qanday uskunalar yetkazilgan?" q_vec = embed_local(query) print(f"Dimension: {len(q_vec)}") # 4096 print() for chunk in chunks: c_vec = embed_local(chunk) sim = cosine_sim(q_vec, c_vec) print(f"Similarity: {sim:.4f} | {chunk[:60]}") # Kutilgan natija: # Similarity: 0.8234 | Nihol kompaniyasi Ucell uchun IBM Power CPU VRM modullari... # Similarity: 0.7891 | Нихол поставила модули IBM Power CPU VRM для Ucell # Similarity: 0.6123 | Dell PowerEdge billing modernizatsiyasi loyihasi # Similarity: 0.1456 | Bugun Toshkentda harorat 35 daraja
E'tibor bering: 1. O'zbekcha savol -> o'zbekcha chunk eng yuqori similarity (0.82) 2. Ruscha chunk ham yaqin (0.79) — multilingual embedding kuchi 3. Dell chunk ham o'rtacha tegishli (0.61) — chunki u ham uskuna haqida 4. Ob-havo chunk mutlaqo aloqasiz (0.15)
Embedding ni tanlashda nimaga e'tibor berish kerak?
1. Dimension soni
Ko'proq dimension = ko'proq ma'no saqlanadi, lekin: - Xotira ko'proq kerak (4096 dim * 4 byte = 16 KB har bir chunk) - Qidiruv biroz sekinroq - 1024-4096 oralig'i ko'p holatlar uchun yetarli
2. Multilingual qobiliyat
Agar bilim bazangiz bir nechta tilda bo'lsa (Nihol loyihasidek — UZ + RU), multilingual model shart.
3. Narx yoki local
- Cloud API (OpenAI, Cohere): oson ishlatiladi, lekin har bir so'rov uchun pul to'lanadi va ma'lumot tashqariga ketadi.
- Local (Qwen3-emb, BGE-M3): GPU kerak, lekin bepul va maxfiy. Nihol loyihasida biz local tanladik.
4. Domain mos kelishi
Agar sizning hujjatlaringiz texnik (tibbiyot, huquq, IT) bo'lsa, MTEB ning umumiy ko'rsatkichiga emas, shu sohaga tegishli benchmarklarga qarang.
5. Context uzunligi
Ba'zi modellar faqat 512 token qabul qiladi, ba'zilari 8192 gacha. Agar chunk laringiz uzun bo'lsa, model context uzunligiga e'tibor bering.
Xulosa
Embedding — bu matnni kompyuter tushuna oladigan raqamli formatga o'tkazish. Lekin bu oddiy raqamlar emas — bu ma'noni saqlaydigan raqamlar.
Asosiy tushunchalar: - Vektor — ko'p o'lchamli fazoda nuqta. 4096 ta son ma'noning 4096 ta jihatini saqlaydi. - Contrastive learning — model yaqin ma'noli gaplarni yaqin vektorlarga aylantishni o'rganadi. - Bi-encoder — tez, oldindan hisoblab qo'yish mumkin (qidiruv uchun). - Cross-encoder — sifatli, lekin sekin (reranking uchun). - Cosine similarity — ikki vektorning o'xshashlik darajasi (0 dan 1 gacha). - Multilingual — turli tillardagi bir xil ma'noli gaplar yaqin vektorlarga aylanadi. - MTEB — embedding modellarni tanlashda asosiy benchmark.
Keyingi bobda chunking strategiyalarini ko'rib chiqamiz — matnni qanday bo'laklarga ajratish kerak va bu nima uchun muhim.
</> Loyihaning haqiqiy kodi — bu bob amalda qanday ishlaydi
app/services/chat.py — savol embeddingi
def generate_query_embedding(text_input: str) -> tuple[list[float] | None, str | None]:
settings = get_settings()
last_error = None
for attempt in range(3):
try:
resp = httpx.post(
f"{settings.EMBED_OLLAMA_URL}/api/embed",
json={"model": settings.EMBED_MODEL, "input": text_input, "keep_alive": -1},
timeout=60,
)
resp.raise_for_status()
return resp.json()["embeddings"][0], None
except Exception as e:
last_error = f"{type(e).__name__}: {e}"
if attempt < 2:
time.sleep(2 ** attempt)
return None, last_errorextractor/chunker.py — chunk embeddinglari
def embed_all(session: Session) -> dict:
pending = session.query(LvContentChunks).filter(
LvContentChunks.embedding_local.is_(None),
).all()
embedded = 0
errors = []
for chunk in pending:
start = time.perf_counter()
vector = None
status = "ok"
error_message = None
try:
vector = _generate_embedding(chunk.chunk_text)
if vector is None:
status = "error"
error_message = "empty response"
errors.append({"chunk_id": chunk.id, "error": "empty response"})
continue
chunk.embedding_local = json.dumps(vector)
session.commit()
embedded += 1
except Exception as e:
status = "error"
error_message = str(e)
errors.append({"chunk_id": chunk.id, "error": str(e)})
session.rollback()
finally:
duration_ms = int((time.perf_counter() - start) * 1000)
_write_analytics_embedding(
chunk_id=chunk.id,
model=EMBED_MODEL,
vector_dim=len(vector) if vector else 0,
duration_ms=duration_ms,
status=status,
error_message=error_message,
)
already = session.query(LvContentChunks).filter(
LvContentChunks.embedding_local.isnot(None),
).count()
return {
"embedded": embedded,
"already_done": already - embedded,
"errors": errors,
}
def _generate_embedding(text: str) -> list[float] | None:
try:
resp = httpx.post(
f"{EMBED_OLLAMA_URL}/api/embed",
json={"model": EMBED_MODEL, "input": text, "keep_alive": -1},
timeout=60,
)
resp.raise_for_status()
return resp.json()["embeddings"][0]
except Exception:
return NoneBu bobni bepul o'qidingiz.
Kitob o'rgatadi, lekin sizning kodingiz nega ishlamaganini ayta olmaydi. Kursda uy vazifangiz tekshiriladi.