记录一下那天晚上的排查过程。客服助手的 system 里写着内部知识库地址和工单系统域名,用户追问文档在哪时模型直接把内网 URL 复述出来,测试环境里还能点开;换成 gpt-4.1-mini 后同样出现,只是触发问法更绕。

刚开始盯着「模型把工具返回的链接原样拼进回答」,折腾了半个多小时,排掉了。

排查方向其实有限,先把可能性排一排。system 里直接写了可访问的内网地址。另一种情况是只靠一句不要泄露,没有输出侧检查。

少数情况下是测试环境的域名和线上一致,风险被低估。

构造几种问法复现泄露

curl -s https://api.openai.com/v1/chat/completions -H "Authorization: Bearer $KEY" -d @probe.json | jq -r '.choices[0].message.content'

然后把地址从 system 换成占位符再渲染

python -c "print(open('sys.txt',encoding='utf-8').read().replace('http://wiki.internal','{{KB_LINK}}'))"

接着输出侧加域名白名单过滤

python guard.py --deny-hosts '*.internal,10.*,172.16.*' --on-hit replace

回归一组问法确认不再出现内网地址

python regress_leak.py --cases leak_cases.jsonl --expect none

别只看报错消失,验证要多做一步。同一组二十种问法都拿不到内网域名,回答里只出现对外可访问的文档链接,过滤日志里能看到被替换的记录。

这里还有个坑。提示词里写不要泄露只是软约束,内网地址要从上下文里移除,再在输出侧加一层硬过滤。报错文案容易误导,真正的原因往往在相邻那一层的日志里。

作者 9823189