# P0 验证报告 · 本地 Qwen3.8-27B > ⚠️ **状态:该服务已于 2026-09-15 停用。** > 原因:用户要求换更强的语音模型(vits-zh-ll 音色不满意), > 而 3090 只有 24GB——27B 的 vLLM 占 21.5GB,装不下 Qwen3-TTS。 > 决定让 LLM 走云端 DeepSeek,GPU 让给语音。见 `P0-Qwen3TTS报告.md`。 > > **本报告的结论仍然有效**(用于将来重启该服务,或评估其它本地 LLM): > 关思考可让首 token 从 1390ms 降到 367ms;思考 token 会吃掉 max_tokens 预算; > 只接受一条 system 消息;思考字段名与 DeepSeek 不同。 日期:2026-09-14。端点:`http://192.168.0.20:18020/v1`(vLLM,局域网 1.4ms)。 脚本:`~/workspace/ai-companion/p0/verify_local_llm.py`。结果:**5/6 通过**(未通过项为视觉,见 §5)。 复现: ```bash set -a; . ~/.config/ai_assistant/env; set +a cd ~/workspace/ai-companion && python3 p0/verify_local_llm.py ``` ## 一、服务实况 方案文档假设 LLM 用 DeepSeek 云 API。实测发现局域网内已有可用服务: | 项 | 值 | |---|---| | 服务 | **vLLM**(不是 llama.cpp,服务器上两套都有) | | 模型 | `Qwen3.8-27B-W4A16-AutoRound-fast`(4bit 权重,16bit 激活) | | `max_model_len` | 65536 | | 思考解析 | `--reasoning-parser qwen3` | | 到 N5095 延迟 | **1.4ms** | | 视觉 | **不支持**(见 §5) | ## 二、思考模式:可关,且必须关 关闭方式(**已实测有效**): ```json "chat_template_kwargs": {"enable_thinking": false} ``` 实测三种模式(同一个数学题,`max_tokens=512`): | 模式 | 思考字数 | 完成 tokens | 首 token(回答) | |---|---|---|---| | 默认(不传) | 168 | 214 | 527ms | | **enable_thinking=false** | **0** | 512 | **81ms** | | enable_thinking=true | 289 | 239 | 620ms | **开思考的代价不只是慢**。看上面第二组数字:开思考时完成 tokens 只有 239, 而关思考是 512——因为思考 token 占用 `max_tokens` 预算。 在真实语音 prompt 上这个问题更严重(`max_tokens=200`): | 模式 | 首 token(回答)P50 | 完成 tokens 中位 | 实际回答 | |---|---|---|---| | **关思考** | **367ms** | 10 | 「物流显示昨天已签收。」 | | 开思考 | **1390ms** | 187 | 「我不」 ← **被截断** | 开思考时首 token 慢 3.8 倍,而且 200 的预算被思考吃光,回答只吐出两个字。 ## 三、对比 DeepSeek 云 API | 指标 | 本机 Qwen3.8-27B | DeepSeek `deepseek-flash` | |---|---|---| | 首 token(关思考) | **367ms** | 786ms | | 网络延迟 | 1.4ms | 含在 786ms 内 | | 思考模式 | 可关(`chat_template_kwargs`) | 可关(`thinking`),但字段名不同 | | 视觉 | ❌ 本实例不支持 | ✅ 可用 | | 费用 | 0(本地) | 按 token 计费 | | 数据 | 不出局域网 | 上传第三方 | **本机首 token 比云端快一倍多**,因为省掉了网络往返与排队。 ## 四、两个会改设计的集成约束 ### 1. 思考内容的字段名不一致 | 后端 | 字段名 | |---|---| | 本机 vLLM | `reasoning` | | DeepSeek | `reasoning_content` | 适配层**必须两个都认**。只按 DeepSeek 的字段名写,会静默丢弃思考内容—— 不报错,但"把思考念出来"或"思考占用显示"这类问题会莫名其妙出现。 ### 2. 只允许一条 system 消息 发送两条 system 消息直接 400: ``` System message must be at the beginning. ``` **这推翻了原记忆设计**。原方案打算"检索到的记忆作为一条独立 system message 注入", 在本机 vLLM 上会直接失败。 修正后的做法:**保持唯一一条 system 消息,每轮重建**: ``` system = 人设 + 规则 + 本轮检索到的记忆 ``` 这其实更干净,也和"注入的记忆每轮替换而非追加"的要求一致。 ## 五、未通过项:视觉 本实例返回: ``` At most 0 image(s) may be provided in one prompt. ``` 模型目录 `Qwen3.8-27B-W4A16-AutoRound-fast/` 只有 safetensors 与 config, **没有视觉塔**,是纯文本部署。 服务器上另有视觉能力:`~/models/mmproj-F16.gguf`(928MB)配合 llama.cpp 的 `128k_vision.sh`,以及 llama.cpp 的 `--mmproj` 参数。 但那是另一套服务,需要单独起。 **影响**:方案 §P5 的视觉问答在本端点不可用,需要么另起一个带 mmproj 的 llama.cpp 实例,要么走 DeepSeek。留到 P5 再定。 ## 六、其余验证项 | 项 | 结果 | |---|---| | 工具调用(关思考) | ✅ `set_light({"room":"客厅","on":true})` | | 纯文本流式 | ✅ | | 端点与模型清单 | ✅ | **未测**:取消/超时、长上下文退化、多客户端并发。 ## 七、对 P1 延迟预算的影响 更新后的预算(用本机 LLM): | 环节 | 耗时 | 来源 | |---|---|---| | VAD 判定说完 | 200–500ms | 估算,待实测 | | STT 冲刷 | ≈0ms | 实测 | | **LLM 首 token** | **367ms** | 实测 | | TTS 首音(vits-zh-ll @服务器) | 57–152ms | 实测 | | 网络 | 1.4–2ms | 实测 | | **合计** | **约 0.6–1.0 秒** | | 方案 P1 目标 P50≤2 秒。**余量超过一倍。** ## 八、上下文建议 实测语音 prompt 约 406 tokens(人设 + 记忆 + 3 轮对话)。 建议按 4k tokens 设上限,超出时截断最旧的轮次: - system(人设 + 本轮记忆):400–800 tokens - 最近对话轮次:500–1000 tokens - 当前输入:~50 tokens vLLM 服务端的 `max_model_len=65536` 是全局配置,**不需要为助手改动** (那是共享服务)——短上下文靠客户端控制实际 prompt 长度即可。 短上下文不只省资源,还直接降低首 token 延迟,这对"回应及时"是关键。 ## 九、工程陷阱记录 1. **本机 vLLM 思考字段名是 `reasoning`**,不是 `reasoning_content`(DeepSeek 的写法)。 2. **只接受一条 system 消息**,多条直接 400。 3. **开思考会吃掉 `max_tokens` 预算**,导致回答被截断。 语音场景下 `max_tokens` 本来就要设小,这个问题会被放大。 4. N5095 上系统 `python3` 无 PIL,测试脚本要用 venv 里的解释器。