【Bug已解决】[Bug] Crash input dump leaks structured-output schema at ERROR level 解决方案

发布时间:2026/9/28 15:50:20

【Bug已解决】[Bug] Crash input dump leaks structured-output schema at ERROR level 解决方案
【Bug已解决】[Bug] Crash input dump leaks structured-output schema at ERROR level 解决方案一、现象长什么样vLLM 在请求处理中崩溃时默认会把出问题的那条请求输入整个 dump 到 ERROR 日志方便排障。但当这条请求用了**结构化输出guided / JSON schema 约束解码**时dump 出来的内容会包含那段 JSON schemaERROR 01-15 11:02:33 engine.py:233] Request crashed, dumping input: { model: qwen-7b, messages: [{role: user, content: 把这张发票解析成结构化数据}], guided_json: { type: object, properties: { invoice_no: {type: string}, buyer_tax_id: {type: string}, amount: {type: number}, items: {type: array, items: {type: object, ...}} }, required: [invoice_no, buyer_tax_id, amount] } }问题schema 属于业务敏感元数据它描述了系统能产出哪些结构化字段发票号、税号、金额项…泄露到日志等于把内部数据模型暴露给能看日志的人日志平台、运维、第三方托管。ERROR 级别被广收ERROR 日志通常接入集中式日志/告警转发范围广比 DEBUG 更容易外泄。dump 没有脱敏prompt 内容 schema 一起明文落盘既可能含用户隐私发票内容也可能含业务 schema。这不是功能 bug而是崩溃转储缺乏脱敏策略把本不该出现在 ERROR 日志里的结构化输出 schema 明文泄露了。下面给出一套崩溃输入脱敏方案。二、背景vLLM 的结构化输出guided decoding要求调用方传一个 schemaJSON schema / regex / grammar来约束模型输出。这个 schema 在请求对象里是一个字段如guided_json/guided_grammar。当请求在 engine 内崩溃排查逻辑会把整个request对象序列化后打到 ERROR。矛盾在于排障确实需要看是哪条请求、什么参数导致崩溃但schema 字段和 prompt 内容都属于不该广泛传播的数据。正确做法是崩溃转储默认脱敏——只保留定位所需的元信息request_id、模型名、错误阶段、是否用了 structured output、schema 的字段名而非完整定义把完整 schema / prompt 内容替换成占位或降级到 DEBUG。下面用可运行代码给出一套ScrubbedCrashDump实现。三、根因拆成三条根因崩溃转储无字段级脱敏转储逻辑直接json.dumps(request)全量打印没有区分定位需要和敏感不该泄露的字段。根因是转储缺少一个字段分类表。敏感字段被印到 ERROR 而非 DEBUG即便要保留 schema 用于排障也应只在 DEBUG / 受限日志里出现而不是 ERROR 这种广收级别。根因是日志级别选择不当。schema 完整定义被当普通字段处理guided_json是个可能很大的嵌套结构既含字段名也含约束细节正则、枚举取值。排障其实只需要知道用了哪种 structured output 顶层字段名完整定义没必要进 ERROR。根因是没有对 schema 做只留骨架、去掉细节的提炼。修复方向定义敏感字段表 转储时脱敏schema 只留顶层 key 名、prompt 截断/哈希 ERROR 只打脱敏摘要、完整内容走 DEBUG。四、最小可运行复现下面复现崩溃转储明文泄露 schema的现状问题import json def naive_crash_dump(request: dict): 现状整个请求对象明文打到 ERROR。 return json.dumps(request, ensure_asciiFalse) req { request_id: req-001, model: qwen-7b, messages: [{role: user, content: 解析这张发票}], guided_json: { type: object, properties: {invoice_no: {type: string}, buyer_tax_id: {type: string}}, required: [invoice_no, buyer_tax_id], }, } print(现状 ERROR 日志:, naive_crash_dump(req)) # 输出里完整 schema 明文暴露现状 ERROR 日志: {... guided_json 完整定义 ...}即复现schema 明文进了 ERROR。下面重做成脱敏转储。五、解决方案第一层最小直接修复最小修复定义敏感字段表转储时把guided_json提炼为只留顶层字段名把messages内容截断/哈希ERROR 只印脱敏摘要。import json import hashlib from typing import Any, Dict # 需要脱敏的请求字段 SENSITIVE {guided_json, guided_grammar, guided_regex, messages, prompt, messages} def schema_skeleton(schema: Any) - Dict[str, Any]: 只保留 schema 的顶层字段名与类型去掉约束细节。 if not isinstance(schema, dict): return {_type: type(schema).__name__} props schema.get(properties, {}) return { type: schema.get(type), top_level_keys: sorted(props.keys()), required: schema.get(required, []), } def redact_messages(messages: list) - list: 消息内容只留长度哈希不印明文。 out [] for m in messages: content m.get(content, ) out.append({ role: m.get(role), content_sha256: hashlib.sha256( str(content).encode()).hexdigest()[:12], content_len: len(str(content)), }) return out def scrub_request(req: dict) - dict: 生成脱敏后的崩溃摘要用于 ERROR 级别。 summary { request_id: req.get(request_id), model: req.get(model), has_structured_output: any(k in req for k in (guided_json, guided_grammar, guided_regex)), } for k in (guided_json, guided_grammar, guided_regex): if k in req: summary[structured_output_skeleton] schema_skeleton(req[k]) summary[messages_scrubbed] redact_messages(req.get(messages, [])) return summary # 用法 print(脱敏 ERROR 摘要:, json.dumps(scrub_request(req), ensure_asciiFalse))这一层改动让 ERROR 日志只含request_id / model / 是否用了结构化输出 / schema 顶层字段名 / 消息长度哈希完整 schema 与 prompt 不再明文出现。六、解决方案第二层结构化改进把脱敏转储做成结构化组件区分 ERROR 摘要脱敏与 DEBUG 全文受限并用配置控制是否允许在 DEBUG 下保留 schema。import logging from dataclasses import dataclass from typing import Optional dataclass class DumpPolicy: redact_structured_output: bool True # ERROR 下是否提炼 schema redact_messages: bool True # ERROR 下是否脱敏 prompt allow_full_at_debug: bool True # DEBUG 级是否允许完整内容 class CrashDumper: def __init__(self, policy: DumpPolicy, error_log: logging.Logger, debug_log: logging.Logger): self.policy policy self.error_log error_log self.debug_log debug_log def dump(self, req: dict, error: Exception): # ERROR永远脱敏 summary scrub_request(req) if (self.policy.redact_structured_output or self.policy.redact_messages) \ else {k: v for k, v in req.items() if k not in SENSITIVE} summary[error] repr(error) self.error_log.error(请求崩溃(已脱敏): %s, json.dumps(summary, ensure_asciiFalse)) # DEBUG受限环境下才打完整内容 if self.policy.allow_full_at_debug: self.debug_log.debug(请求崩溃(完整, DEBUG only): %s, json.dumps(req, ensure_asciiFalse)) # 用法 err logging.getLogger(vllm.error) dbg logging.getLogger(vllm.debug) dumper CrashDumper(DumpPolicy(), err, dbg) dumper.dump(req, RuntimeError(boom))CrashDumper保证 ERROR 永远是脱敏摘要完整内容只在 DEBUG 且仅当策略允许时出现杜绝了schema 随 ERROR 广收外泄。七、解决方案第三层断言 / CI 守护脱敏最怕有人又把完整 schema 印回 ERROR。用断言守两条不变量def check_dump_invariants(req: dict): summary scrub_request(req) msg json.dumps(summary, ensure_asciiFalse) # 不变量 1ERROR 摘要里不得出现完整 schema 的敏感细节如正则/枚举取值 full_schema json.dumps(req.get(guided_json, {}), ensure_asciiFalse) # 若完整 schema 字符串是摘要字符串的子串说明脱敏失败 assert full_schema not in msg, 完整 schema 泄露进 ERROR 摘要 # 不变量 2不得出现明文 prompt 内容 for m in req.get(messages, []): content str(m.get(content, )) if content: assert content not in msg, 明文 prompt 泄露进 ERROR 摘要 # 不变量 3必须保留定位所需的元信息 assert request_id in summary and model in summary, 缺少定位元信息 return True def test_crash_dump_redaction(): assert check_dump_invariants(req) print(OK: 崩溃转储脱敏不变量通过) if __name__ __main__: test_crash_dump_redaction()把test_crash_dump_redaction接进 CI任何把完整 schema / 明文 prompt 写回 ERROR的改动都会立即红。八、排查清单崩溃输入转储泄露 schema按序查先确认 ERROR 日志里有没有完整guided_json/grammar/regexgrep 日志中guided_关键字。若有完整定义说明转储没脱敏按第五节scrub_request改。schema 只留骨架排障只需要用了哪种 structured output 顶层字段名 required 列表完整约束正则、枚举、嵌套细节不该进 ERROR用schema_skeleton提炼。prompt / messages 脱敏ERROR 里只用content_sha256 长度绝不印明文用户隐私内容发票、身份证号尤其敏感。日志级别分离ERROR 只打脱敏摘要完整请求只在 DEBUG 且策略允许时出现。集中式日志/告警通常只接 ERROR 及以上这样就天然把敏感内容挡在广收通道之外。配置开关DumpPolicy.allow_full_at_debug在生产默认关只在排障会话临时开避免长期留完整内容。结构化输出 schema 当资产看待schema 本质是系统能产出什么字段的契约属于内部资产按敏感数据处理不要在广收日志里明文。CI 接test_crash_dump_redaction用完整 schema 串不是摘要子串的断言锁死任何回退到明文转储的改动。九、小结崩溃输入转储把结构化输出 schema 明文打到 ERROR本质是转储缺乏字段级脱敏 日志级别选错。三层修复第一层SENSITIVE字段表 schema_skeleton只留顶层字段名/requiredredact_messages只留哈希/长度ERROR 只印脱敏摘要第二层CrashDumperDumpPolicy把 ERROR永远脱敏与 DEBUG受限全文分离完整内容绝不进广收通道第三层CI 断言守住完整 schema / 明文 prompt 不出现在 ERROR 摘要任何回退立即红。落实后vLLM 崩溃时 ERROR 日志只含request_id / model / 是否结构化输出 / schema 骨架 / 消息长度哈希既能定位又不泄露敏感 schema 与用户内容。

