Milvus
Zilliz
  • Home
  • Blog
  • ماذا لو كان بإمكانك معرفة سبب فشل RAG؟ تصحيح أخطاء RAG ثلاثي الأبعاد باستخدام Project_Golem وMilvus

ماذا لو كان بإمكانك معرفة سبب فشل RAG؟ تصحيح أخطاء RAG ثلاثي الأبعاد باستخدام Project_Golem وMilvus

  • Engineering
February 18, 2026
Min Yin

عندما يحدث خطأ في استرداد RAG، عادةً ما تعرف أنه معطل - حيث لا تظهر المستندات ذات الصلة، أو لا تظهر المستندات غير ذات الصلة. لكن معرفة السبب قصة مختلفة. كل ما عليك التعامل معه هو درجات التشابه وقائمة مسطحة من النتائج. لا توجد طريقة لمعرفة كيفية وضع المستندات فعليًا في مساحة المتجه، أو كيفية ارتباط الأجزاء ببعضها البعض، أو مكان وصول استعلامك بالنسبة للمحتوى الذي كان يجب أن يتطابق معه. في الممارسة العملية، هذا يعني أن تصحيح أخطاء RAG هو في الغالب تجربة وخطأ: قم بتعديل استراتيجية التقطيع، وقم بتبديل نموذج التضمين، واضبط أعلى k، وآمل أن تتحسن النتائج.

Project_Golem هي أداة مفتوحة المصدر تجعل الفضاء المتجه مرئيًا. وهي تستخدم UMAP لإسقاط التضمينات عالية الأبعاد في ثلاثية الأبعاد وThree.js لعرضها بشكل تفاعلي في المتصفح. فبدلاً من تخمين سبب فشل الاسترجاع، يمكنك أن ترى كيف تتجمع القطع دلاليًا، وأين يقع استعلامك، والمستندات التي تم استرجاعها - كل ذلك في واجهة مرئية واحدة.

هذا مذهل. ومع ذلك، تم تصميم Project_Golem الأصلي للعروض التوضيحية الصغيرة، وليس لأنظمة العالم الحقيقي. فهو يعتمد على الملفات المسطحة، والبحث بالقوة الغاشمة، وإعادة بناء مجموعة البيانات الكاملة - مما يعني أنه ينهار بسرعة مع نمو بياناتك لأكثر من بضعة آلاف من المستندات.

لسد هذه الفجوة، قمنا بدمج Project_Golem مع Milvus (تحديدًا الإصدار 2.6.8) باعتباره عموده الفقري المتجه. Milvus عبارة عن قاعدة بيانات متجهات مفتوحة المصدر عالية الأداء تتعامل مع الاستيعاب في الوقت الحقيقي، والفهرسة القابلة للتطوير، والاسترجاع على مستوى أجزاء من الثانية، بينما يظل Project_Golem مركزًا على ما يقوم به بشكل أفضل: جعل سلوك استرجاع المتجهات مرئيًا. معًا، يحولان معًا التصور ثلاثي الأبعاد من عرض توضيحي لعبة إلى أداة تصحيح أخطاء عملية لأنظمة RAG للإنتاج.

في هذا المنشور، سنستعرض مشروع_Golem ونوضح كيف قمنا بدمجه مع Milvus لجعل سلوك البحث عن المتجهات قابلًا للرصد وقابلًا للتطوير وجاهزًا للإنتاج.

ما هو Project_Golem؟

يعد تصحيح أخطاء RAG صعبًا لسبب بسيط: مساحات المتجهات عالية الأبعاد، ولا يمكن للبشر رؤيتها.

Project_Golem هو أداة قائمة على المتصفح تتيح لك رؤية الفضاء المتجه الذي يعمل فيه نظام RAG الخاص بك. يأخذ التضمينات عالية الأبعاد التي تقود الاسترجاع - عادةً 768 أو 1536 بُعدًا - ويعرضها في مشهد تفاعلي ثلاثي الأبعاد يمكنك استكشافه مباشرةً.

