AI_REDACT
AI_REDACT
개인 식별 정보(PII)는 이름, 주소, 전화번호, 이메일 주소, 세금 식별 번호, 그리고 단독으로 또는 다른 정보와 함께 개인을 식별하는 데 사용될 수 있는 기타 데이터를 포함해요. 대부분의 조직은 PII 데이터를 다루는 데 규제·규정 준수 요구 사항이 있어요. AI_REDACT는 대규모 언어 모델(LLM)을 사용해 비정형 텍스트 데이터에서 PII를 감지·위치 확인·편집(redact)하도록 돕는 완전 관리형 Cortex AI 함수예요.
본문
카테고리: String & binary 함수 (AI Functions)
AI_REDACT는 콜센터 코칭, 감정 분석, 보험·의료 분석, 머신러닝(ML) 모델 학습 등을 위한 텍스트 준비에 도움을 줄 수 있어요.
팁: 문서나 음성 데이터를 텍스트로 변환하려면 AI_PARSE_DOCUMENT 또는 AI_TRANSCRIBE를 먼저 사용해 AI_REDACT를 적용하세요. (transcribe: 받아쓰기)
AI_REDACT에는 redact(기본값)와 detect 두 가지 작동 모드가 있어요.
redact모드로 AI_REDACT를 사용해 입력 텍스트의 PII를 자리 표시자 값으로 교체해요.detect모드로 AI_REDACT를 사용해 PII 위치를 식별한 뒤, 프로그래밍 방식으로 어떤 PII를 편집할지 선택해요.
중요: AI_REDACT는 AI 모델을 사용해 최선의 노력(best-effort) 방식으로 감지와 편집을 수행해요. 조직의 데이터 개인정보 보호 정책 준수를 위해 항상 출력을 검토하세요. AI_REDACT가 데이터의 어떤 PII도 감지하거나 편집하지 못하면 Snowflake Support에 문의하세요.
구문 (Syntax)
AI_REDACT( <input> [, <categories> ] [, <return_error_details> ] [, <mode> ] )
인자 (Arguments)
필수:
<input> — 개인 식별 정보(PII)를 포함할 수 있는 텍스트 데이터를 담은 VARCHAR 값이에요.
선택:
<categories> — 편집할 PII 유형을 지정하는 문자열 값 배열이에요. 지정하지 않으면 지원되는 모든 PII 카테고리가 편집돼요. 지원되는 카테고리 목록은 감지된 PII 카테고리를 참고해요. 지원되지 않는 카테고리를 전달하면 오류가 발생해요.
<return_error_details> — 오류 발생 시 오류 세부 정보를 반환할지 여부를 나타내는 BOOLEAN 플래그예요. TRUE로 설정하면 함수는 값과 오류 메시지를 담은 OBJECT를 반환하며, 함수가 성공했는지 실패했는지에 따라 둘 중 하나는 NULL이에요. 세션 파라미터 AI_SQL_ERROR_HANDLING_USE_FAIL_ON_ERROR가 FALSE로 설정되어야 해요.
<mode> — 작동 모드를 지정하는 VARCHAR 값이에요. 허용되는 값:
redact(기본값): 감지된 PII를 [NAME], [ADDRESS] 같은 카테고리 자리 표시자로 교체해요.detect: 텍스트를 편집하지 않고 감지된 각 PII 인스턴스의 위치와 카테고리를 식별하는spans배열을 담은 OBJECT를 반환해요.
참고: mode 인자는 대소문자를 구분하지 않아요.
반환값 (Returns)
AI_REDACT의 반환 값은 mode 인자에 따라 달라져요.
Redact 모드 (기본값)
입력 텍스트가 "John Smith"였던 곳에 [NAME] 같은 카테고리 자리 표시자로 PII를 교체한 입력 텍스트를 담은 VARCHAR를 반환해요.
Detect 모드
spans 배열을 담은 OBJECT를 반환해요. 배열의 각 요소는 다음 필드를 가진 OBJECT예요:
| 필드 | 타입 | 설명 |
|---|---|---|
| category | VARCHAR | PII 카테고리. 예: NAME 또는 ADDRESS. 지원되는 카테고리는 감지된 PII 카테고리를 참고. |
| start | NUMBER | 입력 텍스트에서 감지된 PII의 시작 인덱스. |
| end | NUMBER | 입력 텍스트에서 감지된 PII의 끝 인덱스. |
| text | VARCHAR | 입력에서 일치된 PII 텍스트. |
오류 동작 (Error behavior)
기본적으로 AI_REDACT가 입력을 처리할 수 없으면 함수는 오류를 반환해요. 쿼리가 여러 행을 처리하면 전체 쿼리가 실패해요.
AI_SQL_ERROR_HANDLING_USE_FAIL_ON_ERROR가 FALSE로 설정되면, 오류 시 반환 값은 return_error_details 인자에 따라 달라져요. 다음 표는 return_error_details 인자를 기준으로 한 반환 값을 보여줘요:
| return_error_details | 반환 값 | 설명 |
|---|---|---|
| FALSE 또는 전달 안 함 | NULL | |
| TRUE | value와 error 필드가 있는 OBJECT | value: 편집된 텍스트를 담은 VARCHAR 또는 오류 발생 시 NULL. error: 오류가 발생하면 오류 메시지를 담은 VARCHAR, 함수가 성공하면 NULL. |
다중 행 쿼리에서 행 수준 오류 처리
중요: 쿼리가 모든 행에서 실패한다면 그 원인은 행 수준 오류가 아니라 알려진 제약일 수 있어요. 토큰 한도, 언어 지원, 기타 제한 사항에 대한 자세한 내용은 제한 사항을 참고하세요.
AI_REDACT는 입력 텍스트를 처리할 수 없으면 오류를 발생시켜요. 쿼리가 여러 행을 편집할 때 오류는 전체 쿼리를 실패시켜요. 다른 행으로 처리를 계속하려면 세션 파라미터 AI_SQL_ERROR_HANDLING_USE_FAIL_ON_ERROR를 FALSE로 설정해요. 그러면 오류가 쿼리를 멈추는 대신 NULL을 반환해요.
ALTER SESSION SET AI_SQL_ERROR_HANDLING_USE_FAIL_ON_ERROR=FALSE;
이 파라미터를 FALSE로 설정하면 AI_REDACT에 return_error_details 인자로 TRUE를 전달할 수도 있으며, 그러면 반환 값이 편집된 텍스트와 오류 메시지에 대한 별도 필드를 담은 OBJECT가 돼요. 이 두 필드 중 하나는 AI_REDACT 호출이 성공적으로 처리되었는지에 따라 NULL이에요.
다음 예시는 여러 행을 처리할 때 오류 처리를 사용하는 방법을 보여줘요:
- 편집되지 않은 텍스트가 있는 테이블을 만들어요.
CREATE OR REPLACE TABLE raw_table AS
SELECT 'My previous manager, Washington, used to live in Kirkland. His first name was Mike.' AS my_column
UNION ALL
SELECT 'My name is William and I live in San Francisco. You can reach me at (415).450.0973';
- 세션 파라미터를 설정해요.
ALTER SESSION SET AI_SQL_ERROR_HANDLING_USE_FAIL_ON_ERROR=FALSE;
value와error열이 있는 편집 테이블을 만들어요.
CREATE OR REPLACE TABLE redaction_table (
value VARCHAR,
error VARCHAR
);
raw_table에서 PII를 편집하고 행을redaction_table에 삽입해 편집된 텍스트와 오류 메시지를 저장해요.
INSERT INTO redaction_table
SELECT
result:value::STRING AS value,
result:error::STRING AS error
FROM (SELECT AI_REDACT(my_column, TRUE) AS result FROM raw_table);
접근 제어 요구 사항 (Access control requirements)
사용자는 SNOWFLAKE.CORTEX_USER 데이터베이스 역할이 부여된 역할을 사용해야 해요. 이 역할에 대한 자세한 내용은 Cortex LLM 권한을 참고해요.
감지된 PII 카테고리 (Detected PII categories)
AI_REDACT는 다음 PII 카테고리의 감지와 편집을 지원해요. Category 열의 값은 선택적 categories 인자에서 지원되는 문자열이에요.
| 카테고리 | 주석 |
|---|---|
| NAME | 전체 이름, 이름, 중간 이름, 성 인식 |
| PHONE_NUMBER | |
| DATE_OF_BIRTH | |
| GENDER | 남성·여성·논바이너리 인식 |
| AGE | |
| ADDRESS | 다음을 식별: 완전한 우편 주소(US, UK, CA), 거리 주소(US, UK, CA), 우편 번호(US, UK, CA), 도시(US, UK, CA), 주(US) 또는 주/도(CA), 군·자치구·타운십(US) |
| NATIONAL_ID | 사회보장번호(US) 식별 |
| PASSPORT | 여권 번호(US, UK, CA) 식별 |
| TAX_IDENTIFIER | 개인 납세자 번호(ITNs) 식별 |
| PAYMENT_CARD_DATA | 완전한 카드 정보, 카드 번호, 만료일, CVV 식별 |
| DRIVERS_LICENSE | US, UK, CA 면허 식별 |
| IP_ADDRESS |
참고: AI_REDACT는 일부 PII 카테고리에서 부분 일치를 지원해요. 예를 들어 이름만으로도 [NAME] 자리 표시자로 편집을 촉발하기에 충분해요.
detect 모드로 특정 PII 유지하기
기본적으로 AI_REDACT는 감지된 모든 PII를 자리 표시자 값으로 교체해요. 어떤 경우에는 나머지 PII를 편집하면서 특정 PII는 유지하고 싶을 수도 있어요. 예를 들어 콜센터 대본이나 고객 리뷰에서 알려진 직원 이름을 제외한 모든 이름을 편집하고 싶을 수 있어요.
detect 모드를 사용해 선택적 편집 워크플로를 구성해요:
mode인자를detect로 설정한 채 AI_REDACT를 호출해 입력 텍스트에서 PII를 식별·위치 확인해요.- 감지된 스팬(span)을 유지하려는 값의 허용 목록(allowlist)과 비교해요.
- 허용 목록에 없는 PII만 편집해요.
detect 모드 사용 예시는 감지 및 선택적 편집 예시를 참고해요.
리전 가용성 (Regional availability)
리전 가용성을 참고해요.
제한 사항 (Limitations)
- AI_REDACT는 AI 모델을 사용하며 모든 개인 식별 정보를 찾지 못할 수 있어요. 조직의 데이터 개인정보 보호 정책 준수를 위해 항상 출력을 검토하세요. AI_REDACT가 특정 PII를 편집하지 못하면 Snowflake Support에 문의하세요.
- AI_REDACT는 잘 구성된 영어 텍스트에서 가장 잘 작동해요. 다른 언어나 철자·구두점·문법 오류가 많은 텍스트에서는 성능이 달라질 수 있어요.
- AI_REDACT는 현재 US PII와 일부 UK·Canadian PII만 지원해요(감지된 PII 카테고리에서 명시된 경우).
- AI_REDACT는 현재 입력·출력할 수 있는 토큰 수가 제한돼요. 입력과 출력을 합쳐 최대 4,096 토큰이에요. 출력은 1,024 토큰으로 제한돼요. 입력 텍스트가 더 길면 더 작은 청크로 나눠 각 청크를 별도로 편집하세요. SPLIT_TEXT_RECURSIVE_CHARACTER를 사용할 수 있어요. 토큰 한도를 초과하는 텍스트 편집 예시는 청크 예시를 참고해요.
참고: 토큰은 AI 모델이 처리하는 데이터의 가장 작은 단위예요. 영어 텍스트의 경우 업계 지침은 한 토큰을 약 4자 또는 0.75단어로 간주해요.
비용 고려 사항 (Cost considerations)
AI_REDACT는 다른 Cortex AI 함수와 마찬가지로 처리되는 입력·출력 토큰 수에 따라 비용이 발생해요. 자세한 내용은 Snowflake Pricing Guide를 참고해요.
대규모 데이터셋의 토큰 사용량 추정
대규모 데이터셋에서 AI_REDACT를 실행하기 전에 대표 행에 대한 입력 토큰을 추정해 비용과 토큰 한도를 계획하세요. 테이블의 텍스트를 샘플링하고, 함수 이름으로 'ai_redact'를 사용한 AI_COUNT_TOKENS에 AI_REDACT에 전달할 것과 같은 입력 텍스트와 선택적 categories 인자를 사용해 호출하세요. 결과를 AI_REDACT 토큰 한도와 비교하세요. 행이 한도를 초과하면 편집 전에 텍스트를 청크로 나누세요. 청크 예시를 참고하세요.
AI_COUNT_TOKENS는 입력 토큰만 추정해 반환해요. 출력 토큰 수는 편집된 텍스트에 따라 달라지며 추정에 포함되지 않아요.
예시는 AI_REDACT용 AI_COUNT_TOKENS 예시를 참고해요.
편집 예시 (Redaction examples)
- 기본 편집 예시
- 엔드 투 엔드 예시
- 청크 예시
기본 편집 예시
다음 예시는 입력 텍스트에서 이름과 주소를 편집해요.
SELECT AI_REDACT(
input => 'My name is John Smith and I live at twenty third street, San Francisco.'
);
기본 편집 출력:
My name is [NAME] and I live at [ADDRESS]
다음 예시는 입력 텍스트에서 이름과 이메일 주소만 편집해요. 텍스트에는 이름만 있고, 이는 [NAME]으로 인식·편집돼요. 입력 텍스트에 이메일 주소가 없으므로 출력에 이메일 자리 표시자는 나타나지 않아요.
SELECT AI_REDACT(
input => 'My name is John and I live at twenty third street, San Francisco.',
categories => ['NAME', 'EMAIL']
);
선택적 편집 출력:
My name is [NAME] and I live at twenty third street, San Francisco.
엔드 투 엔드 예시
다음 예시는 한 테이블의 행을 처리하고 편집된 출력을 다른 테이블에 삽입해요. 비슷한 접근 방식을 사용해 기존 테이블의 열에 편집된 데이터를 저장할 수도 있어요. 편집 후 텍스트는 AI_SENTIMENT 함수에 전달되어 전반적인 감정 정보를 추출해요.
- 편집되지 않은 텍스트가 있는 테이블을 만들어요.
CREATE OR REPLACE TABLE raw_table AS
SELECT 'My previous manager, Washington, used to live in Kirkland. His first name was Mike.' AS my_column
UNION ALL
SELECT 'My name is William and I live in San Francisco. You can reach me at (415).450.0973';
- 편집되지 않은 데이터를 봐요.
SELECT * FROM raw_table;
- 편집 테이블을 만들어요.
CREATE OR REPLACE TABLE redaction_table (value VARCHAR);
raw_table에서 PII를 편집하고 행을redaction_table에 삽입해요.
INSERT INTO redaction_table
SELECT AI_REDACT(my_column) AS value FROM raw_table;
- 편집된 결과를 봐요.
SELECT * FROM redaction_table;
- 편집된 텍스트에 AI_SENTIMENT 함수를 실행해요.
SELECT
value AS redacted_text,
AI_SENTIMENT(value) AS summary_sentiment
FROM redaction_table;
청크 예시
이 예시는 긴 텍스트를 더 작은 청크로 나누고, 각 청크를 별도로 편집한 뒤, 편집된 청크를 다시 결합해 최종 출력으로 만드는 방법을 보여줘요. 이 접근 방식은 AI_REDACT의 토큰 한도를 우회해요.
- 환자 데이터가 있는 테이블을 만들어요.
CREATE OR REPLACE TABLE patients (
patient_id INT PRIMARY KEY,
patient_notes TEXT
);
- 텍스트를 청크로 나누고 각 청크에 AI_REDACT를 적용한 뒤 편집된 청크를 연결해요.
CREATE OR REPLACE TABLE final_temp_table AS
WITH chunked_data AS (
SELECT
patient_id,
chunk.value AS chunk_text,
chunk.index AS chunk_index
FROM
patients,
LATERAL FLATTEN(
input => SNOWFLAKE.CORTEX.SPLIT_TEXT_RECURSIVE_CHARACTER(
patient_notes,
'none',
1000
)
) AS chunk
WHERE
patient_notes IS NOT NULL
AND LENGTH(patient_notes) > 0
),
redacted_chunks AS (
SELECT
patient_id,
chunk_index,
chunk_text,
TO_VARIANT(results:value) AS redacted_chunk,
TO_VARIANT(results:error) AS error_string
FROM (
SELECT
patient_id,
chunk_index,
chunk_text,
AI_REDACT(chunk_text,TRUE) AS results
FROM
chunked_data
)
),
final AS (
SELECT
chunk_text AS original,
IFF(error_string IS NOT NULL, chunk_text, redacted_chunk) AS redacted_text,
patient_id,
chunk_index
FROM
redacted_chunks
)
SELECT * FROM final;
- 결과를 조회해요.
SELECT
patient_id,
LISTAGG(redacted_text, '') WITHIN GROUP (ORDER BY chunk_index) AS full_output
FROM final_temp_table
GROUP BY patient_id;
감지 및 선택적 편집 예시 (Detection and selective redaction examples)
- 기본 감지 예시
- 허용 목록을 사용한 엔드 투 엔드 예시
기본 감지 예시
다음 예시는 입력을 편집하지 않고 감지된 각 PII 인스턴스의 카테고리·위치·텍스트를 식별해 반환해요.
SELECT AI_REDACT(
input => 'My old manager, Washington, used to live in Washington. His first name was Mike.',
return_error_details => FALSE,
mode => 'detect'
);
기본 감지 출력:
{
"spans": [
{
"category": "NAME",
"end": 26,
"start": 16,
"text": "Washington"
},
{
"category": "ADDRESS",
"end": 54,
"start": 44,
"text": "Washington"
},
{
"category": "NAME",
"end": 79,
"start": 75,
"text": "Mike"
}
]
}
허용 목록을 사용한 엔드 투 엔드 예시
다음 예시는 detect 모드와 허용 목록을 사용하는 선택적 편집 워크플로를 보여줘요. 스테이징된 파일에서 유지할 이름 목록을 로드하고, detect 모드에서 AI_REDACT를 사용해 PII 위치를 식별한 뒤, 결과를 Python UDF에 전달해 허용 목록에 없는 PII만 편집해요.
- 스테이지에서 목록을 임시 테이블로 로드해 값의 허용 목록을 유지해요.
CREATE OR REPLACE TEMP TABLE string_list (value STRING);
COPY INTO string_list
FROM @mystage/allowlist.txt
FILE_FORMAT = (
TYPE = 'CSV'
RECORD_DELIMITER = '\n'
FIELD_DELIMITER = '\t' -- any char NOT in file
TRIM_SPACE = TRUE
SKIP_HEADER = 0
);
- 허용 목록 테이블을 봐요.
SELECT * FROM string_list;
허용 목록 테이블 출력:
VALUE
Mike
David
- 허용 목록을 기반으로 PII를 선택적으로 편집하는 Python UDF를 만들어요.
CREATE OR REPLACE FUNCTION redact_spans_with_allowlist(
SPAN_DATA VARIANT,
ALLOWLIST ARRAY,
ORIGINAL_TEXT STRING
)
RETURNS STRING
LANGUAGE PYTHON
RUNTIME_VERSION = '3.8'
HANDLER = 'redact_text'
AS
$$
def redact_text(span_data, allowlist, original_text):
spans = span_data.get('spans', [])
# Sort descending to maintain index integrity
sorted_spans = sorted(spans, key=lambda x: x['start'], reverse=True)
result = original_text
for span in sorted_spans:
text_val = span.get('text')
if text_val in allowlist:
continue
start, end = span['start'], span['end']
label = f"[{span['category']}]"
# Splice the string
result = result[:start] + label + result[end:]
return result
$$;
- UDF를 테스트해요.
SELECT redact_spans_with_allowlist(
PARSE_JSON('{"spans": [{"category": "NAME", "end": 26, "start": 16, "text": "Washington"}, {"category": "NAME", "end": 79, "start": 75, "text": "Mike"}]}'),
ARRAY_CONSTRUCT('Washington'), -- This will NOT be redacted
'Hello, my name is Washington and his is Mike.'
);
detect모드로 AI_REDACT를 실행해요.
CREATE OR REPLACE TABLE raw (message TEXT);
INSERT INTO raw (message) VALUES
('My old manager, Washington, used to live in Washington. His first name was Mike.');
SELECT
t.message AS message,
AI_REDACT(input=>t.message, return_error_details=>FALSE, mode=>'detect') AS spans,
redact_spans_with_allowlist(spans, l.str_list, message) AS result
FROM raw t
CROSS JOIN (
SELECT ARRAY_AGG(value) AS str_list
FROM string_list
) l;
허용 목록을 사용한 엔드 투 엔드 예시 출력:
{
"spans": [
{"category": "NAME",
"end": 26,
"start": 16,
"text": "Washington"
},
{"category": "ADDRESS",
"end": 54,
"start": 44,
"text": "Washington"
},
{"category": "NAME",
"end": 79,
"start": 75,
"text": "Mike"
}
]
}
| MESSAGE | SPANS | RESULT |
|---|---|---|
| My old manager, Washington, used to live in Washington. His first name was Mike. | My old manager, [NAME], used to live in [ADDRESS]. His first name was Mike. |
법적 고지 (Legal notices)
입력과 출력의 데이터 분류는 다음 표에 명시된 대로예요.
| 입력 데이터 분류 | 출력 데이터 분류 | 지정 |
|---|---|---|
| Usage Data | Customer Data | 일반 공급 함수는 Covered AI Features예요. 프리뷰 함수는 Preview AI Features예요. |
자세한 내용은 Snowflake AI and ML을 참고해요.