相关新闻

【Bug已解决】[Feature]: Improve DCP error messages 解决方案

【Bug已解决】[Feature]: Improve DCP error messages 解决方案

2026/9/28 15:50:03

【Bug已解决】[Feature]: Improve DCP error messages 解决方案 一、现象长什么样 PyTorch 的 DCP(Distributed Checkpoint,分布式检查点)在保存/加载大模型分片时,报错极其不友好: RuntimeError: Missing keys in sta…

基于Java的学生管理系统的设计与实现开题报告

基于Java的学生管理系统的设计与实现开题报告

2026/9/28 15:49:58

一、项目研究背景与意义 随着我国教育信息化建设的全面深化,各类中小学及高校的办学规模持续扩大,在校学生数量不断增加,学生日常信息、学业成绩、考勤纪律、奖惩信息、班级信息等管理数据呈指数级增长。传统校园学生管理模式以人工纸质登记、…

【Bug已解决】[Bug]: vllm start with TieringOffloadingSpec mmap_obj error 解决方案

【Bug已解决】[Bug]: vllm start with TieringOffloadingSpec mmap_obj error 解决方案

2026/9/8 15:37:51

【Bug已解决】[Bug]: vllm start with TieringOffloadingSpec mmap_obj error 解决方案 一、现象长什么样 vLLM 的 TieringOffloadingSpec(分级卸载规格)用来把 KV cache / 权重按冷热分层,把冷数据 mmap 到文件或共享内存作为慢速层。启动带…