إليك كيفية عمله تحت الغطاء:

  • تقليل الأبعاد باستخدام UMAP. يستخدم Project_Golem برنامج UMAP لضغط المتجهات عالية الأبعاد إلى ثلاثة أبعاد مع الحفاظ على المسافات النسبية بينها. تبقى الأجزاء المتشابهة دلاليًا في الفضاء الأصلي قريبة من بعضها البعض في الإسقاط ثلاثي الأبعاد؛ أما الأجزاء غير المترابطة فتبقى متباعدة.
  • عرض ثلاثي الأبعاد باستخدام Three.js. يظهر كل جزء من المستند كعقدة في مشهد ثلاثي الأبعاد معروض في المتصفح. يمكنك التدوير، والتكبير، واستكشاف المساحة لترى كيف تتجمع مستنداتك - أي الموضوعات التي تتجمع بشكل متقارب وأيها متداخلة، وأين تقع الحدود.
  • تمييز وقت الاستعلام. عند تشغيل استعلام، لا يزال الاسترجاع يحدث في الفضاء الأصلي عالي الأبعاد باستخدام تشابه جيب التمام. ولكن بمجرد ظهور النتائج، تضيء الأجزاء المسترجعة في العرض ثلاثي الأبعاد. يمكنك أن ترى على الفور أين وصل استعلامك بالنسبة للنتائج - وبنفس القدر من الأهمية، بالنسبة للمستندات التي لم يتم استرجاعها.

هذا ما يجعل Project_Golem مفيدًا لتصحيح الأخطاء. فبدلاً من التحديق في قائمة نتائج مرتبة وتخمين سبب عدم العثور على مستند ذي صلة، يمكنك معرفة ما إذا كان المستند موجودًا في مجموعة بعيدة (مشكلة تضمين)، أو متداخلًا مع محتوى غير ذي صلة (مشكلة في التقطيع)، أو بالكاد خارج عتبة الاسترجاع (مشكلة في التكوين). تقوم طريقة العرض ثلاثية الأبعاد بتحويل درجات التشابه المجردة إلى علاقات مكانية يمكنك التفكير فيها.

لماذا Project_Golem ليس جاهزًا للإنتاج

تم تصميم Project_Golem كنموذج أولي للتصور، وهو يعمل بشكل جيد لذلك. لكن بنيته تضع افتراضات تنهار بسرعة على نطاق واسع - بطرق مهمة إذا كنت تريد استخدامه لتصحيح أخطاء RAG في العالم الحقيقي.

كل تحديث يتطلب إعادة بناء كاملة

هذا هو القيد الأساسي. في التصميم الأصلي، تؤدي إضافة مستندات جديدة في التصميم الأصلي إلى إعادة بناء خط أنابيب كامل: يتم إعادة إنشاء التضمينات وكتابتها إلى ملفات .npy، ويتم إعادة تشغيل UMAP عبر مجموعة البيانات بأكملها، ويتم إعادة تصدير الإحداثيات ثلاثية الأبعاد على هيئة JSON.

حتى عند 100,000 مستند، يستغرق تشغيل UMAP أحادي النواة من 5 إلى 10 دقائق. في نطاق المليون مستند، يصبح الأمر غير عملي تمامًا. لا يمكنك استخدام هذا الأمر مع أي مجموعة بيانات تتغير بشكل مستمر - مثل موجز الأخبار، والوثائق، ومحادثات المستخدمين - لأن كل تحديث يعني انتظار دورة إعادة معالجة كاملة.

البحث بالقوة الغاشمة لا يتسع نطاقه

جانب الاسترجاع له سقفه الخاص. يستخدم التطبيق الأصلي NumPy للبحث عن تشابه جيب التمام بالقوة الغاشمة - تعقيد زمني خطي، بدون فهرسة. في مجموعة بيانات من مليون مستند، يمكن أن يستغرق استعلام واحد أكثر من ثانية. وهذا غير قابل للاستخدام في أي نظام تفاعلي أو عبر الإنترنت.

