文档 · 本地脱敏
本地脱敏
magpie 可以在 Agent 发出的请求离开这台电脑之前先做脱敏。API Key、密码和 Token,以及你选择的邮箱、手机号和自定义词,会以 {{API_KEY_es6eu6jk}} 这样的占位符发给模型厂商;回复里的占位符再换回原值,所以 Agent 和你的文件里始终是真值,厂商看不到。脱敏在这台电脑上、在 magpie 的网关里完成,默认关闭。
打开它
- 打开页面进入 设置 → 隐私。
- 脱敏密钥在 要遮什么 下把 脱敏密钥 设为 开启:API Key、私钥、Token 和密码。
- 个人信息(按需)把 脱敏个人信息 设为 开启,邮箱、手机号、身份证号和银行卡号也一并脱敏。打开后,下面会列出其他各类个人信息,每类有自己的开关。
- 自定义词在 脱敏词 里填不想让厂商看到的人名、项目代号或主机名,用逗号分隔。脱敏词不区分大小写 打开后,Nightjar 也会遮掉 NIGHTJAR。magpie 不认识的密钥(比如你自己网关的 key)加到 自定义脱敏规则:填它的开头,或一个正则表达式。
- 试一试把一段文字粘到 试一试,就能看到厂商实际会收到什么。粘进去的内容不会保存。
改动从下一个请求开始生效,不用重启,Agent 那边也不用改。实际做脱敏的是内置插件 隐私遮盖(redact,在 设置 → 插件),只要设置里要求了任何脱敏,它就是开着的。
没有专门的命令行命令。没有窗口时(magpie serve、Docker),可以用 magpie web 打开同一个页面,或者直接写 ~/.config/magpie/settings.json(Docker 里是 /config/magpie/settings.json)。每个请求都会重新读这个文件:
{
"redact": true,
"redactPersonal": true,
"redactWords": ["Nightjar", "db.acme-corp.cn"]
}
会遮掉什么
| 开关 | 能找到什么 |
|---|---|
| 脱敏密钥 | 私钥块(-----BEGIN … PRIVATE KEY-----)。按格式识别的 API Key:sk-…(OpenAI、Anthropic、OpenRouter)、ghp_/github_pat_、glpat-、AIza…、xox…-、sk_live_、AKIA/ASIA、hf_、gsk_、xai-、npm_、pypi-、dop_v1_、SG.,以及 oc_sk_… 这类中转站的 key。JWT。user:password@host 里的密码。.env 和配置文件里以密钥命名的字段的值:DB_PASSWORD=…、api_key: …、client_secret、token、credential。以及你的 自定义脱敏规则。 |
| 脱敏个人信息 | 邮箱、中国大陆手机号、校验位对得上的身份证号和银行卡号。默认也开着的:美国社会安全号、护照号(跟在 passport、护照或パスポート后面)、IBAN、生日(旁边有 birthday、DOB 或「生日」)、MAC 地址、序列号(跟在 S/N 后面)。默认关闭、需要自己打开的(Agent 几乎每个请求都会带):主目录里的用户名、用户名和主机名(user@host)、公网 IP 地址、云存储桶。 |
| 脱敏词 | 你填的每个词,精确匹配,换成 {{TERM_…}}。 |
| 用本地模型查找 | 在 怎么找 下面。一个在这台电脑上运行的模型(OpenAI 的 Privacy Filter,下载 1.6 GB)能找出规则找不到的东西:自由文本里的人名、地址。需要先打开 脱敏密钥 或 脱敏个人信息,找到的内容按同样的开关处理。 |
占位符是「类型 + 8 位带密钥的哈希」。同一个值每次得到同一个占位符,所以对话每一轮读起来都一样,厂商的提示词缓存也不会失效。原值只保存在内存里。
一个例子
打开 脱敏密钥 和 脱敏个人信息,并在 脱敏词 里填 Nightjar。Agent 发出:
Deploy Nightjar with OPENAI_API_KEY=sk-proj-8fK2mQx7Lp4Rt9Vw3Yz6Ab1Cd, then mail li.wei@acme-corp.cn or call 13800138000.
Deploy {{TERM_5hmsrhdc}} with OPENAI_API_KEY={{API_KEY_srhjgvja}}, then mail {{EMAIL_eh5um6mb}} or call {{PHONE_uf7iy2qq}}.
模型回复 “我已在 .env 里把 OPENAI_API_KEY 设为 {{API_KEY_srhjgvja}}” 时,Agent 读到的是真实的 key,流式文本和工具调用参数里都一样,所以它写进文件的也是真 key。模型把占位符稍微改了样子(花括号里加了空格、大小写变了)也照样能换回来。
怎么确认生效
- 事前:设置 → 隐私 里的 试一试 会显示厂商收到的文本,以及每个值的类型。
- 每个请求:在 网关 页的最近调用和 路由 日志里,被脱敏的请求会带一个盾牌徽标和数字。鼠标指上去看类型,点开看这个请求的记录。
- 一段时间:观测 → 脱敏(隐私页的 脱敏记录 也能进)按类型、Agent、供应商显示 7 天或 30 天里遮掉的值,以及每个请求在厂商眼里的原文,占位符会标出来。
记录保存在 ~/.config/magpie/masking,保留 30 天:Agent、供应商、模型,以及每个占位符的类型、长度和开头几个字符,从不保存原值。
发现敏感值时
在 发现敏感值时 下,每种类型可以选:
- 脱敏(默认):换成占位符发出。
- 提醒:原样发出,徽标用琥珀色计数。
- 拦截:请求被拦下,返回 400:“magpie held this request back: Settings › Privacy blocks API_KEY, and it has one (sk-…, 33 characters). Nothing was sent.” 消息里不会出现原值。
任务必须原样使用的值(团队邮箱、测试用的 key)加进 从不脱敏:只要整段匹配,就原样发出。
不处理的内容与限制
- 思考内容保持厂商原样。带签名的 thinking 块、Gemini 的 thoughts、Responses 的加密推理都由厂商签过名,原样发回,签名才对得上。里面只会替换请求其他地方已经遮掉的值。
- ID 和工具定义原样发送:模型 ID、消息和调用 ID、UUID、工具名、MCP 服务名、工具 schema(其中的描述文字会脱敏),这样厂商和工具还能校验它们。
- 图片和文件数据原样发送。截图里的文字不会被遮。
- 失败即不发送。脱敏已打开却运行不了(手动关掉了 隐私遮盖 插件,或本地模型开着但没响应),请求返回 503,说明什么都没发出,绝不会退回成不脱敏直接发送。
- 本地模型可以跳过。供应商的每个地址都在本机或局域网(Ollama、LM Studio)时,打开它的 请求不脱敏,请求就原样发出;命令行是
magpie provider set ollama unmasked=yes。日志里保存的仍是脱敏后的内容。 - 模型只看到占位符。它无法读懂或推理被遮掉的值,只能原样传递。需要模型读的值放进 从不脱敏。
- 规则按格式匹配。其他国家格式的电话号码、自由文本里的人名,需要 用本地模型查找,或者自己的 脱敏词 和 自定义脱敏规则。先用 试一试 测一下你自己的文本。
magpie 自己会发出什么,见 隐私。代码在 internal/redact 和 internal/masking。