Asosiy qismga o'tish

Embedding Chuqur (Embedding Deep Dive)

3-bob 21 kod bloki 3353 so'z

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).

python12 qator
        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":

matn12 qator
          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.

python19 qator
# 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).

python8 qator
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

yaml9 qator
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

matn18 qator
 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

matn12 qator
 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:

python10 qator
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.

python12 qator
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)

python6 qator
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:

python14 qator
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

python3 qator
                    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)

matn18 qator
        ^  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

python29 qator
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:

python9 qator
-- 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?

matn5 qator
"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)

  1. Local ishlaydi — Ollama orqali serverda, internet kerak emas. Ma'lumotlar tashqariga chiqmaydi.
  2. Bepul — API narxi yo'q. Serverda GPU bor — bas.
  3. 4096 dimension — ko'proq dimension = ko'proq ma'no saqlanadi.
  4. Multilingual — o'zbek va rus tillarini yaxshi tushunadi.
  5. 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?

matn9 qator
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?

  1. nDCG@10 (Normalized Discounted Cumulative Gain) — top 10 natijaning sifati. Birinchi o'rindagi natija muhimroq.
  2. MAP (Mean Average Precision) — o'rtacha aniqlik. Barcha tegishli hujjatlar topildimi?
  3. 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

python33 qator
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)

python44 qator
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

python17 qator
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_error

extractor/chunker.py — chunk embeddinglari

python61 qator
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 None

Bu bobni bepul o'qidingiz.

Kitob o'rgatadi, lekin sizning kodingiz nega ishlamaganini ayta olmaydi. Kursda uy vazifangiz tekshiriladi.

Telegramda yozish Narxlar