ضغط الذاكرة يضاعف المشكلة. يستغرق كل متجه عائم 32 ذو 768 بُعدًا حوالي 3 كيلوبايت، لذا فإن مجموعة بيانات بمليون متجه تتطلب أكثر من 3 غيغابايت في الذاكرة - وكلها محملة في مصفوفة NumPy مسطحة بدون بنية فهرسة لجعل البحث فعالاً.

لا يوجد تصفية للبيانات الوصفية ولا تعدد في الإيجار

في نظام RAG الحقيقي، نادرًا ما يكون تشابه المتجهات هو معيار الاسترجاع الوحيد. تحتاج دائمًا تقريبًا إلى التصفية حسب البيانات الوصفية، مثل نوع المستند أو الطوابع الزمنية أو أذونات المستخدم أو الحدود على مستوى التطبيق. يحتاج نظام RAG الخاص بدعم العملاء، على سبيل المثال، إلى تحديد نطاق الاسترجاع لمستندات مستأجر معين - وليس البحث عبر بيانات الجميع.

لا يدعم Project_Golem أيًا من هذا. لا توجد فهارس ANN (مثل HNSW أو IVF)، ولا توجد فهرسة قياسية، ولا عزل للمستأجر، ولا بحث هجين. إنها طبقة تصور بدون محرك استرجاع إنتاج تحتها.

كيف يعمل ميلفوس على تشغيل طبقة الاسترجاع الخاصة بمشروع_غوليم

حدد القسم السابق ثلاث ثغرات: عمليات إعادة البناء الكاملة عند كل تحديث، والبحث بالقوة الغاشمة، وعدم وجود استرجاع مدرك للبيانات الوصفية. تنبع الثغرات الثلاث من نفس السبب الجذري - لا يحتوي Project_Golem على طبقة قاعدة بيانات. الاسترجاع والتخزين والتصور متشابكة في خط أنابيب واحد، لذا فإن تغيير أي جزء يفرض إعادة بناء كل شيء.

لا يكمن الإصلاح في تحسين خط الأنابيب هذا. بل تقسيمه.

من خلال دمج Milvus 2.6.8 كعمود فقري للمتجه، يصبح الاسترجاع طبقة مخصصة على مستوى الإنتاج تعمل بشكل مستقل عن التصور. يتعامل Milvus مع تخزين المتجهات والفهرسة والبحث. يركز Project_Golem_Golem على العرض فقط - حيث يستهلك معرّفات المستندات من Milvus ويبرزها في العرض ثلاثي الأبعاد.

ينتج عن هذا الفصل تدفقان نظيفان ومستقلان:

تدفق الاسترجاع (عبر الإنترنت، على مستوى الميلي ثانية)

  • يتم تحويل استعلامك إلى متجه باستخدام تضمينات OpenAI.
  • يتم إرسال متجه الاستعلام إلى مجموعة Milvus.
  • يقوم Milvus AUTOINDEX بتحديد الفهرس المناسب وتحسينه.
  • يقوم البحث في الوقت الفعلي عن تشابه جيب التمام بإرجاع معرّفات المستندات ذات الصلة.

تدفق التصور (دون اتصال، على نطاق تجريبي)

  • ينشئ UMAP إحداثيات ثلاثية الأبعاد أثناء استيعاب البيانات (n_neighbors=30، min_dist=0.1).
  • يتم تخزين الإحداثيات في golem_cortex.json.
  • تبرز الواجهة الأمامية العقد ثلاثية الأبعاد المقابلة باستخدام معرّفات المستندات التي أرجعها Milvus.

النقطة المهمة: لم يعد الاسترجاع ينتظر التصور. يمكنك استيعاب المستندات الجديدة والبحث عنها على الفور - حيث يمكن للواجهة الأمامية ثلاثية الأبعاد اللحاق بالجدول الزمني الخاص بها.

