사람들은 OpenAI, Gemini, Claude 등과 같은 인기 있는 LLM에 대해 개인 정보 보호에 대한 우려를 갖고 있습니다. 오픈 소스 모델이 아닌 이상 화면 뒤에서 무슨 일이 일어나는지 우리는 실제로 알 수 없습니다. 그러니 우리 입장에서는 조심해야 합니다.
먼저 LLM에 전달되는 정보를 처리하는 것입니다. 전문가들은 프롬프트에 기밀 정보나 개인 식별자를 포함하지 않을 것을 권장합니다. 더 쉬워 보이지만 LLM의 컨텍스트 크기가 증가함에 따라 큰 텍스트를 모델에 전달할 수 있습니다. 따라서 어려운 검토가 되어 모든 식별자를 가릴 수 있습니다.
그래서 저는 식별자와 기밀 정보를 탐지하고 마스킹하는 Python 스크립트를 만들어 보았습니다. Regex는 마술처럼 다양한 기밀 정보를 인식하고 이를 마스크로 대체하도록 구현되었습니다. 또한 이름, 장소 등과 같은 공통 식별자를 감지하기 위해 spacy 라이브러리를 사용했습니다.
참고: 현재는 인도 상황에 적합하지만 공통 식별자는 계속 감지될 수 있습니다.
그럼 구현을 살펴보겠습니다(구현을 위해 LLM의 도움을 받았습니다)
설명을 건너 뛰고 싶다면.
코드 베이스에 대한 링크는 다음과 같습니다: aditykris/prompt-masker-Indian-context
필요한 모듈/라이브러리 가져오기
import re from typing import Dict, List, Tuple import spacy nlp = spacy.load("en_core_web_sm")
아래 스니펫을 사용하여 "en_core_web_sm"을 수동으로 설치해야 합니다
python -m spacy 다운로드 en_core_web_sm
인도 공통 기밀 정보를 설정합니다.
class IndianIdentifier: '''Regex for common Indian identifiers''' PAN = r'[A-Z]{5}[0-9]{4}[A-Z]{1}' AADHAR = r'[2-9]{1}[0-9]{3}\s[0-9]{4}\s[0-9]{4}' INDIAN_PASSPORT = r'[A-PR-WYa-pr-wy][1-9]\d\s?\d{4}[1-9]' DRIVING_LICENSE = r'(([A-Z]{2}[0-9]{2})( )|([A-Z]{2}-[0-9]{2}))((19|20)[0-9][0-9])[0-9]{7}' UPI_ID = r'[\.\-a-z0-9]+@[a-z]+' INDIAN_BANK_ACCOUNT = r'\d{9,18}' IFSC_CODE = r'[A-Z]{4}0[A-Z0-9]{6}' INDIAN_PHONE_NUMBER = r'(\+91|\+91\-|0)?[789]\d{9}' EMAIL = r'[\w\.-]+@[\w\.-]+\.\w+' @classmethod def get_all_patterns(cls) -> Dict[str, str]: """Returns all regex patterns defined in the class""" return { name: pattern for name, pattern in vars(cls).items() if isinstance(pattern, str) and not name.startswith('_') }
그래서 파이썬 클래스와 메소드를 수정하고 있어서 여기에 구현해봤습니다.
DebugPointer에서 이러한 식별자의 정규식이 매우 유용하다는 것을 알았습니다.
이제 감지 기능을 살펴보겠습니다. 일치하는 항목을 찾기 위해 다양한 패턴을 반복하는 데 간단한 re.finditer()가 사용되었습니다. 일치하는 항목은 목록에 저장됩니다.
def find_matches(text: str, pattern: str) -> List[Tuple[int, int, str]]: """ Find all matches of a pattern in text and return their positions and matched text """ matches = [] for match in re.finditer(pattern, text): matches.append((match.start(), match.end(), match.group())) return matches
대체 텍스트를 저장하기 위해 간단한 사전을 사용했습니다. 대체 텍스트를 반환하는 함수로 포장했습니다.
def get_replacement_text(identifier_type: str) -> str: """ Returns appropriate replacement text based on the type of identifier """ replacements = { 'PAN': '[PAN_NUMBER]', 'AADHAR': '[AADHAR_NUMBER]', 'INDIAN_PASSPORT': '[PASSPORT_NUMBER]', 'DRIVING_LICENSE': '[DL_NUMBER]', 'UPI_ID': '[UPI_ID]', 'INDIAN_BANK_ACCOUNT': '[BANK_ACCOUNT]', 'IFSC_CODE': '[IFSC_CODE]', 'INDIAN_PHONE_NUMBER': '[PHONE_NUMBER]', 'EMAIL': '[EMAIL_ADDRESS]', 'PERSON': '[PERSON_NAME]', 'ORG': '[ORGANIZATION]', 'GPE': '[LOCATION]' } return replacements.get(identifier_type, '[MASKED]')
아! 본편이 시작됩니다.
def analyze_identifiers(text: str) -> Tuple[str, Dict[str, List[str]]]: """ Function to identify and hide sensitive information. Returns: - masked_text: Text with all sensitive information masked - found_identifiers: Dictionary containing all identified sensitive information """ # Initialize variables masked_text = text found_identifiers = {} positions_to_mask = [] # First, find all regex matches for identifier_name, pattern in IndianIdentifier.get_all_patterns().items(): matches = find_matches(text, pattern) if matches: found_identifiers[identifier_name] = [match[2] for match in matches] positions_to_mask.extend( (start, end, identifier_name) for start, end, _ in matches ) # Then, process named entities using spaCy doc = nlp(text) for ent in doc.ents: if ent.label_ in ["PERSON", "ORG", "GPE"]: positions_to_mask.append((ent.start_char, ent.end_char, ent.label_)) if ent.label_ not in found_identifiers: found_identifiers[ent.label_] = [] found_identifiers[ent.label_].append(ent.text) # Sort positions by start index in reverse order to handle overlapping matches positions_to_mask.sort(key=lambda x: x[0], reverse=True) # Apply masking for start, end, identifier_type in positions_to_mask: replacement = get_replacement_text(identifier_type) masked_text = masked_text[:start] + replacement + masked_text[end:] return masked_text, found_identifiers
이 함수는 프롬프트를 입력으로 사용하고 식별된 요소와 함께 마스크된 프롬프트를 사전으로 반환합니다.
하나씩 설명드리겠습니다.
다양한 식별자의 정규식을 반복하여 프롬프트에서 일치하는 항목을 찾습니다. 발견되면 다음과 같이 됩니다.
1. 식별된 정보를 식별자 유형을 키로 사용하여 사전에 저장하여 추적하세요.
2. 나중에 마스킹을 적용할 수 있도록 위치를 기록하고 position_to_mask에 저장합니다.
import re from typing import Dict, List, Tuple import spacy nlp = spacy.load("en_core_web_sm")
이제 여유로운 시간입니다. 자연어 처리(nlp) 작업을 위한 훌륭한 라이브러리입니다. nlp 모듈을 사용하여 텍스트에서 식별자를 추출할 수 있습니다.
현재는 이름, 소속, 위치를 감지하는 데 익숙합니다.
이는 위치를 식별하고 저장하는 위의 루프와 동일하게 작동합니다.
class IndianIdentifier: '''Regex for common Indian identifiers''' PAN = r'[A-Z]{5}[0-9]{4}[A-Z]{1}' AADHAR = r'[2-9]{1}[0-9]{3}\s[0-9]{4}\s[0-9]{4}' INDIAN_PASSPORT = r'[A-PR-WYa-pr-wy][1-9]\d\s?\d{4}[1-9]' DRIVING_LICENSE = r'(([A-Z]{2}[0-9]{2})( )|([A-Z]{2}-[0-9]{2}))((19|20)[0-9][0-9])[0-9]{7}' UPI_ID = r'[\.\-a-z0-9]+@[a-z]+' INDIAN_BANK_ACCOUNT = r'\d{9,18}' IFSC_CODE = r'[A-Z]{4}0[A-Z0-9]{6}' INDIAN_PHONE_NUMBER = r'(\+91|\+91\-|0)?[789]\d{9}' EMAIL = r'[\w\.-]+@[\w\.-]+\.\w+' @classmethod def get_all_patterns(cls) -> Dict[str, str]: """Returns all regex patterns defined in the class""" return { name: pattern for name, pattern in vars(cls).items() if isinstance(pattern, str) and not name.startswith('_') }
일부 테스트 사례에서 일부 마스크가 누락된 것을 발견했는데 이는 주로 식별자의 중복 때문이었습니다. 그래서 역순으로 정렬하는 것이 해결에 도움이 되었습니다.
def find_matches(text: str, pattern: str) -> List[Tuple[int, int, str]]: """ Find all matches of a pattern in text and return their positions and matched text """ matches = [] for match in re.finditer(pattern, text): matches.append((match.start(), match.end(), match.group())) return matches
그런 다음 마지막으로found_identifiers 및 position_to_mask의 데이터를 사용하여 마스킹 작업을 수행합니다.
def get_replacement_text(identifier_type: str) -> str: """ Returns appropriate replacement text based on the type of identifier """ replacements = { 'PAN': '[PAN_NUMBER]', 'AADHAR': '[AADHAR_NUMBER]', 'INDIAN_PASSPORT': '[PASSPORT_NUMBER]', 'DRIVING_LICENSE': '[DL_NUMBER]', 'UPI_ID': '[UPI_ID]', 'INDIAN_BANK_ACCOUNT': '[BANK_ACCOUNT]', 'IFSC_CODE': '[IFSC_CODE]', 'INDIAN_PHONE_NUMBER': '[PHONE_NUMBER]', 'EMAIL': '[EMAIL_ADDRESS]', 'PERSON': '[PERSON_NAME]', 'ORG': '[ORGANIZATION]', 'GPE': '[LOCATION]' } return replacements.get(identifier_type, '[MASKED]')
이 프로그램의 샘플 입력은 다음과 같습니다.
입력:
def analyze_identifiers(text: str) -> Tuple[str, Dict[str, List[str]]]: """ Function to identify and hide sensitive information. Returns: - masked_text: Text with all sensitive information masked - found_identifiers: Dictionary containing all identified sensitive information """ # Initialize variables masked_text = text found_identifiers = {} positions_to_mask = [] # First, find all regex matches for identifier_name, pattern in IndianIdentifier.get_all_patterns().items(): matches = find_matches(text, pattern) if matches: found_identifiers[identifier_name] = [match[2] for match in matches] positions_to_mask.extend( (start, end, identifier_name) for start, end, _ in matches ) # Then, process named entities using spaCy doc = nlp(text) for ent in doc.ents: if ent.label_ in ["PERSON", "ORG", "GPE"]: positions_to_mask.append((ent.start_char, ent.end_char, ent.label_)) if ent.label_ not in found_identifiers: found_identifiers[ent.label_] = [] found_identifiers[ent.label_].append(ent.text) # Sort positions by start index in reverse order to handle overlapping matches positions_to_mask.sort(key=lambda x: x[0], reverse=True) # Apply masking for start, end, identifier_type in positions_to_mask: replacement = get_replacement_text(identifier_type) masked_text = masked_text[:start] + replacement + masked_text[end:] return masked_text, found_identifiers
출력:
마스크된 텍스트:
for identifier_name, pattern in IndianIdentifier.get_all_patterns().items(): matches = find_matches(text, pattern) if matches: found_identifiers[identifier_name] = [match[2] for match in matches] positions_to_mask.extend( (start, end, identifier_name) for start, end, _ in matches )
위 내용은 Regex 및 spaCy를 사용하여 프롬프트에서 기밀 데이터 마스킹의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!