向 Notion AI / Agent 提问前扫描提示词:拦截 api_key、私钥、password、ntn_ token 等,降低把密钥写进对话的风险。
先看清成品
- 干净提示 ok;含密钥样例 hits≥1。
- 2 项 pytest 通过。
合规提醒:Notion AI / Custom Agents 只能看到你有权限的页面;回答会过时若资料过时。会议录音前告知参会者。企业需确认管理员的 AI 与数据设置。Agent API 为 public beta,能力与套餐(Business/Enterprise)以官方为准。本文不编造价格。
运行说明:无正式 NOTION_API_KEY / AGENT_ID。A 用 mock sessions;对 api.notion.com 无效 token 实测 HTTP 401。B 本地纪要抽取;C 提示词泄密扫描。2026-10-23(Asia/Shanghai)pytest 通过。
做完之后你会得到什么?
| 成果 | 说明 |
|---|---|
ai_prompt_guard.py |
扫描 |
| 样例 txt | ok/bad |
test_112c.py |
测试 |
需要准备哪些环境?
| 项目 | 说明 |
|---|---|
| Python | 3.10+ |
关键事实
| 事实 | 来源 |
|---|---|
| AI 基于你有权访问的内容回答 | 产品定位 |
| 提示词里硬编码密钥仍是事故 | 实践 |
| 企业应检查管理员 AI/数据设置 | 官方注意 |
文件结构
112-notion-ai-C-src/
├── ai_prompt_guard.py
├── sample_ok.txt
├── sample_bad.txt
└── test_112c.py
第 1 步:扫描
#!/usr/bin/env python3
"""Block secrets / high-risk payloads before sending text to Notion AI / Agent prompts.
Scans for API keys, private keys, passwords. Workspace AI sees pages you can access —
still scrub pasted credentials from the prompt itself.
"""
from __future__ import annotations
import argparse, json, re, sys
from pathlib import Path
PATTERNS = [
("aws_access_key", re.compile(r"AKIA[0-9A-Z]{16}")),
("private_key", re.compile(r"-----BEGIN (?:RSA |EC |OPENSSH )?PRIVATE KEY-----")),
("generic_api_key", re.compile(r"(?i)(?:api[_-]?key|secret|token)\s*[:=]\s*['\"]?[A-Za-z0-9_\-]{20,}")),
("password_assign", re.compile(r"(?i)password\s*[:=]\s*\S+")),
("notion_token", re.compile(r"\bntn_[A-Za-z0-9]{20,}\b")),
]
def scan(text: str) -> dict:
hits = []
for name, rx in PATTERNS:
for m in rx.finditer(text):
hits.append({"rule": name, "span": [m.start(), m.end()]})
return {"ok": not hits, "hits": hits, "char_count": len(text)}
def main(argv=None) -> int:
ap = argparse.ArgumentParser(description=__doc__)
ap.add_argument("prompt_file")
args = ap.parse_args(argv)
text = Path(args.prompt_file).read_text(encoding="utf-8")
r = scan(text)
print(json.dumps(r, ensure_ascii=False, indent=2))
return 0 if r["ok"] else 1
if __name__ == "__main__":
raise SystemExit(main())
第 2 步:测试
import json, subprocess, sys
from pathlib import Path
HERE = Path(__file__).resolve().parent
def test_ok():
r = subprocess.run([sys.executable, str(HERE/"ai_prompt_guard.py"), str(HERE/"sample_ok.txt")],
capture_output=True, text=True)
assert r.returncode == 0
assert json.loads(r.stdout)["ok"] is True
def test_bad():
r = subprocess.run([sys.executable, str(HERE/"ai_prompt_guard.py"), str(HERE/"sample_bad.txt")],
capture_output=True, text=True)
assert r.returncode == 1
assert len(json.loads(r.stdout)["hits"]) >= 1
第 3 步:运行
$ pytest 112c
.. [100%]
2 passed in 0.05s
怎么检查结果?
- ok → exit 0。
- bad → hits 非空。
调试示例
「只是演示密钥」。 一样会进日志与供应商侧。用占位符,门禁过了再发真问题。
常见问题
| 现象 | 原因 | 处理 |
|---|---|---|
| 误报 | 收紧正则 | 白名单演示句 |
| 页面里已有密钥 | 先改页面 | 再问 AI |
| Agent 工具读库 | 靠 Notion 权限 | 仍勿贴 SK |
模板规则
- 提示词无密钥。
- 敏感页限制分享。
- 门禁进 bot 发送前。
项目资源
| 用途 | 地址 |
|---|---|
| Notion AI | https://www.notion.com/product/ai |
| Agent Quickstart(官方) | https://developers.notion.com/guides/notion-agent-apis/quickstart |
| AI 帮助指南 | https://www.notion.com/help/guides/category/ai |
工作区很聪明,密钥不该出现在问题里。