ما الذي تغيره عقد البث

هذا الاستيعاب في الوقت الحقيقي مدعوم بإمكانية جديدة في الإصدار 2.6.8 من ميلفوس: عقد البث. في الإصدارات السابقة، كان الاستيعاب في الوقت الحقيقي يتطلب قائمة انتظار رسائل خارجية مثل Kafka أو Pulsar. تنقل عُقد التدفق هذا التنسيق إلى ميلفوس نفسها - حيث يتم استيعاب المتجهات الجديدة بشكل مستمر، ويتم تحديث الفهارس بشكل تدريجي، وتصبح المستندات المضافة حديثًا قابلة للبحث على الفور دون إعادة بناء كاملة ودون أي تبعيات خارجية.

بالنسبة إلى Project_Golem، هذا ما يجعل البنية عملية. يمكنك الاستمرار في إضافة المستندات إلى نظام RAG الخاص بك - مقالات جديدة ومستندات محدثة ومحتوى من إنشاء المستخدم - ويظل الاسترجاع محدثًا دون تشغيل دورة إعادة التحميل المكلفة UMAP → JSON → إعادة التحميل.

توسيع نطاق التصور إلى نطاق المليون (المسار المستقبلي)

من خلال هذا الإعداد المدعوم من Milvus، يدعم Project_Golem حاليًا العروض التفاعلية بحوالي 10000 مستند. يتسع نطاق الاسترجاع إلى ما هو أبعد من ذلك بكثير - حيث يتعامل Milvus مع الملايين - لكن لا يزال خط أنابيب التصور يعتمد على تشغيل UMAP على دفعات. لسد هذه الفجوة، يمكن توسيع البنية مع خط أنابيب التصور التدريجي:

  • مشغلات التحديث: يستمع النظام إلى أحداث الإدراج في مجموعة ميلفوس. وبمجرد أن تصل المستندات المضافة حديثًا إلى عتبة محددة (على سبيل المثال، 1000 عنصر)، يتم تشغيل تحديث تزايدي.

  • الإسقاط التزايدي: بدلًا من إعادة تشغيل UMAP عبر مجموعة البيانات الكاملة، يتم إسقاط المتجهات الجديدة في الفضاء ثلاثي الأبعاد الحالي باستخدام طريقة التحويل () الخاصة ب UMAP. يحافظ هذا على البنية العامة مع تقليل تكلفة الحساب بشكل كبير.

  • مزامنة الواجهة الأمامية: يتم دفق أجزاء الإحداثيات المحدّثة إلى الواجهة الأمامية عبر WebSocket، مما يسمح للعقد الجديدة بالظهور ديناميكيًا دون إعادة تحميل المشهد بأكمله.

بالإضافة إلى قابلية التوسع، يتيح Milvus 2.6.8 إمكانية البحث الهجين من خلال الجمع بين تشابه المتجهات والبحث في النص الكامل والتصفية القياسية. وهذا يفتح الباب أمام تفاعلات ثلاثية الأبعاد أكثر ثراءً - مثل تمييز الكلمات الرئيسية، وتصفية الفئات، والتقطيع المستند إلى الوقت - مما يمنح المطورين طرقًا أكثر قوة لاستكشاف سلوك RAG وتصحيحه والاستدلال عليه.

كيفية نشر واستكشاف Project_Golem_Golem مع Milvus

أصبح Project_Golem_Golem الذي تمت ترقيته الآن مفتوح المصدر على GitHub. باستخدام وثائق Milvus الرسمية كمجموعة البيانات الخاصة بنا، نسير خلال العملية الكاملة لتصور استرجاع RAG بشكل ثلاثي الأبعاد. يستخدم الإعداد Docker و Python وهو سهل المتابعة، حتى لو كنت تبدأ من الصفر.

