Open-Source AI Cookbook documentation
个人身份信息(PII)检测的 LLM 网关
个人身份信息(PII)检测的 LLM 网关
作者: Anthony Susevski
采用大语言模型(LLM)进行企业级应用时,常见的投诉之一就是数据隐私问题,尤其是对于处理敏感数据的团队来说。尽管开源模型通常是一个不错的选择,如果可能的话应该尝试使用,但有时我们只想快速演示一下,或者有充分的理由使用 LLM API。在这种情况下,最好采用某种网关来处理个人身份信息(PII)数据的清洗,从而降低 PII 泄露的风险。
总部位于加拿大多伦多的金融科技公司 Wealthsimple 已经为了这个目的 开源了一个代码库。在本 Notebook 中,我们将探索如何利用这个代码库,在向 LLM 提供商发出 API 调用之前,对数据进行清洗。为此,我们将使用来自AI4Privacy的 PII 数据集,并使用 Cohere 的 Command R+模型的免费试用 API,演示 Wealthsimple 的 PII 清洗功能。
首先,请按照 README 中的说明进行安装:
- 安装 Poetry 和 Pyenv
- 安装 pyenv 版本 3.11.3
- 安装项目所需的依赖:
brew install gitleaks
poetry install
poetry run pre-commit install
- 运行
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