דלג לתוכן הראשי
מעודכן ליולי 2026 14 דקות קריאה מתקדם

RAG מתקדם
— מ"בערך" למדויק

RAG בסיסי (embed → חפש → הדבק) עובד בהדגמה ונכשל בפרודקשן: מחזיר קטעים לא רלוונטיים, מפספס תשובות קיימות, וגורם להזיות. במדריך: chunking חכם, hybrid search, reranking, metadata filtering ו-GraphRAG — הטכניקות שהופכות אחזור "בערך" למערכת מדויקת שאפשר לסמוך עליה.

Hybrid
מילים + משמעות
Rerank
דיוק אחרי אחזור
GraphRAG
קשרים בין ישויות

למה RAG בסיסי נכשל בפרודקשן

הזרימה הבסיסית מוכרת: מפצלים מסמכים לקטעים, ממירים לווקטורים, שומרים, ובזמן שאלה שולפים את הדומים ומדביקים לפרומפט. זה עובד — עד שהדאטה אמיתי.

שלוש בעיות שוברות אותה, וכל טכניקה בדף הזה מטפלת באחת מהן:

אבל לפני שניגשים לטכניקות, יש שלב אחד שמדלגים עליו כמעט תמיד — והוא זה שקובע אם מה שתעשו אחריו יעזור.

אי אפשר לשפר מה שאי אפשר לייחס

"ה-RAG לא מדויק" אינו אבחנה. זו תוצאה של שרשרת בת ארבעה שלבים, וכל אחד מהם נכשל אחרת ודורש תיקון אחר. הטעות היקרה ביותר בתחום היא להתחיל להחליף טכניקות לפני שיודעים איזה שלב נכשל.

סדר הבדיקה, מהזול לנדיר — וברוב המקרים זה נגמר בשניים הראשונים:

  1. האם הקטע הנכון קיים במאגר בכלל? חפשו אותו בטקסט חופשי, לא דרך הווקטורים. לעתים קרובות מתברר שהוא מעולם לא נכנס — קובץ שנכשל בעיבוד, PDF סרוק, מסמך שלא הועלה. שום דירוג מחדש לא ימצא מה שאין.
  2. איך הוא נראה אחרי החלוקה? הדפיסו את הקטע כפי שנשמר. כאן מתגלים חיתוכים באמצע משפט וטבלאות שהפכו לרצף מספרים.
  3. באיזה מקום הוא דורג? לא בחמישייה — בעשירייה? בעשרים? "לא נמצא כלל" ו"נמצא במקום השביעי" הן שתי בעיות שונות לגמרי שנראות זהות מבחוץ, ורק לשנייה יש פתרון זול.
  4. ואם הוא היה בהקשר והתשובה עדיין שגויה — רק אז זו בעיית ניסוח, וזה השלב האחרון שכדאי לחשוד בו.

המכשיר שמאפשר את כל זה הוא קטן: עשרים עד חמישים שאלות אמיתיות, ולצד כל אחת הקטע שאמור לענות עליה. זה לוקח שעתיים לבנות, הוא לא דורש לשפוט תשובות אלא רק לבדוק אם הקטע נשלף, והוא הופך כל שינוי בהמשך הדף הזה ממשהו שמרגיש נכון למשהו שאפשר למדוד.

שני מדדים שמספיקים

כמה מהשאלות הקטע הנכון הופיע בחמש הראשונות, ובאיזה מקום ממוצע. הראשון אומר אם המערכת עובדת; השני אומר אם הבעיה בשליפה או בדירוג.

חלוקה: התקרה של כל המערכת

איכות החלוקה קובעת את תקרת האיכות של כל מה שמעליה. קטע טוב הוא יחידת מידע שאפשר להבין בפני עצמה — כי זה בדיוק מה שהמודל יקבל, בלי מה שהיה לפניה ואחריה.

ובעברית יש כאן מלכודת שקטה: ספירת תווים מטעה. אותו מספר תווים בעברית ובאנגלית אינו אותו מספר טוקנים, כך שחלוקה לפי תווים מייצרת קטעים לא אחידים בלי שמישהו יבחין. חלקו לפי מבנה, ובדקו את הגודל בטוקנים.