المتطلبات الأساسية

  • دوكر ≥ 20.10
  • إرساء Docker Compose ≥ 2.0
  • بايثون ≥ 3.11
  • مفتاح OpenAI API
  • مجموعة بيانات (وثائق ميلفوس بتنسيق Markdown)

1. نشر ميلفوس

Download docker-compose.yml
wget https://github.com/milvus-io/milvus/releases/download/v2.6.8/milvus-standalone-docker-compose.yml -O docker-compose.yml
Start Milvus(verify port mapping:19530:19530)
docker-compose up -d
Verify that the services are running
docker ps | grep milvus
You should see three containers:milvus-standalone, milvus-etcd, milvus-minio

2. التنفيذ الأساسي

تكامل ميلفوس (ingest.py)

ملاحظة: يدعم التطبيق ما يصل إلى ثماني فئات مستندات. في حال تجاوز عدد الفئات هذا الحد، يُعاد استخدام الألوان بطريقة دائرية.

from pymilvus import MilvusClient
from pymilvus.milvus_client.index import IndexParams
from openai import OpenAI
from langchain_text_splitters import RecursiveCharacterTextSplitter
import umap
from sklearn.neighbors import NearestNeighbors
import json
import numpy as np
import os
import glob
--- CONFIG ---
MILVUS_URI = "http://localhost:19530"
COLLECTION_NAME = "golem_memories"
JSON_OUTPUT_PATH = "./golem_cortex.json"
Data directory (users place .md files in this folder)
DATA_DIR = "./data"
OpenAI Embedding Config
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
OPENAI_BASE_URL = "https://api.openai.com/v1"  #
OPENAI_EMBEDDING_MODEL = "text-embedding-3-small"
1536 dimensions
EMBEDDING_DIM = 1536
Color mapping: colors are assigned automatically and reused in a round-robin manner
COLORS = [
[0.29, 0.87, 0.50],
Green
[0.22, 0.74, 0.97],
Blue
[0.60, 0.20, 0.80],
Purple
[0.94, 0.94, 0.20],
Gold
[0.98, 0.55, 0.00],
Orange
[0.90, 0.30, 0.40],
Red
[0.40, 0.90, 0.90],
Cyan
[0.95, 0.50, 0.90],
Magenta
]
def get_embeddings(texts):
"""Batch embedding using OpenAI API"""
client = OpenAI(api_key=OPENAI_API_KEY, base_url=OPENAI_BASE_URL)
embeddings = []
batch_size = 100
OpenAI allows multiple texts per request
for i in range(0, len(texts), batch_size):
batch = texts[i:i + batch_size]
response = client.embeddings.create(
model=OPENAI_EMBEDDING_MODEL,
input=batch
)
embeddings.extend([item.embedding for item in response.data])
print(f"   ↳ Embedded {min(i + batch_size, len(texts))}/{len(texts)}...")
return np.array(embeddings)
def load_markdown_files(data_dir):
"""Load all markdown files from the data directory"""
md_files = glob.glob(os.path.join(data_dir, "**/*.md"), recursive=True)
if not md_files:
print(f"   ❌ ERROR: No .md files found in '{data_dir}'")
print(f"   👉 Create a '{data_dir}' folder and put your markdown files there.")
print(f"   👉 Example: {data_dir}/doc1.md, {data_dir}/docs/doc2.md")
return None
docs = []
print(f"\n📚 FOUND {len(md_files)} MARKDOWN FILES:")
for i, file_path in enumerate(md_files):
filename = os.path.basename(file_path)
Categories are derived from the file’s path relative to data_dir
rel_path = os.path.relpath(file_path, data_dir)
category = os.path.dirname(rel_path) if os.path.dirname(rel_path) else "default"
with open(file_path, 'r', encoding='utf-8') as f:
content = f.read()
docs.append({
"title": filename,
"text": content,
"cat": category,
"path": file_path
})
print(f"   {i+1}. [{category}] {filename}")
return docs
def ingest_dense():
print(f"🧠 PROJECT GOLEM - NEURAL MEMORY BUILDER")
print(f"=" * 50)
if not OPENAI_API_KEY:
print("   ❌ ERROR: OPENAI_API_KEY environment variable not set!")
print("   👉 Run: export OPENAI_API_KEY='your-key-here'")
return
print(f"   ↳ Using OpenAI Embedding: {OPENAI_EMBEDDING_MODEL}")
print(f"   ↳ Embedding Dimension: {EMBEDDING_DIM}")
print(f"   ↳ Data Directory: {DATA_DIR}")
1. Load local markdown files
docs = load_markdown_files(DATA_DIR)
if docs is None:
return
2. Split documents into chunks
print(f"\n📦 PROCESSING DOCUMENTS...")
splitter = RecursiveCharacterTextSplitter(chunk_size=800, chunk_overlap=50)
chunks = []
raw_texts = []
colors = []
chunk_titles = []
categories = []
for doc in docs:
doc_chunks = splitter.create_documents([doc['text']])
cat_index = hash(doc['cat']) % len(COLORS)
for i, chunk in enumerate(doc_chunks):
chunks.append({
"text": chunk.page_content,
"title": doc['title'],
"cat": doc['cat']
})
raw_texts.append(chunk.page_content)
colors.append(COLORS[cat_index])
chunk_titles.append(f"{doc['title']} (chunk {i+1})")
categories.append(doc['cat'])
print(f"   ↳ Created {len(chunks)} text chunks from {len(docs)} documents")
3. Generate embeddings
print(f"\n🔮 GENERATING EMBEDDINGS...")
vectors = get_embeddings(raw_texts)
4. 3D Projection (UMAP)
print("\n🎨 CALCULATING 3D MANIFOLD...")
reducer = umap.UMAP(n_components=3, n_neighbors=30, min_dist=0.1, metric='cosine')
embeddings_3d = reducer.fit_transform(vectors)
5. Wiring (KNN)
print("   ↳ Wiring Synapses (finding connections)...")
nbrs = NearestNeighbors(n_neighbors=8, metric='cosine').fit(vectors)
distances, indices = nbrs.kneighbors(vectors)
6. Prepare output data
cortex_data = []
milvus_data = []
for i in range(len(chunks)):
cortex_data.append({
"id": i,
"title": chunk_titles[i],
"cat": categories[i],
"pos": embeddings_3d[i].tolist(),
"col": colors[i],
"nbs": indices[i][1:].tolist()
})
milvus_data.append({
"id": i,
"text": chunks[i]['text'],
"title": chunk_titles[i],
"category": categories[i],
"vector": vectors[i].tolist()
})
with open(JSON_OUTPUT_PATH, 'w') as f:
json.dump(cortex_data, f)
7. Store vectors in Milvus
print("\n💾 STORING IN MILVUS...")
client = MilvusClient(uri=MILVUS_URI)
Drop existing collection if it exists
if client.has_collection(COLLECTION_NAME):
print(f"   ↳ Dropping existing collection '{COLLECTION_NAME}'...")
client.drop_collection(COLLECTION_NAME)
Create new collection
print(f"   ↳ Creating collection '{COLLECTION_NAME}' (dim={EMBEDDING_DIM})...")
client.create_collection(
collection_name=COLLECTION_NAME,
dimension=EMBEDDING_DIM
)
Insert data
print(f"   ↳ Inserting {len(milvus_data)} vectors...")
client.insert(
collection_name=COLLECTION_NAME,
data=milvus_data
)
Create index for faster search
print("   ↳ Creating index...")
index_params = IndexParams()
index_params.add_index(
field_name="vector",
index_type="AUTOINDEX",
metric_type="COSINE"
)
client.create_index(
collection_name=COLLECTION_NAME,
index_params=index_params
)
print(f"\n✅ CORTEX GENERATED SUCCESSFULLY!")
print(f"   📊 {len(chunks)} memory nodes stored in Milvus")
print(f"   📁 Cortex data saved to: {JSON_OUTPUT_PATH}")
print(f"   🚀 Run 'python GolemServer.py' to start the server")
if __name__ == "__main__":
ingest_dense()

