Vector DB — הזיכרון
של RAG וסוכני AI
כל מערכת RAG וכל סוכן עם זיכרון ארוך-טווח נשען על מסד נתונים וקטורי — המקום שבו נשמר "הידע" כווקטורים ונשלף לפי דמיון משמעות. במדריך: איך זה עובד באמת, השוואה בין Pinecone, Qdrant, Weaviate ו-pgvector, ואיך לבחור את הנכון לפרויקט שלך.
מה זה מסד נתונים וקטורי ולמה צריך אותו
מסד נתונים רגיל מחפש התאמה מדויקת: "תן לי את כל הרשומות שבהן city = תל אביב". מסד נתונים וקטורי מחפש דמיון משמעות: "תן לי את המסמכים הכי קרובים במשמעות לשאלה הזו". זה בדיוק מה שצריך ל-RAG ולזיכרון של סוכנים — למצוא ידע רלוונטי גם כשלא נכתב באותן מילים.
הקסם עובד דרך embeddings: מודל הופך כל קטע טקסט לווקטור של מספרים (רשימה של, נניח, 1536 ערכים) שמייצג את המשמעות. טקסטים דומים במשמעות מקבלים ווקטורים קרובים במרחב. ה-vector DB שומר את הווקטורים האלה ויודע לשלוף במהירות את הקרובים ביותר לשאילתה.
איך חיפוש דמיון עובד — בקצרה
התהליך מתחלק לשני שלבים: הזנה (indexing) ו-שליפה (query).
חיפוש הווקטור הכי קרוב באופן מדויק בין מיליון ווקטורים איטי מדי. HNSW (Hierarchical Navigable Small World) בונה גרף שכבתי שמאפשר למצוא את השכנים הקרובים בקירוב במהירות עצומה, עם דיוק של 95%+. כמעט כל vector DB מודרני משתמש בו.
טבלת השוואה — במבט אחד
| מסד | מודל | הכי טוב ל |
|---|---|---|
| Pinecone | מנוהל בלבד | הקמה מהירה בלי DevOps |
| Qdrant | קוד פתוח + ענן | ביצועים ו-self-host |
| Weaviate | קוד פתוח + ענן | Hybrid search ומודולים |
| pgvector | תוסף ל-Postgres | כבר יש לך Postgres |
| Chroma | קוד פתוח, embedded | פרוטוטייפ ולמידה |
הכלים המובילים — למי מתאים כל אחד
- Pinecone — שירות מנוהל לחלוטין. אתה לא מנהל שרת, זה פשוט עובד ומתרחב. המחיר על הנוחות. מצוין להתחלה מהירה ולפרודקשן בלי צוות DevOps. ראה את מדריך Pinecone המלא.
- Qdrant — כתוב ב-Rust, מוביל בביצועים ובמהירות, עם payload filtering עשיר. קוד פתוח ל-self-host או ענן מנוהל. הבחירה של הרבה סוכני AI ב-2026.
- Weaviate — חזק ב-Hybrid Search (וקטורי + מילות מפתח יחד) ובמודולים מובנים ל-embedding. קוד פתוח + ענן.
- pgvector — תוסף ל-PostgreSQL. אם כבר יש לך Postgres — אתה מקבל חיפוש וקטורי בלי להוסיף מערכת חדשה. גם Supabase בנוי על זה. אידיאלי לפרויקטים בינוניים.
- Chroma — קל משקל, רץ embedded בתוך האפליקציה. מושלם לפרוטוטייפ, למידה ופרויקטים קטנים מקומיים.
איך לבחור — עץ החלטה
להרים אחד ולבדוק — עשרים דקות
הדרך היחידה לדעת אם אתה בכלל צריך מסד ייעודי היא להריץ אחד על הנתונים שלך. Qdrant מקומי הוא הדרך המהירה, ואין בו הרשמה או מפתח.
docker run -p 6333:6333 -p 6334:6334 \
-v "$(pwd)/qdrant_storage:/qdrant/storage" \
qdrant/qdrant
# ממשק ניהול: http://localhost:6333/dashboard
ה--v חשוב: בלעדיו הנתונים נעלמים כשהקונטיינר נעצר, וזו הפתעה מיותרת אחרי שהעלית עשרת אלפים מסמכים.
from qdrant_client import QdrantClient, models
qc = QdrantClient(url="http://localhost:6333")
qc.create_collection(
collection_name="docs",
vectors_config=models.VectorParams(
size=1536, distance=models.Distance.COSINE
),
)
qc.upsert(
collection_name="docs",
points=[
models.PointStruct(
id=i,
vector=vec,
payload={"text": txt, "source": src, "lang": "he"},
)
for i, (txt, vec, src) in enumerate(zip(chunks, vectors, sources))
],
)
hits = qc.query_points(
collection_name="docs",
query=question_vector,
limit=5,
score_threshold=0.35, # אל תחזיר זבל
query_filter=models.Filter( # סינון לפני החיפוש, לא אחריו
must=[models.FieldCondition(
key="lang", match=models.MatchValue(value="he"))]
),
).points
שני דברים בקוד הזה ששווה לשים לב אליהם
הסינון קורה לפני החיפוש ולא אחריו. זה ההבדל בין מסד ייעודי לפתרון מאולתר: כשמסננים אחרי, ביקשת חמש תוצאות וקיבלת שתיים ששרדו את הסינון. כשמסננים לפני, אתה מקבל חמש רלוונטיות מתוך הקבוצה הנכונה.
סף הציון הוא חלק מהשאילתה. בלעדיו תמיד יחזרו חמש תוצאות, גם כשאף אחת אינה קשורה — והמודל בשלב הבא ינסה לענות מהן.
מה למדוד בבדיקה הזו
- כמה זיכרון תפס האינדקס בפועל, לעומת החישוב התיאורטי. הדשבורד מציג את זה.
- כמה זמן לקחה ההעלאה — זה השלב שמפתיע, לא החיפוש. ההמרה לווקטורים היא רוב הזמן, לא הכתיבה.
- האם התוצאות נכונות על עשר שאלות אמיתיות. אם לא — חזור לחלוקה לקטעים.
אחרי הבדיקה הזו תדע אם אתה בכלל בסדר גודל שדורש מסד ייעודי, וזו החלטה שעדיף לקבל על סמך מספרים ולא על סמך טבלת השוואה.
הצוואר האמיתי: זיכרון, לא מהירות
כמעט כל מדריך על מסדים וקטוריים משווה מהירות שליפה. בפועל, הדבר שמפיל מערכות בייצור הוא RAM — האינדקס גדל, השרת נגמר, והתהליך נהרג באמצע. זה הסעיף שקובע כמה תשלם בחודש, והוא כמעט לא מכוסה.
למה זה קורה
חיפוש דמיון מהיר דורש שהאינדקס יהיה נגיש מהר, וזה אומר בזיכרון. מיליון ווקטורים של 1536 ממדים ב-float32 הם כשישה ג'יגה-בייט של נתונים גולמיים לפני האינדקס עצמו. הגידול לינארי ובלתי מתפשר: פי עשרה מסמכים, פי עשרה זיכרון.
שתי דרכים להתמודד
קוונטיזציה מקטינה כל ווקטור. במקום 32 סיביות למספר, פחות — והדיוק שנפגע קטן בהרבה ממה שנשמע, כי חיפוש דמיון מחפש שכנים ולא ערכים מדויקים.
מיקום זיכרון קובע מה יושב ב-RAM ומה על הדיסק. לא כל רכיב באוסף נחוץ באותה מידה — אפשר להחזיק את מבני החיפוש בזיכרון ואת הווקטורים המקוריים על הדיסק.
בגרסה 1.19 אפשר להגדיר מיקום זיכרון לכל רכיב בנפרד, בשלוש רמות: cold (לא נטען מראש, נכנס למטמון לפי שימוש — לרכיבים שנשאלים לעתים רחוקות או גדולים מה-RAM), cached (נטען בהפעלה, אך עלול להידחק אם הזיכרון נגמר) ו-pinned (נטען ולא נדחק לעולם — מחייב שהרכיב ייכנס ל-RAM תמיד). בנוסף נוספה קוונטיזציה בשם TurboQuant עם רזולוציות של 4, 2, 1.5 ו-1 סיביות, כשברירת המחדל היא 4 — כלומר פי שמונה קטן מ-float32.
PUT /collections/docs
{
"vectors": { "size": 1536, "distance": "Cosine" },
"quantization_config": {
"turbo": { "bits": "bits4", "memory": "pinned" }
}
}
הצירוף הזה — ווקטורים מקוונטזים ב-pinned ומקוריים על הדיסק — הוא התצורה שמאפשרת להריץ אינדקס גדול על שרת קטן: החיפוש רץ על הגרסה המוקטנת בזיכרון, והמקור נקרא רק כשצריך דיוק מלא.
הדגל always_ram הוצא משימוש ב-1.19 לטובת memory. קונפיגורציה קיימת עדיין נקראת, אבל אם אתה כותב חדשה — השתמש ב-memory. כששניהם מוגדרים, memory גובר.
הגנה מפני קריסה
גם עם קוונטיזציה, אינדקס שממשיך לגדול יגיע לגבול. מנגנון strict mode ב-Qdrant דוחה פעולות כתיבה כשצריכת הזיכרון מתקרבת לתקרה, במקום לתת לתהליך להיהרג באמצע. ההבדל מהותי: כתיבה שנדחתה היא שגיאה שאפשר לטפל בה, ותהליך שנהרג הוא הפסקת שירות.
הכלל המעשי: הגדר את הסף לפני שאתה צריך אותו. אחרי הקריסה הראשונה כבר איבדת זמינות, ולפעמים גם נתונים שהיו באמצע כתיבה.
קוונטיזציה — כמה דיוק באמת מאבדים
זה החלק שגורם לאנשים להסס, ולרוב בלי סיבה. האינטואיציה אומרת שהקטנת ווקטור מ-32 סיביות למספר ל-4 חייבת לפגוע קשה. בפועל היא כמעט לא פוגעת, ומהסיבה הבאה: חיפוש דמיון מחפש שכנים, לא ערכים. אם כל הווקטורים מוקטנים באותו אופן, הסדר היחסי ביניהם נשמר גם כשהערכים המדויקים אינם.
ארבע רמות, ומה כל אחת נותנת
| רזולוציה | הקטנה מול float32 | מתי |
|---|---|---|
| 4 סיביות | פי 8 | ברירת המחדל. איזון טוב לרוב המקרים |
| 2 סיביות | פי 16 | כשהזיכרון הוא האילוץ הדומיננטי |
| 1.5 סיביות | ~פי 21 | מקרי קצה עם אינדקס גדול מאוד |
| סיבית אחת | פי 32 | רק עם שלב דירוג מחדש אחרי |
הדפוס שפותר את הפשרה
אין צורך לבחור בין מהיר לזול לבין מדויק. הדפוס המקובל משתמש בשניהם:
- שלב ראשון — חיפוש על הווקטורים המקוונטזים בזיכרון. מהיר וזול, ומחזיר מועמדים רחב: לא חמישה אלא חמישים.
- שלב שני — דירוג מחדש של החמישים על סמך הווקטורים המקוריים בדיוק מלא, שנקראים מהדיסק רק עבורם.
התוצאה קרובה מאוד לחיפוש בדיוק מלא, בשבריר הזיכרון. זה גם מה שמאפשר להשתמש ברזולוציות הנמוכות באמת — סיבית אחת בלי דירוג מחדש תפגע, ועם דירוג מחדש היא סבירה לגמרי.
איך לבדוק ולא לנחש
אל תקבל את זה על אמונה, ואל תוותר על זה מחשש. הבדיקה לוקחת חצי שעה:
- קח עשרים שאילתות אמיתיות מהמערכת שלך — לא שאלות שהמצאת.
- הרץ אותן על האינדקס ללא קוונטיזציה ושמור את חמש התוצאות הראשונות לכל אחת.
- הפעל קוונטיזציה, הרץ שוב, והשווה: כמה מהתוצאות המקוריות עדיין מופיעות בחמישייה.
אם החפיפה גבוהה — וברזולוציית ברירת המחדל היא בדרך כלל תהיה — קיבלת פי שמונה זיכרון בחינם. אם היא נמוכה, זה בעצמו ממצא: הוא לרוב מצביע על חלוקה לקטעים שמייצרת ווקטורים דומים מדי זה לזה, וזו בעיה שהייתה שם גם בלי קוונטיזציה.
מה קורה כשגדלים
שלוש נקודות שבירה טיפוסיות, לפי סדר הופעתן.
עשרות אלפי ווקטורים
שום דבר לא נשבר. בסדר גודל הזה pgvector על מסד PostgreSQL קיים הוא לרוב הבחירה הנכונה — אין תשתית נוספת לתחזק, והנתונים יושבים לצד שאר המידע. מי שמתחיל עם מסד ייעודי בשלב הזה מוסיף מורכבות בלי לקנות שום דבר.
מאות אלפים עד מיליונים
כאן הזיכרון מתחיל להכאיב וקוונטיזציה הופכת נחוצה. זו גם הנקודה שבה מסד ייעודי מצדיק את עצמו, כי מנגנוני הניהול שתוארו למעלה פשוט לא קיימים במסד יחסי.
עשרות מיליונים ומעלה
מכאן זו בעיית תשתית ולא בעיית בחירת כלי: חלוקה לשרתים, שכפול, וניהול עדכונים בלי להפיל את השירות. בסדר גודל הזה שווה לשקול שירות מנוהל, כי עלות התחזוקה עולה על ההפרש במחיר.
מספר הקטעים כפול ממדי הווקטור כפול 4 בתים = הנתונים הגולמיים. הכפל בערך פי 1.5 לאינדקס עצמו. אם המספר קטן מהזיכרון של שרת שאתה כבר מפעיל — אתה לא צריך מסד ייעודי עדיין.
עברית ותוכן רב-לשוני
הנקודה שחסרה בכל מדריך באנגלית, והיא משנה תוצאות בפועל.
אל תערבב שפות באינדקס אחד בלי סיבה. מסמך עברי ומסמך אנגלי על אותו נושא לא בהכרח יימצאו קרובים זה לזה, גם עם מודל רב-לשוני. אם יש לך תוכן בשתי שפות, שקול שני אוספים נפרדים וניתוב לפי שפת השאילתה — זה פשוט יותר מלנסות לגרום למודל לגשר.
מונחים טכניים באנגלית בתוך טקסט עברי הם המקרה הנפוץ אצל קהל ישראלי, והם דווקא עוזרים: הם עוגנים יציבים שהמודל מזהה היטב בשתי השפות. אל תתרגם אותם באינדוקס.
בדוק בפועל ולא בהנחה. קח חמש שאלות אמיתיות והרץ חיפוש. אם התוצאה הראשונה אינה המסמך הנכון, הסיבה כמעט תמיד היא חלוקה לקטעים ולא המודל — קטע ארוך מדי שמכיל שלושה נושאים יימצא לכולם ולא יהיה טוב לאף אחד.
מנוהל או בעצמך
זו ההחלטה שקובעת עלות לאורך זמן יותר מבחירת המסד עצמו, והיא לא באמת שאלה טכנית.
מנוהל מצדיק את עצמו כאשר
- אין מי שיתחזק. מסד וקטורי בייצור דורש גיבויים, עדכוני גרסה וניטור זיכרון. אם אין לזה בעלים בשם, השירות המנוהל זול יותר מהתקלה הראשונה.
- העומס אינו צפוי. שירות שמתרחב לבד חוסך את התכנון מראש, ואת השעה שבה מגלים שהשרת קטן מדי.
- אתה עוד לא יודע מה הגודל הסופי. בשלב שבו מודדים, גמישות שווה יותר מהפרש המחיר.
הרצה עצמית מצדיקה את עצמה כאשר
- המידע לא אמור לצאת מהשרת שלך. מידע רפואי, פיננסי, או פרטי לקוחות תחת דרישת רגולציה. זה השיקול היחיד שמכריע לבדו.
- הנפח יציב וגדול. בסדר גודל קבוע, VPS עולה שבריר ממחיר שירות מנוהל באותו גודל.
- אתה כבר מפעיל תשתית. אם יש לך Docker וניטור, מסד נוסף הוא תוספת שולית ולא פרויקט.
רוב השירותים המנוהלים מציעים אזורים באירופה או בארה"ב, ולא בישראל. לרוב השימושים ההשהיה זניחה — עשרות אלפיות שנייה — אבל אם יש דרישה שהמידע יישאר בגבולות המדינה, זה מוביל להרצה עצמית ולא לבחירת ספק אחר. שווה לברר את הדרישה לפני שבונים, לא אחרי.
ומה שכדאי לעשות בכל מקרה: שמור את הטקסטים המקוריים ואת הצינור שמייצר את הווקטורים אצלך. האינדקס עצמו ניתן לבנייה מחדש בכל רגע מהמקורות, וזה מה שהופך את המעבר בין ספקים לעניין של שעות ולא של פרויקט. מי שמחזיק רק את הווקטורים נעול, כי הם חסרי משמעות מחוץ למודל שייצר אותם.
שאלות שחוזרות
אפשר להסתדר בלי מסד וקטורי בכלל?
לגמרי, ובהרבה יותר מקרים ממה שנדמה. עד כמה אלפי קטעים, חישוב דמיון ישירות ב-numpy על מערך בזיכרון עובד מצוין ולוקח עשר שורות. מה שמסד ייעודי מוסיף הוא התמדה, סינון לפני חיפוש, עדכון אינקרמנטלי וניהול זיכרון — וכל אלה מתחילים להיות נחוצים בסדר גודל, לא בהתחלה.
כמה עולה לתחזק כזה?
בהרצה עצמית, העלות היא השרת: אינדקס של מאות אלפי ווקטורים מקוונטזים רץ בנוחות על VPS צנוע. שירותים מנוהלים מתחילים ממסלול חינמי שמספיק לפיתוח, והמחיר עולה לפי נפח ולפי זמינות. העלות שקל לשכוח היא דווקא ההמרה לווקטורים — אינדוקס מחדש של מאגר גדול הוא הוצאה חד-פעמית שמצטברת אם עושים אותה שוב ושוב בזמן פיתוח. שמור את הווקטורים בזמן שאתה מנסה דברים.
מתי צריך לבנות את האינדקס מחדש?
בשלושה מקרים: החלפת מודל embedding, שינוי אסטרטגיית החלוקה לקטעים, ושינוי מדד המרחק. בכל השאר — הוספה, מחיקה ועדכון של מסמכים — האינדקס מתעדכן במקום. זו הסיבה שכדאי לשמור את הטקסטים המקוריים בצד: בנייה מחדש היא פעולה שתעשה, ואם המקורות אינם אצלך היא הופכת לפרויקט.
מה ההבדל בין זה לבין חיפוש רגיל באתר?
חיפוש רגיל מוצא מילים, וקטורי מוצא משמעות — וכל אחד טוב במה שהשני גרוע בו. חיפוש מילולי מנצח במספרי דגם, בשמות ובקודים, שדווקא בהם החיפוש הסמנטי מפספס. הפתרון המקובל למערכות רציניות אינו לבחור אלא לשלב את השניים ולמזג את התוצאות.
טעויות שחוזרות
- מודל embedding שונה בכתיבה ובחיפוש. התקלה הכי קשה לאבחון כאן, כי המערכת לא שוגה — היא מחזירה תוצאות שנראות סבירות ואינן. אם התוצאות "מוזרות בלי סיבה", זה הדבר הראשון לבדוק.
- לא לשמור את הטקסט המקורי. בלי
metadataעם הטקסט, קיבלת ציון דמיון ואין לך מה להזין למודל בשלב הבא. - קטעים לפי מספר תווים בלבד. חיתוך שמנתק משפט באמצע פוגע בשליפה יותר מכל בחירת מסד. חתוך על גבול פסקה.
- בלי סף רלוונטיות. חיפוש תמיד מחזיר את הקרובים ביותר — גם כשאף אחד מהם אינו רלוונטי. בלי סף, המערכת תענה על כל שאלה, כולל כאלה שאין עליהן תשובה.
- לבחור מסד לפני שיש נתונים. ההשוואות מבוססות על מיליוני ווקטורים. עם עשרת אלפים, כל הכלים ברשימה עובדים היטב וההבדל ביניהם תיאורטי.
פרטי Qdrant 1.19 אומתו מול קוד המקור של הגרסה, לא מול סיכום.
טיפים לאיכות שליפה
- Chunking נכון — קטעים לא גדולים מדי (מאבדים דיוק) ולא קטנים מדי (מאבדים הקשר). התחל מ-300–800 טוקנים עם overlap קטן, וכוונן לפי התוצאות.
- Metadata filtering — שמור metadata (מקור, תאריך, קטגוריה) וסנן לפיו לפני החיפוש הווקטורי. מצמצם רעש ומשפר רלוונטיות דרמטית.
- Hybrid Search — שילוב חיפוש וקטורי עם חיפוש מילות מפתח (BM25) תופס גם מונחים מדויקים וגם משמעות. Weaviate ו-Qdrant תומכים בזה מובנה.
- Reranking — אחרי שליפה ראשונית, מדרג מחדש את התוצאות עם מודל reranker (Cohere, Jina) לדיוק גבוה יותר בטופ.
- אותו מודל embedding — הקפד להשתמש באותו מודל להזנה ולשליפה. ערבוב מודלים = תוצאות אקראיות.
איכות RAG נקבעת הרבה יותר על ידי chunking, בחירת מודל ה-embedding ו-reranking — פחות על ידי איזה vector DB בחרת. כמעט כל הכלים משתמשים באותו HNSW ונותנים תוצאות דומות. תתחיל פשוט (pgvector/Chroma), ושדרג רק כשקנה המידה מחייב. ראה את מדריך ה-RAG המלא.