Detectar e ocultar informações de identificação pessoal (PII)

As informações de identificação pessoal (Personally Identifiable Information, PII) incluem nomes, endereços, números de telefone, endereços de e-mail, números de identificação fiscal e outros dados que podem ser utilizados ​​(sozinhos ou com outras informações) para identificar um indivíduo. A maioria das organizações tem requisitos regulatórios e de conformidade em relação ao tratamento de dados PII. A AI_REDACT é uma função de AI do Cortex totalmente gerenciada que usa um modelo de linguagem grande (Large Language Model, LLM) para ajudar você a detectar, localizar e ocultar PII dos dados de texto não estruturados.

A AI_REDACT ajuda você a preparar texto para treinamento de call center, análise de sentimentos, análises médicas e de seguros e treinamento de modelos de machine learning (ML), entre outros casos de uso.

Dica

Use AI_PARSE_DOCUMENT ou AI_TRANSCRIBE para converter dados de documentos ou fala em texto antes de aplicar AI_REDACT.

AI_REDACT

A função AI_REDACT tem dois modos de operação: detect e redact. O padrão é redact. Use AI_REDACT no modo detect para identificar locais com PII e escolher programaticamente quais PII ocultar. Use AI_REDACT no modo redact para substituir PII no texto de entrada por valores de espaço reservado.

Importante

A função AI_REDACT detecta e oculta os dados da melhor maneira possível usando modelos de AI. Sempre revise a saída para garantir a conformidade com as políticas de privacidade de dados da sua organização. Se AI_REDACT não detectar nem ocultar as PII em seus dados, entre em contato com o suporte Snowflake.

Disponibilidade regional

Consulte Disponibilidade regional.

Limitações

  • A ocultação é realizada usando modelos de AI e pode não encontrar todas as informações de identificação pessoal. Sempre revise a saída para garantir a conformidade com as políticas de privacidade de dados da sua organização. Entre em contato com o suporte Snowflake se AI_REDACT não conseguir ocultar certas PII.

  • As funções COUNT_TOKENS e AI_COUNT_TOKENS ainda não são compatíveis com AI_REDACT.

  • No momento, AI_REDACT funciona melhor com texto em inglês bem formulado. O desempenho pode variar com outros idiomas ou textos com muitos erros de ortografia, pontuação ou gramática.

  • Atualmente, AI_REDACT é compatível apenas com PII dos US e algumas PII do UK e Canadá, conforme indicado em Categorias de PIIs detectadas.

  • AI_REDACT está atualmente limitado no número de tokens que pode receber e produzir. A entrada e a saída juntas podem ter até 4.096 tokens. A saída é limitada a 1.024 tokens. Se o texto de entrada for mais longo, divida-o em partes menores e oculte cada parte separadamente, talvez usando SPLIT_TEXT_RECURSIVE_CHARACTER. Consulte Exemplo de divisão em partes para ver um exemplo de texto oculto que excede os limites de token.

    Nota

    Um token é a menor unidade de dados processada pelo modelo de AI. Para texto em inglês, as diretrizes do setor consideram um token como aproximadamente quatro caracteres ou 0,75 palavra.

Categorias de PIIs detectadas

A função AI_REDACT oferece suporte para detectar e ocultar as seguintes categorias de PII. Os valores na coluna Category são as cadeias de caracteres compatíveis com o argumento opcional categories.

Categoria

Notas

NAME

Reconhece nome completo, primeiro nome, nome do meio e sobrenome

EMAIL

PHONE_NUMBER

DATE_OF_BIRTH

GENDER

Reconhece masculino, feminino e não binário

AGE

ADDRESS

Identifica:

  • endereço postal completo (US, UK, CA)

  • nome da rua (US, UK, CA)

  • código postal (US, UK, CA)

  • cidade (US, UK, CA)

  • estado (US) ou província (CA)

  • condado, distrito ou município (US)

NATIONAL_ID

Identifica números de segurança social (US)

PASSPORT

Identifica números de passaporte (US, UK, CA)

TAX_IDENTIFIER

Identifica números de identificação fiscal individual (ITNs)

PAYMENT_CARD_DATA

Identifica informações completas do cartão, número do cartão, data de vencimento e CVV

DRIVERS_LICENSE