تصوّر الواجهة الأمامية (GolemServer.py)

from flask import Flask, request, jsonify, send_from_directory
from openai import OpenAI
from pymilvus import MilvusClient
import json
import os
import sys
--- CONFIG ---
Explicitly set the folder to where this script is located
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
OpenAI Embedding Config
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
OPENAI_BASE_URL = "https://api.openai.com/v1"
OPENAI_EMBEDDING_MODEL = "text-embedding-3-small"
Milvus Config
MILVUS_URI = "http://localhost:19530"
COLLECTION_NAME = "golem_memories"
These match the files generated by ingest.py
JSON_FILE = "golem_cortex.json"
UPDATED: Matches your new repo filename
HTML_FILE = "index.html"
app = Flask(__name__, static_folder=BASE_DIR)
print(f"\n🧠 PROJECT GOLEM SERVER")
print(f"   📂 Serving from: {BASE_DIR}")
--- DIAGNOSTICS ---
Check if files exist before starting
missing_files = []
if not os.path.exists(os.path.join(BASE_DIR, JSON_FILE)):
missing_files.append(JSON_FILE)
if not os.path.exists(os.path.join(BASE_DIR, HTML_FILE)):
missing_files.append(HTML_FILE)
if missing_files:
print(f"   ❌ CRITICAL ERROR: Missing files in this folder:")
for f in missing_files:
print(f"      - {f}")
print("   👉 Did you run 'python ingest.py' successfully?")
sys.exit(1)
else:
print(f"   ✅ Files Verified: Cortex Map found.")
Check API Key
if not OPENAI_API_KEY:
print(f"   ❌ CRITICAL ERROR: OPENAI_API_KEY environment variable not set!")
print("   👉 Run: export OPENAI_API_KEY='your-key-here'")
sys.exit(1)
print(f"   ↳ Using OpenAI Embedding: {OPENAI_EMBEDDING_MODEL}")
print("   ↳ Connecting to Milvus...")
milvus_client = MilvusClient(uri=MILVUS_URI)
Verify collection exists
if not milvus_client.has_collection(COLLECTION_NAME):
print(f"   ❌ CRITICAL ERROR: Collection '{COLLECTION_NAME}' not found in Milvus.")
print("   👉 Did you run 'python ingest.py' successfully?")
sys.exit(1)
Initialize OpenAI client
openai_client = OpenAI(api_key=OPENAI_API_KEY, base_url=OPENAI_BASE_URL)
--- ROUTES ---
@app.route('/')
def root():
Force serve the specific HTML file
return send_from_directory(BASE_DIR, HTML_FILE)
@app.route('/')
def serve_static(filename):
return send_from_directory(BASE_DIR, filename)
@app.route('/query', methods=['POST'])
def query_brain():
data = request.json
text = data.get('query', '')
if not text: return jsonify({"indices": []})
print(f"🔎 Query: {text}")
Get query embedding from OpenAI
response = openai_client.embeddings.create(
model=OPENAI_EMBEDDING_MODEL,
input=text
)
query_vec = response.data[0].embedding
Search in Milvus
results = milvus_client.search(
collection_name=COLLECTION_NAME,
data=[query_vec],
limit=50,
output_fields=["id"]
)
Extract indices and scores
indices = [r['id'] for r in results[0]]
scores = [r['distance'] for r in results[0]]
return jsonify({
"indices": indices,
"scores": scores
})
if __name__ == '__main__':
print("   ✅ SYSTEM ONLINE: http://localhost:8000")
app.run(port=8000)

