تفشل محركات البحث التقليدية المعتمدة على الكلمات المفتاحية في فهم السياق. إذا بحث المستخدم عن "كيفية إصلاح أنبوب مكسور"، فقد تفوت عملية البحث بالكلمات المفتاحية المستندات التي تحتوي على "إصلاح السباكة" أو "حل التسرب". هنا يلمع البحث الدلالي. من خلال تحويل النص إلى تمثيلات متجهات عالية الأبعاد (تضمينات)، يمكننا التقاط المعنى الكامن للمحتوى بدلاً من مجرد مطابقة السلاسل النصية الدقيقة. للمطورين الذين يبنيون أنظمة توليد معزز بالاسترجاع (RAG)، البحث الدلالي ليس مجرد تحسين، بل هو الخطوة الأولى الحاسمة في استرجاع السياق ذي الصلة لنماذج اللغة الكبيرة (LLMs).
كيف يعمل البحث الدلالي
يعمل البحث الدلالي على مبدأ التشابه الجيبية أو مسافة الجداء النقطي بين المتجهات. تتضمن العملية مرحلتين رئيسيتين:
- توليد التضمينات: باستخدام نموذج محول (Transformer) مُدرَّب مسبقاً (مثل Sentence-BERT أو واجهة برمجة تطبيقات تضمين OpenAI)، يتم تحويل مقاطع النص إلى متجهات رقمية. تؤدي المعاني المتشابهة إلى متجهات تكون قريبة من بعضها البعض في الفضاء متعدد الأبعاد.
- استرجاع المتجهات: عند إجراء استعلام، يتم تضمينه أيضاً. ثم يبحث النظام في فهرس المتجهات لإيجاد أقرب $K$ جيران (KNN) لمتجه الاستعلام.
تنفيذ البحث الدلالي باستخدام FAISS
FAISS (بحث Facebook AI عن التشابه) هي مكتبة شائعة للبحث الفعال عن التشابه في المتجهات الكثيفة. أدناه مثال عملي لإعداد خط أنابيب للبحث الدلالي باستخدام Python وFAISS ومحوّلات Hugging Face.
import faiss
import numpy as np
from transformers import AutoTokenizer, AutoModel
def get_sentence_embeddings(sentences, model_name='sentence-transformers/all-MiniLM-L6-v2'):
"""Generate normalized embeddings for a list of sentences."""
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModel.from_pretrained(model_name)
inputs = tokenizer(sentences, padding=True, truncation=True, return_tensors='pt')
with torch.no_grad():
output = model(**inputs)
embeddings = output.last_hidden_state[:, 0, :] # [CLS] token
embeddings = torch.nn.functional.normalize(embeddings, p=2, dim=1)
return embeddings.cpu().numpy()
# 1. Prepare Data
documents = [
"The sky is blue during the day.",
"Python is a popular programming language.",
"Machine learning models require large datasets.",
"The ocean is vast and deep."
]
# 2. Generate Document Embeddings
doc_embeddings = get_sentence_embeddings(documents)
doc_embeddings = np.float32(doc_embeddings)
# 3. Build FAISS Index (Inner Product)
dimension = doc_embeddings.shape[1]
index = faiss.IndexFlatIP(dimension)
index.add(doc_embeddings)
# 4. Perform Search
query = "What is the weather like outside?"
query_embedding = get_sentence_embeddings([query])
query_embedding = np.float32(query_embedding)
# Search for top 2 relevant documents
k = 2
distances, indices = index.search(query_embedding, k)
for i, doc_idx in enumerate(indices[0]):
print(f"Score: {distances[0][i]:.4f} | Doc: {documents[doc_idx]}")
أفضل الممارسات لأنظمة الإنتاج
- استراتيجية التقطيع: قسّم المستندات الكبيرة إلى مقاطع أصغر مكتملة سياقياً (مثلاً، 100-500 رمز) لتحسين دقة التضمين.
- البحث الهجين: اجمع بين البحث الدلالي وBM25 (بحث الكلمات المفتاحية) للحصول على أفضل النتائج من العالمين. يضمن ذلك إمكانية استرجاع الأعلام النادرة أو الأكواد المحددة.
- إعادة الترتيب: استخدم نموذج Cross-encoder لإعادة ترتيب أفضل $N$ مرشحين إعادتهم بحث المتجهات لتحسين الدقة النهائية.
الخلاصة
البحث الدلالي هو الجسر بين البيانات غير المهيكلة وتطبيقات الذكاء الاصطناعي الذكية. من خلال الاستفادة من قواعد بيانات المتجهات ونماذج التضمين القوية، يمكنك تحسين أداء خطوط أنابيب RAG بشكل كبير، مما يضمن أن نماذج اللغة الخاصة بك لديها وصول إلى أكثر السياق ذي صلة ممكن. ابدأ صغيراً مع FAISS، ولكن فكر في التوسع إلى قواعد بيانات متجهات مخصصة مثل Pinecone أو Weaviate أو Milvus مع نمو حجم بياناتك.