OpenAI, Claude 또는 Gemini에 프롬프트를 보내기 전 PII(개인 식별 정보)를 비식별화하는 방법
요약
LLM 사용 시 발생할 수 있는 개인 식별 정보(PII) 유출 문제를 방지하기 위해 프롬프트를 비식별화하는 패턴을 소개합니다. 데이터를 플레이스홀더로 교체하여 모델에 전달한 후, 답변을 받을 때 다시 복구하는 3단계 프로세스를 설명합니다.
핵심 포인트
- PII를 플레이스홀더로 교체하여 모델 로그에 개인 정보가 남지 않도록 방지
- 비식별화(Redact), 모델 호출, 복구(Restore)의 3단계 패턴 활용
- 토큰화, 마스킹, 제거의 세 가지 비식별화 모드 제공
- GDPR 및 HIPAA 규정 준수를 위한 필수적인 보안 전략
사용자 텍스트를 LLM (대규모 언어 모델)에 전송한다면, 의도치 않게 개인 데이터도 함께 전송하고 있을 가능성이 높습니다. 고객 지원 메시지, 채팅 기록, 붙여넣은 양식 등이 그 예입니다. 여기에는 이름, 이메일, 전화번호, 때로는 카드 번호까지 포함되어 있으며, 이 모든 것이 프롬프트에 포함됩니다. 일단 프롬프트가 귀하의 서버를 떠나면, 해당 개인 데이터는 타인의 로그에 남게 되며, 이는 GDPR 및 HIPAA 규정 하에서 심각한 문제가 됩니다.
해결책은 대부분의 사람들이 예상하는 것보다 간단하며, 모델 사용을 포기할 필요도 없습니다. 프롬프트가 나가기 전에 개인 데이터를 비식별화(Redact)하여 안전한 버전을 모델에 보내고, 답변을 받을 때 실제 값을 다시 채워 넣는 방식입니다. 이 포스트에서는 작동하는 코드를 통해 이 패턴을 설명합니다.
3단계로 이루어진 패턴
- 비식별화 (Redact). 원문 텍스트를 가져와 각 개인 데이터 조각을
[EMAIL_1]과 같은 플레이스홀더(Placeholder)로 교체합니다. 어떤 플레이스홀더가 어떤 실제 값을 나타내는지 기록하는 작은 맵(Map)을 귀하의 측에 보관합니다. - 비식별화된 텍스트로 모델 호출. 모델은 오직 플레이스홀더만 보게 되므로, 실제 데이터는 귀하가 제어할 수 없는 로그에 절대 남지 않습니다.
- 복구 (Restore). 모델의 답변과 귀하의 맵을 사용하여 실제 값을 다시 채워 넣음으로써, 최종 출력이 사용자에게 유용하도록 만듭니다.
이것이 핵심 아이디어입니다. 개인 데이터는 플레이스홀더를 통해 왕복하며 귀하의 스택(Stack)을 벗어나지 않습니다.
실제 예시
고객 이메일을 요약하기 위해 GPT를 사용하는 고객 지원 도구를 운영한다고 가정해 봅시다. 고객이 자신의 이메일과 전화번호를 포함하여 메시지를 보냈습니다. 귀하는 요약본을 원하지만, 고객의 연락처 정보를 OpenAI로 보내고 싶지는 않습니다.
다음은 전체 흐름입니다. 비식별화 및 복구 단계를 위해 제가 직접 만든 작은 API를 사용하고 있지만, 이 두 호출을 어떻게 처리하든 그 형태는 동일합니다.
// 실제 예시: OpenAI에 어떠한 개인 데이터도 보내지 않고
// GPT를 사용하여 고객 지원 이메일을 요약합니다.
const SHIELD = "https://llm-privacy-shield.p.rapidapi.com";
...
고객의 이메일과 전화번호는 OpenAI에 절대 전달되지 않습니다. 모델은 플레이스홀더 (placeholder) 텍스트를 요약하며, 마지막에 실제 값을 다시 교체하여 지원 상담사가 읽을 수 있도록 합니다.
두 가지 호출 방식 비교
비식별화 (redact) 및 복원 (restore) 호출을 개별적으로 확인하고 싶다면 다음과 같습니다:
// 두 가지 호출 방식 요약
const HOST = "https://llm-privacy-shield.p.rapidapi.com";
const headers = {
...
비식별화 (redact) 호출은 안전한 텍스트와 token_map을 반환합니다. 사용자는 이 맵 (map)을 보유합니다. 복원 (restore) 호출은 해당 맵과 모델의 응답을 가져와 실제 답변을 재구성합니다.
세 가지 모드
비식별화는 모든 상황에 동일하게 적용되는 방식이 아닙니다. 알아두어야 할 세 가지 모드가 있습니다:
- 토큰화 (Tokenize) (가역적). 각 값을 나중에 되돌릴 수 있는 플레이스홀더 (placeholder)로 교체합니다. 답변에서 실제 값이 다시 필요한 경우에 사용합니다.
- 마스킹 (Mask). 값을
<EMAIL>과 같은 일반적인 레이블 (label)로 교체합니다. 값을 다시 복구할 필요가 없는 경우에 유용합니다. - 제거 (Remove). 값을 완전히 삭제합니다.
위의 예제에서는 복원 (restore) 단계가 토큰화 (Tokenize)에 의존하기 때문에 이를 기본값으로 사용했습니다.
호스팅된 API를 반드시 사용해야 하나요?
아니요. 직접 호스팅하고 싶다면, Microsoft Presidio는 PII (개인 식별 정보)를 탐지하고 익명화하는 데 있어 강력한 오픈 소스 (open source) 옵션입니다. 중요한 것은 비식별화 (redact) 후 복원 (restore)하는 패턴이며, 이는 직접 실행하든 서비스를 호출하든 동일하게 작동합니다.
제가 호스팅 버전을 구축한 이유는 비식별화와 복원을 한 곳에서 처리하고 싶었기 때문입니다. 프로세스 내부 (in-process)에서 실행되어 보호된 데이터가 제3자에게 절대 전달되지 않으며, 응답 시간은 1밀리초 (millisecond) 미만입니다. 이 서비스는 이메일, 전화번호, SSN (사회보장번호), 신용카드, IP 주소 및 API 키를 탐지하며, 유료 결제 없이 체험해 볼 수 있는 무료 티어 (free tier)도 제공합니다:
마치며
만약 귀하의 앱이 사용자 텍스트를 LLM (Large Language Model)으로 전송한다면, 먼저 비식별화 (redact) 단계를 거치도록 하세요. 매핑 (map) 정보를 유지한 채 모델에는 플레이스홀더 (placeholder)를 보내고, 마지막에 이를 복원하십시오. 이렇게 하면 사용자는 동일하게 유용한 결과물을 얻으면서도, 개인 데이터는 원래 있어야 할 곳에 안전하게 머물게 됩니다.
이 API를 사용하여 어떤 새로운 앱이나 기존 파이프라인 (pipeline)의 프라이버시를 강화할 수 있을까요?
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기