CANN/GE ACL数据集缓冲区添加函数

CANN/GE ACL数据集缓冲区添加函数

2026/9/28 4:08:17

aclmdlAddDatasetBuffer 【免费下载链接】ge GE(Graph Engine)是面向昇腾的图编译器和执行器,提供了计算图优化、多流并行、内存复用和模型下沉等技术手段,加速模型执行效率,减少模型内存占用。 GE 提供对 PyTorch、Te…

用ffmpeg高效批量调整图片尺寸的实战指南

用ffmpeg高效批量调整图片尺寸的实战指南

2026/9/27 1:30:29

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

Transformers 音频特征提取工具库 audio_utils 全解析:从 Mel 刻度换算到对数 Mel 频谱

Transformers 音频特征提取工具库 audio_utils 全解析:从 Mel 刻度换算到对数 Mel 频谱

2026/9/28 2:15:29

Transformers 音频特征提取工具库 audio_utils 全解析:从 Mel 刻度换算到对数 Mel 频谱 【免费下载链接】transformers 🤗 Transformers: the model-definition framework for state-of-the-art machine learning models in text, vision, audio, and mu…

RustFS 多节点集群重启与滚动升级实战:Readiness、Quorum 与 Degraded 模式完全指南

RustFS 多节点集群重启与滚动升级实战:Readiness、Quorum 与 Degraded 模式完全指南

2026/9/28 3:14:54

RustFS 多节点集群重启与滚动升级实战:Readiness、Quorum 与 Degraded 模式完全指南 【免费下载链接】rustfs 🚀2.3x faster than MinIO for 4KB object payloads. RustFS is an open-source, S3-compatible high-performance object storage system sup…

Java Integer缓存揭秘:128陷阱原理、避坑与面试全解

Java Integer缓存揭秘:128陷阱原理、避坑与面试全解

2026/9/28 3:58:00

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

RustFS Scanner 数据用量发布权威性决策:配额准入如何获得可用的权威依据

RustFS Scanner 数据用量发布权威性决策:配额准入如何获得可用的权威依据

2026/9/28 3:47:14

RustFS Scanner 数据用量发布权威性决策:配额准入如何获得可用的权威依据 【免费下载链接】rustfs 🚀2.3x faster than MinIO for 4KB object payloads. RustFS is an open-source, S3-compatible high-performance object storage system supporting mi…

远程协作的工作台整理

远程协作的工作台整理

2026/9/26 14:29:04

远程协作的工作台整理远程协作的核心不是再加一个工具,而是让交接信息足够完整。异步任务要写明目标、输入位置、完成标准和需要决策的人。 工作台的最小配置 将日程、待办、代码和沟通入口收拢到少数固定位置;通知按紧急程度分层。工作台不需要模仿办公…

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

2026/9/28 5:05:21

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

2026/9/26 23:35:16

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…