قم بتنزيل مجموعة البيانات ووضعها في الدليل المحدد

https://github.com/milvus-io/milvus-docs/tree/v2.6.x/site/en

3. بدء المشروع

تحويل تضمينات النص إلى فضاء ثلاثي الأبعاد

python ingest.py

[صورة]

بدء تشغيل خدمة الواجهة الأمامية

python GolemServer.py

4. التصور والتفاعل

بعد أن تتلقى الواجهة الأمامية نتائج الاسترجاع، يتم تحجيم سطوع العقدة بناءً على درجات تشابه جيب التمام، بينما يتم الاحتفاظ بألوان العقدة الأصلية للحفاظ على مجموعات فئات واضحة. يتم رسم خطوط شبه شفافة من نقطة الاستعلام إلى كل عقدة مطابقة، ويتم تحريك الكاميرا وتكبيرها بسلاسة للتركيز على المجموعة المفعلة.

مثال 1: تطابق داخل المجال

استعلام: "ما هي أنواع الفهارس التي يدعمها Milvus؟

سلوك التصور:

  • في الفضاء ثلاثي الأبعاد، تُظهر حوالي 15 عقدة تقريبًا داخل المجموعة الحمراء المسماة INDEXES زيادة ملحوظة في السطوع (حوالي 2-3×).

  • تتضمن العقد المتطابقة أجزاء من مستندات مثل index_types.md و hnsw_index.md و ivf_index.md.

  • يتم عرض خطوط شبه شفافة من متجه الاستعلام إلى كل عقدة مطابقة، وتركز الكاميرا بسلاسة على المجموعة الحمراء.