מה שמסמכים אמיתיים עושים לחלוקה

אלגוריתם החלוקה נראה פשוט עד שפוגשים את המסמכים שבאמת נמצאים בארגון. ארבעה מקרים שמפילים חלוקה נאיבית, וכולם שכיחים:

והכלל שמסכם: איכות המאגר נקבעת בשלב ההכנה, לפני שנגעתם באלגוריתם. שעה של סידור מסמכים שווה יותר משבוע של כוונון פרמטרים.

חיפוש משולב — ההחזר הגבוה ביותר למאמץ

אם עושים דבר אחד מהדף הזה, זה הדבר. חיפוש וקטורי וחיפוש מילולי נכשלים במקומות הפוכים, ושילובם מכסה את שניהם.

הווקטורי תופס משמעות ופרפרזה — "איך מבטלים מנוי" מוצא גם "הפסקת שירות" — ונחלש על מזהים. המילולי עושה בדיוק ההפך: מק״טים, קודי שגיאה, שמות מוצר ומספרי גרסה. מריצים את שניהם, ממזגים את הדירוגים, ומעבירים את המועמדים הלאה.

ובעברית זה חשוב פעמיים, משתי סיבות מנוגדות:

כלומר: בעברית השילוב שווה יותר, ודורש קצת יותר עבודה כדי לעבוד.

דירוג מחדש — שלב הדיוק

השליפה מהירה וגסה; הדירוג מחדש איטי ומדויק. הדפוס הוא לשלוף רחב ולהעביר צר: עשרים עד חמישים מועמדים מהשליפה — שם עדיף לטעות לכיוון של יותר, כי מה שלא נשלף אבוד — ואז מודל דירוג שקורא כל מועמד מול השאלה ומעביר שלושה עד חמישה.

למה זה עובד: חיפוש וקטורי מודד דמיון, והשאלה שאתם באמת שואלים היא רלוונטיות. "המוצר כולל אחריות" ו"המוצר אינו כולל אחריות" הם שכנים קרובים מאוד במרחב — אותו נושא, אותן מילים — ורק אחד מהם עונה. מודל דירוג רואה את השאלה ואת הקטע יחד ויכול להבחין.

המחיר הוא השהיה ועלות, והוא אמיתי. שתי דרכים להקטין אותו: לדרג רק כשמספר המועמדים גדול, ולשמור תוצאות לשאלות חוזרות — שבמערכת שירות חוזרות הרבה יותר משנדמה.

איך זה נראה בקוד

הפייפליין כולו, בצורתו המינימלית — כדי שיהיה ברור שאין כאן קסם ושכל שלב ניתן למדידה בנפרד:

def answer(question, user):
    # 1. סינון בשאילתה עצמה, לא אחריה
    scope = {"tenant": user.tenant_id}

    # 2. שתי שליפות, רחב
    vec  = vector_search(embed(question), scope, k=30)
    lex  = keyword_search(question, scope, k=30)
    cands = merge_ranks(vec, lex)          # מיזוג דירוגים

    # 3. דירוג מחדש, צר
    top = rerank(question, cands)[:4]
    if not top:
        return {"found": False}

    # 4. ניסוח, עם דרישת ציטוט
    out = call_model(
        system=GROUNDED_PROMPT,   # "ענה רק מהמקורות; אם אין — אמור שאין"
        context=top,
        question=question,
        schema=ANSWER_SCHEMA,     # answer, source_quote, source_id, found
    )

    # 5. בדיקה מכנית: הציטוט באמת מופיע במקור?
    if out["found"] and out["source_quote"] not in joined(top):
        out["needs_review"] = True

    log(question=question, retrieved=[c.id for c in cands[:10]],
        sent=[c.id for c in top], output=out)   # 6
    return out

