![【Bug已解决】[Bug]: ValueError: No user query found in messages QWEN 3.5 27B VLLM 0.16.0 NIGHTLY 解决方案](http://pic.xiahunao.cn/yaotu/【Bug已解决】[Bug]: ValueError: No user query found in messages QWEN 3.5 27B VLLM 0.16.0 NIGHTLY 解决方案)
【Bug已解决】[Bug]: ValueError: No user query found in messages QWEN 3.5 27B VLLM 0.16.0 NIGHTLY 解决方案一、现象长什么样用 vLLM 0.16.0 nightly 给Qwen3.5-27B发聊天请求时服务端在处理消息时抛ValueError请求失败。典型日志ValueError: No user query found in messages或者更笼统[Bug]: ValueError: No user query found in messages QWEN 3.5 27B VLLM 0.16.0 NIGHTLY几个特征帮你判断是不是同一个坑报错是ValueError: No user query found in messages说明 chat 模板/消息解析逻辑在messages里没找到 role 为user的消息。错误发生在请求处理/聊天模板渲染阶段不是模型推理。你明明传了 user 消息却仍报错——常见是「role 字段名/大小写/格式不符」或「消息结构被前置处理改掉了」。常见于只传了system消息没传user或用了非标准 role 名或 messages 被某种预处理如把多轮合并弄丢了 user 角色或 Qwen 的特殊模板要求「最后一条必须是 user」而你最后是 assistant/tool。换个模型如 Llama可能不报错说明是Qwen 的 chat 模板对 user 消息有特定要求 nightly 版本模板校验变严。二、背景Chat 模型依赖chat template聊天模板把messages如[{role: system, ...}, {role: user, ...}]渲染成模型输入。模板里通常有逻辑必须存在user消息、且常要求「对话以 user 开头/以 user 结尾」等。Qwen 系列尤其 Qwen3.5的 chat 模板对消息结构有较严格要求nightly 版本可能加强了校验1. 模板硬性要求 user 消息存在Qwen 的模板在渲染时会查找role user的消息来插入特殊标记如|im_start|user。如果你只发了system消息比如想做「纯系统提示续写」没有 user → 模板找不到 → ValueError。你发的 messages 里 user 消息被某种逻辑过滤/合并掉了。2. role 字段名/大小写不符某些客户端把 role 写成User/USER/ 中文用户模板按 user严格匹配 → 找不到 → ValueError。3. 消息顺序/结尾要求Qwen 模板可能要求「最后一条消息必须是 user」因为模型要基于最后一个 user 提问生成。如果最后一条是assistant或tool模板可能仍要求存在一个 user或你的结构让模板误以为没有 user。4. 多轮/工具调用的 message 结构用了 tool_calls / function callingmessages 里混了tool/assistant带 tool_calls角色模板解析时若没正确处理可能「跳过」了真正的 user 消息误判无 user。5. 预处理改动了 messages某些中间件网关、重试逻辑、历史压缩在转发前改写了 messages如把 system 和 user 合并、或过滤空消息结果把 user 角色弄丢/改名。6. nightly 模板校验变严稳定版可能「没有 user 就优雅用空/用 system 兜底」nightly 改成「必须 user 否则 ValueError」于是同样请求在 nightly 崩。核心Qwen3.5 的 chat 模板nightly 加强校验要求 messages 中存在roleuser的消息但你的请求因「缺 user / role 名不符 / 结构被改 / 结尾非 user」导致模板找不到 user → ValueError。三、根因根因一句话vLLM 0.16.0 nightly 的 Qwen3.5-27B chat 模板在渲染时要求messages中存在role user的消息可能还要求结尾为 user但请求因只含 system、role 名大小写/格式不符、消息被预处理改结构、或工具调用消息组织不当导致模板按严格 user匹配时找不到 user 消息抛出ValueError: No user query found in messages。具体成因缺 user 消息只发 system想续写/纯提示没有 user → 模板找不到。role 名不符User/USER/中文角色名模板严格 user匹配失败。结尾非 user模板要求最后一条是 user你最后是 assistant/tool。预处理改结构网关/压缩逻辑改写了 messages丢失/改名 user 角色。工具调用结构tool/assistant(tool_calls) 混排模板解析跳过真正 user。nightly 校验变严稳定版优雅兜底nightly 强制要求 user → ValueError。核心矛盾模板的「必须存在 user 消息」假设与请求实际消息结构缺 user/名不符/被改不一致且 nightly 把优雅兜底改成硬 ValueError。四、最小可运行复现下面用纯 Python 模拟「模板按 user 严格匹配role 名不符/缺 user → ValueError」# reproduce_no_user.py # 复现模板严格匹配 roleuser, 缺 user / role 名不符 - ValueError def render_buggy(messages): # 模板逻辑: 必须找到 roleuser for m in messages: if m.get(role) user: return frender ok with {m[content]} raise ValueError(No user query found in messages) def render_fixed(messages): # 兼容: role 名大小写/中文, 且允许仅 system 时优雅兜底 def norm(r): return (r or ).strip().lower() for m in messages: if norm(m.get(role)) in (user, 用户): return frender ok with {m[content]} # 无 user: 优雅兜底(而非崩) return render with system-only (no user, fallback) if __name__ __main__: # 只发 system try: render_buggy([{role: system, content: 你是个助手}]) except ValueError as e: print(复现成功:, e) # role 名 User(大写) try: render_buggy([{role: User, content: hi}]) except ValueError as e: print(复现成功(role名):, e) print(render_fixed([{role: system, content: x}])) print(render_fixed([{role: User, content: hi}]))运行python reproduce_no_user.py会看到缺 user / role 名不符都触发 ValueError修复版兼容大小写并优雅兜底。五、解决方案第一层最小直接修复最小修复在转发给 vLLM 前做消息规范化——统一 role 名大小写/中文 →user/assistant/system并确保至少有一条user消息若只有 system补一条占位 user 或改用非 chat 接口避免把「严格匹配」的担子全压在模板上。# fix_layer1_msgs.py ROLE_ALIASES { user: user, User: user, USER: user, 用户: user, assistant: assistant, Assistant: assistant, system: system, System: system, } def normalize_messages(messages: list) - list: out [] for m in messages: role ROLE_ALIASES.get(m.get(role), m.get(role)) out.append({role: role, content: m.get(content, )}) return out def ensure_user(messages: list) - list: if not any(m[role] user for m in messages): # 仅 system/其他: 补一条占位 user, 或提示改用 completion messages messages [{role: user, content: 请继续}] return messages if __name__ __main__: msgs [{role: System, content: 你是个助手}, {role: USER, content: 你好}] norm normalize_messages(msgs) print(规范化:, norm) print(保 user:, ensure_user([{role: system, content: x}]))这一层把「模板硬 ValueError」变成「请求侧规范化 role 保证有 user」兼容大小写/中文并优雅兜底。六、解决方案第二层结构性改进把「消息校验/规范化」做成模块覆盖 role 别名、user 存在性、结尾要求、工具调用结构并给出清晰错误# fix_layer2_msgs.py from dataclasses import dataclass, field dataclass class ChatMessageGuard: allow_system_only: bool False def validate(self, messages: list) - list: errs [] norm [] aliases {user: user, User: user, 用户: user, assistant: assistant, system: system} for m in messages: role aliases.get(m.get(role), m.get(role)) norm.append({role: role, content: m.get(content, )}) has_user any(m[role] user for m in norm) if not has_user and not self.allow_system_only: errs.append(messages 缺少 roleuser 的消息(Qwen 模板要求)) if norm and norm[-1][role] not in (user, tool) and has_user is False: errs.append(最后一条应为 user(或工具结果)) return errs def sanitize(self, messages: list) - list: # 规范化 缺 user 补占位(当不允许纯 system 时) aliases {user: user, User: user, 用户: user} out [{role: aliases.get(m.get(role), m.get(role)), content: m.get(content, )} for m in messages] if not any(m[role] user for m in out): out.append({role: user, content: 请继续}) return out if __name__ __main__: g ChatMessageGuard() print(校验(纯系统):, g.validate([{role: system, content: x}])) print(净化(纯系统):, g.sanitize([{role: system, content: x}]))这样换模型/换客户端role 名各异时ChatMessageGuard统一规范化并校验缺 user 清晰报错或优雅补占位。七、解决方案第三层断言 / CI 守护把「消息校验」钉进断言和 CI# fix_layer3_guard.py # ---- pytest 用例进 CI ---- def test_missing_user_caught(): from fix_layer2_msgs import ChatMessageGuard g ChatMessageGuard() assert any(user in e for e in g.validate([{role: system, content: x}])) def test_role_alias_normalized(): from fix_layer2_msgs import ChatMessageGuard g ChatMessageGuard() san g.sanitize([{role: USER, content: hi}]) assert san[0][role] user def test_system_only_sanitized(): from fix_layer2_msgs import ChatMessageGuard g ChatMessageGuard() san g.sanitize([{role: system, content: x}]) assert any(m[role] user for m in san) def test_valid_msgs_ok(): from fix_layer2_msgs import ChatMessageGuard g ChatMessageGuard() assert g.validate([{role: system, content: x}, {role: user, content: hi}]) []再加请求前断言def assert_messages_ok(guard: ChatMessageGuard, messages): errs guard.validate(messages) assert not errs, 消息校验失败:\n \n.join(errs)八、排查清单Qwen3.5-27B nightly 报No user query found in messages按序查先确认是模板找不到 user错误明确No user query是 chat 模板渲染期。查是否真传了 user只发 system想续写必然报错补一条 user。查 role 名大小写/中文User/用户等模板按 user严格匹配会失败规范化。查结尾角色Qwen 模板可能要求最后一条是 user调整消息顺序。查预处理改动网关/压缩逻辑是否把 user 角色改名/丢失检查转发前的 messages。查工具调用结构tool/assistant(tool_calls) 混排时模板是否跳过真正 user。nightly 校验更严稳定版可能兜底nightly 强制 user升级注意。请求侧规范化用ChatMessageGuard统一 role 别名 保证有 user。纯 system 场景用 completion 接口而非 chat或补占位 user。最后才动模板优先在请求侧规范化/校验不要为绕开去改 Qwen chat 模板。九、小结Qwen3.5-27B 在 vLLM 0.16.0 nightly 报ValueError: No user query found in messages根子是Qwen 的 chat 模板nightly 加强校验要求 messages 中存在role user的消息可能还要求结尾为 user但请求因只含 system、role 名大小写/中文不符、消息被预处理改结构、或工具调用结构不当导致模板按严格 user匹配时找不到 user → ValueError。修复三层第一层请求侧规范化 role 名大小写/中文→标准 保证至少一条 user纯 system 补占位或改用 completion第二层抽ChatMessageGuard统一校验 role 别名/存在性/结尾/工具结构并优雅处理第三层用 pytest 把「缺 user 捕获」「role 别名归一」「纯 system 净化」「合法通过」钉进 CI请求前断言。核心认识——chat 模板对「消息结构」有契约要求尤其 Qwen 系 nightly 校验更严正确做法是在请求侧做消息规范化与存在性校验兼容 role 别名、保证 user 存在而不是把严格匹配的担子全压在模板上、等到渲染期才崩。