Files
CamTalk/docs/04-技术选型.md
hhs 4b30e67c2e feat: 扩展 Config 结构体,新增 AuthConfig 配置
- 新增 AuthConfig 结构体(JWTSecret, AccessTTL, RefreshTTL)
- 在 Config 中添加 Auth 字段
- 设置默认值:access_ttl=15分钟,refresh_ttl=10080分钟(7天)
- JWTSecret 必须通过环境变量 CAMTALK_AUTH_JWT_SECRET 设置
2026-06-14 16:40:06 +08:00

13 KiB
Raw Blame History

技术选型

概述

本文档记录项目中各项技术的选型过程、替代方案对比和决策理由。技术选型没有"绝对正确",只有"更适合"。

定位:持久化部分是拓展选型,不阻塞 MVPMVP 用内存存储即可)。前端边缘处理部分是 MVP 阶段就需要确定的技术栈。AI 服务栈STT/LLM/TTS已确定默认选型可通过配置灵活切换。

技术选型
├── AI 服务栈
│   ├── STT: Deepgram默认 / MiMo ASR
│   ├── LLM: GPT-4o默认 / 通义千问等 OpenAI 兼容模型
│   └── TTS: OpenAI TTS默认 / MiMo TTS
├── 持久化层 → 数据库选型: PostgreSQL规划中MVP 阶段使用内存存储)
├── 认证与用户系统
│   ├── 认证方案: JWT (HS256), access 15min + refresh 7day
│   ├── JWT 库: golang-jwt/jwt/v5
│   ├── 密码哈希: bcrypt
│   ├── 数据库驱动: pgx/v5手写 SQL不用 ORM
│   └── 前端 Token 存储: localStorage
└── 前端边缘处理层
    ├── 边缘推理: 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.providerai.llm.modelai.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 麻烦。

MongoDBmessages 需按 session_id 关联 sessionsMongoDB 中要用 $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 集成示例

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 包容查询:

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 直接用浏览器原生接口,不加封装层

与"前端做轻量预处理"原则一致:前端层只需采集和判断"有没有值得发给后端的数据"。


四、认证与用户系统选型

总览

能力 选型 选择理由
认证方案 JWT (HS256) 无状态,分布式友好,实现简单
JWT 库 golang-jwt/jwt/v5 社区主流v5 活跃维护
密码哈希 bcrypt Go 标准库直接可用,安全性足够
数据库驱动 pgx/v5 Go 生态性能最优的 PostgreSQL 驱动
数据库迁移 手写 SQL MVP 阶段足够,后续可引入 golang-migrate

认证方案JWT

方案 特点 适用场景
JWT (HS256) 无状态 token服务端不存 session水平扩展友好 分布式部署、前后端分离
Session + Cookie 有状态,服务端存 session通常 Redis 传统 Web 应用、需要服务端控制会话
OAuth2 第三方登录授权 需要接入微信/GitHub 等第三方登录

选择 JWT 的核心理由:项目架构是前后端分离 + WebSocket 长连接JWT 无需服务端维护 session 状态天然适配。HS256 对称签名足以满足安全需求,实现比 RS256 简单。

Token 策略采用 access (15min) + refresh (7day) 双 tokenaccess_token 短生命周期降低泄露风险refresh_token 支持无感续期。

JWT 库golang-jwt/jwt/v5

方案 状态 特点
golang-jwt/jwt/v5 活跃维护 dgrijalva/jwt-go 的官方继任,社区主流
dgrijalva/jwt-go 已停维护 原始库,不再更新
lestrrat-go/jwx 活跃 功能更全JWE/JWS但项目只需签名过度引入

v5 是 Go 生态中 JWT 的事实标准API 简洁,文档完善。

密码哈希bcrypt

方案 特点 选择理由
bcrypt 自适应 cost factor抗暴力破解 Go 标准库 golang.org/x/crypto/bcrypt 直接可用
argon2 2015 年密码哈希竞赛冠军,抗 GPU/ASIC 安全性更高,但 Go 生态库不如 bcrypt 成熟
scrypt 内存硬哈希 参数调优复杂bcrypt 已足够

bcrypt 的 cost 参数可随硬件升级调大,当前默认 cost=10 足够安全。

数据库驱动pgx/v5

方案 特点 适用场景
pgx/v5 原生 PostgreSQL 协议实现,连接池 pgxpool性能最优 需要高性能、直接写 SQL
GORM 全功能 ORM自动迁移、关联预加载 快速开发、不想写 SQL
Ent Facebook 出品,类型安全的 ORM 大型项目、强类型需求
database/sql + lib/pq 标准接口,但 lib/pq 已停维护 简单场景

项目规模不大4 张表),手写 SQL 更可控,避免 ORM 的抽象泄漏和性能黑盒。pgx 原生支持 pgxpool 连接池,无需额外引入。

数据库迁移:手写 SQL

方案 特点 适用场景
手写 SQL 零依赖,完全可控 表少(<10 张)、团队小
golang-migrate CLI + 库双模式,支持版本回滚 表多、需要严格版本管理
Atlas 声明式迁移HCL 定义 schema 大型项目、多环境管理

MVP 阶段 4 张表,手写 schema.sql 即可。后续表结构复杂后可引入 golang-migrate。

前端 Token 存储

方案 特点 选择理由
localStorage 持久化存储刷新不丢失JS 可直接读写 简单直接SPA 应用标准做法
httpOnly Cookie 防 XSS 读取,但需防 CSRF 传统 Web 应用,需额外 CSRF 防护
sessionStorage 仅当前标签页有效 关闭标签页需重新登录,体验差

JWT 存 localStorage配合请求拦截器统一附加 Authorization: Bearer <token> header。refresh_token 同样存 localStorage401 时自动触发刷新流程。