13 β Embeddings va semantik qidiruv¶
β¬ οΈ Oldingi: 12 β Multimodal: rasm va ovoz Β· π Kitob boshi Β· Keyingi: 14 β Vektor bazalari β‘οΈ
Bu bobda: matnni sonlar ro'yxatiga (vektor) aylantiradigan embedding nima ekanini, ma'no yaqin matnlar nega yaqin vektor olishini tushunamiz; vektor fazosi intuitsiyasini ("o'xshash ma'no β bir joyda klaster") ko'ramiz;
client.embeddings.create(...)bilan embedding olishni, ikki matn o'xshashligini cosine similarity orqali o'lchashni o'rganamiz; kalit so'z emas, ma'no bo'yicha qidiradigan semantik qidiruvning to'liq mini-misolini quramiz; batch embedding (bir so'rovda ko'p matn β arzon va tez), o'lcham (dimensions) va normalizatsiya haqida bilib olamiz. Bu bob β keyingi to'rt bob (RAG) ning poydevori.
Muammodan boshlaymiz: kalit so'z qidiruv yetmaydi¶
Tasavvur qiling, sizda bilim bazasi bor β bir nechta yordam maqolasi. Foydalanuvchi savol beradi:
"Parolimni unutib qo'ydim, nima qilay?"
An'anaviy qidiruv (masalan, if "parol" in maqola) faqat bir xil so'zni topadi. Lekin to'g'ri maqola sarlavhasi "Hisobga kirishni tiklash" bo'lsa-chi? Unda "parol" so'zi umuman bo'lmasligi mumkin! Kalit so'z qidiruv bu yerda hech narsa topmaydi, garchi maqola aynan shu savolga javob bersa ham.
Muammoning ildizi: kalit so'z qidiruv harflarni solishtiradi, ma'noni emas. "Parolni tiklash" va "hisobga kirishni qaytarish" β bir xil ma'no, lekin bir xil so'z emas. Bizga ma'no bo'yicha qidiradigan vosita kerak.
Mana shu yerda embedding o'yinni o'zgartiradi. U har bir matnni sonlar ro'yxatiga aylantiradi shunday tarzdaki, ma'nosi yaqin matnlar β yaqin sonlar oladi. Endi "o'xshashlik"ni harf bilan emas, matematika bilan o'lchaymiz.
Hayotiy o'xshatish. Kalit so'z qidiruv β kitobxonadan "muqovasida aynan shu so'z bor kitobni ber" deyish. Semantik qidiruv esa β kutubxonachiga mavzuni aytib, "shunga o'xshash kitoblarni ber" deyish. Birinchisi so'zga, ikkinchisi ma'noga qaraydi.
Atama: embedding
Embedding (o'qiladi: "embedding", ya'ni "joylashtirish") β matnni (so'z, jumla yoki butun hujjatni) belgilangan uzunlikdagi sonlar ro'yxatiga (vektorga) aylantirish. Bu vektor matnning ma'nosini sonlarda "kodlaydi". Buni amalga oshiradigan model β embedding modeli (chat modelidan alohida).
Vektor nima va vektor fazosi intuitsiyasi¶
Vektor β bu shunchaki sonlar ro'yxati, masalan [0.12, -0.34, 0.88, ...]. Embedding modeli har bir matnga shunday ro'yxat beradi. Bu ro'yxat odatda uzun β masalan, text-embedding-3-small modeli 1536 ta son qaytaradi. Har bir son matnning ma'no "o'lchami"ning bir qirrasini ifodalaydi (qaysi qirra ekani aniq inson tiliga tarjima qilinmaydi β bu modelning ichki "tili").
Eng muhim g'oya: bu sonlarni fazodagi nuqta sifatida tasavvur qiling. 2 ta son bo'lsa β tekislikdagi nuqta (x, y). 3 ta son β uch o'lchovli fazo. Embedding'da minglab son bor β minglab o'lchovli fazo (uni tasavvur qilib bo'lmaydi, lekin matematika bir xil ishlaydi). Va shu fazoda:
- Ma'nosi yaqin matnlar β yaqin nuqtalar (klaster bo'lib to'planadi).
- Ma'nosi uzoq matnlar β uzoq nuqtalar.
Yuqoridagi diagramma bitta matn embedding modeliga kirib, sonlar vektori bo'lib chiqishini ko'rsatadi. Endi ko'p matnni shu fazoga joylashtirsak, ajoyib narsa yuz beradi: o'xshash mavzudagilar bir-biriga yaqin tushadi.
Hayotiy o'xshatish. Vektor fazosi β ulkan kutubxona zali. Kitoblar tasodifan emas, mavzu bo'yicha javonlarga qo'yilgan: oshpazlik kitoblari bir burchakda, fizika kitoblari boshqa burchakda. Yangi kitob kelsa, uni mazmuniga qarab "to'g'ri javon"ga qo'yasiz. Embedding ham xuddi shunday β har matnga fazoda "manzil" beradi va o'xshashlar qo'shni bo'lib qoladi.
Mashhur misol: shoh β erkak + ayol β malika
Embeddinglar ma'noni shunchalik yaxshi tutadiki, ular ustida arifmetika ham ishlaydi. Klassik misol: "shoh" vektoridan "erkak" vektorini ayirib, "ayol"ni qo'shsangiz β natija "malika" vektoriga juda yaqin chiqadi. Bu shuni ko'rsatadiki, fazodagi yo'nalishlar ma'no munosabatlarini (masalan, "jinsi") ifodalaydi. Bu β sodda intuitsiya; amalda biz asosan yaqinlikdan foydalanamiz.
Embedding olish: client.embeddings.create¶
Chat so'rovini eslang (client.chat.completions.create). Embedding ham xuddi shunday oson β boshqa endpoint: client.embeddings.create. Sozlash 2-bobdagidek (.env + python-dotenv).
import os
from dotenv import load_dotenv
from openai import OpenAI
load_dotenv()
client = OpenAI() # OPENAI_API_KEY .env dan olinadi
# Embedding modeli β chat modelidan ALOHIDA model.
# Eslatma: model nomlari o'zgaradi β provayder ro'yxatini tekshiring.
EMBED_MODEL = "text-embedding-3-small"
javob = client.embeddings.create(
model=EMBED_MODEL,
input="It bog'da yuguryapti", # bitta matn (yoki ro'yxat β pastda ko'ramiz)
)
vektor = javob.data[0].embedding # list[float]
print(type(vektor), len(vektor)) # <class 'list'> 1536
print(vektor[:5]) # masalan: [0.013, -0.027, 0.041, -0.008, 0.052]
Asosiy nuqtalar:
inputβ matn (yoki matnlar ro'yxati). Javobjavob.dataro'yxatida keladi: har bir kirish matniga bitta element.javob.data[i].embeddingβ i-chi matnning vektori, oddiylist[float].len(vektor)β vektor o'lchami (text-embedding-3-smalluchun 1536). Bir model doim bir xil o'lchamli vektor qaytaradi.
Hayotiy o'xshatish. Chat modeli β matnga matn bilan javob beradigan suhbatdosh. Embedding modeli β matnga raqamlar bilan javob beradigan "tarjimon": u gapirmaydi, faqat matnni ma'no koordinatalariga aylantiradi. Ikkalasi ikki xil ish uchun.
Embedding modeli β chat modeli
gpt-5.4-mini β chat modeli, u matn yozadi. text-embedding-3-small β embedding modeli, u faqat vektor qaytaradi. Ularni almashtirib bo'lmaydi: chat modelidan vektor so'ramaysiz, embedding modelidan javob yozishini kutmaysiz.
Cosine similarity: ikki vektor qanchalik yaqin?¶
Ikki matnning ma'nosi qanchalik yaqinligini bilish uchun ularning vektorlari orasidagi yaqinlikni o'lchaymiz. Eng keng qo'llaniladigan o'lchov β cosine similarity (kosinus o'xshashligi): ikki vektor orasidagi burchakka qaraydi.
- Natija 1.0 ga yaqin β vektorlar bir yo'nalishda, ma'no juda o'xshash.
- Natija 0 ga yaqin β bog'liq emas.
- Natija manfiy β qarama-qarshi (matnda kam uchraydi).
Formula sodda β ikki vektorning skalyar ko'paytmasini ularning uzunliklari ko'paytmasiga bo'lamiz:
$$\text{cosine}(A, B) = \frac{A \cdot B}{\lVert A\rVert \, \lVert B\rVert} = \frac{\sum_i A_i B_i}{\sqrt{\sum_i A_i^2}\,\sqrt{\sum_i B_i^2}}$$
Avval sof Pythonda (kutubxonasiz) yozamiz β formula ko'rinib tursin:
import math
def cosine_similarity(a: list[float], b: list[float]) -> float:
skalyar = sum(x * y for x, y in zip(a, b)) # A . B
uzunlik_a = math.sqrt(sum(x * x for x in a)) # ||A||
uzunlik_b = math.sqrt(sum(y * y for y in b)) # ||B||
return skalyar / (uzunlik_a * uzunlik_b)
Amalda esa numpy ancha tez va qisqa (pip install numpy):
import numpy as np
def cosine(a, b) -> float:
a, b = np.array(a), np.array(b)
return float(a @ b / (np.linalg.norm(a) * np.linalg.norm(b)))
Endi ikki matnning o'xshashligini hisoblaymiz:
def embed(matn: str) -> list[float]:
"""Bitta matnni vektorga aylantiradi."""
javob = client.embeddings.create(model=EMBED_MODEL, input=matn)
return javob.data[0].embedding
v1 = embed("It bog'da yuguryapti")
v2 = embed("Kuchuk hovlida o'ynayapti") # ma'nosi yaqin (it β kuchuk)
v3 = embed("Python β dasturlash tili") # ma'nosi uzoq
print(cosine(v1, v2)) # yuqori, masalan ~0.78
print(cosine(v1, v3)) # past, masalan ~0.09
Birinchi juftlik ("it" va "kuchuk") yuqori ball oladi β garchi bironta ham bir xil so'z bo'lmasa ham! Ikkinchisi past β mavzular butunlay boshqa. Aynan shu β embeddingning kuchi.
Hayotiy o'xshatish. Cosine similarity β ikki kishi qaysi yo'nalishga qarab turganini solishtirish. Ikkalasi bir tomonga qarasa (burchak kichik) β fikrlari mos, ball ~1. Turli tomonga qarasa β ball past. Ular bir-biridan qancha uzoqda turgani emas, qaysi tomonga qaraganlari muhim.
Cosine vs masofa
O'xshashlikni "masofa" (Euclidean) bilan ham o'lchash mumkin. Lekin matn embeddinglarida odatda cosine ishlatiladi, chunki u vektor uzunligiga emas, yo'nalishiga qaraydi β ma'no aynan yo'nalishda kodlangan. Keyingi bobdagi vektor bazalari ham asosan cosine'ni qo'llaydi.
Semantik qidiruv: to'liq mini-misol¶
Endi hamma bo'laklarni yig'ib, semantik qidiruv quramiz. G'oya juda sodda:
- Barcha hujjatlarni oldindan embedding qilamiz (bir marta).
- Foydalanuvchi savolini embedding qilamiz.
- Savol vektorini har bir hujjat vektori bilan cosine orqali solishtiramiz.
- Eng yuqori ballli hujjat(lar)ni qaytaramiz.
To'liq ishlaydigan misol (kichik bilim bazasi ustida):
import os
import numpy as np
from dotenv import load_dotenv
from openai import OpenAI
load_dotenv()
client = OpenAI()
EMBED_MODEL = "text-embedding-3-small"
# 1) Kichik bilim bazasi (hujjatlar)
hujjatlar = [
"Parolni tiklash uchun 'Kirishni tiklash' tugmasini bosing va emailingizni kiriting.",
"Buyurtmani bekor qilish uchun 'Mening buyurtmalarim' bo'limiga o'ting.",
"Yetkazib berish odatda 3-5 ish kunini oladi.",
"To'lovni karta yoki Payme orqali amalga oshirishingiz mumkin.",
"Hisobingizga kira olmasangiz, emailga yuborilgan tiklash havolasidan foydalaning.",
]
def cosine(a, b) -> float:
a, b = np.array(a), np.array(b)
return float(a @ b / (np.linalg.norm(a) * np.linalg.norm(b)))
# 2) Hujjatlarni BIR SO'ROVDA embedding qilamiz (batch β pastda batafsil)
javob = client.embeddings.create(model=EMBED_MODEL, input=hujjatlar)
hujjat_vektorlari = [d.embedding for d in javob.data]
def semantik_qidiruv(savol: str, top_k: int = 2):
"""Savolga eng mos top_k hujjatni cosine bo'yicha qaytaradi."""
savol_vektori = client.embeddings.create(
model=EMBED_MODEL, input=savol
).data[0].embedding
# Har bir hujjat bilan o'xshashlikni hisoblaymiz
ballar = [
(cosine(savol_vektori, hv), matn)
for hv, matn in zip(hujjat_vektorlari, hujjatlar)
]
# Ball bo'yicha kamayish tartibida saralaymiz
ballar.sort(key=lambda x: x[0], reverse=True)
return ballar[:top_k]
# 3) Sinab ko'ramiz
for ball, matn in semantik_qidiruv("parolimni unutib qo'ydim"):
print(f"{ball:.3f} {matn}")
Natija taxminan shunday bo'ladi:
0.612 Parolni tiklash uchun 'Kirishni tiklash' tugmasini bosing va emailingizni kiriting.
0.541 Hisobingizga kira olmasangiz, emailga yuborilgan tiklash havolasidan foydalaning.
Diqqat qiling: savolda "parol" so'zi bor, lekin ikkinchi topilgan hujjatda u umuman yo'q β baribir topildi, chunki ma'nosi yaqin ("hisobga kirish", "tiklash"). Kalit so'z qidiruv buni hech qachon topa olmasdi. Mana shu β semantik qidiruvning amaliy kuchi.
Embeddinglarni qayta ishlatish
Hujjatlar vektorlarini har safar qayta hisoblamang β bu pul va vaqt. Bir marta embedding qilib, vektorlarni saqlang (faylga, bazaga). Faqat savolni har so'rovda yangi embedding qilasiz. Kichik bazada ro'yxatda saqlash kifoya; kattalashganda β vektor bazasi kerak (aynan 14-bob shu haqida).
Bir xil model bilan embedding qiling
Hujjatlar va savolni bitta xil embedding modeli bilan vektorlashtiring. Turli modellar (yoki bir modelning turli dimensions sozlamasi) turli fazo yaratadi β ularning vektorlarini solishtirish ma'nosiz natija beradi. Modelni almashtirsangiz β butun bazani qayta embedding qiling.
Batch embedding: bir so'rovda ko'p matn¶
Yuqorida sezgan bo'lsangiz, input ga ro'yxat berdik β bu batch (to'plamli) embedding. Bir nechta matnni bitta so'rovda yuborish β har biriga alohida so'rov yuborishdan ancha tez va arzon (tarmoq kechikishi bir marta, ko'p hollarda narx ham qulayroq).
matnlar = ["birinchi matn", "ikkinchi matn", "uchinchi matn"]
javob = client.embeddings.create(model=EMBED_MODEL, input=matnlar)
# javob.data tartibi input tartibiga MOS keladi
for i, d in enumerate(javob.data):
print(i, matnlar[i], "->", len(d.embedding), "o'lcham")
# Faqat vektorlar ro'yxatini olish:
vektorlar = [d.embedding for d in javob.data]
Hayotiy o'xshatish. Batch embedding β pochtaga 100 ta xatni alohida-alohida emas, bitta to'plamda topshirish. Bir marta navbatda turasiz, bir marta to'lov β vaqt ham, kuch ham tejaladi. Natija aynan o'sha 100 ta xat.
Tartib va chegara
javob.data har doim input ro'yxati tartibida keladi β data[0] birinchi matnga mos. Juda katta ro'yxat bo'lsa, uni bo'laklarga (masalan, 100 tadan) bo'lib yuboring: provayderda bir so'rovdagi matnlar soni va umumiy token chegarasi bor.
O'lcham (dimensions) va normalizatsiya¶
O'lcham (dimensions) β vektordagi sonlar soni. Kattaroq o'lcham β ko'proq nuans, lekin ko'proq xotira va hisob. text-embedding-3-small standart 1536 o'lcham beradi, lekin ba'zi modellar uni kichraytirishga ruxsat beradi (sifat biroz pasayadi, tezlik/xotira yutadi):
# Ba'zi modellar dimensions parametrini qo'llab-quvvatlaydi
javob = client.embeddings.create(
model="text-embedding-3-small",
input="qisqartirilgan vektor misoli",
dimensions=512, # 1536 o'rniga 512 β ixchamroq
)
print(len(javob.data[0].embedding)) # 512
Normalizatsiya β vektorni uzunligi 1 bo'ladigan qilib o'zgartirish (har sonni vektor uzunligiga bo'lish). Buni nega bilish kerak:
- Cosine allaqachon uzunlikka bo'lgani uchun, normallashtirilgan vektorlarda cosine = oddiy skalyar ko'paytma (
a @ b) β tezroq. - Ko'p vektor bazalari vektorlarni normallashgan deb kutadi yoki o'zi normallashtiradi. Ba'zi modellar (masalan, OpenAI) allaqachon ~normallangan vektor qaytaradi.
import numpy as np
def normalize(v):
v = np.array(v)
return v / np.linalg.norm(v)
# Normallashgandan keyin cosine = skalyar ko'paytma
a, b = normalize(v1), normalize(v2)
print(float(a @ b)) # cosine(v1, v2) bilan deyarli bir xil
Boshlovchi uchun amaliy maslahat
Boshida dimensions/normalizatsiya bilan ovora bo'lmang β standart o'lchamni va yuqoridagi cosine() funksiyasini ishlating. Ular optimizatsiya (tezlik, xotira); avval ishlaydigan semantik qidiruvni quring, keyin kerak bo'lsa sozlaysiz.
Boshqa provayderlar: Gemini va Ollama¶
Embeddinglar OpenAI'ga xos emas β boshqa provayderlar ham beradi. Asosiy g'oya (matn -> vektor -> cosine) bir xil; faqat model va ulanish o'zgaradi.
Google Gemini (OpenAI-mos endpoint orqali β kod deyarli o'zgarmaydi):
client = OpenAI(
base_url="https://generativelanguage.googleapis.com/v1beta/openai/",
api_key=os.environ["GEMINI_API_KEY"],
)
javob = client.embeddings.create(
model="gemini-embedding-001", # Gemini embedding modeli
input=["birinchi matn", "ikkinchi matn"],
)
vektorlar = [d.embedding for d in javob.data]
Ollama (lokal, bepul, internetsiz β nomic-embed-text modelini avval ollama pull nomic-embed-text bilan yuklab oling):
import ollama
natija = ollama.embed(model="nomic-embed-text", input="It bog'da yuguryapti")
vektor = natija["embeddings"][0] # list[float]
Lokal embedding ayniqsa maxfiy ma'lumot uchun qulay β matningiz kompyuteringizdan chiqmaydi va to'lov yo'q (21-bobda Ollama'ni batafsil ko'ramiz).
Modellar aralashmasin
Eslatib o'tamiz: bir bazadagi barcha vektorlar bir xil modeldan bo'lishi shart. OpenAI'da embedding qilingan hujjatni Gemini bilan embedding qilingan savol bilan solishtirib bo'lmaydi β fazolar boshqa. Provayderni almashtirsangiz, butun korpusni qayta embedding qiling. Model nomlari ham o'zgaradi β provayder ro'yxatini tekshiring.
Bu β RAG'ning poydevori¶
Tabriklaymiz: siz RAG (Retrieval-Augmented Generation β qidiruv bilan boyitilgan generatsiya) ning eng muhim bo'lagini o'zlashtirdingiz. Keyingi to'rt bob aynan shu g'oya ustiga quriladi:
- 14-bob β Vektor bazalari: vektorlarni ro'yxatda emas, maxsus bazada (FAISS, Chroma...) saqlash; minglab hujjat ichidan tez qidirish.
- 15-bob β Chunking: uzun hujjatni qanday bo'laklarga ("chunk") bo'lib embedding qilish.
- 16-bob β RAG quramiz: topilgan hujjatlarni kontekst sifatida chat modeliga berib, manbaga asoslangan javob olish (hallucination'ni kamaytirish).
- 17-bob β RAG sifati: qidiruvni yaxshilash, baholash, qayta tartiblash.
Bugun o'rgangan "matn -> vektor -> cosine -> eng yaqinini top" zanjiri β shularning hammasining yuragi.
Hayotiy o'xshatish. Embedding β RAG binosining poydevori. Poydevor ko'rinmaydi, lekin ustidagi hamma narsa (vektor bazasi, chunking, kontekst, javob) unga tayanadi. Poydevorni mustahkam tushunsangiz β qolgan boblar ravon yotadi.
Xulosa¶
- Embedding β matnni belgilangan uzunlikdagi sonlar ro'yxatiga (vektorga) aylantirish; ma'nosi yaqin matnlar β yaqin vektor oladi. U ma'noni kodlaydi, harflarni emas.
- Vektorni fazodagi nuqta deb tasavvur qiling: o'xshash mavzudagilar klaster bo'lib to'planadi, uzoqlari uzoq tushadi. Ma'no fazodagi yo'nalishlarda yashaydi (shoh β erkak + ayol β malika).
- Embedding olish:
client.embeddings.create(model="text-embedding-3-small", input=...); vektorjavob.data[i].embeddingichida (list[float]). Embedding modeli β chat modelidan alohida. - Cosine similarity ikki vektor orasidagi burchakka qaraydi: 1 ga yaqin β o'xshash, 0 β bog'liq emas. Formula = skalyar ko'paytma / uzunliklar ko'paytmasi (sof Python yoki numpy bilan).
- Semantik qidiruv: hujjatlarni oldindan embedding qil -> savolni embedding qil -> har biri bilan cosine -> eng yuqori ballini qaytar. Kalit so'z bo'lmasa ham ma'no bo'yicha topadi.
- Batch (ro'yxat) embedding β bir so'rovda ko'p matn, tez va arzon;
javob.datatartibiinputtartibiga mos. - O'lcham (
dimensions) vektordagi sonlar soni; ba'zi modellar uni kichraytiradi. Normalizatsiya β uzunlikni 1 ga keltirish; cosine'ni skalyar ko'paytmaga aylantiradi. - Hujjat va savolni bir xil model bilan embedding qiling β aks holda solishtirish ma'nosiz. Gemini (
gemini-embedding-001), Ollama (nomic-embed-text, lokal) ham embedding beradi. - Bu bob β RAG (14β17-boblar) ning poydevori: "matn -> vektor -> cosine -> eng yaqin" zanjiri ularning yuragi.
Amaliy mashqlar¶
-
(Oson)
text-embedding-3-smallbilan bitta matnni embedding qiling valen(vektor)ni chop eting. Boshqa matnni ham qilib, ikkalasining uzunligi bir xil ekanini tasdiqlang. -
(Oson)
cosine()funksiyasini yozing (sof Python yoki numpy). "Olma β meva" va "Banan β meva" hamda "Olma β meva" va "Mashina β transport" juftliklarini embedding qilib, cosine'larini solishtiring. Qaysi juftlik yuqori ball oldi va nega? -
(O'rtacha) Yuqoridagi
semantik_qidiruvmisolini oling, o'z bilim bazangizni (5β7 ta jumla) yozing va 3 ta turli savol bering. Topilgan natijalarning ma'noga mos kelishini baholang.top_kni o'zgartirib ko'ring. -
(O'rtacha) Hujjat vektorlarini bir marta hisoblab, JSON faylga saqlang (
json.dump). Keyin alohida skript yozing: faylni o'qib, vektorlarni qayta hisoblamasdan savol bo'yicha qidirsin. Bu nima uchun arzonroq? -
(Qiyin) Bitta korpusni
dimensions=1536vadimensions=512bilan ikki marta embedding qiling (model qo'llab-quvvatlasa). Bir necha savol uchun ikkala variantning topilgan natijalarini va tezligini solishtiring. Sifat sezilarli pasaydimi? Ixchamlik (512) qachon foydali bo'lishi mumkin?
β¬ οΈ Oldingi: 12 β Multimodal: rasm va ovoz Β· π Kitob boshi Β· Keyingi: 14 β Vektor bazalari β‘οΈ