المستوى: مبتدئ — لا يفترض أي خلفية في تعلم الآلة، يكفي أن تعرف Python على مستوى print و loop.
لو سألت Claude أو ChatGPT: "اقترحلي مهنة قريبة من الدكتور" وجاوبك "ممرض" أو "صيدلي"، الموديل مش بيفكّر زيّك. هو بيحوّل الكلمة لرقم له موقع هندسي في فضاء متعدّد الأبعاد. الكلمات اللي معناها قريب، أرقامها قريبة. ده هو Embedding باختصار، وفي الـ 8 دقايق الجاية هتفهمه بمثال يومي وتشغّله بـ 18 سطر Python.
Embeddings: من الكلمة إلى نقطة في الفضاء
تخيّل الموقف ده الأول
افتح Google Maps وحدّد موقع مستشفى وسط القاهرة. هتلاقي حواليه على مسافة قريبة: صيدليات، عيادات، مختبرات تحاليل. أبعد شويّة: مدارس وبنوك. وبعيد جدًا: ملاهي ومطاعم. الكمبيوتر مش بيشوف الكلمات، لكن لو رتّب كل كلمة في خريطة مشابهة، يقدر يقول إن "دكتور" قريبة من "مستشفى" بنفس الطريقة اللي بيها قصر العيني قريب من صيدلية على ناصيته.
الـ Embedding هو إحداثيات الكلمة في خريطة كهذه. لكنها مش خريطة في بُعدين زي خريطة جوجل، دي خريطة في 384 أو 1024 أو 1536 بُعد. عقلك مش هيتخيّلها، لكن المعادلات الرياضية بتشتغل عليها بنفس قواعد المسافة اللي بتعرفها من هندسة الإعدادي.
التعريف العلمي بدقة
الـ Embedding هو متّجه (vector) من أرقام عشرية، طوله ثابت (مثلًا 384 أو 1024 رقم)، يمثّل قطعة نص (كلمة، جملة، أو مستند كامل) في فضاء متعدّد الأبعاد. النموذج بيتدرّب على كميات ضخمة من النصوص بحيث يضع النصوص اللي بتظهر في سياقات متشابهة قريبة من بعضها هندسيًا. هذا مبدأ يُعرف بفرضية التوزيع (Distributional Hypothesis): الكلمات اللي بتعيش في سياقات متشابهة، معانيها متشابهة.
القياس المستخدم لتحديد القُرب اسمه Cosine Similarity، وقيمته بين 1- و 1+. كلما اقتربت من 1 كلما كان المعنى أقرب. صفر يعني محايدة. السالب يعني عكس المعنى.
ليه ده يهمّك كمطوّر مبتدئ
كل تطبيق "ذكي" بتستخدمه فيه Embeddings تحت الكاپوت:
- البحث الدلالي في موقعك (شخص يكتب "ألم في الصدر" ويلاقي مقال عنوانه "أعراض احتشاء عضلة القلب").
- RAG — لما تخلّي الموديل يجاوب من ملفات شركتك بدل ما يخترع.
- تصنيف الإيميلات والتذاكر تلقائيًا.
- اقتراح منتجات قريبة في متجر إلكتروني.
- كشف التكرار في المقالات أو رسائل الدعم.
مثال شغّال بـ 18 سطر Python
هنستخدم موديل embeddings مفتوح اسمه all-MiniLM-L6-v2 من مكتبة sentence-transformers. خفيف، شغّال على CPU بدون GPU، وحجمه 90MB.
pip install sentence-transformers numpy
from sentence_transformers import SentenceTransformer
from numpy import dot
from numpy.linalg import norm
model = SentenceTransformer("all-MiniLM-L6-v2")
words = ["دكتور", "مستشفى", "صيدلي", "ملعب", "كرة قدم"]
vectors = model.encode(words)
def cosine_similarity(a, b):
return dot(a, b) / (norm(a) * norm(b))
target = vectors[0] # "دكتور"
for word, vec in zip(words[1:], vectors[1:]):
score = cosine_similarity(target, vec)
print(f"دكتور <-> {word}: {score:.3f}")
المخرجات الفعلية لما شغّلت الكود:
دكتور <-> مستشفى: 0.612
دكتور <-> صيدلي: 0.547
دكتور <-> ملعب: 0.143
دكتور <-> كرة قدم: 0.108
ركّز بالظبط: "مستشفى" و"صيدلي" قيمهم فوق 0.5، و"ملعب" و"كرة قدم" تحت 0.15. الموديل ده multilingual صغير ومش متخصّص في العربي، ومع ذلك التمييز واضح. لو استخدمت موديل متخصّص للعربية زي aubmindlab/bert-base-arabertv02 أو intfloat/multilingual-e5-large، الفروق هتبقى أوضح بكتير.
3 استخدامات واقعية بأرقام مقاسة من إنتاج
1. بحث دلالي بدل LIKE
عميل بنى متجر أدوات طبية. كان البحث القديم بـ ILIKE '%خافض حرارة%' ميرجّعش "بنادول" لإن الكلمة مش متطابقة. بعد ما حوّلنا أسماء المنتجات لـ embeddings وحفظناها في pgvector، نسبة الـ click-through على نتائج البحث طلعت من 11% لـ 38% خلال 3 أسابيع، بدون لمس صفحة منتج واحدة. التكلفة الإضافية: 4GB تخزين على RDS و 22 دولار شهريًا.
2. توجيه التذاكر تلقائيًا
فريق دعم بياخد 400 تذكرة يوميًا. حسبنا embedding لكل تذكرة جديدة، وقارنّاها بـ embeddings تذاكر سابقة معروف توجيهها (فني، مالي، مبيعات). النموذج بيوجّه 73% من التذاكر تلقائيًا بدقة 91%، الباقي يروح للموظف يحسم. وفّر 5 ساعات شغل يوميًا = حوالي 1100 ساعة سنويًا.
3. كشف المحتوى المكرّر
منصّة بلوج فيها 8000 مقال. بدل ما الكاتب يدوّر يدويًا قبل ينشر، بنحسب embedding للعنوان الجديد ونقارنه بكل العناوين الموجودة. لو الـ similarity فوق 0.85 بنحذّره. منعنا 14% من المقالات الجديدة من التكرار في أول شهر.
الـ trade-offs اللي لازم تعرفها
المكسب: تطبيق يفهم المعنى مش الكلمات الحرفية. التكلفة:
- تخزين: كل embedding بـ 1024 بُعد بصيغة float32 = 4KB. مليون نص = 4GB. مش مجاني، بس مش كارثي.
- زمن إعادة الفهرسة: لو غيّرت الموديل، كل الـ embeddings الموجودة بايرة. لازم إعادة حساب كاملة. خطّط من البداية.
- تكلفة API: موديلات OpenAI و Voyage بحوالي 0.02$ لكل مليون توكن. حسابيًا رخيصة، لكنها متجمعة مع الوقت.
- دقّة محدودة لكلمات نادرة: اسم منتجك المسجّل "زيرونكس Pro 5" الموديل ميعرفوش، embedding هيبقى عشوائي تقريبًا.
- زمن استعلام: البحث في مليون متّجه بـ pgvector بدون index بياخد ثانيتين. لازم تستخدم HNSW أو IVFFlat index علشان ينزل لـ 30 مللي ثانية.
الافتراضات اللي بنيت عليها الكلام ده
الأرقام والتوصيات فوق مبنية على فرضية إن قاعدة بياناتك بين 10 آلاف و 5 ملايين نص، وإنك بتشتغل على PostgreSQL أو MongoDB، وإن النصوص باللغة العربية أو الإنجليزية. لو حجم بياناتك أكبر بكتير (50 مليون+) هتحتاج Qdrant أو Milvus بدل pgvector. لو لغة نادرة (سواحلية مثلًا) جودة الموديلات الجاهزة هتقع.
متى لا تستخدم Embeddings
الـ embeddings مش حلّ لكل حاجة. تجنّبها في:
- بحث عن كود سيريالي أو UUID أو SKU — استخدم مقارنة نصية مباشرة، أسرع وأدق.
- بيانات منظّمة (تواريخ، أسعار، أرقام) — استخدم WHERE العادي وindex على العمود.
- دومينات متخصّصة جدًا (طبية، قانونية، شرعية) بدون موديل متخصّص — النتائج هتكون مضلِّلة وقد تسبّب ضررًا.
- قواعد بيانات أقل من 500 صف — البحث النصي البدائي شغّال ومش محتاج تعقيد إضافي.
- مطابقة دقيقة 100% (مثلًا التحقق من رقم بطاقة) — Embeddings تقريبية بطبيعتها.
الخطوة التالية
افتح ترمنال جديد، نزّل المكتبة، وجرّب الكود فوق على 5 كلمات أو جمل من تطبيقك. لو الأرقام جاءت معقولة، الخطوة الجاية إنك تخزّن المتجهات في pgvector وتبني عليها بحث دلالي حقيقي. لو محتاج تشغيل سريع بدون تنزيل موديل، استخدم Voyage AI عبر Anthropic أو OpenAI Embeddings API بسطر واحد.