의료 기록의 비식별화만으로 충분하다고 생각했지만, GPT-5가 실제로 필요로 하는 것을 보기 전까지는 그랬습니다
요약
의료 텍스트를 GPT-5나 Claude 같은 모델로 처리할 때, 단순 비식별화(redaction)는 관계 정보를 파괴하여 추론 능력을 저해합니다. 대신, 일관되고 가역적인 가명화(pseudonymization) 방식을 사용하여 개체 간의 참조 구조를 보존하는 것이 중요하며, 이는 에이전트 워크플로 구축에 필수적입니다.
핵심 포인트
- 단순 비식별화는 관계 정보를 파괴하여 모델 추론 능력을 저해합니다.
- 일관되고 가역적인 가명화(pseudonymization)가 핵심 패턴입니다.
- 개체 간의 참조 구조를 보존해야 요약, 추출 등 다운스트림 작업이 가능합니다.
- n8n, Make 같은 자동화 스택에서 이 원칙을 적용하는 것이 중요합니다.
GPT-5 또는 Claude를 사용하여 의료 텍스트를 처리하는 대부분의 팀은 동일한 두 가지 실수를 저지르는 것으로 보입니다:
- 클라우드 모델에 가공되지 않은 임상 기록 (clinical notes)을 그대로 보내고 작업을 끝냈다고 생각함
- 모델이 더 이상 기록에 대해 추론할 수 없을 정도로 너무 공격적으로 비식별화 (redact)를 수행함
두 가지 모두 좋지 않습니다.
에이전트 워크플로 (agent workflows)에 실제로 유효한 패턴은 보통 일관되고 가역적인 가명화 (pseudonymization)입니다.
다음과 같은 방식 대신:
John Smith visited on 2024-01-12 and spoke with Dr. Patel.
또는 다음과 같은 방식 대신:
[NAME] visited on [DATE] and spoke with [NAME].
다음과 같은 방식을 사용하세요:
[PATIENT_NAME_1] visited on [VISIT_DATE_1] and spoke with [CLINICIAN_NAME_1].
이 작은 변화가 GPT-5, Claude, 그리고 다운스트림 에이전트 (downstream agents)가 실제로 필요로 하는 구조를 보존합니다.
만약 여러분이 n8n, OpenClaw, Make, Zapier 또는 커스텀 OpenAI 호환 스택 (OpenAI-compatible stack)에서 자동화 기능을 구축하고 있다면, 이는 사람들이 생각하는 것보다 훨씬 더 중요합니다.
전통적인 비식별화 (redaction)의 진짜 문제
단순한 비식별화는 문자열을 보호하지만, 종종 관계를 파괴합니다.
임상 기록은 모델이 명확하게 파악해야 할 참조 정보들로 가득 차 있습니다:
- 환자가 누구인지
- 어떤 임상의 (clinician)가 무엇을 말했는지
- 동일 인물이 여러 번 등장하는지
- 두 날짜가 동일한 사건을 가리키는지
- 식별자 (identifier)가 기록 전체에 걸쳐 일관되게 반복되는지
모든 사람이 [NAME]이 되고 모든 날짜가 [DATE]가 되면, 모델은 상호 참조 (co-reference) 능력을 상실합니다.
이는 다음과 같은 매우 일반적인 워크플로들을 망가뜨립니다:
- 요약 (summarization)
- 추출 (extraction)
- 코딩 지원 (coding assistance)
- 트리아지 (triage)
- 라우팅 (routing)
- 다운스트림 에이전트 전달 (downstream agent handoffs)
차이점은 다음과 같습니다.
나쁜 비식별화 (Bad redaction)
[NAME] was admitted on [DATE]. [NAME] reported chest pain. [NAME] discussed family history with [NAME].
누가 누구인가요? 환자인가요? 부모인가요? 심장 전문의인가요? 알 수 없습니다.
더 나은 가명화 (Better pseudonymization)
[PATIENT_NAME_1] was admitted on [ADMISSION_DATE_1]. [PATIENT_NAME_1] reported chest pain. [PATIENT_NAME_1] discussed family history with [CLINICIAN_NAME_1].
이제 GPT-5는 여전히 이야기의 흐름을 따라갈 수 있습니다.
그것이 바로 핵심입니다.
저에게 깨달음을 준 Reddit 스레드
저는 r/openclaw에서 Redacta라고 불리는 OpenClaw 기술에 관한 스레드를 발견했습니다:
https://reddit.com/r/openclaw/comments/1vidd43/i_built_an_openclaw_skill_that_pseudonymises/
핵심 아이디어는 간단했습니다:
단순히 정보를 삭제하는 대신 (예: John Smith → [NAME]), 유용한 문맥을 보존할 수 있습니다: John Smith → PERSON_001
사소하게 들릴 수도 있습니다.
하지만 그렇지 않습니다.
이것은 LLM (대규모 언어 모델)에서 여전히 작동하는 노트와, 노이즈(static)로 변해버리는 노트 사이의 차이입니다.
제대로 된 가명화(Pseudonymization)란 무엇인가
실질적인 패턴은 다음과 같습니다:
- 식별자(identifiers)를 로컬에서 탐지합니다.
- 이를 안정적인 유형화된 토큰(stable typed tokens)으로 교체합니다.
- 매핑 테이블(mapping table)을 별도로 유지합니다.
- 가명화된 텍스트만 모델로 전송합니다.
- 필요한 경우에만, 그리고 가능한 한 늦게 재식별(re-identify)합니다.
예를 들어:
{
"original": "Jane Doe, DOB 1982-04-16, MRN 123456, seen by Dr. Singh on 2025-02-01",
"pseudonymized": "[PATIENT_NAME_1], DOB [DATE_OF_BIRTH_1], MRN [MRN_1], seen by [CLINICIAN_NAME_1] on [VISIT_DATE_1]"
...
그리고 로컬에서는:
{
"[PATIENT_NAME_1]": "Jane Doe",
"[DATE_OF_BIRTH_1]": "1982-04-16",
...
이 로컬 토큰 맵(token map)이 중요한 부분입니다.
이를 통해 에이전트(agents)는 상위 단계로 원본 식별자를 노출하지 않고도 노트를 바탕으로 추론할 수 있습니다.
왜 안정적인 토큰이 일반적인 플레이스홀더(placeholders)보다 나은가
안정적인 토큰은 세 가지 유용한 역할을 합니다.
1. 상호 참조(co-reference)를 보존합니다.
3행의 [PATIENT_NAME_1]은 40행의 [PATIENT_NAME_1]과 동일합니다.
2. 역할 정보를 보존합니다.
[PATIENT_NAME_1]과 [CLINICIAN_NAME_1]은 서로 교체될 수 없습니다.
3. 다운스트림(downstream) 활용성을 보존합니다.
추출 에이전트, 요약기, 코딩 워크플로우 또는 인간 검토 대기열이 여전히 노트의 내용을 파악할 수 있습니다.
에이전트 파이프라인(agent pipelines)에 있어 이것은 엄청난 차이입니다.
정규 표현식(Regex)만으로는 해결할 수 없습니다
많은 엔지니어들이 여기서 시작합니다:
import re
text = re.sub(r"\b\d{3}-\d{2}-\d{4}\b", "[SSN]", text)
...
고정된 패턴(fixed patterns)에는 그것으로 충분합니다.
하지만 전체 문제를 해결하기에는 부족합니다.
정규 표현식(Regex)은 다음과 같은 항목에는 적합합니다:
- 사회보장번호 (SSNs)
- NHS 번호 (NHS numbers)
- 의료 기록 번호 (MRNs)
- 전화번호 (phone numbers)
- 이메일 (emails)
- 생년월일 (dates of birth)
- 우편번호 (ZIP codes or postcodes)
정규 표현식(Regex)이 취약한 부분은 다음과 같습니다:
- 환자 이름과 의료진 이름의 구분
- 친척 및 간병인
- 자유 형식의 주소 (free-text addresses)
- 간접적인 연령 참조
- 직업이나 위치와 같은 맥락적 식별자 (contextual identifiers)
현실적인 아키텍처는 2단계 파이프라인(two-layer pipeline)입니다.
합리적인 아키텍처: 결정론적 방식 우선, 모델은 두 번째
레이어 1: 로컬 결정론적 매칭 (local deterministic matching)
명확한 항목에는 패턴 매칭(pattern matching)을 사용합니다.
- NHS 번호 (NHS numbers)
- 국민 보험 번호 (National Insurance numbers)
- 의료 기록 번호 (MRNs)
...
레이어 2: 맥락적 엔티티 탐지 (contextual entity detection)
모호한 엔티티(ambiguous entities)에는 로컬 모델이나 엄격하게 제어된 서비스를 사용합니다.
- 환자 vs 의료진 이름
- 친척
- 간병인
...
그 다음, 모든 것을 안정적인 타입 토큰(stable typed tokens)으로 교체합니다.
이러한 분리는 정직한 엔지니어링(engineering)일 뿐입니다.
가명화 (Pseudonymization)는 비식별화 (de-identification)와 같지 않습니다
이 지점에서 팀들이 부주의해집니다.
만약 매핑(mapping)을 역추적할 수 있다면, 해당 데이터는 여전히 규제 대상일 수 있습니다.
따라서 가명화(pseudonymization)는 마법이 아닙니다.
토큰 맵(token map)을 유지한다면, 다음 사항들을 여전히 수행해야 합니다:
- 토큰 맵 보호
- 액세스 제어 (control access)
- 사용 감사 (audit usage)
- 재식별 (re-identification)이 허용되는 범위 정의
- 가역적 매핑 (reversible mapping)이 해당 유스케이스(use case)에 수용 가능한지 여부 검토
때로는 가역적인 가명(reversible pseudonyms)이 적절할 수 있습니다.
때로는 단방향 토큰화 (one-way tokenization)나 더 엄격한 비식별화 (de-identification)가 필요합니다.
Google Sensitive Data Protection은 이 차이점에 대해 매우 명확하게 설명합니다. 이 서비스는 다음을 지원합니다:
- AES-SIV 결정론적 암호화 (AES-SIV deterministic encryption)
- FPE-FFX 형식 보존 암호화 (FPE-FFX format-preserving encryption)
- HMAC-SHA-256 해싱 (HMAC-SHA-256 hashing)
이는 문제를 올바르게 정의하기 때문에 유용합니다: 즉, 유용성(utility)을 파괴하지 않으면서 노출을 줄이는 것입니다.
반대편의 함정: 너무 많은 정보를 보존하는 것
노트를 가명화하더라도 여전히 신원이 유출될 수 있습니다.
만약 노트에 다음과 같은 내용이 남아 있다면:
- 희귀한 직업
- 아주 작은 마을
- 특이한 진단 날짜
- 매우 구체적인 연령
- 독특한 임상적 사건
이러한 내용이 남아 있다면, 해당 노트는 여전히 식별 가능할 수 있습니다.
따라서 "이름을 삭제했다"는 것만으로는 충분하지 않습니다.
때로는 더 엄격한 검토가 필요합니다.
때로는 Safe Harbor 방식의 삭제가 필요합니다.
때로는 인간의 검토 단계가 필요합니다.
AWS Comprehend Medical의 PHI (개인 건강 정보) 카테고리는 개인정보 보호가 이름보다 훨씬 광범위하다는 점을 잘 상기시켜 줍니다. 여기에는 다음과 같은 항목들이 포함됩니다:
- 연령 (age)
- 날짜 (date)
- 이름 (name)
- 전화 또는 팩스 (phone or fax)
- 이메일 (email)
- ID
- URL
- 주소 (address)
- 직업 (profession)
이것이 실제 문제에 더 가깝습니다.
실제로 고려해 볼 만한 도구들
만약 제가 내부 워크플로우를 위해 GPT-5, Claude, Grok, Qwen 또는 Llama 앞에 게이트웨이를 구축한다면, 다음 도구들을 살펴볼 것입니다:
| 옵션 | 가장 적합한 용도 |
|---|---|
| Redacta | 안정적인 레이블링된 토큰을 사용한 임상 가명화 (pseudonymization), 로컬 우선 워크플로우 및 로컬 재식별 |
| ... |
저의 주관적인 견해:
- 텍스트가 실제로 임상 데이터라면 Redacta가 가장 흥미롭습니다.
- 자체 서비스를 구축하고 싶다면 Microsoft Presidio가 가장 좋은 시작점입니다.
- 관리형 토큰화 프리미티브 (tokenization primitives)와 엔터프라이즈 제어 기능이 필요하다면 Google Sensitive Data Protection이 강력합니다.
간단한 Presidio 예시
Presidio는 라이브러리나 HTTP 서비스로 실행할 수 있기 때문에 실용적입니다.
문서에는 다음과 같은 익명화 엔드포인트가 나와 있습니다:
curl -XPOST http://localhost:3000/anonymize \
-H "Content-Type: application/json" \
-d '{
...
이것이 완전한 임상 가명화 파이프라인은 아니지만, 유용한 토대가 됩니다.
간단한 Redacta 예시
이미 OpenClaw 스타일의 자동화 환경에서 작업하고 있다면:
openclaw skills install redacta
npx -y redacta-mcp
패키징이 기대했던 것보다 더 잘 되어 있습니다.
이 프로젝트는 다음과 같은 다양한 환경에서 제공되는 것으로 설명되어 있습니다:
- OpenClaw skill
- MCP server
- TypeScript library
- Python library
- CLI
개발자들은 개인정보 보호 도구가 하나의 UI에 갇히는 것을 원하지 않기 때문에 이 점은 중요합니다.
프로덕션 파이프라인 (production pipeline)이 갖춰야 할 모습
만약 제가 실제 자동화 스택 (automation stack)을 위해 이를 구현한다면, 다음과 같이 할 것입니다:
1. 명백한 식별자(identifiers)를 로컬에서 탐지
의료 기록 번호 (MRN), NHS 번호, 사회보장번호 (SSN), 생년월일 (DOB), 이메일, 전화번호, 우편번호에 대해 결정론적 매칭 (deterministic matching)을 사용합니다.
2. 엄격하게 제어된 레이어에서 문맥적 탐지 (contextual detection) 실행
환자 이름과 의료진 이름, 친척, 간병인 및 모호한 참조를 분리합니다.
3. 안정적인 타입 토큰 (stable typed tokens)으로 교체
다음과 같이 사용합니다:
[PATIENT_NAME_1]
[CLINICIAN_NAME_1]
[DOB_1]
...
다음과 같이 사용하지 마십시오:
[NAME]
[DATE]
4. 매핑 테이블 (mapping table)을 별도로 저장
로컬에 보관하십시오. 잠금(Lock down) 처리하고, 감사(Audit)하십시오.
5. 가명화된 (pseudonymized) 노트만 모델로 전송
대상은 GPT-5, Claude, 또는 모든 OpenAI 호환 엔드포인트 (OpenAI-compatible endpoint)가 될 수 있습니다.
6. 마지막 단계에서만 재식별 (re-identify)
필요한 경우에만, 그리고 가능한 한 가장 작은 제어 범위 내에서 수행하십시오.
에이전트 워크플로우 (agent workflows)에서 이것이 더욱 중요한 이유
일회성 프롬프트 (one-off prompts)에서 상시 가동되는 자동화 (always-on automations)로 넘어갈 때 이 문제는 더욱 악화됩니다.
실제 파이프라인은 다음과 같을 수 있습니다:
로컬 탐지 (local detection) -> 가명화 (pseudonymization) -> GPT-5 추출 (extraction) -> n8n 라우팅 (routing) -> 인간 검토 (human review) -> 제어된 재식별 (controlled re-identification)
이것이 팀들이 실제로 시스템을 구축하는 방식입니다.
다음과 같은 방식이 아닙니다:
챗봇에 노트를 붙여넣기
이 점을 받아들이고 나면, 경제성 (economics) 또한 중요해집니다.
이제 단일 프롬프트에 대해 비용을 지불하는 것이 아니기 때문입니다. 여러 단계의 패스 (passes)를 거치는 워크플로우에 대해 비용을 지불하게 됩니다:
- 탐지 (detection)
- 가명화 (pseudonymization)
- 추출 (extraction)
- 검증 (validation)
- 요약 (summarization)
- 라우팅 (routing)
- 어쩌면 두 번째 검토 패스 (second review pass)
이 지점에서 정액제 컴퓨팅 (flat-rate compute)이 흥미로워집니다.
만약 귀하의 스택이 OpenAI 호환 엔드포인트를 사용한다면, Standard Compute가 여기서 유의미합니다. 왜냐하면 팀들이 토큰당 과금 (per-token billing)에 대한 불안감 없이 다단계 에이전트 흐름 (multi-step agent flows)을 실행할 수 있게 해주기 때문입니다. 안전 단계가 선택 사항이 아니라 기본 파이프라인의 일부가 될 때, 이 점은 매우 중요합니다.
n8n, Make, Zapier, OpenClaw 및 사용자 지정 자동화의 경우, 이는 동작 방식을 변경합니다. 모든 추가 패스가 청구 이벤트처럼 느껴지지 않을 때, 팀들은 부주의하게 행동할 가능성이 줄어듭니다.
저의 실질적인 권장 사항
만약 의료 기록을 중심으로 LLM 워크플로우를 구축하고 있다면, 이 두 가지 나쁜 옵션 사이에서 선택하지 마십시오:
- raw-note 프롬프팅
- 문맥 파괴적 비식별화(context-destroying redaction)
일관된 가명화(pseudonymization)를 먼저 사용하십시오.
그다음, 어느 부분에서 더 엄격한 비식별화가 필요한지 결정하십시오.
이것이 실제로 작동하는 중간 경로입니다. GPT-5나 Claude가 올바르게 추론할 수 있도록 충분한 구조를 보존하면서도, 합리적인 파이프라인을 구축하기에 충분히 노출을 줄일 수 있습니다.
개발자를 위한 핵심은 간단합니다:
privacy and utility are not enemies
bad implementations of both are
만약 에이전트가 기록을 이해해야 한다면, 구조를 제공하십시오.
단지 그들이 정말로 필요하지 않은 한 환자의 신원을 주지 마십시오.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기