Open-Source AI Cookbook documentation

个人身份信息(PII)检测的 LLM 网关

Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

Open In Colab

个人身份信息(PII)检测的 LLM 网关

作者: Anthony Susevski

采用大语言模型(LLM)进行企业级应用时,常见的投诉之一就是数据隐私问题,尤其是对于处理敏感数据的团队来说。尽管开源模型通常是一个不错的选择,如果可能的话应该尝试使用,但有时我们只想快速演示一下,或者有充分的理由使用 LLM API。在这种情况下,最好采用某种网关来处理个人身份信息(PII)数据的清洗,从而降低 PII 泄露的风险。

总部位于加拿大多伦多的金融科技公司 Wealthsimple 已经为了这个目的 开源了一个代码库。在本 Notebook 中,我们将探索如何利用这个代码库,在向 LLM 提供商发出 API 调用之前,对数据进行清洗。为此,我们将使用来自AI4Privacy的 PII 数据集,并使用 Cohere 的 Command R+模型的免费试用 API,演示 Wealthsimple 的 PII 清洗功能。

首先,请按照 README 中的说明进行安装:

  1. 安装 Poetry 和 Pyenv
  2. 安装 pyenv 版本 3.11.3
  3. 安装项目所需的依赖:
brew install gitleaks
poetry install
poetry run pre-commit install
  1. 运行 cp .envrc.example .envrc 并用 API 密钥更新配置。
import os
from llm_gateway.providers.cohere import CohereWrapper
from datasets import load_dataset
import cohere
import types
import re
COHERE_API_KEY = os.environ["COHERE_API_KEY"]
DATABASE_URL = os.environ[
    "DATABASE_URL"
]  # default database url: "postgresql://postgres:postgres@postgres:5432/llm_gateway"

LLM 包装器

包装器对象是一个简单的封装器,它在发起 API 调用之前,将“清洗器”应用到输入的提示语上。使用包装器发起请求时,我们将获得一个响应和一个 db_record 对象。在深入了解更多细节之前,让我们先来看一下它的实际应用。

wrapper = CohereWrapper()
example = "Michael Smith (msmith@gmail.com, (+1) 111-111-1111) committed a mistake when he used PyTorch Trainer instead of HF Trainer."
>>> response, db_record = wrapper.send_cohere_request(
...     endpoint="generate",
...     model="command-r-plus",
...     max_tokens=25,
...     prompt=f"{example}\n\nSummarize the above text in 1-2 sentences.",
...     temperature=0.3,
... )

>>> print(response)
{'data': ['Michael Smith made a mistake by using PyTorch Trainer instead of HF Trainer.'], 'return_likelihoods': None, 'meta': {'api_version': {'version': '1'}, 'billed_units': {'input_tokens': 48, 'output_tokens': 14}}}

响应返回的是 LLM 的输出;在这个例子中,由于我们要求模型对一个已经很简短的句子进行总结,它返回了以下消息:

['Michael Smith made a mistake by using PyTorch Trainer instead of HF Trainer.']

>>> print(db_record)
{'user_input': 'Michael Smith ([REDACTED EMAIL ADDRESS], (+1) [REDACTED PHONE NUMBER]) committed a mistake when he used PyTorch Trainer instead of HF Trainer.\n\nSummarize the above text in 1-2 sentences.', 'user_email': None, 'cohere_response': {'data': ['Michael Smith made a mistake by using PyTorch Trainer instead of HF Trainer.'], 'return_likelihoods': None, 'meta': {'api_version': {'version': '1'}, 'billed_units': {'input_tokens': 48, 'output_tokens': 14}}}, 'cohere_model': 'command-r-plus', 'temperature': 0.3, 'extras': '{}', 'created_at': datetime.datetime(2024, 6, 10, 2, 16, 7, 666438), 'cohere_endpoint': 'generate'}

第二个返回项是数据库记录。该代码库是为使用 Postgres 后端而设计的;实际上,代码库自带一个使用 Docker 构建的完整前端。Postgres 数据库用于存储网关的聊天历史记录。然而,它也非常有用,因为它展示了每个请求中实际发送的数据。如我们所见,提示语经过了清洗,实际发送的内容如下:

Michael Smith ([REDACTED EMAIL ADDRESS], (+1) [REDACTED PHONE NUMBER]) committed a mistake when he used PyTorch Trainer instead of HF Trainer.\n\nSummarize the above text in 1-2 sentences.

但等等,我听到你在想。Michael Smith 不就是 PII 吗?确实是。但是这个代码库实际上并没有实现姓名清洗功能。接下来,我们将探讨在提示语中应用了哪些清洗器:

[!提示]
Cohere 的 generate 端点实际上已经被弃用,因此,如果有人能为 Cohere API 的新的 Chat 端点创建并提交集成,这将是一个非常棒的开源贡献。

清洗器!

根据他们的代码库,以下是实现的清洗器:

ALL_SCRUBBERS = [
    scrub_phone_numbers,
    scrub_credit_card_numbers,
    scrub_email_addresses,
    scrub_postal_codes,
    scrub_sin_numbers,
]

网关会依次应用每个清洗器。

这虽然有些 “hacky”(不够优雅),但如果你确实需要实现另一个清洗器,可以通过修改包装器方法来实现。以下是一个演示:

