Files
CamTalk/docs/04-技术选型.md
hhs 6e0c67e1cb docs: 文档与代码一致性检查与修复
- 修复心跳 Bug:应用层 ping 不更新 lastPong,60 秒后连接会被错误断开
- 03-接口文档:audio/mpeg→audio/mp3、STTConfig/TTSConfig 补充 Model 字段、
  APP_ENV 环境变量名修正、配置搜索路径补充、.env 加载说明、Vite proxy 说明修正
- 02-系统架构:补充 ConfigPanel/Toast 组件、Model Router/Rate Limiter 标注规划中、
  补充 Gin 框架、MVP 存储改为 Memory、AI 服务 provider 更新、Orchestrator 伪代码对齐
- 04-技术选型:新增 AI 服务栈选型章节(STT/LLM/TTS)、PostgreSQL 标注规划中
- 06-语音交互:VAD 参数名修正、STT 改为一次性识别描述、音频编码格式补充
- 07-视觉理解:关键帧检测代码改为 TypeScript、分辨率修正、阈值逻辑统一
- 08-成本控制:变量名修正、未实现功能标注规划中、对话历史裁剪策略补充
- CLAUDE.md:同步更新技术栈、模块结构、存储策略描述
2026-06-14 08:52:36 +08:00

217 lines
9.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 技术选型
## 概述
本文档记录项目中各项技术的**选型过程、替代方案对比和决策理由**。技术选型没有"绝对正确",只有"更适合"。
**定位**:持久化部分是拓展选型,不阻塞 MVPMVP 用内存存储即可)。前端边缘处理部分是 MVP 阶段就需要确定的技术栈。AI 服务栈STT/LLM/TTS已确定默认选型可通过配置灵活切换。
```
技术选型
├── AI 服务栈
│ ├── STT: Deepgram默认 / MiMo ASR
│ ├── LLM: GPT-4o默认 / 通义千问等 OpenAI 兼容模型
│ └── TTS: OpenAI TTS默认 / MiMo TTS
├── 持久化层 → 数据库选型: PostgreSQL规划中MVP 阶段使用内存存储)
└── 前端边缘处理层
├── 边缘推理: ONNX Runtime Web规划中MVP 使用 Canvas 像素比较)
├── 语音检测: @ricky0123/vad-web
└── 媒体采集: MediaDevices API
```
---
## 一、AI 服务栈选型
### STT语音识别
| 方案 | 延迟 | 成本 | 特点 |
|------|------|------|------|
| **Deepgram**(默认) | <500ms | 按分钟计费 | 流式识别延迟极低WebSocket 接口 |
| **MiMo ASR**(小米) | ~1s | 按量计费 | 国产替代,兼容 OpenAI chat/completions 格式HTTP 非流式 |
| Whisper API | 1-3s | 按分钟计费 | 准确率高,支持多语言 |
| FunASR | <500ms | 自部署免费 | 阿里开源,中文优化 |
当前默认使用 Deepgram nova-2可通过 `ai.stt.provider` 配置切换到 MiMo ASR。
### LLM多模态大模型
| 方案 | 成本 | 特点 |
|------|------|------|
| **GPT-4o**(默认) | $2.5/1M tokens | 视觉理解能力强API 成熟,流式推理 |
| 通义千问 qwen3-vl-plus | 按量计费 | 阿里云,通过 OpenAI 兼容接口调用 |
| Claude Sonnet | $3/1M tokens | Anthropic长上下文能力强 |
代码通过 OpenAI 兼容接口调用,可灵活切换到任何兼容服务商。配置 `ai.llm.provider``ai.llm.model``ai.llm.endpoint` 即可。
### TTS语音合成
| 方案 | 成本 | 特点 |
|------|------|------|
| **OpenAI TTS**(默认) | $15/1M 字符 | 音质自然,支持流式,默认模型 tts-1语音 alloy |
| MiMo TTS小米 | 按量计费 | 国产替代,通过配置切换 |
当前默认使用 OpenAI TTStts-1, alloy可通过 `ai.tts.provider` 配置切换。
---
## 二、持久化层选型规划中MVP 阶段使用内存存储)
### 数据特征分析
| 数据 | 结构特征 | 读写模式 | 数据量级 |
|------|---------|---------|---------|
| 对话消息 | 强结构化 | 写多读少,按会话聚合读取 | 中(每用户日均 ~100 条) |
| 会话元信息 | 强结构化 | 写少读少 | 低 |
| 对话上下文 | 半结构化 JSON | 高频读写TTL 过期 | 低(仅当前窗口) |
| 用量统计 | 强结构化 | 写多,定期聚合读 | 低(日粒度汇总后很小) |
| 用户偏好 | 强结构化 KV | 写极少读少 | 极低 |
| 关键帧图像 | 非结构化二进制 | 写少,按需读 | 大(单张 100KB~1MB |
核心数据(对话、会话、统计)都是**强结构化**的,关系型数据库天然适配。"对话上下文"是半结构化 JSON需要数据库对 JSON 有良好支持。
### 候选方案对比
| 维度 | PostgreSQL | MySQL | SQLite | MongoDB | TiDB |
|------|-----------|-------|--------|---------|------|
| 数据模型 | 关系型 + JSONB | 关系型 | 关系型(嵌入式) | 文档型BSON | 关系型(分布式) |
| JSON 支持 | JSONB 原生索引 | JSON 类型,索引弱 | 无原生支持 | 天生擅长 | 兼容 MySQL JSON |
| 关联查询 | 强 | 强 | 强 | 弱(需 $lookup | 强 |
| 聚合统计 | 窗口函数/CTE | 基础聚合 | 基础聚合 | 聚合管道 | 强 |
| 并发能力 | 高MVCC | 中 | 低(单写锁) | 高 | 极高(分布式) |
| Go 生态 | pgx / GORM | go-sql-driver | go-sqlite3 | mongo-go-driver | 兼容 MySQL 驱动 |
### 淘汰理由
**SQLite** — 写锁是全局的,并发写入会频繁锁等待。多个 Go Gateway 实例无法共享同一 SQLite 文件。适合单机桌面应用,不适合 Web 服务。
**MySQL** — JSON 类型索引能力弱,无法对 JSON 内部字段高效查询。缺少 `gen_random_uuid()` 等原生函数。如果团队只熟悉 MySQLMVP 阶段完全可用,后续复杂查询会比 PostgreSQL 麻烦。
**MongoDB**`messages` 需按 `session_id` 关联 `sessions`MongoDB 中要用 `$lookup`,写法复杂且性能不如 SQL JOIN。用量统计的"按天聚合"用 SQL 一句话搞定MongoDB 聚合管道代码量多 3-5 倍。
**TiDB** — 部署复杂(至少 3 PD + 3 TiKV + 2 TiDB单机 PostgreSQL 完全够用,过度设计。
### 选择 PostgreSQL 的理由
| 项目需求 | PostgreSQL 匹配点 |
|---------|------------------|
| 强结构化数据 | 原生关系型SQL 标准完备 |
| JSON 半结构化 | JSONB 支持索引、路径查询、部分更新 |
| messages ↔ sessions 关联 | 完整的 FK 约束 + JOIN |
| 用量按天/周/月聚合 | 窗口函数、CTE、`DATE_TRUNC` |
| Go 后端对接 | pgx 驱动性能优秀GORM/Ent 支持成熟 |
| 未来全文搜索 | 内置 `tsvector`,无需额外引入 ES |
### Go 集成示例
```go
import "github.com/jackc/pgx/v5/pgxpool"
pool, _ := pgxpool.New(ctx, "postgres://user:pass@localhost:5432/vision_ai")
func SaveMessage(ctx context.Context, pool *pgxpool.Pool, msg *Message) error {
_, err := pool.Exec(ctx,
`INSERT INTO messages (session_id, role, content, image_url, tokens_used)
VALUES ($1, $2, $3, $4, $5)`,
msg.SessionID, msg.Role, msg.Content, msg.ImageURL, msg.TokensUsed,
)
return err
}
func GetWeeklyUsage(ctx context.Context, pool *pgxpool.Pool, userID string) ([]UsageRow, error) {
rows, _ := pool.Query(ctx,
`SELECT date, llm_tokens, estimated_cost
FROM usage_daily
WHERE user_id = $1 AND date >= CURRENT_DATE - INTERVAL '7 days'
ORDER BY date`, userID)
defer rows.Close()
// ... scan rows
}
```
JSONB 包容查询:
```sql
SELECT id, content, created_at
FROM messages
WHERE role = 'user'
AND content @> '{"text": "花"}'
ORDER BY created_at DESC
LIMIT 20;
```
### 冷热分离架构
```
Go Gateway
├── 写入路径 → Redis实时会话状态
│ → PostgreSQL对话历史 + 用量)
└── 读取路径 → Redis当前上下文
→ PostgreSQL历史记录
```
建议异步写入——实时消息先写 Redis异步批量刷入 PostgreSQL不影响对话体验。
### 决策流程
```
需要持久化?
├── 否 → 继续用 Redis
└── 是 → 数据强结构化?
├── 否, 高度嵌套 → 考虑 MongoDB
└── 是 → 数据量级?
├── < 100GB, 单机可扛 → PostgreSQL
├── 海量, 需水平扩展 → TiDB / CockroachDB
└── 极小, 单文件即可 → SQLite
```
---
## 二、前端边缘处理层选型
### 总览
| 能力 | 当前选型 | 选择理由 |
|------|---------|---------|
| 边缘推理 | ONNX Runtime Web | 通用推理引擎模型无关WASM 加速 |
| 语音检测 | @ricky0123/vad-web | 包装原生 WebRTC VAD零延迟体积极小 |
| 媒体采集 | MediaDevices API | 浏览器原生接口,无中间层,零依赖 |
### 边缘推理ONNX Runtime Web
| 方案 | 特点 | 适用场景 |
|------|------|---------|
| **ONNX Runtime Web** | 通用推理引擎,支持任意 ONNX 模型WASM 加速 | 自定义模型 pipeline |
| TensorFlow.js | Google 生态WebGL/WebGPU 加速 | 模型本身就是 TF 格式 |
| MediaPipe | 开箱即用 CV 任务 | 只需常见 CV 任务,不需自定义模型 |
| Transformers.js | HuggingFace 生态 | 快速集成预训练模型 |
项目需要同时跑 VAD 和关键帧检测两种自定义模型。ONNX 是跨框架通用格式,核心优势是**模型无关**。
### 语音检测:@ricky0123/vad-web
| 方案 | 特点 | 适用场景 |
|------|------|---------|
| **@ricky0123/vad-web** | 基于 WebRTC VAD~100KB 含 WASM纯前端零延迟 | "有没有人说话"二分类 |
| Web Audio API + 能量检测 | AnalyserNode 计算 RMS | 极简但不抗噪 |
| Silero VAD (ONNX) | 神经网络级 VAD | 嘈杂环境需更精准 |
| Picovoice Porcupine | 商业级唤醒词引擎 | 需要唤醒词功能 |
vad-web 是"够用且最轻"的平衡点——直接包装浏览器原生 WebRTC VAD 算法。
### 媒体采集MediaDevices API
`navigator.mediaDevices.getUserMedia()` 是所有浏览器音视频采集的**唯一标准入口**。所有上层封装库底层都是调这个 API。项目需要原始 MediaStream用封装库反而要多一层解包。
### 选型共同逻辑
三个技术选择的共同决策模式——**选择最薄的抽象层**
| 技术 | "最薄"体现在 |
|------|------------|
| ONNX Runtime Web | 不绑定特定框架,模型格式通用 |
| @ricky0123/vad-web | 包装原生 WebRTC VAD没有多余的模型加载 |
| MediaDevices API | 直接用浏览器原生接口,不加封装层 |
与"前端做轻量预处理"原则一致:前端层只需采集和判断"有没有值得发给后端的数据"。