کشف PII قبل از مصرف RAG: اسناد صفحه نمایش C#

Retrieval Augmented Generation (RAG) به سرعت به یکی از مفیدترین مدل ها در دنیای در حال رشد هوش مصنوعی سازمانی تبدیل شده است. به جای اصلاح یک مدل بر روی داده های خصوصی، سیستم RAG در عوض متن را از اسناد داخلی استخراج می کند، آن متن را به قسمت هایی تقسیم می کند، هر قسمت را به یک جاسازی برداری تبدیل می کند، و آن بردارها را ذخیره می کند تا مدل زبان بتواند به آرامی مرتبط ترین متن ها را در طول پرس و جو بازیابی کند. سود یک سیستم RAG که به خوبی طراحی شده است قابل توجه است: کارمندان می توانند سوالاتی به زبان ساده در ویکی ها، قراردادها، بلیط های پشتیبانی و فایل های خط مشی بپرسند و پاسخ های مستدل و نقل شده را در پاسخ دریافت کنند – بدون نیاز به آموزش.
همین راحتی همان چیزی است که اطلاعات شناسایی شخصی (PII) را در اینجا خطرناک می کند. ارائه اسناد داخلی به یک سرویس هوش مصنوعی به معنای کپی کردن محتوای آنها در فرم جدید، قابل جستجو و تمیز کردن سخت است. اگر هر یک از این اسناد حاوی شماره های تامین اجتماعی، شماره حساب بانکی یا داده های بهداشتی باشد، آن سیستم قدرتمند RAG بی سر و صدا به منبع نقض مقررات و انطباق تبدیل می شود.
در این مقاله، ابتدا موضوع RAG PII را با جزئیات بیشتری مورد بحث قرار میدهیم و سپس به نحوه پیادهسازی راهحل C# که مشکل را کاهش میدهد، تمرکز میکنیم. در نهایت، ما راه حلی خواهیم ساخت که از متن استخراج شده قبل از جاسازی شدن فرار کند.
ذخیره سازی وکتور PII را مدت ها پس از مصرف ذخیره می کند
PII در خط لوله RAG نیز یک مشکل در معرض قرار گرفتن است و پایداری در یک پرس و جو ساده، داده های حساس به همان سرعتی که آمدند از بین می روند و ناپدید می شوند.
با این حال، هنگام مصرف، این داده تنظیم باقی میماند. هنگامی که یک سند تکه تکه و جاسازی می شود، هر PII حاوی آن در بردارها، در فراداده قطعه، و در هر نتیجه بازیابی که آن قطعات را به عقب می کشد، باقی می ماند. این بدان معنی است که می تواند در پاسخ مدل به دور از سندی که از آن آمده است، برای کاربری که هرگز قرار نبود آن را ببیند ظاهر شود. تا زمانی که این باگ شناسایی شود، کاهش به معنای یافتن و حذف هر کپی واکشی شده در کل فهرست است، که البته بسیار سخت تر از عدم مصرف آن داده است. بازرسی در زمان مصرف آخرین لحظه کم هزینه ای است که ما برای محافظت از داده های تنظیم شده در دسترس داریم.
کشف یک نقطه تصمیم است، نه یک مرحله ویرایش
قبل از اینکه بسازیم راه حلی برای کاهش RAG PII، به جدا کردن دو چیزی که میتوانیم کمک میکند انجام دهید با متن حساس پس از شناسایی. ما میتوانیم آن را شناسایی کنیم و تصمیم بگیریم که آیا سند میتواند در خط لوله ادامه یابد یا اینکه میتوانیم آن را ویرایش کنیم و بنابراین سند را قبل از خروج از گردش کارمان تغییر دهیم.
این مقاله در نهایت بر اجرای اولین مفهوم متمرکز شده است: دروازه PII. سیاست برای این ساده است. سندی که آشکارساز برای استفاده در RAG پاک می کند، الزامات شاخص را برآورده می کند. سندی که آن را منحرف میکند، ذخیره میشود، و ما یک دسته قفلشده (مانند شماره امنیت اجتماعی یا شماره حساب بانکی) را از مواردی که صرفاً به چشم انسان نیاز دارد، تشخیص میدهیم.
متن دقیقی را که در حال جاسازی هستید مرور کنید
فرآیند جاسازی به متن نیاز دارد – و البته این به معنای خط لوله RAG است همیشه متن استخراج شده را تولید می کند. این متن همان چیزی است که می خواهیم نمایش دهیم. این مصنوع دقیقی است که در شرف تقسیم و جاسازی است. مشاهده تصویر یا فایل منبع و سپس استخراج متن به طور جداگانه به معنای بررسی یک نمایش در حالی که دیگری را دریافت می کند، مشکل ساز است زیرا این دو می توانند از هم جدا شوند. لایههای پنهان، تفاوتهای OCR و ابردادهها میتوانند دادههایی را حمل کنند که نسخه اسکنشده شما هرگز نشان نداد. بنابراین با غربالگری از این مشکل جلوگیری می کنیم بعد از استخراج و قبل از chunking، که باعث می شود بایت هایی که ما تایید می کنیم همان بایت هایی باشند که جاسازی کرده ایم.
آنچه می توانیم با کامپوننت های منبع باز بسازیم
بسیاری از ابزارهای مورد نیاز ما در حال حاضر در اکوسیستم ما زندگی می کنند. دات نت تمام ماشین آلات پس زمینه مورد نیاز را به صورت رایگان در اختیار ما قرار می دهد: مدیریت فایل، محدودیت اندازه، پخش جریانی و غیره. او چه می کند؟ نه با این حال، هر ابزاری را به ما بدهید که به طور خاص بهینه شده است تا PII را با اطمینان شناسایی کند.
عبارات معمولی به ذهن میآیند، و مطمئناً میتوانند شماره کارتهای اعتباری و تأمین اجتماعی را به خوبی ثبت کنند، اما نامها، آدرسها و شناسههای بسیاری را که به شکل آزاد و وابسته به زمینه ظاهر میشوند را از دست میدهند و مستعد هشدارهای نادرست برای شمارههای معمولی هستند. اطلاعات بهداشتی حتی دشوارتر است زیرا تشخیص ارجاع به شرایط پزشکی یا درمان های تجویز شده مستلزم سطحی از درک زمینه ای است که تطبیق الگوی ساده به تنهایی نمی تواند آن را جبران کند. یک آشکارساز قابل هدایت، که یکی از نمونه های آن در راه حل خود در زیر استفاده خواهیم کرد، این مشکل تشخیص را جذب می کند. تکهای از پازلی که ما را رها میکند، انکارناپذیر است: انتخاب کردن کدام دسته ها را مجاز کنیم، تنظیم قوانین مسدود کردن دسته های غیرمجاز و تست کردن آنهایی که علیه اسنادی هستند که بسیار شبیه مجموعه اسناد واقعی ما هستند.
افزودن مرحله تشخیص PII در سی شارپ
در نسخه ی نمایشی خود، از یک DLP API بهینه شده برای شناسایی دسته های قابل تنظیم PII و PHI در متن استفاده می کنیم و حکم آن را به عنوان نتیجه اعتبارسنجی که دروازه RAG PII را هدایت می کند، در نظر می گیریم.
لطفاً به یک فرض قوی توجه کنید که در اینجا وارد شده است: ما از یک نقطه پایانی استفاده می کنیم واقع در زیرساخت های خودمان. این برای هر سرویس قابل مقایسه صادق است. اگر این را در نظر نگیریم، به سادگی در معرض از دست دادن داده ها دو برابر می شویم. ما باید نه از خدمات وب با میزبانی عمومی برای تأیید داده های حساس استفاده کنید.
برای راهاندازی، ابتدا یک پروژه کنسول ایجاد میکنیم و SDK را نصب میکنیم:
dotnet new console --framework net8.0 -n RagPiiGate
cd RagPiiGate
dotnet add package Cloudmersive.APIClient.NETCore.DLP --version 1.1.0
using System;
using System.IO;
using Cloudmersive.APIClient.NETCore.DLP.Api;
using Cloudmersive.APIClient.NETCore.DLP.Client;
using Cloudmersive.APIClient.NETCore.DLP.Model;
ساختن یک صفحه نمایش PII گام به گام
اکنون برنامه را به ترتیب جریان داده ها می سازیم. قطعات زیر به صورت یک به سطح متصل می شوند Program.cs; ما برای وضوح بیشتر آن را به این صورت تقسیم کرده ایم.
ابتدا آنچه را که اپراتور کنترل میکند جمعآوری میکنیم و هر چیزی را که از دست میدهد دور میاندازیم. کلید API و هر دو دایرکتوری هدف از محیط می آیند، نه از سند.
try
{
if (args.Length != 2)
throw new ArgumentException("Usage: RagPiiGate ");
string Required(string name) =>
Environment.GetEnvironmentVariable(name) is { Length: > 0 } value
? value : throw new InvalidOperationException($"Set {name}.");
string key = Required("CLOUDMERSIVE_API_KEY");
string acceptDir = Required("ACCEPT_DIR");
string quarantineDir = Required("QUARANTINE_DIR");
// Pipeline-supplied, never derived from document content.
string documentId = Path.GetFileName(args[1]);
if (string.IsNullOrWhiteSpace(documentId) || documentId != args[1])
throw new InvalidOperationException("Document id must be a simple file name.");
با یک پیکربندی معتبر، هیچ چیز پایین دستی به یک مقدار غیرقابل اعتماد بستگی ندارد. فرض میکنیم فایل ورودی محصول نهایی مرحله استخراج قبلی است، بنابراین فقط آن را میخوانیم، اندازه آن را محدود میکنیم و تأیید میکنیم که خالی نیست (متن خالی در غیر این صورت پاک میشود).
const int maxChars = 1 * 1024 * 1024;
var info = new FileInfo(args[0]);
if (!info.Exists)
throw new InvalidOperationException("Extracted-text file was not found.");
if (info.Length > maxChars)
throw new InvalidOperationException("Extracted text exceeds the screening size limit.");
string text = File.ReadAllText(args[0]);
if (string.IsNullOrWhiteSpace(text))
throw new InvalidOperationException("Extracted text is empty; nothing to screen.");
در این مرحله ما در نهایت متن معنیداری روی صفحه داریم – بنابراین آن را ارسال میکنیم و قضاوت را رزرو میکنیم. را Allow پرچمها خط مشی ما هستند: به نامها و آدرسهایی که معمولاً در یک پایگاه دانش داخلی یافت میشوند اجازه میدهیم و شناسههای پرخطر، دادههای مالی، PHI سلامت و اسرار را رد میکنیم.
bool accepted = verdict.CleanResult == true;
bool hardBlock =
verdict.ContainsSocialSecurityNumber == true ||
verdict.ContainsCreditCardNumber == true ||
verdict.ContainsBankAccountNumber == true ||
verdict.ContainsPassportNumber == true ||
verdict.ContainsPrivateKeys == true ||
verdict.ContainsCredentials == true ||
verdict.ContainsHealthInsuranceNumber == true;
string decision = accepted ? "accept"
: hardBlock ? "quarantine (blocked category)"
: "quarantine (review)";
کشف آنچه در سند بود به ما گفت. سیاست اکنون تصمیم می گیرد که واقعاً چه معنایی دارد. در این مورد CleanResult دروازه است و Contains پرچمها به ما اجازه میدهند که دلیل نگهداری یک سند را طبقهبندی کنیم.
var configuration = new Configuration();
configuration.AddApiKey("Apikey", key);
var detector = new DetectApi(configuration);
var request = new DlpAdvancedDetectionRequest
{
InputText = text,
AllowPersonName = true,
AllowStreetAddress = true,
AllowEmailAddress = false,
AllowPhoneNumber = false,
AllowBirthDate = false,
AllowPassportNumber = false,
AllowDriversLicense = false,
AllowSocialSecurityNumber = false,
AllowTaxpayerID = false,
AllowCreditCardNumber = false,
AllowBankAccountNumber = false,
AllowIBAN = false,
AllowHealthInsuranceNumber = false,
AllowHealthInsuranceMemberID = false,
AllowHealthInjuryOrDisease = false,
AllowHealthTypeOfTreatment = false,
AllowCredentials = false,
AllowPrivateKeys = false,
AllowBearerToken = false,
ProvideAnalysisRationale = true
};
DlpAdvancedDetectionResponse verdict = detector.DetectTextAdvanced(request);
if (verdict is null)
throw new InvalidOperationException("Detection returned no result.");
یک نکته سریع در اینجا: زیرا ما میپرسیم ProvideAnalysisRationale، پاسخ AnalysisRationale به زبانی ساده توضیح میدهد که چرا یک سند پرچمگذاری شده است، که به منظور کمک به بازبینی کننده در مرتبسازی مسیر قرنطینه است. با استناد به دادههای حساس، این ابزار را به دست میآورد، بنابراین ما فقط با آن مانند PII توصیف شده رفتار میکنیم: هرگز ثبت نمیشود و فقط در یک مخزن قرنطینه شده و با دسترسی کنترل شده ظاهر میشود.
برای مرحله آخر، فایل را به یک پوشه انتخاب شده توسط اپراتور هدایت می کنیم. متن واضح برای بقیه خط لوله به دایرکتوری “accept” می رود. همه چیز دیگر به قرنطینه می رود و خارج از شاخص باقی می ماند. FileMode.CreateNew از بازنویسی امتناع می کند، بنابراین یک شناسه تکراری به عنوان یک خطا ظاهر می شود.
string targetDir = accepted ? acceptDir : quarantineDir;
Directory.CreateDirectory(targetDir);
string targetPath = Path.Combine(targetDir, documentId + ".txt");
using (var output = new FileStream(targetPath, FileMode.CreateNew,
FileAccess.Write, FileShare.None))
using (var writer = new StreamWriter(output))
{
writer.Write(text);
}
Console.WriteLine($"{documentId}: {decision}.");
}
در این مثال، یک catch تنها کل خط لوله را پوشش میدهد و هرگز متن، مقادیر شناساییشده یا توجیه را منعکس نمیکند، که هر یک از آنها ممکن است همان PII را که ما سعی در حفظ آن داریم داشته باشد.
catch (Exception error)
{
Console.Error.WriteLine($"Screening stopped ({error.GetType().Name}).");
Environment.ExitCode = 1;
}
از آنجایی که تنها مسیر دایرکتوری “accept” یک عبارت تمیز صریح است، هر خطا و هر نتیجه مبهم به همان روش ایمن حل می شود: به هر حال بلعیده نشد، هرگز بلعیده نشد.
نتیجه گیری
PII از لحظه ای که وارد فهرست بازیابی می شود به یک بدهی جدی و دائمی تبدیل می شود، بنابراین زمان بررسی آن در زمان مصرف است، قبل از تقسیم و جاسازی متن. ما دیدهایم که مکان صحیح برای فرار دقیقاً متن استخراجشدهای است که میخواهیم جاسازی کنیم، و این تشخیص بیشتر یک لحظه تصمیمگیری است تا یک مرحله پاکسازی. ما یاد گرفتیم که دروازه برای PII همیشه باید ایمن باشد: فقط یک حکم صریح و تمیز باید به شاخص برسد و هر خطا یا نتیجه مبهم باید حفظ شود.
با یک خط مشی طبقه بندی واضح و مدیریت بسیار منظم محتوای پرچم گذاری شده، خط لوله RAG می تواند بدون تبدیل یک پایگاه دانش داخلی به مجرای برای افشای داده های تنظیم شده مفید باقی بماند.