Compatível com US, UK, CA

IP_ADDRESS

Nota

O AI_REDACT oferece suporte a correspondências parciais para algumas categorias de PII. Por exemplo, apenas o primeiro nome é suficiente para acionar a ocultação de [NAME] usando um espaço reservado.

Reter PII específicas com o modo de detecção

Por padrão, a AI_REDACT substitui todas as PII detectadas por valores de espaço reservado. Em alguns casos, você talvez queira manter certas PII enquanto oculta o restante. Por exemplo, você pode ocultar todos os nomes em transcrições de call center ou avaliações de clientes, exceto os nomes de funcionários conhecidos.

Use o modo detect para criar um fluxo de trabalho de ocultação seletiva:

  1. Chame AI_REDACT com o argumento mode definido como``detect`` para identificar e localizar PII no texto de entrada.

  2. Compare os intervalos detectados com uma lista de permissão de valores que você deseja manter.

  3. Oculte apenas as PII que não estão na lista de permissão.

Quando você chama AI_REDACT no modo detect, a função retorna um OBJECT contendo um matriz spans. Cada elemento da matriz é um OBJECT com os seguintes campos:

Campo

Tipo

Descrição

category

VARCHAR

A categoria PII, como NAME ou ADDRESS. Consulte Categorias de PIIs detectadas para ver as categorias compatíveis.

start

NUMBER

O índice inicial das PII detectadas no texto de entrada.

end

NUMBER

O índice final das PII detectadas no texto de entrada.

text

VARCHAR

O texto das PII correspondentes da entrada.

Para conferir exemplos de uso do modo detect, consulte Exemplos de detecção e ocultação seletiva.

Tratar erros no nível da linha em consultas de várias linhas

Importante

Se sua consulta falhar em todas as linhas, a causa pode ser uma restrição conhecida, e não um erro no nível da linha. Consulte Limitações para obter detalhes sobre limites de token, suporte a idiomas e outras restrições.

A função AI_REDACT vai gerar um erro se não puder processar o texto de entrada. Quando uma consulta oculta várias linhas, um erro gera uma falha em toda a consulta. Para permitir que o processamento continue com outras linhas, você pode definir o parâmetro de sessão AI_SQL_ERROR_HANDLING_USE_FAIL_ON_ERROR como FALSE. Os erros retornam NULL em vez de interromper a consulta.

ALTER SESSION SET AI_SQL_ERROR_HANDLING_USE_FAIL_ON_ERROR=FALSE;
Copy

Com esse parâmetro definido como FALSE, você também pode passar TRUE como argumento final para AI_REDACT, o que faz com que o valor de retorno seja um OBJECT que contém campos separados para o texto oculto e qualquer mensagem de erro. Um desses campos será NULL, dependendo se a chamada AI_REDACT foi processada com sucesso.

O exemplo a seguir mostra como usar o tratamento de erros ao processar várias linhas:

  1. Crie uma tabela com texto não oculto.

    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';
    
    Copy
  2. Defina o parâmetro de sessão.

    ALTER SESSION SET AI_SQL_ERROR_HANDLING_USE_FAIL_ON_ERROR=FALSE;
    
    Copy
  3. Crie uma tabela de ocultação com colunas para value e error.

    CREATE OR REPLACE TABLE redaction_table (
      value VARCHAR,
      error VARCHAR
      );
    
    Copy
  4. Oculte as PII de raw_table e insira as linhas em redaction_table para armazenar o texto oculto e as mensagens de erro.

    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);
    
    Copy

Considerações sobre custo

AI_REDACT gera custos conforme o número de tokens de entrada e saída processados, assim como nas outras funções da Cortex AI. Consulte o Guia de preços do Snowflake para obter detalhes.

Exemplos de ocultação

Exemplos básicos de ocultação

O exemplo a seguir oculta um nome e um endereço do texto de entrada.

SELECT AI_REDACT(
  input => 'My name is John Smith and I live at twenty third street, San Francisco.'
  );
Copy

Saída de ocultação básica:

My name is [NAME] and I live at [ADDRESS]

O exemplo a seguir oculta apenas nomes e endereços de e-mail do texto de entrada. Observe que o texto contém apenas o primeiro nome, que é reconhecido e oculto como [NAME]. O texto de entrada não contém um endereço de e-mail, portanto, nenhum espaço reservado de e-mail aparece na saída.

