hyeonsangjeon/pyveil
GitHub: hyeonsangjeon/pyveil
pyveil 是一款零依赖的 Python 中间件,用于在数据到达 LLM、工具调用或日志之前对 PII 和密钥进行本地脱敏。
Stars: 3 | Forks: 0
# pyveil:面向 Python AI agent 的 PII 和密钥脱敏中间件
在敏感数据到达 LLM、工具、MCP 资源、内存存储、日志或 trace 之前将其拦截。
文档 · 指南 · 评估 · PyPI · 实用手册 · 检测参考 · 支持 · 安全
`pyveil` 是一款面向 LLM 应用和 AI agent 的本地化、无依赖脱敏中间件。它会在数据跨越应用边界之前,将高置信度的 PII 和凭据替换为确定性的、作用域内的 HMAC 占位符。 | 原始应用上下文 | 发送至模型的上下文 | | --- | --- | | `Email alice@example.com` | `Email [EMAIL:a13f7c91b0d2]` | | `api_key: sk-proj-...` | `api_key: [API_KEY:38ded98a17e7]` | | `Authorization: Bearer ...` | `[AUTH_HEADER:4fe2926b7d20]` | 无网络调用。无可逆存储库。默认情况下,检测结果中不包含原始值。 ## 试用 ``` pip install pyveil pyveil demo # 或:python -m pyveil demo ``` 或在隔离环境中运行合成演示: ``` uvx pyveil demo ``` ``` before: Email alice@example.com, call 010-1234-5678, and use API key sk-proj-... after: Email [EMAIL:...], call [PHONE:...], and use API key [API_KEY:...] found: API_KEY, EMAIL, PHONE ``` ## 从你的集成开始 选择你需要的边界,并从一个可运行的示例开始。无密钥路径使用合成输入,并在发起 provider 请求前停止。 | 你正在使用 | 安装 | 从这里开始 | 受保护的边界 | | --- | --- | --- | --- | | OpenAI Agents SDK | `pip install pyveil openai-agents` | [预分发 Runner 包装器](https://github.com/hyeonsangjeon/pyveil/blob/main/examples/openai_agents_guardrail.py) | 在 `Runner.run` 之前对输入进行脱敏;当前的 SDK 需要 Python 3.10+ | | LiteLLM SDK 或 Proxy | `pip install pyveil litellm` 或 `pip install pyveil "litellm[proxy]"` | [SDK 包装器和 Proxy 预调用 hook](https://github.com/hyeonsangjeon/pyveil/blob/main/examples/litellm_proxy_filter.py) | 在 `completion(...)` 或 proxy provider 分发之前对消息进行脱敏;当前的 LiteLLM 需要 Python 3.10+ | | OpenAI Responses API | `pip install "pyveil[openai]"` | [无密钥契约指南](https://github.com/hyeonsangjeon/pyveil/blob/main/docs/integrations/openai.md) | 在 `client.responses.create(...)` 之前的精确输入 | | Anthropic / Claude | `pip install "pyveil[anthropic]"` | [无密钥契约指南](https://github.com/hyeonsangjeon/pyveil/blob/main/docs/integrations/anthropic.md) | 在 `client.messages.create(...)` 之前的精确内容 | | Azure OpenAI | `pip install "pyveil[azure-openai]"` | [环境和 YAML 示例](https://github.com/hyeonsangjeon/pyveil/blob/main/examples/azure_openai.py) | Azure Responses API 请求之前的 prompt | | Ollama | `pip install "pyveil[ollama]"` | [本地端到端指南](https://github.com/hyeonsangjeon/pyveil/blob/main/docs/integrations/ollama.md) | 本地模型调用之前的 prompt | | MCP | `pip install pyveil` | [Server 包装器](https://github.com/hyeonsangjeon/pyveil/blob/main/examples/mcp_server_wrapper.py) | agent 上下文之前的工具结果和资源内容 | | FastAPI、日志或内存 | `pip install pyveil` | [实用手册](https://github.com/hyeonsangjeon/pyveil/blob/main/docs/cookbook.md) | 请求 payload、日志记录和内存写入 | 在生产使用之前,请确认支持的[检测形态](https://github.com/hyeonsangjeon/pyveil/blob/main/docs/redaction-reference.md)并阅读[安全契约](https://github.com/hyeonsangjeon/pyveil/blob/main/SECURITY.md)。这些示例演示了如何放置边界;它们并不宣称具有完美的 PII 召回率或合规性。 ### OpenAI Agents 和 LiteLLM 并排对比 | | OpenAI Agents SDK | LiteLLM Python SDK | LiteLLM Proxy | | --- | --- | --- | --- | | 检测点 | `Runner.run` 之前 | `litellm.completion` 之前 | provider 分发之前的 `async_pre_call_hook` | | 输入 | 字符串或结构化的 agent 输入 | 消息列表 | 当作为列表时的 `data["messages"]` | | 安全输出 | 传递给 `Runner.run` 的相同结构 | 传递给 `completion(...)` 的已脱敏消息列表 | 带有已脱敏 `messages` 的 payload 副本 | | 绕过风险 | 直接调用 `Runner.run` | 直接调用 `completion(...)` | 非消息 payload 和字段 | | 示例限制 | 不涵盖后续的工具、内存、日志或 trace | 不涵盖其他 LiteLLM API | 仅处理 completion 风格的 `messages` | 查看[完整对比](https://github.com/hyeonsangjeon/pyveil/blob/main/docs/integrations/openai-agents-vs-litellm.md)以获取安装命令、失败行为、预期输出、检测器范围和安全限制。 ## 保护 LLM 调用 将 `pyveil` 直接放置在 provider 调用之前。相同的代码适用于 OpenAI、Azure OpenAI、Anthropic、Gemini、LiteLLM 或内部网关。 ``` from pyveil import Channel, Veil veil = Veil.high( secret=b"tenant-or-run-secret", scope="tenant/session", ) messages = [ {"role": "user", "content": "Email alice@example.com about my account."}, ] safe = veil.redact_data(messages, channel=Channel.PROMPT_INPUT) response = call_llm(safe.data) # Your provider SDK call ``` provider 会接收到相同的列表和字典结构,敏感值在序列化或传输之前已被替换。 ## OpenAI 和 Claude:经过契约测试的无密钥模板 安装特定于 provider 的模板,而无需将任一 SDK 添加到 pyveil 的零依赖核心中: ``` pip install "pyveil[openai]" # OpenAI Responses API pip install "pyveil[anthropic]" # Claude Messages API ``` 这两种集成都会在最终的 SDK 边界进行本地脱敏,并返回确切的 provider 输入以供检查: ``` from pyveil.integrations.openai import ask_openai, load_settings settings = load_settings() result = ask_openai( "Write a follow-up for alice@example.com or 010-1234-5678.", settings, ) print(result.redacted_input) # exact client.responses.create(...) input print(result.output_text) ``` ``` from pyveil.integrations.anthropic import ask_anthropic, load_settings settings = load_settings() result = ask_anthropic( "Write a follow-up for alice@example.com or 010-1234-5678.", settings, ) print(result.redacted_input) # exact client.messages.create(...) content print(result.output_text) ``` 无需 API key 即可证明任一边界: ``` PYVEIL_SECRET=docs-demo-secret OPENAI_MODEL=gpt-5.6-luna \ python -m pyveil.integrations.openai --dry-run PYVEIL_SECRET=docs-demo-secret ANTHROPIC_MODEL=claude-haiku-4-5 \ python -m pyveil.integrations.anthropic --dry-run ``` ``` sent-to-openai: ... [EMAIL:17c25f8a4fe3] ... [PHONE:3f6dc5a3c9f3]. sent-to-anthropic: ... [EMAIL:0b77abd1b26b] ... [PHONE:ec56e2456ba2]. provider-response: skipped (--dry-run) ``` 该代码库还通过本地 mock HTTP transport 运行了真实的官方 SDK,并针对序列化后的 `/v1/responses` 和 `/v1/messages` JSON body 进行断言。这些测试不使用凭据,不发起网络请求,也不会产生 provider 费用。**并未**声明进行了真实的付费 API 调用。 历史 provider 模型不是免费的备用方案,可能会被淘汰;请保持 model ID 可配置,并使用 dry-run 或 mock 契约进行无成本检查。 当前的 OpenAI 和 Anthropic SDK 需要 Python 3.9+。pyveil 核心以及两条无密钥 dry-run 路径仍与 Python 3.8 到 3.14 兼容。请使用已提交的 [OpenAI 指南](docs/integrations/openai.md)和 [Anthropic / Claude 指南](docs/integrations/anthropic.md)了解配置、离线验证和边界说明。 ## Ollama:本地端到端 在相同的脱敏边界后运行本地模型。可选的集成使用 Ollama 官方的 Python 客户端,默认使用 `qwen3.5:4b`,这是一个 Q4_K_M 4.7B 模型,在配备 4K 上下文的 16GB Apple silicon Mac 上可以轻松运行: ``` pip install "pyveil[ollama]" ollama pull qwen3.5:4b ``` ``` from pyveil.integrations.ollama import ask_ollama, load_settings settings = load_settings() # OLLAMA_* + PYVEIL_* environment variables result = ask_ollama( "Write a follow-up for alice@example.com or 010-1234-5678.", settings, ) print(result.redacted_input) # The exact prompt sent to Ollama print(result.output_text) # The local model response ``` 无需加载模型即可证明边界: ``` PYVEIL_SECRET=docs-demo-secret \ python -m pyveil.integrations.ollama --dry-run ``` ``` mode: dry-run model: qwen3.5:4b host: http://127.0.0.1:11434 sent-to-ollama: Write a one-sentence support follow-up for [EMAIL:71c6727a7fa2] or [PHONE:b4b889df07ce]. findings: EMAIL=1, PHONE=1 ollama-response: skipped (--dry-run) ``` 要进行实时本地调用,请设置 `PYVEIL_SECRET` 并运行该模块。配置优先级依次为:进程环境变量、`.env`、YAML,最后是默认值: ``` PYVEIL_SECRET=a-long-random-hmac-secret \ python -m pyveil.integrations.ollama python -m pyveil.integrations.ollama \ --config examples/ollama.example.yaml --env-file .env ``` 已提交的 [`.env` 模板](examples/ollama.env.example)和 [YAML 模板](examples/ollama.example.yaml)公开了模型、主机、上下文、输出长度、temperature、timeout 和 keep-alive。pyveil 将默认上下文限制为 4096,并使用 `keep_alive=0`,以便单次调用能释放模型内存;设置 `OLLAMA_KEEP_ALIVE=5m` 可以加快重复调用的速度。 在此项目的 M1 Mac mini(16GB 内存,Ollama 0.31.2)上观察到的情况:在 4096-token 上下文下,`qwen3.5:4b` 使用了约 3.2GB 内存,冷请求耗时 8.1 秒,热请求耗时 1.3 秒。这些是本地测量结果,并非可移植的性能保证。请参阅 [Ollama 集成指南](docs/integrations/ollama.md)了解完整的设置和内存权衡。 ## Azure OpenAI:端到端 安装可选的 Azure 示例依赖项,然后从环境变量、`.env` 或 YAML 加载配置: ``` pip install "pyveil[azure-openai]" ``` ``` from pyveil.integrations.azure_openai import ask_azure_openai, load_settings settings = load_settings() # AZURE_OPENAI_* + PYVEIL_* environment variables result = ask_azure_openai( "Write a follow-up for alice@example.com or 010-1234-5678.", settings, ) print(result.redacted_input) # The exact text sent to Azure OpenAI print(result.output_text) # The model response ``` 该集成使用 Azure OpenAI 的 v1 端点和 Responses API。部署名称作为 `model` 传递;pyveil 会在 `client.responses.create(...)` 运行之前对 prompt 进行脱敏。 无需 Azure 请求即可证明边界: ``` PYVEIL_SECRET=docs-demo-secret \ python -m pyveil.integrations.azure_openai --dry-run ``` ``` mode: dry-run deployment: not configured sent-to-azure: Write a one-sentence support follow-up for [EMAIL:347ab11285a3] or [PHONE:548017338f6f]. findings: EMAIL=1, PHONE=1 azure-response: skipped (--dry-run) ``` 要进行实时调用,请导出 `AZURE_OPENAI_ENDPOINT`、`AZURE_OPENAI_DEPLOYMENT`、`AZURE_OPENAI_API_KEY`、`PYVEIL_SECRET` 以及可选的 `PYVEIL_SCOPE`,或者使用已提交的 [`.env` 模板](https://github.com/hyeonsangjeon/pyveil/blob/main/examples/azure_openai.env.example) 和 [YAML 模板](https://github.com/hyeonsangjeon/pyveil/blob/main/examples/azure_openai.example.yaml): ``` python -m pyveil.integrations.azure_openai --env-file .env python -m pyveil.integrations.azure_openai \ --config examples/azure_openai.example.yaml --env-file .env ``` 进程环境变量会覆盖 `.env`,而后者会覆盖非机密的 YAML 设置。如果将 API key 和 pyveil HMAC 密钥直接放在 YAML 中,将会被拒绝;YAML 仅指定包含它们的环境变量。
标签:AI风险缓解, Python, 人工智能, 敏感信息脱敏, 无后门, 用户模式Hook绕过, 网络安全, 逆向工具, 隐私保护