ההבדל בין פילטרים לחומות

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

סינון (Filtering) פירושו שהשאילתה שלכם מחזירה רק שורות מסוימות. בניית חומות (Walling) פירושה שהסוכן לא יכול להגיע לשורות המוסתרות בכלל.

זה נראה אותו דבר עד שמשהו נשבר.

לאחרונה בניתי מערכת שהפכה 1.2 מיליון מילים לבסיס ידע. השתמשתי ב-Supabase כדי לנהל את הנתונים. רציתי שסוכני ה-AI שלי יראו רק תוכן ציבורי.

השתמשתי ב-Postgres view סטנדרטי כדי לסנן את הנתונים:

CREATE VIEW public_seeds AS
  SELECT * FROM moments
  WHERE visibility = 'public'
    AND is_canonical = true;

זה נראה תקין. אבל יש לזה פגם עצום. כברירת מחדל, Postgres view רץ תחת בעל ה-view, ולא תחת המשתמש שמפעיל אותו. לבעל ה-view יש לרוב גישה מלאה. המשמעות היא שמדיניות ה-Row Level Security (RLS) שלכם לא חלה על ה-view.

לא בניתם חומת הגנה. בניתם פילטר.

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

Postgres 15 פתר זאת באמצעות האופציה security_invoker.

כשאתם מגדירים את security_invoker ל-true, ה-view רץ תחת התפקיד (role) המפעיל אותו. זה מאלץ את ה-view לציית למדיניות ה-RLS שלכם. ה-view הופך לשער מבני.

הדרך הנכונה:

CREATE VIEW public_seeds
  WITH (security_invoker = true)
AS
  SELECT * FROM moments
  WHERE visibility = 'public'
    AND is_canonical = true;

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

"זה לא אמור לקרות" מסתמך על כך שהכל עובד בצורה מושלמת. "זה לא יכול לקרות" מסתמך על הארכיטקטורה שלכם.

כשאתם בונים עבור AI, אתם חייבים לתכנן עבור מה ש"לא יכול לקרות".

שלושה דברים שכדאי לבדוק בהגדרה שלכם:

מקור: https://dev.to/chadtdyar/the-difference-between-this-shouldnt-happen-and-this-cannot-happen-in-ai-content-pipelines-1g0p

קהילת למידה אופציונלית: https://t.me/GyaanSetuAi