콘텐츠로 이동

개인정보 마스킹

SensitiveInfoMask는 SDK가 소유하는 deterministic 개인정보 detector와 마스킹 전략입니다. Registry rule ID·이름·pattern을 개인정보 종류로 추측하지 않으므로 Registry 없이 단독으로 쓸 수 있고, Registry regex가 놓친 값도 설정한 kind에 해당하면 마스킹합니다.

GuardrailConfig에서 id를 생략하고 sensitive_info만 선언합니다. 이 경로는 Registry 조회와 prompt judge LLM 호출을 하지 않습니다.

app/config.py
from llamon_agent import GuardrailConfig, SensitiveInfoMask
from llamon_agent.agent import Agent
AGENT = Agent(
model="qwen3",
provider="ollama",
output_guardrail=GuardrailConfig(
mask_replacement="[REDACTED]",
sensitive_info=[
SensitiveInfoMask(
kind="kr_rrn",
strategy="front7_v1",
),
SensitiveInfoMask(
kind="email",
strategy="domain_v1",
),
],
),
)

idsensitive_info를 모두 생략한 빈 GuardrailConfig는 거부됩니다. Registry 없는 설정에는 의미가 없는 regex_action, prompt_action, judge_llm도 설정 오류로 처리됩니다. SensitiveInfoMask 자체가 항상 마스킹 정책이므로 별도의 action="mask"는 없습니다.

기존 Registry 가드레일에 SDK 개인정보 안전망을 추가할 수 있습니다.

GuardrailConfig(
id="output-guardrail",
regex_action="mask",
prompt_action="block",
mask_replacement="[REDACTED]",
sensitive_info=[
SensitiveInfoMask(
kind="kr_rrn",
strategy="front7_v1",
),
],
)

처리 우선순위는 다음과 같습니다.

  1. Registry가 block으로 판정하면 전체 응답을 차단합니다.
  2. SDK sensitive_info가 탐지한 값에는 kind별 strategy를 적용합니다.
  3. 겹치지 않는 Registry regex match는 기존 mask_replacement로 치환합니다.

따라서 Registry regex가 주민등록번호를 탐지하지 못해도 SDK detector가 탐지하면 9001011234567900101-1******로 나갑니다. Registry regex도 같은 값을 mask로 탐지했다면 SDK의 더 구체적인 strategy가 우선합니다. 반대로 해당 Registry rule이 block이면 마스킹 결과를 반환하지 않습니다.

id가 있는 설정에서 Registry 조회·판정이 실패하면 SDK 마스킹만 하고 통과시키지 않고 기존 정책대로 fail-closed 처리합니다.

strategy를 생략하면 모든 kind에서 가장 보수적인 full_v1을 사용합니다. full_v1의 결과 토큰은 GuardrailConfig.mask_replacement입니다. 부분 마스킹 전략은 출력 형태가 이름에서 드러나며, 같은 버전 이름의 의미는 SDK 업데이트에서 바꾸지 않습니다.

kindstrategy입력 예시출력 예시
kr_rrnfull_v1900101-1234567[REDACTED]
kr_rrnfront6_v19001011234567900101-*******
kr_rrnfront7_v19001011234567900101-1******
kr_foreigner_idfull_v1900101-5123456[REDACTED]
kr_foreigner_idfront6_v19001015123456900101-*******
kr_foreigner_idfront7_v19001015123456900101-5******
emailfull_v1user@example.com[REDACTED]
emaildomain_v1user@example.com***@example.com
emaillocal_first_v1user@example.comu***@example.com
kr_phonefull_v1010-1234-5678[REDACTED]
kr_phonemiddle_v101012345678010-****-5678
payment_cardfull_v11234-5678-9012-3456[REDACTED]
payment_cardlast4_v11234567890123456****-****-****-3456

kind에 없는 strategy를 조합하거나 같은 kind를 두 번 선언하면 GuardrailConfig 생성 시점에 오류가 납니다. 예를 들어 SensitiveInfoMask(kind="email", strategy="front7_v1")은 실행까지 미뤄지지 않습니다.

부분 마스킹은 일부 정보를 의도적으로 공개합니다. 업무상 표시 필요가 확실하지 않으면 기본 full_v1을 유지하세요.

기본 inspect_parts={"text", "data", "file"}에서는 다음 위치에 같은 strategy가 적용됩니다.

  • 사용자 표시 text와 artifact text
  • DataPart의 중첩 dict·list 안 모든 문자열 값
  • artifact/task metadata 문자열
  • FilePart의 이름·URI·MIME 등 metadata

숫자·boolean·null과 JSON의 키 및 전체 구조는 유지합니다. FilePart의 bytes_b64 본문은 검사하거나 바꾸지 않습니다. inspect_parts를 좁히면 제외한 채널은 탐지도 마스킹도 하지 않습니다.

탐지는 되었지만 난독화·인코딩 때문에 원문 위치에 동일한 변환을 안전하게 적용할 수 없거나, 마스킹 후 detector가 다시 매치하면 응답을 내보내지 않고 fail-closed 차단합니다.

현재 built-in은 형식 기반으로 일관되게 탐지할 수 있는 주민등록번호, 외국인등록번호, 이메일, 한국 전화번호, 16자리 결제카드번호를 제공합니다. 이름·주소처럼 문맥에 따라 달라지는 정보는 deterministic detector가 안정적으로 span을 확정할 수 없으므로 포함하지 않습니다. 이런 의미 기반 정책은 Registry prompt의 block을 사용하세요.