SELECT AI_REDACT(
  input => 'My name is John and I live at twenty third street, San Francisco.',
  categories => ['NAME', 'EMAIL']
  );
Copy

Saída de ocultação seletiva:

My name is [NAME] and I live at twenty third street, San Francisco.

Exemplo de ponta a ponta

O exemplo a seguir processa linhas de uma tabela e insere a saída ocultada em outra tabela. Você pode usar uma abordagem semelhante para armazenar os dados ocultos em uma coluna de uma tabela existente. Após a ocultação, o texto será passado para a função AI_SENTIMENT para extrair informações de sentimento gerais.

  1. Crie uma tabela com texto não oculto.

    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';
    
    Copy
  2. Visualize os dados não ocultos.

    SELECT * FROM raw_table;
    
    Copy
  3. Crie uma tabela de ocultação.

    CREATE OR REPLACE TABLE redaction_table (value VARCHAR);
    
    Copy
  4. Oculte as PII de raw_table e insira as linhas em``redaction_table``.

    INSERT INTO redaction_table
      SELECT AI_REDACT(my_column) AS value FROM raw_table;
    
    Copy
  5. Visualize os resultados ocultos.

    SELECT * FROM redaction_table;
    
    Copy
  6. Execute a função AI_SENTIMENT no texto oculto.

    SELECT
        value AS redacted_text,
        AI_SENTIMENT(value) AS summary_sentiment
      FROM redaction_table;
    
    Copy

Exemplo de divisão em partes

Este exemplo ilustra como ocultar PII em texto longo, dividindo o texto em partes menores, ocultando cada parte separadamente e reunindo as partes ocultas na saída final. Essa abordagem é uma solução alternativa para os limites de token de AI_REDACT.

  1. Crie uma tabela com dados do paciente.

    CREATE OR REPLACE TABLE patients (
      patient_id INT PRIMARY KEY,
      patient_notes TEXT
      );
    
    Copy
  2. Divida o texto em partes, aplique AI_REDACT a cada parte e concatene as partes ocultas.

    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;
    
    Copy
  3. Consulte os resultados.

    SELECT
        patient_id,
        LISTAGG(redacted_text, '') WITHIN GROUP (ORDER BY chunk_index) AS full_output
      FROM final_temp_table
      GROUP BY patient_id;
    
    Copy

Exemplos de detecção e ocultação seletiva

Exemplo de detecção básica

O exemplo a seguir identifica e retorna a categoria, o local e o texto de cada instância de PII detectada sem ocultar a entrada.

SELECT AI_REDACT(
    input => 'My old manager, Washington, used to live in Washington. His first name was Mike.',
    return_error_details => FALSE,
    mode => 'detect'
    );
Copy

Saída de detecção básica:

{
  "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"
    }
  ]
}

Exemplo completo com lista de permissão

O exemplo a seguir demonstra um fluxo de trabalho de ocultação seletiva que utiliza o modo detect e uma lista de permissão. Ele carrega uma lista de nomes a serem retidos de um arquivo preparado, usa AI_REDACT no modo detect para identificar locais com PII e depois passa os resultados para uma UDF Python que oculta apenas as PII que não estão na lista de permissão.

  1. Para reter uma lista de permissão de valores, carregue-a de uma área de preparação para uma tabela temporária.

    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
        );
    
    Copy
  2. Visualizar a tabela da lista de permissão

    SELECT * FROM string_list;
    
    Copy

    Saída da tabela da lista de permissão:

    VALUE
    Mike
    David
    
  3. Crie uma UDF Python que oculte seletivamente as PII com base na lista de permissão.

    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
      $$;
    
    Copy
  4. Teste a 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.'
      );
    
    Copy
  5. Execute AI_REDACT no modo detect.

    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;
    
    Copy

Exemplo completo de saída com lista de permissão:

MESSAGE

SPANS

RESULT

Meu antigo gerente, Washington, costumava morar em Washington. O nome dele era Mike.

{
  "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"
    }
  ]
}
Copy

Meu antigo gerente, [NAME], costumava morar em [ADDRESS]. O nome dele era Mike.