חזרה לבלוג

מחמיר או רופף: כוונון של answer prompt עם ציטוט-חובה

מערכת ה-Q&A שלי סירבה לענות על שאלה שהתשובה לה בספר. ה-router עשה את העבודה שלו — הבאג היה כלל אחד ב-answer prompt. Diff של שלוש שורות הזיז את ה-slider.

ai llm prompt-engineering rag-alternative context-engineering pattern gemini

כתבתי בשבוע שעבר על pattern שתי השכבות מאחורי מערכת ה-Q&A שלי על ספר של 640 עמודים: LLM מנתב לפרקים הנכונים, ואז קריאה שנייה מצטטת אותם מילה-במילה עם ציטוטי עמודים. בלי embeddings, בלי chunks. שכבת ה-router קיבלה את רוב תשומת הלב בפוסט ההוא — בניית ה-index, האימות שלו, המחיר של precision על מטא-דאטה עשירה. הפוסט הזה הוא על השכבה שאחריה.

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

כשמערכת LLM מחזירה תוצאה לא צפויה — אבחני באיזו שכבה הבאג לפני שאת מתקנת. הוא יכול להיות בכל מקום: router, prompt, temperature, המקור עצמו.

אימות הסירוב

ביקשתי מ-Claude לעשות grep על ה-markdown הגולמי של הפרקים עבור הקונספט שעליו נשאלה השאלה. אותו קונספט, אוצר מילים שונה: הספר השתמש ב-X כשהשאלה השתמשה ב-Y. Grep מצא את התוכן מיד — בשניים משלושת הפרקים שה-router בחר. הסירוב לא היה נכון. ה-router עשה את העבודה שלו.

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

ה-prompt המקורי

החלק הרלוונטי ב-answer prompt היה:

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

אין לשכתב או לפרפרזות את מילותיה של אילנה. אם אין ציטוט ישיר מתאים — אמרי שאין.

Temperature היה 0.2. השילוב של כלל מחמיר עם temperature נמוך הפך את המודל ללקסיקלית-מילולי. המשתמש/ת שואל/ת על X, הספר מדבר על X תחת שם אחר, המודל רואה שאין ציטוט מדויק שמתאים לניסוח השאלה, והוא מציית לכלל: אומר שאין.

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

ה-slider

Answer prompts במערכות עם ציטוט-חובה יושבים על slider. צד מחמיר: המודל מסרב על פערי אוצר מילים. צד רופף: המודל מגשר בין קונספטים בחופשיות כזו שהוא ממציא טענות שהמקור לא תומך בהן. שני הכשלים נראים בטוחים מבחוץ. המשתמש/ת לא יכול/ה לדעת מתגובה אחת באיזה צד של ה-slider היא/הוא נחת/ה.

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

כוונון ה-slider הוא מציאת הנקודה שבה המודל יכול לגשר על אוצר מילים בלי להמציא עובדות.

שלוש איטרציות

ה-draft הראשון של התיקון היה כתיבה מחדש. סקשן חדש שמנסח את ה-framework של הספר במפורש, רשימת כללים מאורגנת מחדש, anti-hallucination guardrails בסקשן נפרד, דוגמאות שנכתבו מחדש. בערך שישים שורות של prompt במקום שלושים. יותר מדי שטח פגיעה לבאג של כלל אחד, והוא הטמיע את תפישת העולם של המקור בתוך ה-system prompt כטענה — תלות שבירה בתוכן שעלול להיות מנוסח אחרת בעתיד.

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

מה שנחת היה diff של שלושה עריכות על גבי ה-prompt המקורי. שבע תוספות, מחיקה אחת. כל כלל מקורי וכל דוגמה מקורית נשמרו.

שלוש העריכות

אחת. הוראה חדשה, נוספה מיד אחרי “אין ידע חיצוני”:

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

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

שתיים. כלל הסירוב עבר מהכרזה חדה לתבנית:

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

השינוי חשוב בשתי דרכים. ה-trigger מתחלף מ”אין התאמה לקסיקלית” ל”אין התאמה מושגית”. והסירוב עצמו נהיה שיתופי — הוא מציע למשתמש/ת לנסח מחדש באוצר המילים של המקור במקום סתם לומר שהתוכן לא קיים.

שלוש. דוגמה שלישית, נוספה אחרי שתי דוגמאות קיימות של סוגי שאלות:

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

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

מה לא השתנה

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

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

אימות

כל ה-unit tests הקיימים נשארו ירוקים — ה-prompt עדיין מפיק עברית, עדיין משתמש ב-> ל-blockquotes, עדיין מייצר ציטוטי עמוד N, עדיין אוסר פרפרזות. הרצתי מחדש את השאלה שסורבה מול ה-revision שנפרס. התשובה עכשיו נפתחת במשפט גשר וכוללת חמישה ציטוטים ישירים משלושה עמודים בשני פרקים. בדיוק הצורה שהדוגמה השלישית מלמדת.

מתי העיצוב הזה לא יתאים

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

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

הצורה הרחבה

Q&A עם ציטוט-חובה על פרוזה מקורית יש לו שני משטחי כשל בשכבת ה-answer, והם נמצאים בצדדים מנוגדים של slider. מחמיר: סרב כשאוצר המילים לא תואם. רופף: גשר בין קונספטים בחופשיות כזו שתמציא. אף אחד מהכשלים לא נראה עד שהשאלה הלא-נכונה פוגעת. שניהם נראים בטוחים.

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

Rewrite הוא הדרך לתקן טעות ארכיטקטורלית. תוספת של שלוש שורות היא הדרך לתקן עיצוב של כלל.