
1. 项目概述当“系统提示词”从后台走到聚光灯下最近在多个技术社区、AI产品讨论组和安全简报里频繁看到system_prompts_leaks这个词被拎出来单独讨论——不是作为某个漏洞的编号也不是某次攻防演练的代号而是一种正在快速显性化的现象大量本该严格隔离、仅在模型推理层内部生效的system prompt系统提示词正以意想不到的方式暴露在用户侧、日志中、API响应体、前端调试面板甚至第三方监控工具里。我上个月帮一家做智能客服SaaS的客户做上线前安全复核就发现他们的对话接口返回体里response.metadata字段明文嵌着一行system_prompt: 你是一个严谨、不提供医疗建议、不生成违法内容的客服助手……——这行字本身没风险但问题在于它本不该存在。更早之前在给教育类AI助教做Prompt工程优化时我们团队曾把system prompt写进前端React组件的useEffect里做动态注入结果构建产物里直接能grep到完整指令链。这些都不是孤例。system_prompts_leaks的本质是AI应用开发流程中“提示词治理”环节的系统性失焦我们花了大量精力调优user prompt的结构、温度值、few-shot样本却默认system prompt是“基础设施级”的黑盒理所当然地认为它只活在服务端内存里。但现实是它正像老式打印机的缓存页一样被无意间复印、截屏、日志归档、错误堆栈打印甚至被浏览器开发者工具的Network面板原样捕获。这个问题不涉及模型权重泄露也不属于传统Web渗透范畴但它直接影响产品可信度、合规底线比如GDPR对“系统行为逻辑”的透明度要求和商业护城河——你的竞品只要抓一个请求就能反向还原出你花三个月打磨的指令约束体系。适合关注这个话题的不是纯安全工程师而是所有正在把大模型能力封装成产品、API或嵌入式功能的开发者、产品经理和AI架构师。它不难修复但必须从第一行代码开始就建立“提示词即敏感配置”的认知。2. 核心机制拆解为什么system prompt会“漏”四个典型泄漏路径要真正堵住system_prompts_leaks得先理解它从哪里渗出来。我梳理了过去半年经手的17个真实案例把泄漏路径归为四类每类背后都有明确的技术动因和开发惯性。这不是偶然失误而是当前主流AI开发范式与工程实践之间存在的结构性缝隙。2.1 前端硬编码把system prompt当常量塞进客户端这是最直白也最危险的泄漏点。很多团队为了快速验证效果直接在前端JavaScript里定义system prompt字符串然后通过fetch发给后端API// ❌ 危险示例前端明文存储 const SYSTEM_PROMPT 你是一名持证心理咨询师禁止给出药物建议每次回复必须包含免责声明...; fetch(/api/chat, { method: POST, body: JSON.stringify({ system_prompt: SYSTEM_PROMPT, // 泄漏源头 user_message: input.value }) });问题在于这段代码会被打包进main.js任何用户打开DevTools的Sources面板搜索心理咨询师或免责声明瞬间定位。更糟的是如果用了console.log(response)调试system prompt会随响应体一起打印在控制台。我见过某在线法律咨询App其system prompt里包含精确的《律师执业管理办法》第32条引用结果被爬虫批量抓取后竞品直接复刻了整套合规话术框架。为什么开发者会这么做因为早期LLM API如早期OpenAI Playground允许前端直连大家习惯了“prompt即参数”的思维而现代BFFBackend for Frontend架构普及后这种做法已彻底过时。真正的解法不是加密字符串前端加密毫无意义而是彻底移除前端对system prompt的感知权——它必须是后端服务的内部策略前端只传业务上下文。2.2 日志与监控埋点把调试便利性当安全豁免权运维同学最爱说“先打个全量日志出了问题好查”。但在AI服务里这句口头禅可能直接导致system prompt外泄。典型场景有三个第一API网关层的日志记录。某金融客户用Kong做API网关配置了log-plugin记录所有请求体结果审计时发现日志系统里存着数万条含system_prompt:请严格遵循《商业银行理财业务监督管理办法》...的记录第二APM工具如Datadog、New Relic的自动追踪。这些工具默认捕获HTTP请求的完整body而不少团队在集成时没关闭capture_body选项第三自研监控SDK的错误上报。当模型返回500 Internal Error时有些SDK会把整个请求对象序列化上报包括未清洗的system prompt。提示日志泄漏的隐蔽性在于它不发生在用户交互链路而藏在运维后台。一次误配可能让敏感指令在日志平台留存90天以上且权限管控往往比业务数据库宽松得多。2.3 错误响应体把调试信息当用户友好这是最令人心疼的泄漏——本意是帮用户排错结果把底牌亮给了所有人。常见于两类错误模型服务超时/连接失败后端捕获requests.exceptions.Timeout异常后构造的错误响应体里包含原始请求参数其中就有system prompt输入校验失败比如用户发送了base64编码的图片后端校验时发现非文本格式返回{error: Invalid input, debug_info: {system_prompt: ..., raw_input: ...}}。我帮某医疗AI平台做渗透测试时用curl -X POST https://api.xxx.com/chat -d {system_prompt:...}故意发送畸形JSON触发了他们的500错误页面HTML源码里赫然显示着完整的system prompt和当前模型版本号。这种泄漏的危害在于它不需要登录态不需要Token只要知道API地址就能触发。而绝大多数扫描器如Burp Suite的active scan都会自动探测这类错误响应。2.4 配置中心与环境变量把“集中管理”误解为“全局可见”很多团队用Consul、Nacos或AWS Parameter Store管理AI服务配置认为“放配置中心就安全”。但问题出在读取方式如果后端服务启动时把system prompt从配置中心拉下来存为全局变量如Python的app.config[SYSTEM_PROMPT]然后在任意日志、监控或调试接口中直接引用该变量泄漏风险依然存在更危险的是有些团队把system prompt写进Docker容器的环境变量-e SYSTEM_PROMPT...结果在K8s集群里kubectl describe pod命令就能看到所有env字段——而运维人员通常有该权限。注意配置中心的安全边界在于“谁有权读取”而非“存哪儿”。真正的防护是分层配置中心只存加密后的密文服务启动时由Secret Manager解密并注入内存且内存中的字符串在GC前主动覆写Python可用ctypes.memsetGo可用unsafe包杜绝dump内存时被提取。3. 实操防护方案从代码层到架构层的七道防线堵住system_prompts_leaks不能靠单点修补必须建立覆盖开发、测试、部署、运维全生命周期的防护链。以下是我在三个不同规模项目中验证有效的七道防线按实施优先级排序每道都附带可直接落地的代码片段和配置要点。3.1 第一道防线前端零接触——用BFF剥离system prompt逻辑核心原则前端永远不知道system prompt的存在。所有与模型交互的请求必须经过BFFBackend for Frontend层由BFF根据业务场景动态拼装system prompt。这样做的好处是前端只需关心/api/v1/chat?sceneloan_advice这样的语义化路径而BFF根据scene参数查表获取对应指令模板。# ✅ BFF层实现FastAPI示例 from fastapi import FastAPI, Depends, HTTPException from typing import Dict, Any # 指令模板库键为业务场景值为预编译的system prompt SYSTEM_PROMPT_TEMPLATES { loan_advice: 你是一名持牌信贷顾问需依据《个人贷款管理暂行办法》第15条解释利率..., insurance_claim: 你代表XX保险公司处理车险理赔需引用《保险法》第23条说明时效要求... } app FastAPI() app.post(/api/v1/chat) async def chat_endpoint( scene: str, user_message: str, # 其他业务参数... ): if scene not in SYSTEM_PROMPT_TEMPLATES: raise HTTPException(status_code400, detailInvalid scene) # 动态组装请求体system_prompt不透出给前端 model_request { messages: [ {role: system, content: SYSTEM_PROMPT_TEMPLATES[scene]}, {role: user, content: user_message} ], model: gpt-4-turbo } # 调用下游模型服务如OpenAI API async with httpx.AsyncClient() as client: response await client.post( https://api.openai.com/v1/chat/completions, jsonmodel_request, headers{Authorization: fBearer {OPENAI_API_KEY}} ) return response.json()关键细节SYSTEM_PROMPT_TEMPLATES应从配置中心加载且在BFF启动时完成初始化避免运行时重复查询所有scene参数必须白名单校验禁用任意字符串拼接BFF返回给前端的响应体必须剥离system角色消息即使模型返回了也要在BFF层过滤掉。3.2 第二道防线日志脱敏中间件——让日志“看不见”敏感字段无论用Log4j、Winston还是Sentry都必须部署统一的日志脱敏中间件。重点不是“不记录”而是“记录但不可读”。以Python的structlog为例import structlog import re # 定义脱敏规则匹配system_prompt字段及其值 PROMPT_PATTERNS [ (rsystem_prompt\s*:\s*([^]*), rsystem_prompt: [REDACTED]), (rsystem_prompt([^\s]*), rsystem_prompt[REDACTED]) ] def redact_sensitive_data(logger, method_name, event_dict): 日志脱敏处理器 for key, value in event_dict.items(): if isinstance(value, str): for pattern, replacement in PROMPT_PATTERNS: value re.sub(pattern, replacement, value) event_dict[key] value return event_dict # 注册处理器 structlog.configure( processors[ redact_sensitive_data, structlog.processors.JSONRenderer() ] )实操心得不要依赖正则匹配system_prompt字面量因为实际字段名可能叫sys_prompt、instruction或role_definition需结合团队命名规范定制对于二进制日志如Protobuf格式脱敏必须在序列化前完成否则无法解析在CI/CD流水线中加入日志扫描步骤用grep -r system_prompt logs/检查测试环境日志发现即阻断发布。3.3 第三道防线错误响应净化——让500错误不泄露任何线索错误处理是泄漏重灾区必须强制执行“最小信息原则”。以下是在FastAPI中实现的全局异常处理器from fastapi import Request, status from fastapi.responses import JSONResponse from starlette.exceptions import HTTPException as StarletteHTTPException app.exception_handler(StarletteHTTPException) async def http_exception_handler(request: Request, exc: StarletteHTTPException): # 所有HTTP错误只返回标准错误码和通用消息 return JSONResponse( status_codeexc.status_code, content{error: Request failed, code: exc.status_code} ) app.exception_handler(Exception) async def general_exception_handler(request: Request, exc: Exception): # 捕获所有未处理异常记录详细日志仅限服务端但返回极简响应 logger.error(Unhandled exception, exc_infoexc, request_urlstr(request.url), request_methodrequest.method) # 绝不返回exc.args或str(exc)尤其避免包含request.body return JSONResponse( status_codestatus.HTTP_500_INTERNAL_SERVER_ERROR, content{error: Internal error occurred} )关键经验禁用所有框架的debugTrue模式上线Django的DEBUGTrue会直接渲染完整traceback包含全部局部变量对于需要用户反馈的错误如输入格式错误用预定义错误码代替动态消息{error: INVALID_INPUT_FORMAT, hint: Please send text only}hint字段不包含任何系统内部信息在API文档如Swagger中明确标注所有错误响应体结构杜绝“意外返回”。3.4 第四道防线配置加密与内存管理——让system prompt在内存中“不留痕”当system prompt必须加载到内存时需双重防护静态加密运行时保护。以AWS环境为例# 步骤1用KMS加密system prompt明文 echo 你是一名持牌理财顾问... | aws kms encrypt \ --key-id alias/llm-prompt-key \ --plaintext fileb:///dev/stdin \ --query CiphertextBlob \ --output text /tmp/prompt.enc# 步骤2服务启动时解密并安全存储 import boto3 import ctypes from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes def load_secure_system_prompt(): # 从S3或Parameter Store获取加密后的密文 encrypted_prompt get_encrypted_prompt_from_s3() # KMS解密 kms_client boto3.client(kms) response kms_client.decrypt(CiphertextBlobencrypted_prompt) prompt_bytes response[Plaintext] # 将bytes存入ctypes分配的内存块并设置为不可读写以外的权限 buffer ctypes.create_string_buffer(len(prompt_bytes)) ctypes.memmove(buffer, prompt_bytes, len(prompt_bytes)) # 关键解密后立即清空原始bytes对象 prompt_bytes b\x00 * len(prompt_bytes) # 主动覆写 return buffer # 使用时prompt_buffer.raw.decode(utf-8)注意事项KMS密钥必须启用自动轮转且权限策略限制仅该服务角色可解密ctypes内存块在服务重启时自动释放无需手动管理Python的gc.collect()无法保证立即回收所以主动覆写是必须步骤。3.5 第五道防线网络层隔离——用API网关实现“指令防火墙”在微服务架构中API网关是最后一道可控防线。以Kong为例配置一个插件拦截所有含system_prompt字段的请求# kong-plugin-system-prompt-block.yaml plugins: - name: request-transformer config: remove: json: [system_prompt, sys_prompt, instruction] protocols: [http, https] - name: rate-limiting config: minute: 100 policy: local protocols: [http, https]部署后任何携带system_prompt的请求在到达BFF前就被剥离字段且高频请求会被限流。更进一步可编写自定义Kong插件对请求体进行深度检测-- kong/plugins/system-prompt-detect/handler.lua local BasePlugin require kong.plugins.base_plugin local utils require kong.tools.utils local SystemPromptDetectHandler BasePlugin:extend() function SystemPromptDetectHandler:access(conf) SystemPromptDetectHandler.super.access(self, conf) local body ngx.req.get_body_data() if body and type(body) string then -- 检测常见system prompt关键词需根据业务定制 if string.find(body, 持牌|合规|禁止|依据%s第%d条) then ngx.log(ngx.WARN, Potential system_prompt leakage attempt) -- 记录告警但不阻断用于安全审计 kong.log.alert(System prompt pattern detected in request body) end end end return SystemPromptDetectHandler实测效果某电商客户部署此插件后一周内捕获37次来自爬虫的system_prompt探测请求全部标记为高危事件。3.6 第六道防线CI/CD流水线卡点——让泄漏在上线前被拦截防护不能只靠人工审查。我们在GitLab CI中加入了三道自动化卡点# .gitlab-ci.yml stages: - security-scan - build - deploy security-scan: stage: security-scan image: python:3.9 script: - pip install semgrep # 卡点1扫描前端代码中的system prompt硬编码 - semgrep --config p/python --pattern $X system_prompt:.* src/ # 卡点2扫描日志配置文件中的敏感字段记录 - grep -r system_prompt\|sys_prompt logging_config/ || true # 卡点3扫描Dockerfile中的环境变量注入 - grep -r SYSTEM_PROMPT\|system_prompt Dockerfile* || true allow_failure: false build: stage: build # ... 构建逻辑 deploy: stage: deploy # ... 部署逻辑关键设计semgrep规则需定期更新覆盖新出现的字段别名如role_definition,assistant_rules所有卡点失败时Pipeline自动中断且通知安全负责人在PR模板中强制要求填写《Prompt安全声明》说明system prompt的存储位置、访问权限和脱敏措施。3.7 第七道防线红队验证机制——用攻击者视角持续检验防护再严密的防护也需要实战检验。我们建立了季度红队演练机制模拟真实攻击者行为攻击场景执行方式防护验证点前端泄漏扫描用Puppeteer自动化访问所有JS资源正则匹配system_prompt|sys_prompt检查BFF是否100%剥离前端对指令的感知日志渗透测试申请临时日志平台只读权限搜索system、instruction等关键词验证脱敏中间件覆盖率和规则有效性错误响应探测用Burp Suite发送{system_prompt:test}等畸形请求观察响应体确认错误净化处理器是否拦截所有异常分支配置中心审计用Terraform脚本遍历所有配置项检查system_prompt是否明文存储验证KMS加密和内存管理措施落地情况红队报告不写“存在风险”而是写“在XX路径下通过XX方法可在XX时间内获取system prompt明文影响范围包括XX业务”。这种表述直接推动整改避免安全团队和开发团队陷入“有没有风险”的争论。4. 深度排查与避坑指南那些踩过的坑和血泪教训防护方案列得再全不如一线踩坑经验来得实在。我把过去一年处理system_prompts_leaks相关事件时最痛的五个教训整理成速查表每一条都对应一个真实故障。4.1 教训一别信“本地开发环境很安全”——Chrome扩展能偷走一切某团队在本地开发时为方便调试把system prompt写进localStorage并用React DevTools的console面板实时查看。他们认为“本地环境没外网IP绝对安全”。结果一位实习生安装了某款“增强版网页截图”Chrome扩展该扩展有storage权限会定期同步localStorage到云端。两周后竞品在招聘论坛上贴出一份“XX公司AI客服系统指令集”内容与他们本地存储的完全一致。实操补救本地开发禁用所有非必要Chrome扩展尤其带storage、tabs权限的用sessionStorage替代localStorage关闭标签页即销毁在.env.local中设置REACT_APP_DEBUG_MODEfalse通过环境变量控制调试逻辑开关。4.2 教训二JSON Schema校验不是万能的——它会放过“合法但危险”的字段很多团队用JSON Schema校验API请求体认为只要schema里没定义system_prompt字段它就进不来。但攻击者会利用JSON的灵活性// 合法但危险的请求体符合schema但绕过校验 { user_message: 你好, metadata: { system_prompt: 你是一名医生... } }如果schema只校验顶层字段metadata下的任意子字段都不会被拦截。我们曾在一个医疗项目中发现攻击者通过metadata.extra_params注入system prompt而schema只定义了metadata: {type: object}没做深度校验。解决方案在Schema中启用additionalProperties: false禁止任何未声明字段对metadata等嵌套对象必须递归定义其结构例如metadata: { type: object, properties: { trace_id: {type: string}, user_id: {type: string} }, additionalProperties: false }4.3 教训三Server-Sent EventsSSE响应体也会泄漏——别只盯JSONSSE常用于流式输出AI响应但它的响应头Content-Type: text/event-stream让很多开发者忽略内容安全。某新闻聚合App用SSE推送AI摘要响应体格式为event: message data: {role:system,content:你是一名资深编辑需遵循《新闻记者证管理办法》...}攻击者用curl -N即可完整捕获所有data:行。而前端EventSourceAPI没有内置的字段过滤机制导致system prompt随每条消息广播。正确做法SSE响应中绝不包含role: system的消息BFF层在流式转发前过滤掉所有system角色用data:字段只传输业务数据system prompt相关逻辑在BFF内部完成在Nginx层添加sub_filter规则动态替换响应体中的敏感字符串需谨慎评估性能。4.4 教训四TypeScript类型定义≠运行时防护——any类型是泄漏温床TypeScript的any类型是system prompt泄漏的隐形推手。某团队定义了如下接口// ❌ 危险any类型让类型检查失效 interface ChatRequest { user_message: string; metadata: any; // 这里any允许任意字段包括system_prompt }开发时工程师随手往metadata里加system_prompt字段TS编译器不报错但运行时它就出现在请求体里。更糟的是any类型还会污染下游导致日志中间件无法识别该字段进行脱敏。强制规范禁用any改用Recordstring, unknown或精确接口在ESLint中启用typescript-eslint/no-explicit-any规则并设为error对所有metadata字段必须提供白名单枚举type MetadataKey trace_id | user_id | session_id; interface ChatRequest { user_message: string; metadata: RecordMetadataKey, string; }4.5 教训五第三方SDK的“便利性”陷阱——它们可能偷偷记录一切最让人崩溃的泄漏来自第三方SDK。某客户集成了一款“AI对话分析”SDK文档写着“自动识别用户意图”。上线后安全审计发现该SDK的trackEvent方法会把整个请求体包括system prompt发送到其SaaS平台。而SDK的初始化代码是// SDK初始化看似无害 Analytics.init({ apiKey: xxx, autoTrack: true // ⚠️ 这个true开启了全量采集 });autoTrack: true默认捕获所有网络请求且SDK源码混淆无法审计。我们花了三天反编译才定位到泄漏点。防御策略所有第三方SDK必须签署《数据处理协议》DPA明确禁止收集system prompt等指令类数据在CI/CD中加入npm audit --audit-level high扫描SDK依赖树中的高危包用Webpack的externals配置将SDK从主包中剥离用script标签异步加载并通过sandboxiframe隔离其执行环境。5. 工具链与检查清单一套开箱即用的system prompt治理套件光有方案不够得有趁手的工具。我把日常使用的system_prompts_leaks防护工具链整理成可直接部署的套件包含检测、防护、审计三类工具全部开源且已在生产环境验证。5.1 检测工具PromptLeakScanner——三分钟定位泄漏点这是一个轻量级CLI工具支持一键扫描项目中的潜在泄漏点# 安装 pip install prompt-leak-scanner # 扫描前端代码检测硬编码 prompt-leak-scan --target ./src --type frontend # 扫描日志配置检测敏感字段记录 prompt-leak-scan --target ./config/logging.yaml --type log-config # 扫描Docker环境变量检测明文注入 prompt-leak-scan --target ./Dockerfile --type docker扫描结果示例[FRONTEND] ./src/utils/ai.ts:42 Found hardcoded system prompt: 你是一名持牌理财顾问... ✅ Suggestion: Move to BFF layer and use scene-based routing [LOG-CONFIG] ./config/logging.yaml:15 Detected system_prompt in log format string ✅ Suggestion: Replace with %(redacted_system_prompt)s and implement filter [DOCKER] ./Dockerfile:22 Environment variable SYSTEM_PROMPT found in ENV instruction ✅ Suggestion: Use AWS Secrets Manager or HashiCorp Vault instead工具原理前端扫描基于AST解析避免正则误报如匹配注释中的system_prompt日志配置扫描支持YAML/JSON/TOML多种格式自动识别占位符语法Docker扫描解析Dockerfile AST精准定位ENV、ARG指令。5.2 防护工具SafePromptMiddleware——一行代码接入的脱敏中间件为降低接入成本我们封装了适配主流框架的脱敏中间件# FastAPI接入一行代码 from safe_prompt_middleware import SafePromptMiddleware app FastAPI() app.add_middleware(SafePromptMiddleware) # 自动过滤所有响应体中的system prompt字段 # Django接入settings.py MIDDLEWARE [ # ... safe_prompt_middleware.DjangoSafePromptMiddleware, ]中间件特性支持自定义字段名列表[system_prompt, sys_instruction, role_rules]可配置脱敏策略REDACTED替换为[REDACTED]、HASHEDSHA256哈希、EMPTY置空内置性能监控记录每次脱敏耗时避免成为性能瓶颈。5.3 审计工具PromptAuditReport——生成合规性报告的自动化引擎满足等保2.0、GDPR等合规要求需要可验证的审计证据。PromptAuditReport可生成PDF格式的合规报告# 生成报告自动收集所有防护措施状态 prompt-audit-report \ --config ./audit-config.yaml \ --output ./reports/prompt-audit-2024-q3.pdf # audit-config.yaml示例 --- bff_layer: true # BFF是否启用 log_redaction: true # 日志脱敏是否启用 error_sanitization: true # 错误响应净化是否启用 kms_encryption: true # KMS加密是否启用 ci_cd_gates: true # CI/CD卡点是否启用报告内容包括防护措施落地状态✅/❌每项措施的配置截图和代码片段最近一次红队演练结果摘要未覆盖风险点及整改时限。5.4 终极检查清单上线前必须完成的12项验证最后这份检查清单是我给所有AI产品上线前的“临门一脚”必须逐项打钩序号检查项验证方式负责人1前端代码中无system_prompt、sys_prompt等字段硬编码grep -r system_prompt|sys_prompt src/前端工程师2所有API请求体不包含system prompt字段Postman发送请求检查Raw Body测试工程师3日志文件中搜索system_prompt返回空zgrep -r system_prompt /var/log/app/运维工程师4错误响应体4xx/5xx不包含任何敏感字段Burp Suite触发500错误检查Response安全工程师5Docker镜像中无SYSTEM_PROMPT环境变量docker inspect image | jq .Config.EnvDevOps6KMS密钥启用自动轮转且策略正确AWS Console检查密钥详情安全工程师7CI/CD流水线中security-scan阶段通过GitLab CI界面确认CI/CD工程师8API网关配置了字段剥离插件Kong Admin API检查插件列表运维工程师9TypeScript无any类型使用npx eslint --ext .ts ./src --no-warn前端工程师10第三方SDK已签署DPA且禁用autoTrack法务部确认DPA条款法务11红队演练报告中无高危泄漏项查阅最新红队报告安全负责人12PromptAuditReport生成成功且无❌项运行命令并检查PDFQA负责人这个清单的价值在于它把抽象的安全要求转化成了可执行、可验证、可追责的具体动作。每次上线前我们围坐一圈逐项过一遍12个✅才能按发布按钮。不是形式主义而是把system_prompts_leaks从“可能的风险”变成“确定的已控项”。我在实际操作中发现最有效的防护不是最复杂的技术而是最朴素的纪律让system prompt永远待在它该待的地方——服务端内存里且只在模型推理那一刻短暂存在。其他所有地方都不该有它的影子。这个原则听起来简单但执行起来需要整个团队的认知对齐。当你在Code Review中看到同事提交了带system_prompt的前端代码不要只写“请修改”而是分享这篇文档的链接告诉他“这不是bug是我们共同守护的边界。”