PII Redaction للـ AI: نظّف بيانات العميل قبل ما تبعتها للنموذج
مستوى القارئ: متوسط
هتطلع من المقال ده ببوابة بسيطة تقلل البيانات الحساسة اللي بتتبعت للـ LLM، بدل ما تعتمد على الثقة أو النية الطيبة في البرومبت.
المشكلة باختصار
لو عندك بوت دعم فني بيقرأ تذاكر العملاء، التذكرة ممكن تحتوي بريد، رقم هاتف، عنوان، رقم طلب، أو آخر أربع أرقام من بطاقة. الطريقة الشائعة الغلط إنك تبعت النص كله للنموذج وتقول له: “متستخدمش البيانات الحساسة”. الطريقة دي بتفشل لأن المنع هنا داخل البرومبت نفسه، وليس قبل نقطة الخروج.
الافتراض في هذا الشرح إن عندك تطبيق Python يرسل نصوصًا قصيرة أو متوسطة إلى API نموذج لغوي، بحجم 1K إلى 20K رسالة يوميًا. الهدف ليس إخفاء كل شيء بنسبة 100%. الهدف العملي هو تقليل البيانات غير الضرورية قبل ما تغادر النظام.
مثال سريع قبل التعريف
ركز في المثال ده. عميل كتب: “أنا أحمد، بريدي ahmed@example.com ورقمي +201001112223، والطلب ORD-9931 وصل ناقص”. النموذج غالبًا لا يحتاج البريد ولا الهاتف عشان يكتب رد دعم جيد. هو يحتاج المشكلة ورقم الطلب فقط لو رقم الطلب داخلي وغير حساس عندك.
بعد التنقية، النص يبقى: “أنا [PERSON]، بريدي [EMAIL] ورقمي [PHONE]، والطلب ORD-9931 وصل ناقص”. كده النموذج يفهم السياق، لكنك قللت البيانات الشخصية الخارجة. التعريف الأدق: PII Redaction هي طبقة تكتشف الكيانات الشخصية في النص، ثم تستبدلها أو تخفيها قبل أي معالجة خارجية.
الحل: بوابة صغيرة قبل استدعاء النموذج
أفضل طريقة هنا إنك تعمل gateway قبل كود استدعاء الـ LLM. استخدم Microsoft Presidio لاكتشاف كيانات مثل البريد والهاتف والأسماء، ثم Presidio Anonymizer لاستبدالها. Presidio مبني على Analyzer لاكتشاف الـ PII وAnonymizer لإزالة أو استبدال القيم، حسب التوثيق الرسمي.
pip install presidio-analyzer presidio-anonymizer spacy
python -m spacy download en_core_web_lg
from presidio_analyzer import AnalyzerEngine
from presidio_anonymizer import AnonymizerEngine
from presidio_anonymizer.entities import OperatorConfig
analyzer = AnalyzerEngine()
anonymizer = AnonymizerEngine()
TEXT = "Customer Ahmed sent ahmed@example.com and +201001112223 about order ORD-9931"
results = analyzer.analyze(
text=TEXT,
language="en",
entities=["EMAIL_ADDRESS", "PHONE_NUMBER", "PERSON"],
)
operators = {
"EMAIL_ADDRESS": OperatorConfig("replace", {"new_value": "[EMAIL]"}),
"PHONE_NUMBER": OperatorConfig("replace", {"new_value": "[PHONE]"}),
"PERSON": OperatorConfig("replace", {"new_value": "[PERSON]"}),
}
safe_text = anonymizer.anonymize(
text=TEXT,
analyzer_results=results,
operators=operators,
).text
print(safe_text)
# Customer [PERSON] sent [EMAIL] and [PHONE] about order ORD-9931
بعد كده ابعت safe_text للنموذج، وليس النص الأصلي. لو محتاج تربط الرد بالعميل داخليًا، استخدم request_id في قاعدة بياناتك بدل ما تمرر بيانات العميل للنموذج.
القياس: قبل وبعد
في سيناريو واقعي: فريق دعم عنده 12 ألف تذكرة يوميًا، وكل تذكرة تحتوي في المتوسط 7 حقول حساسة محتملة. قبل البوابة، 7 حقول ممكن تخرج للنموذج. بعد البوابة، الرقم ينزل إلى 1 أو 0 حسب جودة الاكتشاف وقواعدك الداخلية. التكلفة: حوالي 50 إلى 120ms معالجة إضافية لكل تذكرة على نص قصير. المكسب: تقليل سطح تسريب البيانات وتقليل كمية النص غير الضروري.
الـ trade-off هنا واضح. بتكسب تحكمًا أفضل في البيانات، وتخسر قليلًا من زمن المعالجة وبعض الدقة لو الـ detector أخطأ. لذلك لازم تسجل أرقامًا مجمعة فقط: عدد الكيانات التي تم حذفها، نوعها، وزمن المعالجة. لا تسجل النص الأصلي في log عادي.
ما الذي لا تعالجه هذه الطريقة
بوابة التنقية لا تلغي الحاجة إلى سياسات خصوصية واحتفاظ بالبيانات. OpenAI يوضح أن بيانات API لا تُستخدم لتدريب النماذج افتراضيًا إلا عند opt-in، لكن هذا لا يعني إنك ترسل كل بيانات العميل بلا فلترة. كذلك OWASP يضع تسريب المعلومات الحساسة ضمن مخاطر تطبيقات LLM، والوقاية الأفضل تبدأ قبل إرسال الطلب.
كمان Presidio ليس عصا سحرية. الأسماء العربية، اللهجات، أو أرقام داخلية بصيغ غريبة قد تحتاج recognizers مخصصة. لو عندك رقم عميل مثل CUST-44192، Presidio قد لا يعتبره PII إلا إذا عرّفته أنت كقاعدة.
متى لا تستخدم هذه الطريقة
لا تستخدمها كطبقة وحيدة لو التطبيق طبي أو مالي أو قانوني عالي الحساسية. في الحالة دي تحتاج مراجعة قانونية، تصنيف بيانات، صلاحيات وصول، وربما منع كامل لإرسال بعض الحقول. ولا تستخدمها لو المهمة نفسها تحتاج البيانات الأصلية، مثل التحقق من هوية العميل عبر رقم هاتف. وقتها افصل المهمة: تحقق داخليًا أولًا، ثم ابعت للنموذج ملخصًا منزوع البيانات.
مصادر اعتمدت عليها
- Microsoft Presidio Text anonymization
- Microsoft Presidio Anonymizer
- OpenAI API data controls
- OWASP LLM06 Sensitive Information Disclosure
الخطوة التالية
افتح مكان استدعاء الـ LLM في تطبيقك، وضع دالة redact_pii(text) قبله مباشرة. قِس عدد الكيانات المحذوفة وزمن المعالجة لمدة يوم واحد، ثم قرر هل تحتاج قواعد مخصصة للأرقام الداخلية أم لا.