مثال 2: رفض الاستعلام خارج المجال

استعلام: "كم تبلغ قيمة وجبة كنتاكي فرايد تشيكن؟

سلوك التصور:

  • تحتفظ جميع العقد بألوانها الأصلية، مع تغييرات طفيفة في الحجم فقط (أقل من 1.1×).

  • تتناثر العقد المتطابقة عبر مجموعات متعددة بألوان مختلفة، ولا تظهر أي تركيز دلالي واضح.

  • لا تقوم الكاميرا بتشغيل إجراء التركيز، حيث لم يتم استيفاء عتبة التشابه (0.5).

الخلاصة

لن يحل Project_Golem المقترن بـ Milvus محل خط أنابيب تقييم RAG الحالي الخاص بك - لكنه يضيف شيئًا تفتقر إليه معظم خطوط الأنابيب تمامًا: القدرة على رؤية ما يحدث داخل مساحة المتجه.

باستخدام هذا الإعداد، يمكنك معرفة الفرق بين فشل الاسترجاع الناجم عن التضمين السيئ، والفشل الناجم عن سوء التقطيع، والفشل الناجم عن عتبة ضيقة جدًا. كان هذا النوع من التشخيص يتطلب التخمين والتكرار. الآن يمكنك رؤيته.

يدعم التكامل الحالي التصحيح التفاعلي على نطاق تجريبي (حوالي 10000 مستند)، مع قاعدة بيانات Milvus المتجهة التي تتعامل مع الاسترجاع على مستوى الإنتاج خلف الكواليس. تم تخطيط المسار إلى التصور على نطاق المليون ولكن لم يتم بناؤه بعد - مما يجعل هذا هو الوقت المناسب للمشاركة.

تحقق من Project_Golem على GitHub، وجربه مع مجموعة البيانات الخاصة بك، وشاهد كيف يبدو الفضاء المتجه الخاص بك بالفعل.

إذا كانت لديك أسئلة أو ترغب في مشاركة ما تجده، انضم إلى قناة Slack الخاصة بنا، أو احجز جلسة ساعات عمل Milvus للحصول على إرشادات عملية حول الإعداد الخاص بك.

    Try Managed Milvus for Free

    Zilliz Cloud is hassle-free, powered by Milvus and 10x faster.

    Get Started

    Like the article? Spread the word

    استمر في القراءة