Engineering
한국어 Legal RAG에서 PII를 먼저 지우는 이유
공개 Korean PII 모델 두 개와 Schift STRONG v2를 같은 gate에서 비교했다. KDPII도 mapped subset으로 돌려보고, 우리가 이긴 범위와 아직 주장하지 않을 범위를 분리한다.
법률/상담 RAG에서 개인정보는 검색 품질 문제가 아니라 ingest 순서 문제입니다.
문서를 먼저 vector store에 넣고 나중에 마스킹하면 늦습니다. 원문 PII는 이미 embedding input, chunk store, logs, retry payload, evaluation fixtures 어딘가를 지나갔을 수 있습니다. 그래서 Schift의 기준은 단순합니다.
검색 전에 지운다. 마스킹된 텍스트만 넣는다.
이번 글은 우리가 자신 있게 말할 수 있는 범위만 적은 기록입니다. 모든 한국어 PII, 모든 판결문 비식별화 SOTA를 주장하지 않습니다. 제품 claim은 Schift STRONG v2 release gate로 제한합니다.
결론
같은 STRONG v2 gate에서 로컬 Schift v4 adapter + production postprocess는 F1 0.968을 기록했습니다.
| 대상 | rows | Precision | Recall | F1 |
|---|---|---|---|---|
| Schift local STRONG v2 | 339 | 0.947 | 0.991 | 0.968 |
seungkukim/korean-pii-masking | 339 | 0.431 | 0.338 | 0.379 |
alphagyuu/Korean-PII-Masking-BertForTokenClassification | 339 | 0.180 | 0.391 | 0.247 |
이 표가 말하는 것은 좁습니다.
Schift가 이긴 범위는 “모든 한국어 PII”가 아니라 법률/상담 RAG에 넣기 전에 반드시 줄여야 하는 구조화 식별자와 핵심 연락처입니다.
비교 판정
한 줄로 쓰면 이렇습니다.
점수판에 올린 공개 HF token classifier 두 개는 이겼습니다. 다만 논문/데이터셋/정책 레퍼런스까지 “다 이겼다”고 쓰지는 않습니다.
| 대상 | 공개 커버 범위 | STRONG v2와의 관계 | 판정 |
|---|---|---|---|
| Schift STRONG v2 | RRN/ARN, 운전면허, 카드, 전화, 주소, 계정 ID/SNS, OTP, 이메일, IP, 계좌, 사업자번호, 여권, 차량번호, URL/SNS, 희귀명 | 제품 release gate 자체 | 기준 |
seungkukim/korean-pii-masking | 이름, 전화번호, 이메일, 주민등록번호, 카드번호 | 같은 339-row STRONG v2 gate에서 실행 | Schift 승. F1 0.968 vs 0.379 |
alphagyuu/Korean-PII-Masking-BertForTokenClassification | URL, 계정, 금융, 번호, 소속, 신원, 이름, 주소 | 같은 339-row STRONG v2 gate에서 실행 | Schift 승. F1 0.968 vs 0.247 |
skan0779/korean-pii | 주민등록번호, 외국인등록번호, 운전면허번호, 여권번호 즉시 차단. 이름/전화/이메일/계좌/카드/사업자번호 조합탐지 | 정책형 DLP 레퍼런스. 동일 벤치는 아직 아님 | 직접 승패 아님. Schift는 이 방향을 STRONG v2에 흡수했고, 주소/IP/URL/SNS/차량/OTP까지 제품 gate에 포함 |
| KDPII | 한국어 대화형 PII 데이터셋. 범용 PII와 한국어 특화 PII를 함께 다룸 | 공개 dataset을 Schift coarse label로 매핑해 별도 실행 | Schift mapped/no-date strict F1 0.800, coverage F1 0.834. 같은 mapped JSONL에서 seungkukim F1 0.626 |
| K-LegalDeID | 한국 판결문 비식별화 benchmark. name, address, number, bank name, account number, security code, school, company, URL, email, ID | 자체 판결문 benchmark와 KLUEBERT-CRF 결과 | 직접 승패 아님. 2026-05-09 현재 공개 dataset/model artifact를 찾지 못해 테스트하지 못했다. 공개되면 돌려야 한다 |
그래서 제품 문장은 이렇게 좁혀야 정확합니다.
Schift STRONG v2는 우리가 같은 release gate에서 직접 실행한 공개 Korean PII HF baseline 두 개를 크게 이겼다. 그러나 K-LegalDeID나 KDPII 같은 별도 연구 benchmark 전체를 이겼다고 주장하지는 않는다.
KDPII도 돌려봤다
KDPII revised dataset은 공개되어 있습니다. PII_dataset_V3.json 기준으로 4,981개 dialogue, 53,778개 sentence, 23,965개 PNE span이 있습니다.
다만 KDPII tagset은 Schift STRONG보다 넓습니다. 예를 들어 나이, 성별, 직위, 전공, 종교, 학교, 직장, 동호회 같은 category가 포함됩니다. 이 글의 제품 claim은 그 전체가 아니라 Schift가 실제로 배포한 coarse redaction label로 매핑 가능한 subset에 한정합니다.
우리가 매핑한 것은 이름/닉네임, 전화, 이메일, 주소, URL/site, ID, IP, 계좌, 카드, 주민등록번호, 외국인등록번호, 운전면허, 여권, 차량번호, 생년월일입니다.
| KDPII mapped run | rows | Precision | Recall | F1 |
|---|---|---|---|---|
| Schift local v4 + postprocess, strict no-date | 10,143 | 0.840 | 0.764 | 0.800 |
| Schift local v4 + postprocess, coverage no-date | 10,143 | 0.883 | 0.790 | 0.834 |
seungkukim/korean-pii-masking, same mapped JSONL | 10,143 | 0.987 | 0.459 | 0.626 |
alphagyuu/..., same mapped JSONL | - | - | - | full run not completed |
여기서 strict는 one prediction이 one gold span만 맞힐 수 있는 기존 entity-F1입니다. coverage는 redaction 관점에서 큰 predicted span이 작은 gold span을 덮는 경우를 덜 불리하게 봅니다.
KDPII에서 Schift가 약한 곳도 분명합니다.
LC_ADDRESS: KDPII는서울시,종로구,종로 26처럼 짧은 주소 조각을 별도 span으로 잡습니다. Schift는 법률/상담 문서에서 위험한 주소 덩어리를 보수적으로 잡는 쪽이라 recall이 낮습니다.DT_BIRTH: 현재 STRONG v2에서는 날짜를 제외합니다. KDPII 전체 claim을 하려면 생년월일 policy를 다시 켜야 합니다.PS_NICKNAME: 대화형 nickname/pet-name boundary는 아직 legal-RAG STRONG보다 더 넓은 문제입니다.
그래서 KDPII에 대해서는 이렇게만 씁니다.
KDPII 공개 데이터셋의 Schift-mapped subset에서도 Schift는 같은 mapped JSONL로 돌린
seungkukim/korean-pii-masking보다 높았다. 하지만 KDPII 전체 33-label surface를 이겼다는 뜻은 아니다.
STRONG v2에 넣은 것
이번에 STRONG gate로 올린 범위는 다음입니다.
| category | 왜 넣었나 |
|---|---|
| RRN / ARN | 한국 PII의 핵심 직접 식별자 |
| 운전면허번호 | 법률/보험/사고 문서에서 자주 나온다 |
| 카드번호 | Luhn validation으로 false positive를 줄일 수 있다 |
| 휴대폰 +82 표기 | 상담/계약서에 국제 표기가 섞인다 |
| 지번/농촌 주소 | 도로명 주소만으로는 법률 문서 주소를 커버하지 못한다 |
| 계정 ID / SNS handle | 카카오ID, 텔레그램 handle, @handle이 상담 기록에 직접 등장한다 |
| 보안코드 / OTP | K-LegalDeID의 security code 범위와 맞다 |
기존 strong gate의 이메일, IP, 계좌, 사업자번호, 여권, 차량번호, URL/SNS, 희귀명도 유지했습니다.
공개 모델과 왜 차이가 났나
seungkukim/korean-pii-masking은 모델 카드 기준으로 이름, 전화번호, 이메일, 주민등록번호, 카드번호를 지원합니다. 겹치는 범위에서는 쓸모가 있지만, 제품 STRONG gate의 주소, 사업자번호, 계좌, IP, URL/SNS, 차량번호, 여권, OTP, 계정 ID가 상당 부분 밖에 있습니다.
alphagyuu/Korean-PII-Masking-BertForTokenClassification은 KcBERT 기반 TensorFlow token classifier이고 URL, 계정, 금융, 번호, 소속, 신원, 이름, 주소 label surface를 갖습니다. 범주는 넓어 보이지만, 우리 gate에서는 이메일을 URL 조각으로 나누거나 차량번호/여권번호를 여러 조각으로 쪼개는 span fragmentation이 컸습니다.
skan0779/korean-pii는 비교 대상이라기보다 정책 레퍼런스에 가깝습니다. 주민등록번호, 외국인등록번호, 운전면허번호, 여권번호를 regex + checksum으로 단일탐지 즉시 차단하고, 나머지 일반 개인정보는 조합탐지로 다룹니다. 이 방향성은 우리가 STRONG v2에 반영했습니다.
K-LegalDeID는 왜 중요하지만 직접 승패가 아닌가
K-LegalDeID는 EACL 2026 논문입니다. 한국 판결문 비식별화 benchmark를 만들고 KLUEBERT-CRF로 entity-level micro F1 0.9923을 보고했습니다.
이 숫자는 중요합니다. 한국 법률 문서 비식별화가 연구 장난감이 아니라 실제 제품 문제가 됐다는 강한 신호입니다.
하지만 우리 표와 직접 승패 비교하면 안 됩니다.
- K-LegalDeID는 자체 판결문 dataset과 annotation scheme 기준입니다.
- Schift STRONG v2는 법률/상담 RAG pre-ingest safety gate입니다.
- K-LegalDeID의 label은 name, address, number, bank name, account number, security code, school, company, URL, email, ID입니다.
- Schift STRONG v2는 RRN/ARN, 운전면허, 카드, 전화, 주소, 계정 ID, OTP 같은 deployable redaction category를 더 제품적으로 쪼갭니다.
그래서 K-LegalDeID는 “우리가 이겼다”의 근거가 아니라, 이 시장과 문제가 맞다는 근거입니다.
우리가 주장하지 않는 것
우리는 아직 다음 문장을 쓰면 안 됩니다.
Schift is the SOTA for all Korean legal de-identification.
이 문장은 너무 넓습니다. 대신 지금 쓸 수 있는 문장은 이쪽입니다.
공개 Korean PII token classifier 두 개를 Schift STRONG v2 release gate에 맞춰 돌리면, Schift local STRONG v2는 F1 0.968이고 공개 HF baseline은 같은 gate에서 F1 0.379 / 0.247에 그친다. 우리가 이긴 범위는 모든 한국어 PII가 아니라, 법률/상담 RAG에 넣기 전 반드시 지워야 하는 구조화 식별자와 핵심 연락처의 제품 범위다.
KDPII 공개 데이터셋의 Schift-mapped subset에서도 Schift local v4 + postprocess는 date 제외 strict F1 0.800, coverage F1 0.834를 기록했고, 같은 mapped JSONL에서
seungkukim/korean-pii-maskingF1 0.626보다 높다.
재현한 방법
로컬 리포트는 다음 산출물로 남겼습니다.
bench/pii-ko-v1/v4_repaired_compare_report.jsonbench/pii-ko-v1/public_hf_compare_strong_report.jsonbench/pii-ko-v1/kdpii_v4_report.jsonbench/pii-ko-v1/public_hf_kdpii_mapped_seungkukim_report.jsonbench/pii-ko-v1/public_hf_kdpii_mapped_alphagyuu_smoke100_report.jsonSTRONG v2 aggregate:
rows: 339tp: 337fp: 19fn: 3precision: 0.947recall: 0.991f1: 0.968공개 HF baseline:
seungkukim/korean-pii-masking: P 0.431 / R 0.338 / F1 0.379alphagyuu/Korean-PII-Masking-BertForTokenClassification: P 0.180 / R 0.391 / F1 0.247KDPII mapped run:
Schift strict no-date: P 0.840 / R 0.764 / F1 0.800Schift coverage no-date: P 0.883 / R 0.790 / F1 0.834seungkukim/korean-pii-masking: P 0.987 / R 0.459 / F1 0.626라이브 베타는 여기서 직접 만져볼 수 있습니다.
단, 라이브 Cloud endpoint는 배포 타이밍에 따라 로컬 STRONG v2보다 늦을 수 있습니다. 운영 데이터나 실제 민감 문서는 넣지 말고, 테스트용 문장으로 확인하는 것이 맞습니다.
Sources
RAG Lab 구독
schift 만들면서 직접 굴린 RAG 실험 일지. 매주 새 실험이 올라옵니다.