AI桌面陪伴助手:方案更新至 v2.4,代码剥离到独立仓库
代码剥离 - 助手本体、TTS 服务、P0 基准脚本、ESP32 固件移到 ~/workspace/ai-companion (独立 git 仓库),本目录只留方案、P0 报告与硬件记录 - 因此删除 esp32_smile_test.ino / esp32_touch_eyes.ino - 同时移除已失效的 .gitignore(原本只为挡住模型体积,代码已搬走) 方案 v2.4 重大变更:架构从"单机"改为"服务器即助手、本地为客户端" - 起因:实测 N5095 无 AVX2,跑不动可用的语音模型 - N5095 降为客户端/外设桥,只做 USB 接入、DoA、WebRTC 客户端 - 实施阶段表加进度列(P0/P1/P3/P4a 部分完成),新增三条验收要求 - 采购清单按实际到货更新,标出屏幕形态待确认(2.8寸 vs 原定1.28寸圆屏) 技术栈(实测更新) - LLM:DeepSeek deepseek-flash(云端,必须关思考);本机 27B 已停用 - TTS:Qwen3-TTS 1.7B(服务器 3090);vits-zh-ll 因音色不满意被替换 - STT:Zipformer int8 未变,中文识别率仍是未闭合项 新增两份 P0 报告 - P0-Qwen3TTS报告.md:TTS 换型过程与实测 - P0-DeepSeek验证报告.md:四条路径验证 两份旧报告加了状态说明(结论仍有效但选型已变), 并修正了随代码移走而失效的引用与复现命令。
This commit is contained in:
@@ -0,0 +1,169 @@
|
||||
# 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 里的解释器。
|
||||
Reference in New Issue
Block a user