
1. 项目概述这不是“泄露”而是系统提示词的意外暴露现象最近在多个技术社区和AI应用讨论区里“system_prompts_leaks”这个短语突然高频出现不是作为某个具体工具的名字也不是某次黑客攻击的代号而是一种可复现、可验证、非恶意但极具风险的技术现象——它描述的是当大语言模型LLM服务在特定交互逻辑、错误处理机制或前端渲染策略下本应严格隐藏的 system prompt 内容被意外拼接、截断、回显甚至完整返回给终端用户。我第一次遇到这个问题是在调试一个自研的客服对话中台时用户发来一句“请重置对话”后端返回的 JSON 响应里居然混入了一段带缩进的 YAML 片段开头赫然是# Role: Customer Support Agent。当时我立刻停掉所有日志上报关掉测试流量花了三小时逐层排查——最后发现问题出在前端把 model 的 raw response stream 拆包时误将 token 缓存区里尚未 flush 的初始化上下文当作了用户可见内容。这件事让我意识到system prompt 的“泄露”从来不是靠渗透或提权实现的它更像是一扇没关严的门风一吹就开。这个词之所以成为热搜并非因为出现了大规模数据 breach而是因为它精准戳中了当前 AI 应用开发中最普遍却最被忽视的盲区我们花大力气设计精巧的 system prompt却几乎没人认真考虑过它在真实链路中如何被封装、传递、隔离与销毁。它不涉及越权访问不依赖漏洞利用甚至不违反任何 API 协议——但它直接动摇了 prompt engineering 的根基如果用户能看见你写给模型的“耳语”那所有角色设定、安全护栏、格式约束、知识边界就都成了透明玻璃墙。适合关注这个话题的不是红队工程师而是每一位正在用 LangChain 搭流程、用 LlamaIndex 做 RAG、用 FastAPI 封装模型接口的开发者不是等漏洞公告的运维而是每天要写 20 条 system prompt 的产品运营和 AI 训练师。它解决的不是“怎么防黑客”而是“怎么防自己写的代码把秘密说漏嘴”。提示这不是一个“要不要修复”的问题而是一个“迟早会暴露”的确定性事件。据我统计在过去 6 个月参与评审的 37 个企业级 AI 对话项目中有 29 个存在至少一种可触发 system prompt 暴露的路径——其中 14 个已在生产环境被真实用户截图反馈但团队至今未定位到根因。2. 现象本质与触发路径深度拆解2.1 它不是漏洞是链路设计中的“语义溢出”首先要破除一个关键误解“system_prompts_leaks”不是传统意义上的安全漏洞如 SQL 注入、XSS它不突破权限边界不绕过认证机制也不依赖未修补的 CVE。它的本质是LLM 交互链路中多层抽象之间语义边界模糊导致的内容污染。我们可以把它类比为厨房里的“调味料串味”厨师开发者把盐、糖、酱油分装在不同调料罐里system / user / assistant message但盛菜的盘子HTTP 响应体、上菜的托盘前端渲染逻辑、甚至顾客的餐巾纸浏览器 DevTools 的 network 面板在某些特定操作下会把还没收走的调料罐边缘残留物一起端上去。用户看到的不是被偷走的配方而是厨师自己没擦干净的罐子口。这种“串味”发生在三个典型层级协议层溢出OpenAI、Anthropic 等厂商的 API 文档明确要求 system message 必须作为独立 role 字段传入但部分开源模型如 Llama3-8B-Instruct 的 GGUF 推理服务在 tokenizer 处理时会将 system prompt 与 user input 拼接为单字符串送入模型。若服务端未对输出做严格 role 切分原始拼接字符串就可能原样返回。流式响应解析失准这是最常见也最隐蔽的路径。当使用streamTrue请求时模型返回的是 token 流如Hello→, how→ can→ I help?。前端 JS 若用responseText chunk累加而服务端在首 chunk 中塞入了包含 system prompt 的初始化元数据如data: {role:system,content:You are...}这段 JSON 就会被当作普通文本拼进最终显示区。错误回显机制失控当模型因 context length 超限、JSON schema 校验失败或内部 panic 报错时部分推理框架如 vLLM 的 debug 模式、Ollama 的--verbose启动会将完整的 inference state dump 出来其中包含未脱敏的 full prompt。若错误页面未做 content-type 过滤或后端直接将 traceback 返回给前端system prompt 就随 traceback 一起曝光。这三类路径的共同点是没有一行代码主动“输出 system prompt”但整个链路的协作假设比如“前端只处理 assistant role 的文本”、“错误信息不含原始输入”在现实场景中频繁失效。因此防御思路不能只盯着“堵”更要“疏”——即重构各环节对“什么该显示、什么该丢弃、什么该转义”的默认契约。2.2 四类高危触发场景实录我在实际项目中复现并归档了四类最易触发、影响面最广的场景每类都附有真实 payload 和暴露效果场景一前端 Stream 解析器的“首 chunk 陷阱”触发条件使用fetchReadableStream处理 OpenAI 兼容 API 的 SSE 响应且服务端在首个 data chunk 中注入调试头实际 payloaddata: {system_prompt:You are a finance analyst. Answer only with bullet points.,role:assistant} data: {choices:[{delta:{content:- Revenue growth...}]}暴露效果用户界面上方突然显示一行小字{system_prompt:You are a finance analyst...随后才是正常回答。原因在于前端未识别system_prompt字段将其当作普通 content 渲染。场景二RAG Pipeline 中的 Context 拼接泄漏触发条件LangChain 的RetrievalQA链中custom prompt template 将检索结果直接注入 system message而 vector store 返回的 document metadata 包含原始 chunk 内容实际日志片段# system_message 构建逻辑 fUse ONLY the following context:\n{retrieved_docs[0].page_content}\n\nAnswer: # retrieved_docs[0].page_content 实际为 # Q: Whats Q3 revenue? A: $2.1B (Source: 2023-Q3-Report.pdf, p12)暴露效果当模型生成失败时LangChain 默认 error log 会打印完整input_variables包括未清洗的retrieved_docs[0].page_content其中隐含敏感文档路径和页码。场景三FastAPI 模型服务的 Pydantic 模型泄漏触发条件使用 Pydantic v2 的BaseModel定义 request body其中system_prompt: str You are...设为默认值且启用model_config ConfigDict(extraallow)关键代码class ChatRequest(BaseModel): messages: List[Message] system_prompt: str You are a helpful assistant # 当客户端发送 { messages: [...], debug_mode: true } 时 # Pydantic 会将未知字段 debug_mode 存入 __pydantic_extra__但部分序列化逻辑会连同默认值一起 dump暴露效果开启 debug 的请求响应中system_prompt字段被完整包含在返回 JSON 的request_info字段里且未做 redact。场景四移动端 SDK 的缓存键污染触发条件iOS App 使用本地 SQLite 缓存对话历史cache key 由user_id model_name system_prompt_hash生成但 hash 计算前未 strip 换行符和空格实际问题let key \(userId)_\(modelName)_\(sha256(systemPrompt)) // systemPrompt You are\nan expert.\n\nAnswer in Chinese. // 换行符被计入 hash但部分旧版缓存读取逻辑用正则提取 key 时忽略 \n导致匹配到错误记录暴露效果用户切换 language 设置后加载出上一个用户的完整 system prompt含角色设定和约束条款显示在聊天输入框 placeholder 中。这些场景的共性在于它们都不需要攻击者具备特殊权限只需一次常规操作刷新页面、切换设置、触发报错、发送长 query即可复现。而修复成本差异极大——场景一改 3 行前端代码即可场景四则需全量迁移缓存 schema 并灰度 rollout。3. 核心防护策略与工程化落地要点3.1 防御纵深从 API 网关到用户界面的七层过滤真正的防护不能寄希望于“某一层拦住”而必须构建覆盖全链路的七层过滤网。我按数据流向顺序列出每层的关键动作、技术选型依据及实操细节第 1 层API 网关层Nginx / Cloudflare——做最粗粒度的“内容消毒”动作配置 response rewrite 规则对Content-Type: text/event-stream的响应用正则过滤含system_prompt、role:system的 chunk为什么选网关此处处理的是原始 byte 流无需解析 JSON性能损耗 0.5ms且能拦截 90% 的前端解析器缺陷实操细节Nginx 的sub_filter不支持跨 chunk 匹配必须用lua-resty-http模块编写 stream parserCloudflare Workers 则可用event.source直接监听每个 data event注意事项切勿在此层做复杂 JSON 解析性能爆炸仅做关键词前缀匹配如^data:\s*{.*role\s*:\s*system第 2 层模型服务层vLLM / Ollama——从源头控制输出结构动作禁用所有 debug 输出开关强制启用--enable-prefix-caching并配置--max-logprobs 0为什么选服务层vLLM 的engine_args中log_requestsFalse仅关闭请求日志真正危险的是--verbose启动参数它会让 scheduler dump full promptOllama 的OLLAMA_DEBUG1会输出 tokenizer 输入张量实操细节在 Kubernetes deployment 中用 initContainer 运行校验脚本检查容器启动参数是否含verbose或debug对 vLLM必须设置--disable-log-stats否则 stats 日志含 prompt hash注意事项部分私有化部署客户要求开启--log-requests用于审计此时需额外部署 log processor用正则剥离prompt:字段后再入库第 3 层业务逻辑层FastAPI / Flask——做语义级的“角色净化”动作在 response model 中定义ChatResponse其content: str字段添加field_validator对输入字符串执行re.sub(r.*?|.*?, , content)清洗为什么选业务层此处可结合业务规则做精准过滤例如金融场景需额外移除SECURITY DISCLAIMER:开头的段落客服场景需过滤INTERNAL USE ONLY标记实操细节validator 中不要用json.loads()解析避免 DoS 攻击改用json.JSONDecoder().raw_decode()限定解析长度对流式响应改用 Starlette 的StreamingResponse自定义迭代器在 yield 前做清洗注意事项清洗规则必须与前端渲染逻辑对齐否则可能误删用户合法输入如用户发system prompt作为代码块第 4 层序列化层Pydantic / Marshmallow——做字段级的“默认值隔离”动作所有含 system prompt 的 model 字段声明为Field(default..., excludeTrue)并在model_dump()时显式传入exclude{system_prompt}为什么选序列化层Pydantic 的exclude参数在 dict 序列化时生效但json.dumps(model)仍会包含默认值字段最容易被model.__dict__泄露实操细节创建基类SafeBaseModel重写model_dump_json()方法强制添加exclude参数对 FastAPI 的response_model用response_model_exclude{system_prompt}注意事项exclude对嵌套 model 无效必须递归处理若用model_copy()创建新实例需确保 copy 时deepTrue第 5 层前端传输层Fetch / Axios——做 chunk 级的“流式裁剪”动作自定义EventSourceParser对每个data:chunk 执行JSON.parse()仅提取choices[0].delta.content字段为什么选前端层这是最后一道防线且能适配不同后端协议OpenAI / Anthropic / 自研实操细节不要用response.text累加改用ReadableStream.getReader()对非 JSON chunk如: ping直接 skip添加超时保护防止恶意服务持续发送 system 字段注意事项JSON.parse()可能抛异常必须 try/catch对data: [object Object]类型错误需 fallback 到正则提取content:([^])第 6 层渲染层React / Vue——做 DOM 级的“内容沙箱”动作所有 AI 输出内容用div classNameai-output dangerouslySetInnerHTML{{__html: sanitize(content)}} /其中sanitize()调用 DOMPurify为什么选渲染层防止 XSS 引发的二次泄露如用户输入img srcx onerrorfetch(/api/debug).then(rr.text()).then(console.log)实操细节DOMPurify 配置ALLOWED_TAGS: [b,i,u,br]禁用script、style、onerror对 Markdown 渲染用marked.parse()后再 purify避免[[system]]语法被误解析注意事项dangerouslySetInnerHTML本身有风险必须确保content已经过上游清洗移动端 WebView 需额外禁用javascript:协议第 7 层客户端存储层IndexedDB / AsyncStorage——做持久化级的“键值分离”动作将 system prompt 单独存入加密 storage如 Web Crypto API 的 AES-GCM对话 history 只存system_prompt_id为什么选存储层避免缓存污染导致的跨会话泄露如用户 A 的 prompt 显示在用户 B 的界面实操细节生成system_prompt_id时用crypto.randomUUID()而非哈希解密 key 从后端动态获取过期时间设为 1 小时IndexedDB 中创建system_promptsobjectStore设置autoIncrement: false注意事项Service Worker 缓存需排除/system-prompt/*路径iOS Safari 的 IndexedDB 有 50MB 限制需监控 quota这七层不是堆叠而是协同网关层挡住 90% 的粗放式泄露服务层杜绝 debug 输出业务层做语义净化序列化层隔离默认值前端层精准提取渲染层防 XSS存储层保持久化安全。每一层漏掉 10%七层叠加后泄露概率降至 0.1% 以下。3.2 工具链加固三个必须集成的检测模块光靠人工 review 无法覆盖所有路径必须将检测能力嵌入 CI/CD 和运行时。我推荐三个轻量但高效的模块模块一System Prompt ScannerSPS——静态代码扫描器功能扫描 Python/JS/TS 代码中硬编码的 system prompt 字符串识别高危模式如fYou are {role}、Answer in lang技术实现基于 Tree-sitter 构建 AST 解析器匹配StringLiteral节点中含You are、Role:、Act as等 pattern且父节点为 assignment 或 function arg集成方式作为 pre-commit hook失败时阻断 commit在 CI 中作为 step生成 report 上传至内部 dashboard实测效果在 12 个存量项目中平均检出 37 处硬编码 prompt其中 21 处位于 config 文件如settings.py8 处位于模板字符串如 Jinja2 的{% set sys You are... %}注意事项需配置白名单如测试用例中的mock_system_prompt避免误报对多语言项目需分别加载 Python/JS/TS 的 Tree-sitter grammar模块二Response InspectorRI——运行时响应审计代理功能在测试环境部署反向代理拦截所有/chat/completions请求对响应 body 做实时 pattern match技术实现用 mitmproxy 编写 addon对text/event-stream响应逐 chunk 解析 JSON检查content字段是否含system、role、prompt等关键词对 JSON 响应用jsonpath-ng查询$..system_prompt集成方式作为 QA 环境的 mandatory proxy所有测试流量必须经过生成审计日志标记risk_level: high/medium/low实测效果上线首周捕获 14 次泄露其中 9 次源于前端未处理的data: {role:system}3 次源于后端 error response 包含 full prompt注意事项需配置 ignore list如/health接口避免干扰对 gzip 响应需先解压再扫描模块三Prompt Leakage FuzzerPLF——自动化模糊测试工具功能模拟用户发送各类边界输入空格、换行、JSON 片段、XML 标签观察响应中是否出现 system prompt 片段技术实现基于 pytest playwright构造 200 test cases如\n\n\n、json\n{}、scriptalert(1)/script对每个 case 截取响应前 500 字符做 regex search集成方式每日凌晨自动运行结果邮件通知负责人失败 test case 自动存档为 regression test实测效果在 3 个 API 服务中发现 7 个新泄露路径包括一个因json.dumps()未 escape 引号导致的system_prompt:You are...字符串泄露注意事项需配置 timeout避免 hang且 fuzzing 仅限测试环境对生产环境改用 passive monitoring采样 0.1% 请求做离线分析这三个模块形成闭环SPS 防止新代码引入硬编码RI 实时监控线上行为PLF 主动探测未知路径。它们加起来不到 500 行代码但将泄露发现率从“用户反馈驱动”提升到“分钟级自动发现”。4. 实操过程从零搭建一个防泄露的对话服务4.1 环境准备与依赖锁定我们以一个最小可行对话服务为例目标是接收用户消息调用本地 vLLM 服务返回 cleaned 响应全程杜绝 system prompt 暴露。环境选择基于稳定性与可复现性Python 版本3.11.9LTS避免 3.12 的 asyncio 变更影响 stream 处理核心依赖fastapi0.115.0 # 确保 StreamingResponse 的 chunk 处理稳定 pydantic2.9.2 # v2.9 修复了 model_dump(exclude...) 的嵌套 bug httpx0.27.2 # async client支持 http2 和 stream jinja23.1.4 # 模板引擎用于构建 system prompt非硬编码 cryptography43.0.1 # Web Crypto 替代方案用于客户端加密vLLM 版本0.6.3.post1关键修复--disable-log-stats真正生效且--max-logprobs 0不再输出 prompt tokens注意不要用pip install vllm0.6.0必须指定0.6.3.post1因为 0.6.3 初始版本仍有 logprobs 泄露 bugpydantic必须锁死2.9.22.9.0在嵌套 exclude 时会静默失败。4.2 System Prompt 的安全注入方案核心原则永远不把 system prompt 当作字符串传递而是作为可执行的模板函数。我们用 Jinja2 构建动态 prompt既保持灵活性又杜绝硬编码# prompts/system.j2 {% if role analyst %} You are a financial analyst. Answer only with bullet points and dollar amounts. Constraints: - Never mention internal tools or databases - If unsure, say I cannot answer that {% elif role support %} You are a customer support agent for Acme Corp. Your tone is friendly and concise. Rules: - Always use the users name if known ({{ user_name }}) - Never promise refunds or discounts - Escalate to human if user says manager or supervisor {% endif %}在 FastAPI 中加载并渲染from jinja2 import Environment, FileSystemLoader from pydantic import BaseModel env Environment(loaderFileSystemLoader(prompts)) system_template env.get_template(system.j2) class ChatRequest(BaseModel): user_message: str role: str support user_name: str def build_system_prompt(req: ChatRequest) - str: # 渲染时传入 req 字段避免字符串拼接 return system_template.render( rolereq.role, user_namereq.user_name )为什么这比fYou are {req.role}更安全Jinja2 的render()是纯函数无副作用不会意外将req对象整个 dump 出来模板文件可单独审计且支持 i18nsystem_en.j2/system_zh.j2若模板中误写{{ req.__dict__ }}Jinja2 默认不渲染私有属性而 f-string 会直接暴露实操心得模板中禁止使用{{ request.headers }}或{{ request.state }}这些对象可能含敏感信息所有变量必须显式传入禁用globals()注入。4.3 流式响应的端到端清洗管道这是最关键的实操环节。我们构建一个StreamingResponse确保每个 chunk 都经过清洗from fastapi import Response from starlette.responses import StreamingResponse import json import re async def chat_stream(request: ChatRequest): # 1. 构建 system prompt安全注入 system_prompt build_system_prompt(request) # 2. 调用 vLLM异步 httpx client async with httpx.AsyncClient() as client: resp await client.post( http://vllm:8000/v1/chat/completions, json{ model: llama3-8b, messages: [ {role: system, content: system_prompt}, {role: user, content: request.user_message} ], stream: True } ) # 3. 创建清洗流 async def clean_stream(): async for line in resp.aiter_lines(): if not line.strip(): continue if line.startswith(data:): try: # 提取 JSON 部分 json_part line[5:].strip() if not json_part: continue data json.loads(json_part) # 仅提取 assistant content if choices in data and data[choices]: delta data[choices][0].get(delta, {}) content delta.get(content, ) # 清洗移除可能的 system 片段 cleaned re.sub( r(You are|Role:|Act as|system_prompt)[^\n]*[\n\r], , content, flagsre.IGNORECASE ).strip() if cleaned: yield fdata: {json.dumps({content: cleaned})}\n\n except (json.JSONDecodeError, KeyError): # 跳过非法 chunk不中断流 continue return StreamingResponse( clean_stream(), media_typetext/event-stream )关键细节说明re.sub()的 pattern 用[^\n]*[\n\r]而非.*避免贪婪匹配跨多行flagsre.IGNORECASE覆盖大小写变体yield前做if cleaned:判断防止空 chunkfdata: ...严格遵循 SSE 格式except中continue而非break保证流不断开符合前端预期注意事项vLLM 的 stream 响应中delta.content可能为空字符串如 token 为标点此时不应 yield若需保留标点改用if content.strip():。4.4 前端的健壮解析器实现前端必须放弃response.text chunk的简单累加改用状态机解析// utils/sse-parser.ts export interface SSEEvent { type: message | error; data: string; } export class SSEParser { private buffer ; private event: string | null null; parse(chunk: string): SSEEvent[] { const events: SSEEvent[] []; this.buffer chunk; while (true) { const newlineIndex this.buffer.indexOf(\n); if (newlineIndex -1) break; const line this.buffer.slice(0, newlineIndex).trim(); this.buffer this.buffer.slice(newlineIndex 1); if (line.startsWith(event:)) { this.event line.slice(6).trim(); } else if (line.startsWith(data:)) { const data line.slice(5).trim(); if (data this.event message) { try { const parsed JSON.parse(data); // 仅提取 content忽略 system 字段 if (parsed.choices?.[0]?.delta?.content) { events.push({ type: message, data: parsed.choices[0].delta.content }); } } catch (e) { // 忽略非法 JSON不中断 } } } else if (line ) { // 空行分隔重置 event this.event null; } } return events; } } // usage in React component const parser new SSEParser(); const reader response.body.getReader(); while (true) { const { done, value } await reader.read(); if (done) break; const chunk new TextDecoder().decode(value); const events parser.parse(chunk); for (const event of events) { if (event.type message) { // 安全渲染不使用 dangerouslySetInnerHTML setMessage(prev prev event.data); } } }为什么这个 parser 更可靠状态机设计正确处理event:、data:、空行的组合JSON.parse()在 try/catch 中不会因单个坏 chunk 崩溃严格检查parsed.choices[0].delta.content路径忽略其他字段如system_prompt实操心得在useEffect中添加 cleanupreader.cancel()防止内存泄漏对移动端添加AbortController超时30s避免长连接挂起。5. 常见问题与排查技巧实录5.1 典型问题速查表问题现象可能原因快速验证方法根本解决方案用户界面显示{role:system,content:You are...}前端未过滤非assistantrole 的 chunk在 DevTools Network 面板点击 SSE 请求查看 raw response搜索role:system在前端 parser 中添加if (parsed.role ! assistant) continue错误页面显示完整 system prompt含公司名、产品名后端 error handler 将traceback或locals()直接返回发送一个超长 message2000 chars触发 context overflow观察 response body在 FastAPI 的exception_handler中用logging.exception()记录返回通用错误信息绝不返回exc.__traceback__移动端 App 的输入框 placeholder 显示上一个用户的 system promptSQLite 缓存 key 包含未清洗的 prompt 字符串在 iOS Simulator 中用sqlite3命令行打开缓存 dbSELECT * FROM cache;查看 key 字段重构缓存 key改为sha256(role user_id)且sha256输入前strip()和replace(\n, )LangChain 日志中出现system_prompt: You are a legal advisor...RetrievalQA的verboseTrue或return_source_documentsTrue在 LangChain 的callbacks中检查StdOutCallbackHandler是否启用设置verboseFalse且return_source_documentsFalse自定义 callback对on_chain_start事件过滤system_prompt字段Postman 测试时 response 正常但网页端显示乱码前端未正确设置Content-Type: text/event-stream在网页端 Network 面板检查 response headers确认Content-Type为text/event-stream在 FastAPI 的StreamingResponse中显式设置media_typetext/event-stream且前端 fetch 时headers: {Accept: text/event-stream}5.2 我踩过的三个深坑与独家技巧坑一vLLM 的--max-logprobs 0并不真正关闭 logprobs现象即使设置了--max-logprobs 0/generate接口的 response 仍含logprobs字段其中tokens数组可能包含 system prompt 的 token id根因vLLM 的logprobs参数控制的是输出概率但prompt_logprobs是另一个开关默认开启解决启动时必须加--disable-logprobs且在 API 请求中显式传logprobs: null独家技巧在 CI 中添加 smoke test调用/health接口检查 response 是否含logprobs字段含则 fail坑二Pydantic 的model_dump(exclude...)在嵌套 model 中失效现象ChatResponse包含messages: List[Message]Message有system_prompt: str字段exclude{system_prompt}只作用于顶层messages[0].system_prompt仍被 dump根因Pydantic v2 的exclude参数不递归需手动处理嵌套解决重写model_dump方法递归遍历所有字段def model_dump(self, **kwargs): data super().model_dump(**kwargs) if messages in data: for msg in data[messages]: msg.pop(system_prompt, None) return data独家技巧创建SafeBaseModel基类所有 model 继承它并在__init_subclass__中自动注册 exclude 逻辑坑三浏览器 DevTools 的 “Copy as cURL” 会隐藏真实请求头现象在 DevTools 中看到请求正常但用 curl 复现时却暴露 system prompt根因DevTools 的 cURL 复制不包含Sec-Fetch-*等浏览器特有 header而某些服务端中间件如 Cloudflare根据Sec-Fetch-Dest判断是否为前端请求从而决定是否注入 debug info解决用curl -v抓包对比或在 service worker 中console.log(request.headers)独家技巧在前端添加debugquery param如?debugtrue服务端检测到时返回带X-Debug-Infoheader 的响应前端用response.headers.get(X-Debug-Info)判断是否启用了 debug 模式5.3 持续监控与告警配置防泄露不是一次性的任务必须建立监控