입문편의 정규식 점검은 주민등록번호·전화번호처럼 모양이 정해진 개인정보를 잡습니다. "김철수 소방관이 마포구 성산동 현장에서"(가상 문장)의 이름과 주소는 정해진 모양이 없어서 정규식으로는 잡지 못합니다. 수천 건을 분석에 쓰려면 자동 탐지가 필요하고, 시작하기 전에 처리 목적과 기관 절차를 개인정보보호 담당과 확인합니다(4절).
이 안내서는 프로젝트 아이디어 신고 텍스트 개인정보 마스킹 파이프라인의 기술 배경을 설명합니다.
- 패턴 규칙과 문맥 개체명 인식의 역할을 나눠 설계할 수 있습니다.
- 합성 골든셋으로 탐지 놓침과 과잉 마스킹을 함께 검토할 수 있습니다.
- 마스킹·가명화 중 업무 목적에 맞는 최소 처리를 선택할 수 있습니다.
- 원본·비식별본·가명 대응표의 권한을 분리하고 공개 전 사람 검토로 연결할 수 있습니다.
AI에게 맡기는 프롬프트
코드를 실행할 수 있는 AI(코딩 에이전트)에게 비식별 코드와 재현율 검증을 맡길 때 쓰는 프롬프트입니다. 실제 신고·상담 텍스트가 없는 작업 폴더에 합성 골든셋만 두고 씁니다. 실제 자료에 돌리는 일은 기관이 승인한 내부 환경에서 따로 합니다.
[목적] 합성 신고 텍스트에서 이름·주소·전화번호·주민등록번호와 사건번호를 찾아 가리는 비식별 코드를 만들고, 놓친 개체를 목록으로 보고합니다. [자료] sample 폴더: 합성 신고 텍스트(CSV), 가려야 할 개체의 위치를 사람이 표시한 골든셋(JSON). 사건번호 표기 형식: (예: 연도 4자리-일련번호 6자리) [완성 기준] - 한국어(ko) 설정으로 탐지기를 구성하고, 켜진 개체 유형 목록을 먼저 출력해 주세요. - 재현율과 놓친 개체 목록을 출력하고, 일부만 가린 부분 탐지는 성공이 아니라 따로 세어 주세요. - 검산: 골든셋 개체 수 = 완전 탐지 + 부분 탐지 + 놓침 [하지 말 것] - sample 폴더 밖의 파일을 열지 말고, 텍스트를 외부 API나 외부 언어모델로 보내지 마세요. - 가명 대응표는 만들지 마세요. 필요해 보이면 먼저 이유를 물어 주세요. - 결과를 공개하거나 외부 AI에 넣어도 되는지는 판단하지 말고 [확인 필요]로 남겨 주세요. 자료에 없는 형식이나 값은 지어내지 말고 [확인 필요]로 남겨 주세요. 개인정보·비식별 관련 법령과 공공 도구는 https://119-ai-studio.kr/kg/topic-privacy-deid.txt 에서 맥락을 먼저 파악하고, 근거는 원문 주소와 함께 정리해 주세요. 확인 기준은 https://119-ai-studio.kr/pii-pipeline.html 안내서를 따릅니다. 작업 전에 빠진 정보가 있으면 먼저 질문해 주세요.
결과를 받은 뒤 확인할 것은 다음과 같습니다.
- 켜진 개체 유형 목록에 한국용 인식기(
KR_RRN등)와 사건번호 인식기가 있는지 봅니다. 목록이 비어 있으면 언어 설정부터 확인합니다. - 골든셋에 조사가 붙은 번호("…5678이고요")가 들어 있고, 그것이 잡혔는지 봅니다.
- 놓친 목록과 부분 탐지 목록을 사람이 직접 읽습니다. 재현율 숫자만 보고 통과시키지 않습니다.
정규식만으로 부족한 이유
| 개인정보 | 모양(패턴) | 정규식 | 문맥 탐지(NER) |
|---|---|---|---|
| 주민번호·전화·차량번호 | 있음 | 잡음(조사가 붙은 표기는 따로 시험) | 불필요 |
| 이름 | 없음 | 못 잡음 | 문맥으로 잡음 |
| 상세주소·지명 | 약함 | 일부 | 문맥으로 잡음 |
| 병원명·직책 조합 | 없음 | 못 잡음 | 별도 규칙 필요 |
정규식은 모양이 정해진 값을, 개체명 인식(NER)은 문맥으로 알아보는 이름·지명을 맡고 Presidio가 두 결과를 합칩니다.
1. Presidio의 탐지와 익명화
Presidio는 탐지(Analyzer)와 익명화(Anonymizer)를 나눕니다. 먼저 무엇이 어디 있는지 찾고, 그다음 어떻게 가릴지 정합니다. 처리는 신고 전사와 같은 원칙으로 기관 PC 안에서 합니다. 아래 코드는 AI가 만든 코드에 한국어 설정과 개체 목록 확인이 들어 있는지 보는 기준입니다.
from presidio_analyzer import AnalyzerEngine from presidio_analyzer.nlp_engine import NlpEngineProvider from presidio_anonymizer import AnonymizerEngine from presidio_anonymizer.entities import OperatorConfig # 1) 한국어 설정: 기본값은 영어 전용이므로 언어 코드 ko 로 모델을 연결한다 nlp = NlpEngineProvider(nlp_configuration={ "nlp_engine_name": "spacy", "models": [{"lang_code": "ko", "model_name": "ko_core_news_lg"}], # 반입해 둔 한국어 모델 # 한국어 모델의 개체 이름표(PS 사람, LC 지명)를 Presidio 개체 유형에 연결한다. 이 연결이 없으면 이름·지명이 잡히지 않는다 "ner_model_configuration": {"model_to_presidio_entity_mapping": {"PS": "PERSON", "LC": "LOCATION"}}, }).create_engine() analyzer = AnalyzerEngine(nlp_engine=nlp, supported_languages=["ko"]) print(analyzer.get_supported_entities(language="ko")) # 켜진 개체 유형을 먼저 확인 # 2) 탐지 text = "신고자 김철수님, 마포구 성산동, 연락처 010-1234-5678" # 합성 문장 found = analyzer.analyze(text=text, language="ko") # 3) 익명화: 개체 유형별로 가리는 방식 지정 result = AnonymizerEngine().anonymize( text=text, analyzer_results=found, operators={ "PERSON": OperatorConfig("replace", {"new_value": "<이름>"}), "LOCATION": OperatorConfig("replace", {"new_value": "<지역>"}), "PHONE_NUMBER": OperatorConfig("mask", {"masking_char": "*", "chars_to_mask": 8, "from_end": True}), }) print(result.text) # 세 개체가 모두 탐지되면: 신고자 <이름>님, <지역>, 연락처 010-1********
ko로 적고 인식기마다 지원 언어를 맞춥니다. 맞지 않으면 오류 없이 빈 결과가 나옵니다. 목록에 PERSON·LOCATION이 있어도 한국어 모델의 개체 이름표가 설정(model_to_presidio_entity_mapping)으로 연결되지 않으면 이름·지명이 잡히지 않습니다. 위 예처럼 연결한 뒤에도 합성 이름·지명이 실제로 잡히는지 골든셋으로 확인합니다. 전화번호도 잡히는지 골든셋으로 확인하고, 놓치면 2절처럼 한국 번호 규칙을 직접 넣습니다.2. 소방 특화 커스텀 인식기
Presidio에는 주민등록번호(KR_RRN)·외국인등록번호·여권번호·사업자등록번호·운전면허번호를 찾는 한국용 인식기가 들어 있습니다. 나라별 인식기는 기본 설정 파일에서 꺼져 있으므로, 설정 파일(YAML)에서 켜고 지원 언어를 ko로 지정한 뒤 1절의 목록에 KR_RRN이 나오는지 확인합니다. 직접 만드는 것은 일반 인식기가 모르는 소방 고유 번호(사건번호·출동번호·관서 내부 코드)입니다.
from presidio_analyzer import Pattern, PatternRecognizer case_no = PatternRecognizer( supported_entity="KR_CASE_NO", # 사건번호(관서 서식에 맞춰 조정) supported_language="ko", # 적지 않으면 영어용으로 등록돼 한국어 요청에서 빠진다 patterns=[Pattern("case", r"(?<!\d)\d{4}-\d{5,6}(?!\d)", 0.6)]) # \b 대신 숫자 경계 analyzer.registry.add_recognizer(case_no)
정규식의 \b는 숫자 바로 뒤에 한글 조사가 붙으면("…5678이고요") 경계로 보지 않아 번호를 놓칩니다. 그래서 앞뒤가 숫자가 아닌지만 보는 (?<!\d)…(?!\d)를 씁니다.
3. 재현율 검증
비식별에서 가장 위험한 실수는 가려야 할 것을 놓치는 것(재현율 실패)입니다. 이름 하나를 흘리면 그 한 건으로 개인정보가 노출됩니다. 과잉 마스킹(정밀도 문제)은 분석에 쓸 정보를 줄이지만 노출로 이어지지는 않으므로, 재현율을 먼저 관리합니다.
합성 신고 데이터로 골든셋을 만들고, 문장마다 가려야 할 개체의 위치를 사람이 표시합니다.
def overlap(a, b): """두 span (start, end)이 한 글자라도 겹치면 True.""" return a[0] < b[1] and b[0] < a[1] def recall(gold_spans, found_spans): """가려야 할 것 중 실제로 잡은 비율. 놓친 개수를 함께 본다.""" hit = sum(1 for g in gold_spans if any(overlap(g, f) for f in found_spans)) missed = [g for g in gold_spans if not any(overlap(g, f) for f in found_spans)] return hit / max(len(gold_spans), 1), missed rate, missed = recall(gold, [(x.start, x.end) for x in found]) print(f"재현율 {rate:.1%}, 놓친 개체 {len(missed)}건") for m in missed: # 놓친 것은 전부 사람이 보고 인식기를 보강 print(" 놓침:", m)
recall 함수의 한계: 골드 span과 탐지 span이 한 글자라도 겹치면 해당 개체를 hit로 집계합니다.- 위험: 이름이나 주소의 일부만 가려 나머지가 노출돼도 성공으로 세어집니다.
- 운영 검증: 실제로는 다음을 추가로 구현해야 합니다.
- 문자/토큰 coverage 검사: 가려야 할 글자 가운데 실제로 가린 비율을 잽니다.
- 골드 span 완전 포함 검사: 탐지 span이 골드 span의 시작과 끝을 모두 덮는지 봅니다.
- 부분 탐지 분류: 부분 탐지를 놓침 목록으로 보내 재검수합니다.
4. 일관된 가명화
이름을 전부 <이름>으로 바꾸면 같은 사람이 여러 번 나온다는 정보가 사라집니다. 반복 관계가 분석에 꼭 필요할 때만 같은 원본을 같은 가명으로 바꿉니다(가명화). 합성 이름 '김철수'가 배치 전체에서 인물A로 바뀌면 이름은 지워지고 같은 인물이라는 관계는 남습니다.
가명처리는 추가 정보가 있으면 다시 개인에 연결할 수 있는 처리라서 익명처리와 보호 요구가 다릅니다. 이 절의 원본↔가명 대응표(entity_mapping)가 그 추가 정보이며, 이 표만 있으면 재식별이 됩니다. 대응표는 비식별 데이터와 다른 곳에 최소 권한으로 두고, 재식별이 필요 없으면 만들지 않습니다.
개인정보 보호법 제28조의2는 가명정보 처리 목적을 통계작성·과학적 연구·공익적 기록보존 등으로 정합니다. 분석 목적과 대응표의 보관·폐기·접속기록 절차는 개인정보보호 담당과 소방청 개인정보 보호규정(적용 범위 먼저 확인)·개인정보의 안전성 확보조치 기준 원문으로 확인합니다.
이름·번호를 모두 가려도 준식별자가 남습니다. "43세 남성, 마포구 성산동, 소규모 관서 근무"(가상 예시)처럼 하나하나는 개인정보가 아니어도, 겹쳐 놓으면 한 사람으로 좁혀집니다. 직책이 드물거나 관서가 작을수록 좁혀지기 쉽습니다. 비식별화는 이런 조합까지 줄이는 처리이므로, 주소를 행정동으로, 나이를 연령대로 일반화하거나 지우고 남은 조합으로 한 사람이 특정되는지 표본으로 확인합니다.
설계 판단
비식별의 목표는 사용 목적에 필요한 정보만 남기고 다시 알아볼 가능성을 줄이는 것입니다. 자동 결과를 공개해도 된다는 판단으로 쓰지 않습니다.
| 방식 | 맞는 상황 | 트레이드오프 | 사람이 확인할 것 |
|---|---|---|---|
| 패턴 규칙 중심 마스킹 | 전화번호·이메일·정형 ID처럼 형식이 명확할 때 | 빠르고 설명하기 쉬우나 이름·지명 문맥을 놓침 | 새 표기 형식과 오탐 표본 |
| 규칙 + NER 결합 | 비정형 이름·주소·직책 표현이 다양할 때 | 놓침을 줄이지만 지명·조직명을 개인으로 오인할 수 있음 | 놓침과 과잉 마스킹의 원문 문맥 |
| 일반화 | 나이·지역·직책 같은 준식별자가 함께 남을 때 | 분석에 쓸 세부 정보가 줄어듦 | 일반화 단위와 남은 희소 조합 |
| 일관된 가명화 | 동일 인물·개체의 반복 관계가 분석에 정말 필요할 때 | 대응표가 새로운 최고 민감 자료가 됨 | 재식별 필요성과 대응표 보관·폐기 승인 |
직접 만들기 전에 공공 AX에 공개된 다음 한국어 도구를 먼저 봅니다.
- K-PoliShield(경찰청, 로컬 탐지)
- 개인식별정보 비식별 처리
- 주소 익명화도구: 주소를 인근 랜드마크로 바꿉니다.
외부 지도 API를 부르는 도구도 있으므로 외부 호출 여부를 저장소에서 확인하고, 어느 도구든 같은 골든셋으로 재현율을 잰 뒤 씁니다.
운영 시나리오
다음 사례의 문장·식별자는 모두 학습을 위해 만든 가상 자료입니다. 실제 신고·상담 원문을 연습에 넣지 않습니다.
가상 시나리오 1: 새 사건번호 표기를 인식기가 놓친 경우
- 탐지: 합성 골든셋에 추가한 새 형식의 사건번호가 가려지지 않고 남았습니다.
- 원인 가설: 규칙이 이전 구분자와 자릿수만 알고 있었다고 봅니다.
- 대응: 해당 배치의 공개·외부 전달을 멈추고, 새 형식만 잡는 커스텀 인식기와 가리면 안 되는 일반 문자열 시험 문장을 함께 추가합니다.
- 재발 확인: 신·구 형식과 비슷한 일반 문자열을 함께 돌려 식별자만 가려지는지 사람이 확인합니다.
가상 시나리오 2: 이름 일부만 탐지됐는데 재현율이 통과한 경우
- 탐지: 집계 재현율은 기준을 통과했지만 비식별 결과를 사람이 보니 가상 이름의 한 글자만 가려지고 나머지 글자가 그대로 남았습니다.
- 원인 가설: 본문의
overlap기반 계산은 골드 span과 탐지 span이 한 글자라도 겹치면hit로 세므로, 부분 노출을 성공으로 집계했다고 봅니다. - 대응: 해당 배치의 공개·외부 전달을 멈추고 문자·토큰 coverage 또는 골드 span 완전 포함 검사를 별도 지표로 추가해 부분 탐지를 놓침으로 분리합니다.
- 재발 확인: 완전 탐지·한 글자 겹침·앞뒤 일부 누락 합성 문장을 함께 실행해 완전 포함만 통과하고 부분 노출은 사람 검토 대상으로 남는지 확인합니다.
한계와 리스크
| 리스크 | 발생 조건 | 영향 | 완화·사람 승인 |
|---|---|---|---|
| 새 표현의 놓침 | 골든셋과 인식기가 기존 형식에만 맞춰짐 | 한 건의 식별자가 외부 자료에 남을 수 있음 | 표본 재검수와 놓침 목록을 계속 보강하고 공개·배포는 사람 승인 |
| 가명 대응표 노출 | 대응표를 비식별본과 같은 저장소·권한에 둠 | 비식별본을 원본 인물에게 다시 연결할 수 있음 | 재식별이 불필요하면 대응표를 만들지 않고, 필요하면 분리·최소 권한·폐기를 보안 담당자가 승인 |
| 준식별자 조합 | 이름·번호는 가렸지만 나이·지역·희귀 직책이 함께 남음 | 조각을 결합해 특정 인물을 추정할 수 있음 | 희소 조합을 일반화·제거하고 보안된 표본 검토 후 활용 담당자 승인 |
자주 묻는 질문
Q. 골든셋 재현율이 높으면 공개해도 되나요?
아닙니다. 골든셋은 그 안에 든 표현만 검증합니다. 공개·배포 전에는 사람 표본 검토와 소속 기관 기준을 따로 통과해야 합니다.
Q. 가명 대응표는 항상 필요한가요?
아닙니다. 반복 관계 분석이 없다면 만들지 않습니다. 필요할 때만 용도·권한·보관·폐기를 먼저 승인받습니다.
Q. 과잉 마스킹은 안전하므로 무시해도 되나요?
노출 위험은 낮지만 분석에 필요한 의미까지 지우면 잘못된 결론을 낳으므로, 놓침을 늘리지 않는 범위에서 함께 검토합니다.
Q. 자동 비식별 후 외부 AI에 넣어도 되나요?
자동 비식별은 외부 전송 허가가 아닙니다. 외부 제공 여부, 남은 준식별자, 계약·보안 조건은 소속 기관 기준으로 따로 확인합니다. 확인할 문서와 담당은 AI에 개인정보가 들어가는지 묻는 사전검토와 생성형 AI 입력 확인에 있습니다.
핵심 정리
- 한국어 문장은 언어 설정(
ko)과 켜진 개체 목록을 먼저 확인합니다. 설정이 맞지 않으면 오류 없이 빈 결과가 나옵니다. - 주민등록번호 등은 내장 한국용 인식기를 켜서 쓰고, 소방 고유 번호만 직접 만들며 조사가 붙은 표기까지 시험합니다.
- 예제의 overlap 재현율은 한 글자만 겹쳐도 성공으로 세므로, 문자·토큰 coverage나 완전 포함 검사로 부분 노출을 따로 잡습니다.
- 가명화와 대응표는 반복 관계가 꼭 필요할 때만 쓰고, 처리 목적과 보관 절차는 법령 원문과 개인정보보호 담당으로 확인합니다.
- 자동 비식별은 공개나 외부 전송의 근거가 아니며, 공개·배포 전에는 사람이 소속 기관 기준으로 최종 확인합니다.
다음 단계
- 개인정보, AI에 넣기 전에 점검하기 — 자동 파이프라인 전에 block·warn 경계와 사람 확인 원칙을 다시 점검합니다.
- 119 합성 데이터로 안전하게 연습하기 — 실제 개인정보 없이 놓침·과잉 탐지·준식별자 시험 문장을 만드는 기초를 익힙니다.
- RAG 운영, 골든셋 회귀 평가와 가드레일 — 인식기·모델·규칙 변경 전후를 골든셋 회귀로 관리하는 방식을 익힙니다.