<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Llm Pipeline on ICE-ICE-BEAR-BLOG</title><link>https://ice-ice-bear.github.io/ko/tags/llm-pipeline/</link><description>Recent content in Llm Pipeline on ICE-ICE-BEAR-BLOG</description><generator>Hugo -- gohugo.io</generator><language>ko</language><lastBuildDate>Thu, 07 May 2026 00:00:00 +0900</lastBuildDate><atom:link href="https://ice-ice-bear.github.io/ko/tags/llm-pipeline/index.xml" rel="self" type="application/rss+xml"/><item><title>OPENAI Privacy Filter Reversible — 익명화가 아니라 '복원 가능한 가명화' 레이어</title><link>https://ice-ice-bear.github.io/ko/posts/2026-05-07-openai-privacy-filter-reversible-tokenization/</link><pubDate>Thu, 07 May 2026 00:00:00 +0900</pubDate><guid>https://ice-ice-bear.github.io/ko/posts/2026-05-07-openai-privacy-filter-reversible-tokenization/</guid><description>&lt;img src="https://ice-ice-bear.github.io/" alt="Featured image of post OPENAI Privacy Filter Reversible — 익명화가 아니라 '복원 가능한 가명화' 레이어" /&gt;&lt;h2 id="개요"&gt;개요
&lt;/h2&gt;&lt;p&gt;OpenAI Privacy Filter(OPF)는 텍스트에서 PII span을 검출해 &lt;code&gt;&amp;lt;PRIVATE_PERSON&amp;gt;&lt;/code&gt; 같은 typed placeholder로 마스킹하는 도구다. 기본 동작은 &lt;strong&gt;irreversible redaction&lt;/strong&gt; — 같은 사람이 여러 번 등장해도 모두 같은 generic placeholder로 뭉개진다. 관계 정보가 다 날아가는 게 단점이다.&lt;/p&gt;
&lt;p&gt;&lt;a class="link" href="https://github.com/deformatic/OPENAI-Privacy-Filter-Reversible-Tokenization" target="_blank" rel="noopener"
 &gt;deformatic/OPENAI-Privacy-Filter-Reversible-Tokenization&lt;/a&gt; 은 그 위에 &lt;strong&gt;reversible tokenization vault&lt;/strong&gt; 레이어를 옵트인으로 얹는다. 마스킹은 살리되 같은 entity는 같은 인덱스 토큰(&lt;code&gt;&amp;lt;PRIVATE_PERSON_1&amp;gt;&lt;/code&gt;)으로 묶고, 원본은 별도 vault에 저장해 인가된 경로에서만 복원한다. &lt;strong&gt;공유 시점 기준 만들어진 지 하루&lt;/strong&gt;, Apache 2.0, Python, 별 20개.&lt;/p&gt;
&lt;pre class="mermaid" style="visibility:hidden"&gt;flowchart TD
 Client["Client"] --&gt; API["PII Tokenization API"]
 API --&gt; Detector["OPF Detector &amp;lt;br/&amp;gt; (span + label + offset)"]
 Detector --&gt; Resolver["Token Resolver &amp;lt;br/&amp;gt; label + canonical_text"]
 Resolver --&gt; Writer["Vault Writer &amp;lt;br/&amp;gt; token to original (encrypted at rest)"]
 Writer --&gt; Token["tokenized_text"]
 Token --&gt; Down["downstream LLM / pipeline"]

 Auth["Authorized restore request"] --&gt; Restore["Restore API"]
 Restore --&gt; Reader["Vault Reader"]
 Reader --&gt; Out["restored_text"]&lt;/pre&gt;&lt;h2 id="기본-opf-vs-reversible-레이어"&gt;기본 OPF vs reversible 레이어