שלושה פרטים נושאים כאן את רוב המשקל. ה-scope נכנס לשליפה ולא מסנן אחריה. הבדיקה בשלב 5 תופסת תשובה שנשמעת מצוין ומצטטת משהו שלא נאמר — בשורה אחת של קוד, בלי מודל נוסף. והתיעוד מפריד בין מה שנשלף למה שנשלח, וזו בדיוק ההפרדה שמאפשרת לענות מאוחר יותר על השאלה אם הבעיה הייתה בשליפה או בדירוג.

לטפל בשאלה, לא רק במסמכים

כמעט כל המאמץ בתחום מושקע בצד המסמכים, ויש אי-התאמה מובנית בצד השני: השאלה קצרה והקטע ארוך, והם כתובים אחרת. "איך מבטלים?" הוא שלוש מילים בגוף ראשון; הקטע שעונה עליו הוא פסקה רשמית בגוף שלישי.

שלוש טכניקות, לפי סדר העלות:

ובעברית יש כאן תוספת: כתיב חסר ומלא וטעויות הקלדה. "תוכנה" מול "תכנה", "מיליון" מול "מליון". אלה חלק מהקלט האמיתי, והם צריכים להופיע גם במערך הבדיקה — אחרת מודדים מערכת על שאלות מנוסחות יפה יותר ממה שמגיע בפועל.

סינון, הרשאות, וגרף

סינון לפי מטא-נתונים הוא הדרך הזולה ביותר לשפר דיוק: לצמצם את מרחב החיפוש לפני שמחפשים. תאריך, סוג מסמך, מחלקה, לקוח.

ונקודה שהיא לא אופטימיזציה אלא תנאי: סינון הרשאות שייך לשאילתה, לא לשלב שאחריה. מערכת רב-לקוחית שמחפשת בכל המאגר ואז מסננת היא גם איטית וגם דולפת — ותמיד יופיעו בה תשובות ריקות בלי סיבה גלויה, כי חמש התוצאות הטובות שייכות למישהו אחר.

ולגבי GraphRAG — ייצוג הידע כגרף של ישויות וקשרים: הוא פותר סוג שאלות שחיפוש רגיל לא פותר, כאלה שדורשות לחבר מידע ממקומות שאינם דומים זה לזה ("אילו לקוחות שקנו X פנו גם על Y"). הוא גם יקר להקמה ולתחזוקה, ובמאגר שמשתנה הוא דורש עדכון מתמיד. הוא נכנס אחרי שכל השאר עובד ועדיין חסר, לא כשדרוג ראשון.

שלב הניסוח, וההבדל בין תשובה לציטוט

הקטע הנכון הגיע להקשר וזה עדיין לא נגמר. שלושה דברים בשלב הניסוח שמשנים את התוצאה יותר מכל טכניקת שליפה נוספת:

לדרוש ציטוט. לבקש שהתשובה תצרף את המשפט מהמקור שעליו היא נשענת — ואז לבדוק בקוד שהמשפט הזה אכן מופיע בקטע שנשלף. אם לא, התשובה חשודה. זו בדיקה מכנית וזולה שתופסת בדיוק את סוג הטעות שמדדי שליפה לא תופסים.

לאפשר "אין לי מידע". מערכת שחייבת לענות תמיד תמציא כשאין. הרשות לומר שאין תשובה במקורות היא לא ויתור — היא מה שהופך שיעור ה"לא יודע" למדד שימושי: עלייה בו מצביעה על תוכן חסר או על שליפה שנשברה, וזו התרעה מוקדמת שמגיעה בחינם.

לומר מאיפה. תשובה שמפנה למסמך ולסעיף מאפשרת למשתמש לבדוק, ומורידה דרמטית את הנזק מתשובה שגויה. בעסק, זה גם ההבדל בין מערכת שאנשים סומכים עליה לבין מערכת שהם מאמתים ידנית ממילא.

כשהמודל מקבל שני קטעים סותרים

מצב שקורה הרבה יותר ממה שמדברים עליו: השליפה עבדה, שני הקטעים רלוונטיים — והם אומרים דברים הפוכים. מדיניות שהתעדכנה, נוהל שהוחלף, מסמך ישן לצד חדש.

