iiTzAK/toolmask
GitHub: iiTzAK/toolmask
一个零依赖的 Python 库,在 LLM 工具调用的输出边界通过基于角色的访问控制自动遮盖敏感个人信息。
Stars: 1 | Forks: 0
# toolmask
在 LLM tool call 输出到达模型之前,通过基于角色的访问控制对其进行 PII 遮盖。零依赖。




## 为什么
Agent 会调用工具进行数据库查询、内部 API 请求和 CRM 查询,而这些工具通常会返回敏感数据:PAN、Aadhaar、银行详情、薪水。这些原始输出会被直接塞进 LLM 的 context window 中,进而可能通过模型响应、日志或可观测性追踪泄露出去。`toolmask` 处于工具输出边界,在数据到达模型之前对其进行遮盖,而基于角色的访问控制(RBAC)决定了每个调用者的角色被允许查看哪些未遮盖的内容。
```
# 问题:原始 tool 输出直接进入 LLM 上下文
def get_employee_record(emp_id):
return {"pan": "ABCDE1234F", "salary": 2500000, "email": "a@b.com"}
# 解决方案:在边界处进行 mask,在 model 看到之前
from toolmask import mask_tool_output
@mask_tool_output()
def get_employee_record(emp_id):
return {"pan": "ABCDE1234F", "salary": 2500000, "email": "a@b.com"}
# -> {"pan": "[PAN]", "salary": "[SENSITIVE]", "email": "[EMAIL]"}
```
## 安装
```
pip install toolmask-llm
```
导入名为 `toolmask`:
```
from toolmask import mask
```
或者从源码安装:
```
git clone https://github.com/iiTzAK/toolmask
pip install -e ./toolmask
```
## 快速开始
```
from toolmask import mask
mask({"pan": "ABCDE1234F", "salary": 2500000, "email": "a@b.com"})
# {"pan": "[PAN]", "salary": "[SENSITIVE]", "email": "[EMAIL]"}
```
包装一个 tool 函数,使其返回值被自动遮盖:
```
from toolmask import mask_tool_output
@mask_tool_output()
def get_employee_record(emp_id: str) -> dict:
return {"pan": "ABCDE1234F", "email": "a@b.com"}
get_employee_record("E1") # {"pan": "[PAN]", "email": "[EMAIL]"}
```
RBAC:允许特定角色查看未遮盖的特定类别:
```
from toolmask import mask_tool_output, Policy
analyst_policy = Policy.allow("analyst", {"EMAIL"})
admin_policy = Policy.allow_all("admin")
@mask_tool_output(role="analyst", policy=analyst_policy)
def get_record(emp_id: str) -> dict:
return {"pan": "ABCDE1234F", "email": "a@b.com"}
get_record("E1") # {"pan": "[PAN]", "email": "a@b.com"} <- EMAIL allowed for analyst
```
完整的可运行示例请参见 [`examples/openai_tool_calling.py`](examples/openai_tool_calling.py)。
## 检测内容
| 类别 | 匹配内容 |
|---|---|
| `PAN` | 印度 PAN 卡格式 (`ABCDE1234F`) |
| `AADHAAR` | 12 位 Aadhaar 号码,可带空格/连字符分组或不分组 |
| `IFSC` | 印度银行 IFSC 代码 (`HDFC0001234`) |
| `BANK_ACCOUNT` | 9-18 位的数字串(请参阅下文关于误报的说明) |
| `CREDIT_CARD` | 13-19 位的卡号,通过 Luhn 校验和验证 |
| `EMAIL` | 标准电子邮件地址 |
| `PHONE` | 印度手机号码,可选 `+91` 前缀 |
基于字段名(无论值的形状如何都会被遮盖,例如数字形式的薪水):匹配 `salary`、`ctc`、`compensation`、`account`/`account_number`、`ifsc`、`password`、`secret`、`token`、`api_key`、`ssn`、`dob` 的键。
## RBAC
默认拒绝:任何未明确授予角色的类别都将被遮盖,并且没有策略条目的角色将看不到任何未遮盖的内容。`Policy` 是一个简单的 角色 -> 允许类别 映射:
```
from toolmask import Policy
policy = Policy.allow("hr_admin", {"PAN", "EMAIL", "AADHAAR"})
policy = Policy.allow_all("superadmin") # sees everything unmasked
```
## 适用场景
任何调用 Python 函数并返回 `str`/`dict`/`list`/可 JSON 序列化值的事物 —— OpenAI function calling、Anthropic tool use、LangChain tools 或手动实现的 agent loop。`toolmask` 只处理 tool 的返回值,因此除了包装函数之外,无需进行任何集成。请参见 [`examples/`](examples/)。
## 设计说明
- **零运行时依赖** — 仅使用标准库 `re` 和 `copy`。
- **默认拒绝** — 没有策略,或角色未被策略涵盖,意味着所有内容都会被遮盖。
- **非变动性** — 遮盖操作始终在深拷贝上进行;您的原始数据不会被触碰。
- **基于 Regex,并诚实面对局限** — `BANK_ACCOUNT`(任何 9-18 位的数字串)具有实际的误报率,且 `PHONE` 不会根据真实的印度号码分配计划进行验证。这是一个轻量级的边界防护,不能替代 [Presidio](https://github.com/microsoft/presidio) 或 [LLM-Guard](https://github.com/protectai/llm-guard) —— 在高风险的 pipeline 中,请将它们配合使用。欢迎提交添加更好检测器或支持更多区域的 PR。
## toolmask 对比 Presidio 对比 LLM-Guard
简而言之:它们是检测器/匿名化工具;而 `toolmask` 是一个*带有 RBAC 的 tool 输出边界防护*。当您需要“根据角色遮盖我的 agent 工具返回的内容”时,请使用 `toolmask`;当您需要在自由文本上进行 ML 级别的 NER 时,请使用 Presidio/LLM-Guard。详细对比:[docs/comparison.md](docs/comparison.md)。
| | toolmask | Presidio | LLM-Guard |
|---|---|---|---|
| 重点 | Tool/function call **输出** | 通用 PII 检测/匿名化 | LLM 输入/输出扫描器 |
| 基于角色的去遮盖 (RBAC) | ✅ 内置 | ❌ | ❌ |
| 开箱即用的印度 PII (PAN/Aadhaar/IFSC) | ✅ | 部分 | 部分 |
| 依赖项 | **0** | spaCy + models | 若干 |
- 即插即用的装饰器 | ✅ | ❌ | ❌ |
## 路线图
- 印度特定格式之外的区域支持
- 每次调用的允许列表/拒绝列表覆盖
- 流式处理(随着 token 到达增量遮盖)
- 基于熵的通用密钥检测
## 许可证
MIT
标签:DLL 劫持, LLM Agent, PII保护, Python, RBAC, 大语言模型, 数据脱敏, 无后门, 逆向工具, 隐私合规