&lt;/h2&gt;&lt;p&gt;기본 OPF:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Alice emailed Bob.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;-&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&amp;lt;PRIVATE_PERSON&amp;gt; emailed &amp;lt;PRIVATE_PERSON&amp;gt;.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;→ 두 person이 같은 사람인지 다른 사람인지 정보가 사라진다.&lt;/p&gt;
&lt;p&gt;Reversible 레이어:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Alice emailed Bob. Alice&amp;#39;s phone is 555-1111.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;-&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&amp;lt;PRIVATE_PERSON_1&amp;gt; emailed &amp;lt;PRIVATE_PERSON_2&amp;gt;. &amp;lt;PRIVATE_PERSON_1&amp;gt;&amp;#39;s phone is &amp;lt;PRIVATE_PHONE_1&amp;gt;.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;별도 vault:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;schema_version&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;opf.reversible.v1&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;vault_id&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;7c1d...&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;entries&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;&amp;lt;PRIVATE_PERSON_1&amp;gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;label&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;private_person&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;text&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Alice&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;canonical_text&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Alice&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;index&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="핵심-강조"&gt;핵심 강조
&lt;/h2&gt;
 &lt;blockquote&gt;
 &lt;p&gt;&lt;em&gt;&amp;ldquo;This is &lt;strong&gt;not anonymization&lt;/strong&gt;. It is &lt;strong&gt;recoverable pseudonymization&lt;/strong&gt;. The tokenized text is useful only if the vault is protected like source PII.&amp;rdquo;&lt;/em&gt; — README&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;&lt;a class="link" href="https://gdpr-info.eu/art-4-gdpr/" target="_blank" rel="noopener"
 &gt;가명화(pseudonymization)와 익명화(anonymization)는 GDPR에서도 명확히 다른 개념&lt;/a&gt;이다. 익명화된 데이터는 더이상 personal data가 아니어서 GDPR 적용 대상이 아니지만, &lt;strong&gt;가명화는 여전히 personal data로 취급&lt;/strong&gt;된다 (&lt;a class="link" href="https://gdpr-info.eu/recitals/no-26/" target="_blank" rel="noopener"
 &gt;GDPR Recital 26&lt;/a&gt;). 즉 vault를 분리 보관해 컴플라이언스 면에서 유리하더라도, vault 자체는 원본 PII와 동등한 보안 등급으로 보호해야 한다.&lt;/p&gt;
&lt;h2 id="풀려는-문제"&gt;풀려는 문제
&lt;/h2&gt;&lt;p&gt;일반 redaction은 sensitive value를 지우지만 &lt;strong&gt;다운스트림이 필요로 하는 관계 정보까지 파괴&lt;/strong&gt;한다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;리뷰어가 같은 사람이 여러 번 등장한 걸 봐야 할 때&lt;/li&gt;
&lt;li&gt;LLM 다운스트림 task가 일관된 placeholder를 요구할 때 (Alice를 보고 Alice라고 응답해야 함)&lt;/li&gt;
&lt;li&gt;데이터 파이프라인이 enrichment / approval 후 원본 복원이 필요할 때&lt;/li&gt;
&lt;li&gt;서비스 boundary에서 tokenized text는 enclave 밖으로 나가도 OK이지만 vault는 enclave 안에 머물러야 할 때&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="디자인-원칙"&gt;디자인 원칙
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;하위호환&lt;/strong&gt; — 기존 &lt;code&gt;redact()&lt;/code&gt; 동작 그대로 유지&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;옵트인&lt;/strong&gt; — &lt;code&gt;OPF.tokenize()&lt;/code&gt; / &lt;code&gt;opf --recoverable&lt;/code&gt; 만 reversible 경로&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;모델 무수정&lt;/strong&gt; — checkpoint, decoder, Viterbi, training, eval 경로 손대지 않음&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;value 안정성&lt;/strong&gt; — 같은 &lt;code&gt;label + canonical_text&lt;/code&gt; → 같은 토큰 (vault 내에서)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;batch 친화&lt;/strong&gt; — 한 vault를 여러 입력에 재사용 가능&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;감사 가능&lt;/strong&gt; — 토큰 매핑이 명확한 schema(&lt;code&gt;opf.reversible.v1&lt;/code&gt;)로 직렬화&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;보안 인식&lt;/strong&gt; — README와 schema 모두 &lt;em&gt;&amp;ldquo;plaintext vault는 development-grade only&amp;rdquo;&lt;/em&gt; 명시&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="토큰-할당-규칙"&gt;토큰 할당 규칙
&lt;/h2&gt;&lt;p&gt;한 vault 내부에서:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;같은 label + 같은 canonical text → 같은 토큰&lt;/li&gt;
&lt;li&gt;같은 label + 다른 canonical text → 다음 인덱스&lt;/li&gt;
&lt;li&gt;다른 label + 같은 text → 다른 토큰 family&lt;/li&gt;
&lt;li&gt;source text collision → 다음 빈 인덱스로 skip&lt;/li&gt;
&lt;li&gt;겹치는 span → &lt;code&gt;ValueError&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="의미"&gt;의미
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;가명화는 &amp;ldquo;마스킹 vs 익명화 vs 가명화&amp;rdquo; 3분법 중 가장 실용적이지만 오픈소스 구현체가 거의 없었다. 이게 한 답.&lt;/li&gt;
&lt;li&gt;vault 분리 보관 → &amp;ldquo;tokenized text는 LLM provider에 보내도 PII 전송이 아니다&amp;quot;라는 &lt;strong&gt;컴플라이언스 논리 구성&lt;/strong&gt;이 가능 (단, vault 보안 보장 시).&lt;/li&gt;
&lt;li&gt;LLM 파이프라인이 점점 enterprise로 들어가면서 자주 마주치는 패턴을 명시적으로 풀이.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="참고"&gt;참고
&lt;/h2&gt;&lt;h3 id="repo"&gt;Repo
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/deformatic/OPENAI-Privacy-Filter-Reversible-Tokenization" target="_blank" rel="noopener"
 &gt;deformatic/OPENAI-Privacy-Filter-Reversible-Tokenization&lt;/a&gt; — Apache 2.0, Python, 별 20개 (작성일 기준)&lt;/li&gt;