מה שהמודל עושה בלי הנחיה הוא כמעט הגרוע ביותר: הוא בוחר אחד מהם, בדרך כלל את זה שנוסח בביטחון רב יותר, ועונה כאילו אין סתירה. המשתמש מקבל תשובה חד-משמעית ואין לו דרך לדעת שהייתה מחלוקת.

שלושה תיקונים, לפי סדר היעילות:

מאגר שמתעדכן

רוב ההסברים מניחים מאגר סטטי. בפועל מסמכים משתנים ונמחקים, ושלוש תקלות חוזרות:

הפתרון לשלושתם זהה: לקשור כל קטע למזהה המסמך ולעדכן ברמת המסמך — למחוק את כל קטעיו ולהכניס את החדשים כיחידה אחת. ולצד זה, בדיקה תקופתית שסופרת כמה מסמכים קיימים במקור וכמה מיוצגים במאגר; פער בין המספרים הוא ממצא ולא רעש.

ופרט שחוסך הרבה במאגרים גדולים: לשמור גיבוב של הטקסט לצד כל קטע, כדי שעדכון מסמך יטמיע מחדש רק את מה שבאמת השתנה.

בעברית, מה שבאמת שונה

ריכוז של מה שפזור בדף, כי זה החלק שאין לו מקבילה בתיעוד האנגלי ושמפיל מערכות עבריות:

והמבחן שמסכם את כולם, ולוקח חצי שעה: עשרים שאלות אמיתיות בעברית, עשרים קטעים שעונים עליהן, ובדיקה אם המערכת מזווגת נכון. זה שווה יותר מכל השוואת מודלים שתקראו.

מה זה עולה

שתי עלויות שונות באופיין, ונוח לבלבל ביניהן. הטמעת המאגר היא חד-פעמית — משולמת שוב רק בהחלפת מודל או בעדכון תוכן. כל שאילתה משלמת הטמעה של השאלה, ואם יש דירוג מחדש — גם אותו, על כל מועמד.

שלוש נקודות מעשיות: מטמון על שאלות חוזרות — במערכות שירות אותן שאלות חוזרות בלי סוף; לדרג רק כשצריך — לא על כל שאילתה; ולזכור שבעברית ההערכה יוצאת נמוכה מדי, כי אותו תוכן נשבר ליותר טוקנים.

ומעל הכול, המדד שמנהלים לפיו: עלות לשאלה שנענתה נכון. מערכת זולה שעונה לא נכון היא לא זולה.

מה למדוד בייצור

מערך השאלות מודד מול מה שידעתם לשאול בזמן הבנייה. מה שמשתמשים שואלים בפועל זז, ולכן צריך גם אותות מהייצור — ושלושה מהם לא דורשים שום סימון ידני:

ומה שמחבר בין השניים: כל דפוס שמתגלה בייצור חוזר למערך כמקרה בדיקה. זה מה שהופך את המערך למשהו שמשתפר עם הזמן במקום להתיישן — ובפרט, כל תלונה על תשובה שגויה נכנסת אליו לפני שמתקנים, אחרת אין דרך לדעת שהתיקון עבד.

הפייפליין המלא

איך הכול מתחבר, ובאיזה סדר לבנות. כל שלב הוא תוספת, ואין טעם להוסיף אותו לפני שהמדידה מראה שהוא נחוץ:

  1. חלוקה לפי מבנה עם כותרות, חפיפה ומטא-נתונים. זה הבסיס, וזה גם מה שקובע את התקרה.
  2. הטמעה ואחסון, עם שיוך ומזהה מסמך לכל קטע.
  3. סינון לפי הרשאה ומטא-נתונים — בשאילתה עצמה.
  4. חיפוש משולב, וקטורי ומילולי, ומיזוג הדירוגים.
  5. דירוג מחדש של המועמדים לשלושה עד חמישה.
  6. ניסוח עם ציטוט ועם רשות לומר שאין מידע.
  7. תיעוד של מה נשלף, באיזה דירוג, ומה נשלח למודל.

והשלב האחרון אינו האחרון בחשיבות. בלי לדעת מה נשלף ובאיזה סדר, כל תקלה עתידית תהיה חקירה מאפס.

מתי הבעיה אינה RAG

טעויות שחוזרות