Bảo mật LLM: Dùng Microsoft Presidio để ‘tẩy trần’ dữ liệu nhạy cảm (PII) trước khi gọi API

Artificial Intelligence tutorial - IT technology blog
Artificial Intelligence tutorial - IT technology blog

Vấn đề: Đừng gửi thẳng dữ liệu khách hàng lên OpenAI

Cách đây 6 tháng, mình triển khai hệ thống RAG Chatbot cho một ngân hàng lớn. Thách thức lớn nhất lúc đó không phải là prompt engineering hay chọn model, mà là Data Privacy (Bảo mật dữ liệu). Khách hàng hỏi mình một câu rất thực tế: ‘Làm sao để chắc chắn số thẻ, số điện thoại hay địa chỉ nhà của user không bị đẩy thẳng lên server của OpenAI hay Claude?’.

Với dự án cá nhân, rủi ro có thể thấp. Nhưng trong môi trường doanh nghiệp, để lộ PII (Thông tin định danh cá nhân) là một rắc rối pháp lý cực lớn. Các quy định như GDPR hay Nghị định 13/2023/NĐ-CP của Việt Nam đều có chế tài rất nặng. Sau khi thử nghiệm nhiều phương án, mình chọn Microsoft Presidio. Đây là bộ công cụ giúp ‘lọc’ sạch dữ liệu cực kỳ ổn định trước khi nó rời khỏi server nội bộ.

Presidio hoạt động như thế nào?

Hãy coi Microsoft Presidio là một ‘máy lọc nước’ cho dữ liệu văn bản. Bạn đổ văn bản thô vào, nó soi tìm tên người, email, số căn cước… rồi thay thế chúng bằng nhãn giả hoặc mã hóa đi. Hệ thống này gồm hai bộ phận chính:

  • Presidio Analyzer: Đóng vai trò ‘thám tử’. Nó kết hợp Regex, mô hình NLP (Spacy, Transformers) và logic checksum (như thuật toán Luhn cho số thẻ tín dụng) để truy tìm thực thể nhạy cảm.
  • Presidio Anonymizer: Đóng vai trò ‘thợ sửa’. Dựa trên kết quả từ Analyzer, nó sẽ thực hiện: Thay thế (Replace), Xóa (Redact), Băm (Hash) hoặc Mã hóa (Encrypt).

Điểm cộng lớn nhất là khả năng hiểu ngữ cảnh. Presidio không chỉ dựa vào Regex khô khan. Nó phân biệt được khi nào ‘Washington’ là tên người, khi nào là địa điểm, giúp giảm tỷ lệ nhận diện sai (False Positive) xuống đáng kể.

Cùng bắt tay vào triển khai

Mình đang sử dụng Python 3.10 cho dự án này. Việc cài đặt Presidio cùng model ngôn ngữ của Spacy chỉ mất vài phút:

pip install presidio-analyzer presidio-anonymizer spacy
python -m spacy download en_core_web_lg

1. Phân tích dữ liệu với Analyzer

Đoạn code dưới đây sẽ giúp bạn ‘soi’ xem trong câu chat của người dùng chứa những gì nhạy cảm:

from presidio_analyzer import AnalyzerEngine

analyzer = AnalyzerEngine()
text_to_analyze = "Chào admin, tôi là Nguyễn Văn A, số điện thoại là 0901234567. Tôi muốn hỏi về đơn hàng gửi tới 123 Đường Lê Lợi."

# Chỉ định các thực thể cần tìm
results = analyzer.analyze(text=text_to_analyze, entities=["PERSON", "PHONE_NUMBER", "LOCATION"], language='en')

for res in results:
    print(res)

Kinh nghiệm thực tế cho thấy model en_core_web_lg của Spacy nhận diện tên người Việt khá ổn dù đang để language='en'. Tuy nhiên, để đạt độ chính xác trên 95% cho tiếng Việt, bạn sẽ cần tinh chỉnh thêm ở bước sau.

2. Ẩn danh dữ liệu với Anonymizer

Sau khi thám tử Analyzer đã báo cáo, chúng ta tiến hành ‘che’ dữ liệu trước khi đẩy lên AI API.

from presidio_anonymizer import AnonymizerEngine
from presidio_anonymizer.entities import OperatorConfig

anonymizer = AnonymizerEngine()

# Cấu hình: Tên thì thay thế, số điện thoại thì che bớt, địa chỉ thì xóa hẳn
operators = {
    "PERSON": OperatorConfig("replace", {"new_value": "[NAME]"}),
    "PHONE_NUMBER": OperatorConfig("mask", {"type": "mask", "masking_char": "*", "chars_to_mask": 6, "from_end": True}),
    "LOCATION": OperatorConfig("redact", {})
}

anonymized_result = anonymizer.anonymize(
    text=text_to_analyze,
    analyzer_results=results,
    operators=operators
)

print(anonymized_result.text)

Kết quả trả về: “Chào admin, tôi là [NAME], số điện thoại là 0901******. Tôi muốn hỏi về đơn hàng gửi tới .”. Chuỗi này đã đủ an toàn để gửi tới GPT-4 mà không lo vi phạm chính sách bảo mật.

3. Tùy biến cho dữ liệu Việt Nam (Số CCCD, Biển số xe)

Presidio không mặc định hỗ trợ số Căn cước công dân (CCCD) 12 chữ số của Việt Nam. Bạn cần định nghĩa thêm một Custom Recognizer bằng Regex như sau:

from presidio_analyzer import PatternRecognizer, Pattern

# Định nghĩa pattern cho CCCD (12 chữ số liên tiếp)
cccd_pattern = Pattern(name="cccd_pattern", regex=r"\b\d{12}\b", score=0.5)

cccd_recognizer = PatternRecognizer(
    supported_entity="VN_CCCD", 
    patterns=[cccd_pattern],
    context=["số căn cước", "cccd", "định danh", "số định danh"]
)

analyzer.registry.add_recognizer(cccd_recognizer)

Kinh nghiệm thực chiến trên Production

Sau nửa năm vận hành, mình rút ra 3 bài học mấu chốt để hệ thống không bị ‘nghẽn’:

  1. Tốc độ xử lý: Đừng dùng model Transformer (BERT/RoBERTa) nếu ứng dụng yêu cầu real-time. Spacy model lg kết hợp Regex cho độ trễ chỉ khoảng 50-100ms, nhanh hơn gấp 10 lần so với Transformer mà vẫn đảm bảo độ chính xác.
  2. Kiểm soát nhận diện nhầm: Đừng dùng score_threshold mặc định. Hãy điều chỉnh con số này về khoảng 0.35 sau khi test với dữ liệu mẫu để cân bằng giữa việc bỏ sót và nhận diện nhầm.
  3. Cơ chế hoàn tác (De-anonymization): Đôi khi AI cần trả lời đích danh tên khách hàng. Bạn nên lưu mapping giữa giá trị gốc và giá trị ẩn danh vào Redis theo session. Khi AI trả về kết quả chứa [NAME], bạn chỉ việc map ngược lại để phản hồi cho user.

Lời kết

Bảo mật dữ liệu không phải là việc ‘phó mặc’ cho các ông lớn như OpenAI hay Microsoft. Chủ động lọc PII bằng Presidio giúp bạn xây dựng uy tín với khách hàng, đặc biệt trong mảng FinTech và Healthcare. Chỉ với vài dòng code, bạn đã tạo ra một lớp giáp bảo vệ vững chắc cho hệ thống AI của mình.

Share: