חיפוש וקטורי ב-pgvector: היכן נשבר ה-RAG
בעמדת הדגמה, RAG על בסיס מאגר ידע פנימי עונה בשברירי שנייה: כל עוד הקורפוס הוא כמה אלפי מקטעים, pgvector משווה את וקטור השאילתה עם כל אחד מהם ונכנס לזמן תגובה סביר. הגבול מופיע בלי שימו לב.
מעבר מדויק על כל הוקטורים הוא ליניארי ביחס לגודל הקורפוס, ועל מאות אלפי מקטעים החיפוש מתחיל להתחרות על המעבד עם שאר פעולות מסד הנתונים — תחילה גדל הזנב של זמני השהיה, ואחר כך הרקע הכללי.
הסימפטום השני — צריכת זיכרון על חישובי ביניים. כדי להחזיר את ההתאמות העליונות, המסד מחזיק במיון את כל המרחקים, ולא רק את הפסגה הנדרשת; בשאילתות מקבילות זה דוחק החוצה את מטמון העמודים, וזמן התגובה מפסיק להיות צפוי.
די להוסיף סינון לפי מאפיינים — הרשאות גישה, תאריך המסמך, מקור — והתוכנית עשויה לעקוף את האינדקס, גם אם הוא בנוי.
הדרדרות החיפוש עם גדילת הקורפוס לעיתים נדירות מתבטאת כשגיאה מפורשת. לעיתים קרובות זהו פער שקט: היום נכנסו להקשר של המודל מקטעים מסוימים, מחר — אחרים, והתשובות מתנדנדות משאילתה לשאילתה.
אינדוקס וקטורים מסיר את תקרת החישוב, אבל מביא איתו הגדרות משלו — כמה קשרים להחזיק בגרף, כמה מועמדים לסרוק לכל שאילתה — ובערכים שגויים השלמות של התוצאות נחתכת בשקט על ניסוחים נדירים אך חשובים.
מלכודת נפרדת — ערבוב של שני מצבים באינדקס אחד: חלק מהקורפוס מתעדכן בתדירות גבוהה יותר מאשר הגרף נבנה מחדש, ומסמכים טריים נופלים מהחיפוש, אף שהם מונחים בטבלה. לכן האיכות כאן נמדדת לא על שאלה יפה אחת, אלא על סט עם תשובות נכונות ידועות — לפני ואחרי כל שינוי פרמטרים. כיצד זה נסגר בפועל ובאיזה סדר, מנתחים בהמשך.
מה נותן חיפוש RAG: זמנים, דיוק, סירובים
ארבעה אפקטים אנו מתעדים בקבלה, וכל אחד נבדק על הקורפוס שלכם: זמן תגובת החיפוש, שיעור התוצאות הרלוונטיות, מחלקת הסירובים שנעלמה ונפח הבדיקה הידנית של התוצאות. להלן — כיצד זה מתקבל ומה בדיוק נמדד, ולא מוצהר.
מהירות התגובה עם גדילת הקורפוס
בלי אינדקס וקטורי זמן התגובה גדל יחד עם הקורפוס: כל שאילתה מושווית עם כל המקטעים, ולכן בגידול פי עשרה של מסמכים החיפוש מאט באותם שיעורים.
אינדקס HNSW ב-pgvector בונה גרף קשרים בין הוקטורים, והמעבר מתבצע דרכו ולא על פני כל הטבלה — זמן התגובה נשאר כמעט קבוע, כל עוד נפח הקורפוס גדל פי כמה. הדיוק נשלט על ידי פרמטר המעבר: ככל שהוא רחב יותר, כך התוצאה קרובה יותר למעבר מלא, וזו בחירה מודעת ולא הדרדרות נסתרת.
שיעור התוצאות הרלוונטיות ובדיקה ידנית
המדידה השנייה — שיעור השאילתות שבהן המקטע הנדרש נכנס לשורות הראשונות של התוצאות. הוא תלוי באופן שבו המסמכים נחתכים: מקטעים גדולים מטשטשים את המשמעות, קטנים מאבדים הקשר, ולכן את הגודל והחפיפה אנו מתאימים לקורפוס שלכם ומוסיפים סינון לפי מטא-נתונים — תאריך, סוג המסמך, מחלקה.
מחלקת הסירובים «נמצא משהו לא נכון» נעלמת באופן צפוי: לצד החיפוש הוקטורי אנו מציבים חיפוש טקסטואלי מלא ודירוג מחדש, כדי שהתאמות לפי מילות מפתח ולפי משמעות לא יתחרו זו בזו. יחד עם זה יורד נפח הבדיקה הידנית: האנליסט מפסיק לבדוק כל תוצאה ומסתכל רק על אלה שבהן הופעל סף הביטחון הנמוך.
השוואה בין גישות לחיפוש וקטורי ב-pgvector
מנגנון החיפוש קובע כמה מהר גדל מאגר הידע ומתי יידרש מעבר לסטאק אחר. להלן — ארבע סכמות שביניהן בוחרים בפועל בעת פיתוח חיפוש ב-pgvector בתוך PostgreSQL.
| אפשרות | מתי מתאימה | מגבלות |
|---|---|---|
| מעבר מדויק | עד מאות אלפי וקטורים, נדרשת שלמות תוצאות בסיסית | זמן התגובה גדל ליניארית: נקראת כל הטבלה |
| אינדקס מקורב בתוך המסד | מיליוני וקטורים, אובדן של שברירי אחוז בשלמות מותר | נדרשת כוונון פרמטרים ובנייה מחדש תקופתית של האינדקס |
| מאגר וקטורי חיצוני | עשרות מיליוני וקטורים, קו עומס נפרד | מקור נתונים שני, חוסר סנכרון, קו עמידות תקלות משלו |
| סכמה היברידית עם חיפוש טקסטואלי | שאילתות עם מילים, מק"טים, שמות | דירוג מורכב יותר: שתי תוצאות מאוחדות לרשימה אחת |
אינדקס מקורב מול מעבר מדויק
מעבר מדויק מבטיח את הטופ הנכון של התוצאות, אך בנפחים גדולים קורא את כל הטבלה, וזמן התגובה גדל ליניארית. חיפוש מקורב לפי אינדקס עונה פי כמה מהר יותר, אבל עשוי להחמיץ חלק מהוקטורים הקרובים.
את השלמות מכווננים עם פרמטר החיפוש: מרימים אותה לרמה שבה התוצאות חופפות לבסיס הייחוס על סט שאלות המבחן.
מתי מאגר וקטורי חיצוני הוא מיותר
מאגר נפרד מוצדק כאשר הנפח והעומס לא נכנסים לקו אחד של המסד. אם המסמכים והוקטורים מונחים זה לצד זה ומתעדכנים יחד, הוצאתם החוצה מוסיפה תעבורת רשת, סכמת הרשאות שנייה וחוסר סנכרון באינדוקס מחדש.
כל עוד מדובר במיליוני שורות, די באינדקס בתוך המסד, וחיפוש היברידי נבנה בשאילתת חיפוש טקסטואלי מלא רגילה לצד הוקטורי.
שלבי הטמעת חיפוש RAG במוצר
הטמעת חיפוש לפי מסמכים לעיתים נדירות נתקעת בבחירת המסד — היא נתקעת באיכות הנתונים ובצפיות העדכונים. המסלול עובר מניתוח הקורפוס והשאילתות לתכנון האחסון, ורק אחר כך — לכוונון התוצאות.
- ניתוח הקורפוס והשאילתות. פורמטים, נפח, כפילויות, תדירות השינויים ואיך העובדים מנסחים שאלות בפועל.
- סכמת אחסון הוקטורים. ב-pgvector מתכננים טבלאות של מקטעים ומטא-נתונים לסינון לפי הרשאות גישה וגרסאות מסמכים.
- אסטרטגיית חיפוש וחיתוך. גודל וחפיפת המקטעים, שקלול, מצב היברידי עם חיפוש טקסטואלי מלא.
- עדכון האינדקס. אינדוקס מחדש בעת שינוי מסמכים, מחיקת גרסאות מיושנות, בקרה על גדילת האחסון.
- בדיקת איכות. הרצה של סט שאילתות בקרה עם השוואה למקטעי בסיס הייחוס.
- מסירה לתפעול. נהלים, ניטור, הנחיות לצוות התמיכה.
חיתוך מסמכים והכנת וקטורים
גודל המקטע מתאים למבנה הטקסט: תקנות וטבלאות דורשות גישה אחת, טקסט רציף — אחרת. החפיפה שומרת על המשמעות בגבולות, והמטא-נתונים — מסמך, פרק, גרסה, הרשאות — חותכים את המיותר עוד לפני החיפוש עצמו.
בדיקה על סט שאילתות בקרה
אוספים שאלות אמיתיות עם מקטעי בסיס ייחוס ובודקים אם המקור הנדרש נכנס לשורות הראשונות של התוצאות. פערים מנתחים ומתקנים בחיתוך, במשקלים או באסטרטגיית החיפוש.
מה מועבר לידיים: תצורה ונהלים
חבילת המסירה — לא תיקייה עם קוד, אלא ערכה שלפיה צוות הליווי משחזר את החיפוש בלעדינו. להלן — מה בדיוק מתעדים בתיעוד ובתצורה.
סכמת אחסון ופרמטרי האינדקס
- סכמת הטבלאות: חיתוך למקטעים, סוגי שדות, קישורים למקור, מדיניות מחיקה בעת שלילת מסמך.
- תצורת האינדקס הוקטורי ב-pgvector: סוג, מימדיות הוקטורים, פרמטרי בנייה וחיפוש, המעוגנים בקובץ המיגרציה.
- תיאור חיתוך הטקסט: גודל המקטע, חפיפה, כללי טיפול בטבלאות, כותרות וקוד.
- סט שאילתות בסיס ייחוס עם התוצאות הצפויות — לפיהן בודקים שאחרי בניית האינדקס מחדש איכות החיפוש לא ירדה.
נהלי עדכון וגישה
- נוהל עדכון הקורפוס: תדירות וטריגרים לאינדוקס מחדש, סדר טעינת מסמכים חדשים, טיפול בשינויים ובמחיקות.
- מדיניות גישה למסמכים ולמקטעים: סינון ברמת השורות והצמדת הרשאות לפרקים — החיפוש לא מחזיר את מה שלא מגיע לעובד.
- סדר בנייה מחדש של האינדקס: הרצה על עותק, השוואה לשאילתות בסיס ייחוס, נקודת שחזור.
- הנחיות למשמרת התורנית: תקלות טיפוסיות, כיצד להבחין בין בעיית טעינה להדרדרות החיפוש, למי להעביר הלאה.
בנפרד — תיעוד החיפוש: כיצד לנסח שאילתות, כיצד לקרוא מדדי רלוונטיות ואילו תיקונים בקורפוס דורשים תיאום עם בעל הנתונים.
מקרה בוחן: חיפוש במאגר ידע ב-pgvector
המשימה הגיעה מצוות התמיכה: מאגר ידע של כמה אלפי מסמכים — תקנות, הנחיות, ניתוחי אירועים — גדל מהר יותר מאשר הספיקו לתאר אותו, וחיפוש לפי מילות מפתח מצא עמוד רק בהתאמה מדויקת של הניסוח.
איך זה היה לפני ההטמעה
המומחים חיפשו את התשובה בעיניים לפי תוכן העניינים: לפתוח פרק, לדפדף במסמכים סמוכים, לחזור אחורה. בפניות אמיתיות שאלה אחת ארכה בין שתיים לשלוש דקות, והפרק הנדרש נמצא בערך בארבעה מקרים מתוך עשרה — את השאר סגרו בשאלה לעמית בצ'אט. החיפוש הידני היה דרך העבודה העיקרית, ועובדים חדשים הגיעו למהירות התקנית רק אחרי כמה שבועות.
מה השתנה לאחר כוונון האינדקס
החיפוש הועבר ל-PostgreSQL: pgvector שומר ייצוגים וקטוריים לצד טקסט המסמך, ולכן סינון לפי מחלקה, סוג ותאריך מוחל באותה שאילתה שבה מתבצעת גם ההשוואה לפי קרבה.
את האינדקס כיווננו בשני מעברים — תחילה טענו את הקורפוס ומדדנו את שלמות התוצאות הבסיסית, ואחר כך התאמנו את פרמטרי הרשימות ומספר הסגמנטים לגודל המסד, כדי שהדיוק לא יירד עם גדילתו.
התשובה לשאלה מגיעה כעת תוך 2-4 שניות במקום דקות, הפגיעה בפרק הנדרש עלתה מ-40 ל-85 % על אותו סט שאילתות, והפניות לחיפוש הידני פחתו פי ארבעה. הקורפוס מתעדכן באינדוקס מחדש לילי: תקנה חדשה נכנסת לתוצאות למחרת בלי תיקונים ידניים.
במה pgvector שונה ממסד וקטורי נפרד
pgvector הוא הרחבה של PostgreSQL, שבה הוקטורים מונחים באותה טבלה שבה מונחים הנתונים הרגילים. חיפוש השכנים הקרובים מתבצע בשאילתה אחת יחד עם סינון לפי מטא-נתונים — שוכר, הרשאות גישה, רעננות המסמך; הוקטור ורשומת המסמך הראשי נכנסים לאותה טרנזקציה, וגיבוי נשאר אחד.
מאגר וקטורי נפרד נלקח למשימה אחרת: כאשר אינדקס החיפוש לא נכנס לזיכרון יחד עם נתוני העבודה ונדרש חיפוש על אינדקס מבוזר. הוא נותן השהיה צפויה על אוספים גדולים מאוד, אבל מעביר את המורכבות לאינטגרציה — מופיע מקור אמת שני.
המחיר העיקרי — סנכרון הנתונים והוקטורים. את השורה והוקטור שלה מקשרים במשימת רקע או בזרם שינויים, ובין הכתיבה לאינדוקס נוצר חלון שבו המסמך כבר מעודכן, והחיפוש מחזיר מקטע ישן. בנפרד נפתרים המחיקה — אחרת מצטברים צ'אנקים יתומים — ובנייה מחדש מלאה בעת החלפת מודל ההטמעה.
בהמשך — נקודות כשל: למסד נוספים שירות, ההרשאות שלו, הגיבוי שלו והסכמה שלו. כשל של המסד ממילא היה עוצר את האפליקציה, ועכשיו יכולים להישבר שני קווים בלתי תלויים.
לכן את הבחירה עושים לפי סף הנפח: כל עוד הקורפוס והאינדקס נכנסים לזיכרון הצומת והחיפוש לא מתחרה בשאילתות העבודה, מסד אחד פשוט יותר — גיבוי אחד, טרנזקציה אחת, בלי סנכרון. כדאי להפריד במקום שבו האינדקס מפסיק להיכנס לזיכרון או שהחיפוש מתחיל להפריע לעבודה העיקרית עם הנתונים.
ספקות טכניים: מגבלות והדרדרות
כל עוד הקורפוס הוא עשרות אלפי מקטעים, החיפוש ב-pgvector עונה מהר ובאופן צפוי. על מאות אלפים אותן שאילתות הולכות זמן רב יותר באופן ניכר, והתוצאות על שאלות מנוסחות מחדש מתפצלות: אותה משמעות, שניתנה במילים אחרות, מובילה למסמכים שונים.
זו תוצאה של כך שהאינדקס נבנה על נפח ומבנה נתונים אחרים מאלה שמונחים בטבלה כעת — ובנפרד עומדת שאלת העבודה מעל מערכת שכבר פרוסה.
איך להבין שהאינדקס הגיע זמנו להיבנות מחדש?
סימנים: זמן התגובה גדל במספר שורות שלא השתנה, שיעור התשובות הרלוונטיות בפסגת התוצאות יורד, אחרי טעינות ומחיקות המוניות מופיעה פריפריה של פסולת.
אינדקס שנבנה על קורפוס חלקי מאבד דיוק ככל שטוענים עוד, ולכן בונים אותו מחדש כאשר עיקר המסמכים כבר במקום — בענף נפרד, עם בדיקה על שאלות בקרה והחלפה לאחר מכן.
איך לבודד נתונים של לקוחות שונים במסד אחד?
מפרידים ברמת הסכמה והשורות: מחיצה נפרדת לכל לקוח ועוד סינון חובה לפי המזהה שלו, המוחל לפני שלב הדירוג. מוסיפים מדיניות גישה ברמת השורות ב-PostgreSQL ובקרה בצד השירות שבונה את השאילתה. הבדיקה — בטסט שלילי: שאילתה בשם לקוח אחד לא מוצאת אף מקטע של אחר.
מדוע התוצאות אינן יציבות על ניסוחים דומים?
חיפוש וקטורי מבחין היטב בשאלות קרובות במשמעות כאשר בקורפוס יש הרבה מסמכים מאותו סוג. עוזר שילוב עם חיפוש טקסטואלי מלא, שלב דירוג מחדש, סף חיתוך לפי קרבה ונרמול השאילתה. שמירת תוצאות של ניסוחים נפוצים מסירה חלק מהעומס מהמסד.
האם המסד לא יירד בעבודה מעל מערכת קיימת?
החיפוש קורא נתונים בנפרד מהעומס העיקרי: שאילתות הולכות לרפליקה, ובנייה מחדש כבדה — בחלון תחזוקה. את הסכמה עם הוקטורים מוסיפים בצד, האכלה מתבצעת ברקע, והחיפוש מופעל בהדרגה. שחזור — כיבוי שכבת החיפוש: שאר המערכת ממשיכה לעבוד כמו קודם.
נדון במשימה: מה להכין לשיחה
כדי שההערכה תהיה עניינית ולא «עבור חיפוש וקטורי בכללי», די בכמה נתוני פתיחה לשיחה. חלק נבהיר בהתכתבות, את השאר ננתח בפגישה.
- הגדרת משימת החיפוש: אילו החלטות אדם מקבל לפי התוצאות — מוצא סעיף תקנה מסוים, משווה תנאים או מבקש סינתזה על פני כמה מסמכים בבת אחת. מכך תלוי אם נדרש רק חיפוש ב-pgvector או שכבת יצירה מעליו.
- דוגמאות לשאילתות משתמשים — 10–20 ניסוחים אמיתיים, כולל קצרים, עם שגיאות כתיב ובשתי שפות. לפיהם מכווננים את החיתוך למקטעים ומבינים היכן נדרש בנוסף חיפוש לפי מילות מפתח.
- נפח וסוגי המסמכים: כמה קבצים, אילו פורמטים, כמה מהר גדל הקורפוס. זה קובע את בחירת האינדקס ב-pgvector ואת סדר האינדוקס מחדש בלי לעצור את השירות.
- דרישות לרעננות הנתונים: הפיגור המותר בין פרסום מסמך להופעתו בתוצאות. אם מדובר בדקות, מניחים טעינה זורמת ותור עדכון וקטורים.
- סכמת הגישה למידע: מי רואה אילו מסמכים. את ההרשאות מפרידים בסינון ברמת השורות ב-PostgreSQL, כדי שיוחלו לפני בחירת הוקטורים הקרובים ולא אחריה.
- העומס הנוכחי וההתנהגות בעת תקלה: כמה שאילתות בשנייה בשיא, איזה זמן תגובה מקובל ומה השירות עושה כאשר המסד אינו זמין — מחזיר מטמון או מדווח בכנות על שגיאה.
תארו את המשימה בצורה חופשית — נחזור עם הערכה ותוכנית עבודה לפי שלבים.







