你的日志比聚合站漏得更多:在一把 key 上把提示词与响应从客户端追踪里擦掉
提示词与响应经常在你自己的日志、调试器和 CI 日志里先泄漏,而不是聚合站。本文从开发者侧出发,介绍在客户端把请求与响应内容从日志中擦除的实操方法,包括日志分级、结构化脱敏、错误负载处理、CI 日志抑制,以及失败时的降级观察策略。
泄漏往往先发生在你这一侧
讨论多模型聚合站时,很多人担心的是服务端会不会留存提示词。但更常见、更隐蔽的泄漏点,其实在开发者自己的机器和流水线里:
- 本地调试时
print或console.log直接打印整个请求体。 - HTTP 调试代理或抓包工具把带
Authorization和messages的完整请求落盘。 - 错误处理里把上游返回的原始响应体拼进异常消息,再被上报到日志平台。
- CI 里跑测试或 eval 时,stdout 被采集进构建日志,而日志默认保留很久。
- 容器日志、Kubernetes events、serverless 平台日志自动捕获 stdout。
这些位置大多不由聚合站控制。要先把这一侧的出口堵住,再谈服务端留存。
先做日志分级:默认不打印正文
最有效的做法是改变默认行为,而不是依赖开发者自觉。
- 把日志内容分成几档:元信息(时间、模型、
status、耗时、request_id)、结构信息(消息条数、token 估算、工具调用名)、正文(messages内容、choices内容)。 - 默认只记录前两档。正文打印需要显式开关,例如环境变量
LLMLOGPAYLOAD=1,且只在交互式终端内生效。 - 生产环境强制关闭正文打印;开发环境也让它只在该次调试会话内有效。
这样做的好处是:即使有人随手写了 print(response),日志框架因为默认脱敏而不会把正文带出去。
结构化脱敏:在序列化前动手
在日志框架里做字符串正则匹配容易漏,更稳的方式是在对象被序列化之前替换字段。
- 写一个
redact(obj)函数,递归遍历请求和响应对象。 - 对
messages[].content、choices[].message.content、prompt、input等字段,替换成固定占位符,例如<redacted:{len}>,保留长度信息便于排查截断问题。 - 对
Authorization、api-key、x-api-key等头直接置空。 - 对工具调用的
arguments与function结果同样处理,这部分常被忽略。 - 对 base64 或长字符串先截断再打印,避免大字段污染日志。
把 redact 挂在日志记录的入口,而不是挂在每个调用点,这样新增代码路径也不会绕过。
错误负载:最容易漏的出口
异常路径是脱敏的重灾区,因为开发者往往想保留“上游原样返回”以便排查。
- 不要直接把上游响应体塞进异常消息。单独存一个错误对象,只带
status、request_id、错误码和简短的message。 - 如果必须保留原始响应用于工单,写入一个独立的、访问受限的调试目录,并在写入前做同样的脱敏。
- 日志平台的上报 SDK 常会序列化异常对象的所有属性;确认你的
redact也覆盖异常携带的request/response挂载字段。
一个可行的观察策略是:只记录“发生了什么错误”(如 401、429、超时、内容过滤)和请求的元信息,不记录触发了错误的正文。排查多数问题并不需要正文。
CI 与自动化流水线
测试和评测脚本经常把真实提示词发出去,然后把响应打印到构建日志。
- 在 CI 中把
LLMLOGPAYLOAD一类开关强制置为关闭,即使仓库里的配置文件误开也不生效。 - 评测脚本输出只写指标与判定结果,不写原始输入输出。需要复现时,用指标 + 种子 + 脱敏片段。
- 确认 CI 平台是否把 stdout 转发到第三方日志服务,以及保留期。保留期越长,越要默认关闭正文。
- 不要把含真实提示词的 fixture 提交进仓库;用合成数据或占位符。
调试代理与抓包工具
本地 HTTP 调试器很方便,但会把完整请求和响应写到磁盘或界面历史里。
- 为 LLM 请求设置单独的代理配置,只在你明确需要时开启捕获。
- 关闭“保存响应体”选项,或者把捕获文件放到临时目录,会话结束后清理。
- 注意工具是否会把历史同步到云端或分享链接;分享出去的历史同样属于泄漏。
- 如果必须保存一次完整会话用于复现,用脱敏后的副本,而不是原始抓包文件。
一把 key 下的实践约定
聚合站用同一把 key 调多个模型,请求结构大致一致,这反而让客户端脱敏更容易统一:
- 在封装层统一处理请求构造与日志,所有模型走同一个
redact出口。 - 把元信息日志(模型名、
request_id、耗时、状态码)和正文日志彻底分离,前者可以长期保留,后者默认丢弃。 - 给团队一个明确的规则:要看正文,就在本地交互式会话里看,看完即丢;不要把它带进共享日志系统。
检查清单
- 默认日志级别不包含任何
messages或choices的content。 - 异常对象在进入日志框架前已经过
redact。 - CI 中正文打印开关被强制关闭,评测输出只含指标。
- 抓包工具不落盘响应体,历史不自动同步到云端。
- 仓库里没有含真实提示词的 fixture。
- 需要复现时,用长度、哈希前缀或合成样本代替原文。
把这几件事做好,提示词与响应在到达聚合站之前就已经在你的客户端被擦掉了。剩下的服务端留存问题,才是聚合站该回答的部分。