&lt;li&gt;원본 &lt;a class="link" href="https://github.com/openai/openai-privacy-filter" target="_blank" rel="noopener"
 &gt;OpenAI Privacy Filter (OPF)&lt;/a&gt; — span 검출 + 마스킹 도구&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="privacy-개념"&gt;Privacy 개념
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://gdpr-info.eu/art-4-gdpr/" target="_blank" rel="noopener"
 &gt;GDPR Article 4 — Definitions&lt;/a&gt; (가명화 / 익명화 정의)&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://gdpr-info.eu/recitals/no-26/" target="_blank" rel="noopener"
 &gt;GDPR Recital 26 — Not applicable to anonymous data&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://www.apache.org/licenses/LICENSE-2.0" target="_blank" rel="noopener"
 &gt;Apache License 2.0&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="관련-인프라"&gt;관련 인프라
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://platform.openai.com/docs/guides/your-data" target="_blank" rel="noopener"
 &gt;OpenAI Platform — Privacy &amp;amp; Data Use&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://openai.github.io/openai-agents-js/guides/guardrails/" target="_blank" rel="noopener"
 &gt;OpenAI Agents SDK — Guardrails&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="인사이트"&gt;인사이트
&lt;/h2&gt;&lt;p&gt;가명화는 LLM 파이프라인이 컴플라이언스 영역으로 들어가는 과정에서 가장 자주 막히는 지점이다. 완전 redact하면 다운스트림 품질이 망가지고, 그대로 보내면 PII가 boundary를 넘는다. 이 레이어는 정확히 그 사이를 노린다 — 토큰화된 텍스트는 enclave 밖으로 나가도 되고, vault는 안에 머문다. 디자인이 작고 깔끔한 것도 좋다: 모델 경로 무수정, 옵트인, 기존 &lt;code&gt;redact()&lt;/code&gt; 그대로 유지. 다만 README가 반복해서 강조하듯 &lt;strong&gt;vault 자체는 원본 PII와 같은 보안 등급으로 보호&lt;/strong&gt;해야 하고, 평문 vault는 development-grade에 불과하다. 만들어진 지 하루 만에 별 20개가 붙었다는 건 이 패턴이 이미 여러 팀에서 사내 도구로 굴러가고 있었음을 시사한다 — 단지 공개된 구현체가 없었을 뿐. OPF 원본의 모델 경로를 건드리지 않은 점도 PR-able한 깔끔한 확장 디자인이라 fork보다는 upstream merge 가능성도 보인다.&lt;/p&gt;</description></item></channel></rss>