Files
ylhan bdd6bfb63d 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:四条路径验证

两份旧报告加了状态说明(结论仍有效但选型已变),
并修正了随代码移走而失效的引用与复现命令。
2026-09-15 11:08:56 +08:00

5.2 KiB
Raw Permalink Blame History

P0 验证报告 · DeepSeek API

日期:2026-09-14。机器:N5095 / Ubuntu 24.04.3 / Python 3.13.5。 脚本:~/workspace/ai-companion/p0/verify_deepseek.py。结果:11/11 通过。

复现:

set -a; . ~/.config/ai_assistant/env; set +a
cd ~/workspace/ai-companion && python3 p0/verify_deepseek.py

密钥存放:~/.config/ai_assistant/env(权限 600,不在项目目录内,不进版本管理)。

结论摘要

# 项目 结果
0 模型清单 仅 deepseek-flash、deepseek-v4-pro
1a 纯文本流式 可用
1b 思考内容分离 on 模式有 reasoning_content;off 模式无
1c 首 token 延迟 P50 = 786ms,P95 = 1100ms(N=8)
2a 流式工具调用 可用,参数 JSON 正确
2b 工具结果回灌 可用
2c 思考模式约束 开启时必须回传 reasoning_content
3a 图片输入 可用,正确读出图中数字
4a 中途断开(打断) 无异常
4b 超时 正确抛出 TimeoutError
4c 错误模型名 HTTP 400,可作启动自检

逐条说明

1. 模型名:方案文档正确,Pipecat 默认值错误

GET /v1/models 实际返回:

[{"id": "deepseek-flash"}, {"id": "deepseek-v4-pro"}]
  • 方案文档 §2 记的 deepseek-flash 正确。
  • Pipecat 的 DeepSeekLLMService 默认模型是 deepseek-v4-flash,该模型不存在,直接用会 400。 实例化时必须显式覆盖为 deepseek-flash。

2. 思考模式必须显式关闭(重要)

deepseek-flash 默认开启思考模式。此时 API 要求把上一轮 assistant 消息里的 reasoning_content 原样回传,否则任何多轮对话与工具回灌都返回:

400 invalid_request_error: The `reasoning_content` in the thinking mode must be passed back to the API.

实测三种手工构造 assistant 消息的写法(content=None / content="" / 不带 tools)全部 400; 只有回传服务端返回的原始 assistant 消息才通过。

影响:多数框架的上下文层按 OpenAI 格式存储消息,不保留 reasoning_content—— 一旦开启思考模式,Pipecat 的上下文管理与工具循环会持续踩这个坑。

决定:会话主路径传 "thinking": {"type": "disabled"}。两条理由:

  1. 彻底消除 reasoning_content 回传要求,上下文层可安全裁剪消息;
  2. 开启时第一个流式 chunk 是 reasoning_content 而非 content,若直接送 TTS 会念出思考过程。 关闭后两者合一,无需分流。

Pipecat 该服务的默认值恰好是 DeepSeekThinkingConfig(type="disabled"),与本结论一致。 若将来要开思考以提升回答质量,必须同时改造上下文层保证 reasoning_content 不丢。

3. 首 token 延迟

N=8,短问答,thinking=disabled:P50 = 786ms,P95 = 1100ms(min 515 / max 1100)。

对照方案 P1 验收目标"短问答结束到首段有声回复 P50≤2 秒、P95≤4 秒", LLM 占约 0.8 秒,余下约 1.2 秒预算留给 STT 收尾判定 + TTS 首段合成。这个余量是否够, 取决于本地 TTS 的 RTF(待测,见下)。

注:thinking 开关对首包时间影响不大(约 700ms vs 718ms),但关闭后总耗时更短,因为不再生成思考 token。

4. 图片输入可用(P5 的意外好消息)

deepseek-flash 接受 image_url 的 base64 data URI,正确读出图中文字("7391")。

方案 §P5 的视觉问答不需要另找模型,按需抓拍 → 缩放 → base64 上传即可。 未测:视觉请求的 TTFT(预估显著长于纯文本)、大图 token 消耗、并发下的表现。 按需视觉是按次计费项,接 P5 时需单独测成本。

5. 工具调用链路完整

流式工具调用可用,finish_reason="tool_calls",参数 JSON 正确。 回灌工具结果后模型能生成自然语言确认("客厅的灯已经打开了")。 这是 P5 米家控制的基础链路,已验证通畅。

注意:回灌时 tool_call_id 必须用服务端返回的真实值,assistant 消息必须用服务端返回的原始对象,不能手工构造。

6. 打断与超时

  • 打断(收到若干 chunk 后主动 close):无异常抛出,连接正常释放。对应方案"打断时取消旧回复生成"的客户端能力成立。
  • 超时:非流式长生成 + 2 秒预算,正确抛出 TimeoutError。
  • 流式下 socket 超时不会因首包快而触发——"打断"和"超时"必须分开实现检测,不能只做一种。

7. 计费与缓存

usage 返回 prompt_cache_hit_tokens / prompt_cache_miss_tokens,实测命中 256/398。 系统提示词固定可吃到缓存,对月费有利。方案 §8 要求的费用统计应记录这两个字段。

遗留与未验证

  • 视觉请求的延迟与 token 成本未测。
  • 长上下文(多轮 + 记忆注入)下的延迟退化未测。
  • 并发请求未测(多用户场景下的表现)。
  • 本次仅验证 API 链路,未接入 Pipecat、未写任何管线代码。
  • 本机 github.com / huggingface.co 直连不通,需走本地 mihomo 代理 127.0.0.1:7890 或国内镜像。DeepSeek API 直连正常,不需要代理。