[!提示]
作者提到,SIN(社会保险号)清洗器特别容易误清洗数据,因此它会被放在最后,以确保其他与数字相关的 PII 先被清洗。

def my_custom_scrubber(text: str) -> str:
    """
    Scrub Michael Smith in text

    :param text: Input text to scrub
    :type text: str
    :return: Input text with any mentions of Michael Smith scrubbed
    :rtype: str
    """
    return re.sub(r"Michael Smith", "[REDACTED PERSON]", text, re.IGNORECASE)
original_method = wrapper.send_cohere_request


def modified_method(self, **kwargs):
    self._validate_cohere_endpoint(kwargs.get("endpoint", None))  # Unfortunate double validate cohere endpoint call
    prompt = kwargs.get("prompt", None)
    text = my_custom_scrubber(prompt)
    kwargs["prompt"] = text
    return original_method(**kwargs)


# Assign the new method to the instance
wrapper.send_cohere_request = types.MethodType(modified_method, wrapper)
>>> response, db_record = wrapper.send_cohere_request(
...     endpoint="generate",
...     model="command-r-plus",
...     max_tokens=25,
...     prompt=f"{example}\n\nSummarize the above text in 1-2 sentences.",
...     temperature=0.3,
... )

>>> print(response)
{'data': ['[REDACTED PERSON] made an error by using PyTorch Trainer instead of HF Trainer. They can be contacted at [RED'], 'return_likelihoods': None, 'meta': {'api_version': {'version': '1'}, 'billed_units': {'input_tokens': 52, 'output_tokens': 25}}}
>>> print(db_record)
{'user_input': '[REDACTED PERSON] ([REDACTED EMAIL ADDRESS], (+1) [REDACTED PHONE NUMBER]) committed a mistake when he used PyTorch Trainer instead of HF Trainer.\n\nSummarize the above text in 1-2 sentences.', 'user_email': None, 'cohere_response': {'data': ['[REDACTED PERSON] made an error by using PyTorch Trainer instead of HF Trainer. They can be contacted at [RED'], 'return_likelihoods': None, 'meta': {'api_version': {'version': '1'}, 'billed_units': {'input_tokens': 52, 'output_tokens': 25}}}, 'cohere_model': 'command-r-plus', 'temperature': 0.3, 'extras': '{}', 'created_at': datetime.datetime(2024, 6, 10, 2, 59, 58, 733195), 'cohere_endpoint': 'generate'}

如果你确实需要这样做,请务必记住,清洗器是按顺序应用的,因此,如果你的自定义清洗器与任何默认清洗器发生冲突,可能会导致一些意外行为。

例如,针对姓名的清洗,实际上有其他清洗库可以探索,这些库采用更复杂的算法来清洗 PII。这个代码库涵盖了更多的PII类型,例如 IP 地址、主机名等。然而,如果你仅仅需要删除特定的匹配项,你仍然可以使用上述代码进行处理。

数据集

让我们在一个完整的数据集上演示这个包装器的实际应用。

pii_ds = load_dataset("ai4privacy/pii-masking-200k")
pii_ds["train"][36]["source_text"]
>>> example = pii_ds["train"][36]["source_text"]

>>> response, db_record = wrapper.send_cohere_request(
...     endpoint="generate",
...     model="command-r-plus",
...     max_tokens=50,
...     prompt=f"{example}\n\nSummarize the above text in 1-2 sentences.",
...     temperature=0.3,
... )

>>> print(response)
{'data': ["The person is requesting an update on assessment results and is offering Kip 100,000 in exchange for the information and the recipient's account details."], 'return_likelihoods': None, 'meta': {'api_version': {'version': '1'}, 'billed_units': {'input_tokens': 64, 'output_tokens': 33}}}
>>> print(db_record)
{'user_input': "I need the latest update on assessment results. Please send the files to V[REDACTED EMAIL ADDRESS]. For your extra time, we'll offer you Kip 100,000 but please provide your лв account details.\n\nSummarize the above text in 1-2 sentences.", 'user_email': None, 'cohere_response': {'data': ["The person is requesting an update on assessment results and is offering Kip 100,000 in exchange for the information and the recipient's account details."], 'return_likelihoods': None, 'meta': {'api_version': {'version': '1'}, 'billed_units': {'input_tokens': 64, 'output_tokens': 33}}}, 'cohere_model': 'command-r-plus', 'temperature': 0.3, 'extras': '{}', 'created_at': datetime.datetime(2024, 6, 10, 3, 10, 51, 416091), 'cohere_endpoint': 'generate'}

常规输出

如果我们直接将文本发送到端点而不进行任何清洗,摘要结果如下所示:

 co = cohere.Client(
    api_key=os.environ['COHERE_API_KEY']


 esponse_vanilla = co.generate(
    prompt=f"{example}\n\nSummarize the above text in 1-2 sentences.",
    model="command-r-plus",
    max_tokens=50,
    temperature=0.3
response_vanilla

总结一下,在 Notebook 中,我们演示了如何使用 Wealthsimple 开源的 PII 检测示例网关,并在此基础上添加了自定义清洗器。如果你真的需要可靠的 PII 检测,确保运行自己的测试,验证你所采用的清洗算法是否真正覆盖了你的应用场景。最重要的是,尽可能在你自己托管的基础设施上部署开源模型,这将始终是构建 LLM 应用时最安全、最可靠的选择 :)

< > Update on GitHub