docs #25
@@ -79,7 +79,7 @@ Browser Go Gateway STT LLM TTS
|
||||
| 模块 | 职责 | 关键实现 |
|
||||
|------|------|---------|
|
||||
| WebSocket Hub | 管理所有客户端连接,广播/定向推送 | goroutine per connection |
|
||||
| Session Manager | 维护用户会话状态、对话历史 | Redis + TTL 过期策略 |
|
||||
| Session Manager | 维护用户会话状态、对话历史 | Redis Hash + List,30 分钟 TTL(详见 `03-接口文档.md` 第五章) |
|
||||
| Model Router | 根据请求类型选择 AI 模型 | 规则引擎 + 成本阈值 |
|
||||
| AI Orchestrator | 编排多路 AI 调用(并行/串行) | context 取消 + 超时控制 |
|
||||
| Rate Limiter | 防止单用户过度消耗 API 额度 | 令牌桶算法 |
|
||||
|
||||
148
docs/03-接口文档.md
148
docs/03-接口文档.md
@@ -533,7 +533,147 @@ func isSentenceEnd(delta string) bool {
|
||||
|
||||
---
|
||||
|
||||
## 五、数据模型
|
||||
## 五、Session Manager
|
||||
|
||||
WebSocket Handler 和 AI Orchestrator 之间的会话管理层。负责维护会话生命周期、对话上下文和配置状态。
|
||||
|
||||
### Redis 数据结构
|
||||
|
||||
每个会话在 Redis 中占 2 个 key:
|
||||
|
||||
```
|
||||
session:{id}:meta → Hash (会话元数据)
|
||||
session:{id}:history → List (对话历史)
|
||||
```
|
||||
|
||||
**Hash — `session:{id}:meta`**
|
||||
|
||||
| field | 类型 | 示例 | 说明 |
|
||||
|-------|------|------|------|
|
||||
| `session_id` | string | `"550e8400-..."` | 主键冗余 |
|
||||
| `config.tts_enabled` | string | `"true"` | Redis Hash 值均为 string |
|
||||
| `config.detail_level` | string | `"low"` | |
|
||||
| `config.language` | string | `"zh-CN"` | |
|
||||
| `created_at` | string | `"2026-06-13T10:00:00Z"` | RFC3339 |
|
||||
| `last_active` | string | `"2026-06-13T10:05:30Z"` | 每次消息刷新 |
|
||||
| `active_request_id` | string | `"uuid"` 或 `""` | 当前处理中的请求 ID,用于 interrupt |
|
||||
|
||||
**List — `session:{id}:history`**
|
||||
|
||||
每个元素是一条 JSON 序列化的 Message:
|
||||
|
||||
```json
|
||||
{"role":"user","content":"这是什么花?"}
|
||||
{"role":"assistant","content":"这是一朵红色的玫瑰。"}
|
||||
```
|
||||
|
||||
- `LPUSH` 新消息到左头(最新在前)
|
||||
- `LRANGE 0 {limit-1}` 取最近 N 轮
|
||||
- `LTRIM 0 {max-1}` 限制总条数(默认保留最近 20 条 = 10 轮对话)
|
||||
|
||||
### TTL 策略
|
||||
|
||||
| 场景 | TTL | 说明 |
|
||||
|------|-----|------|
|
||||
| 创建时 | 30 分钟 | `EXPIRE` 设置 |
|
||||
| 每次收到消息 | 重置 30 分钟 | `EXPIRE` 刷新 |
|
||||
| WebSocket 断开 | 不主动删 | 等自然过期,支持重连恢复 |
|
||||
| 超过 30 分钟无活动 | 自动过期 | Redis 自动清理 meta + history |
|
||||
| 显式销毁(REST API) | 立即 `DEL` | 两个 key 一起删 |
|
||||
|
||||
### 接口定义
|
||||
|
||||
```go
|
||||
// SessionManager 会话管理器。
|
||||
// WebSocket Handler 通过此接口操作会话,不直接接触 Redis。
|
||||
type SessionManager interface {
|
||||
// Create 创建新会话,返回 session ID。
|
||||
Create(ctx context.Context, config models.SessionConfig) (string, error)
|
||||
|
||||
// Get 获取会话(含 config)。不存在返回 ErrSessionNotFound。
|
||||
Get(ctx context.Context, sessionID string) (*models.Session, error)
|
||||
|
||||
// UpdateConfig 更新会话配置(config 消息触发)。
|
||||
UpdateConfig(ctx context.Context, sessionID string, patch models.SessionConfigPatch) error
|
||||
|
||||
// GetHistory 获取最近 N 轮对话历史(供 Orchestrator 构建 LLM 上下文)。
|
||||
GetHistory(ctx context.Context, sessionID string, limit int) ([]models.Message, error)
|
||||
|
||||
// AppendMessage 追加一条对话消息,同时刷新 TTL。
|
||||
AppendMessage(ctx context.Context, sessionID string, msg models.Message) error
|
||||
|
||||
// SetActiveRequest 标记当前正在处理的请求 ID(interrupt 用)。
|
||||
SetActiveRequest(ctx context.Context, sessionID string, requestID string) error
|
||||
|
||||
// ClearActiveRequest 清除活跃请求标记(请求完成或中断后)。
|
||||
ClearActiveRequest(ctx context.Context, sessionID string) error
|
||||
|
||||
// Touch 刷新 TTL(心跳时调用)。
|
||||
Touch(ctx context.Context, sessionID string) error
|
||||
|
||||
// Destroy 显式销毁会话(REST API DELETE 或连接断开清理)。
|
||||
Destroy(ctx context.Context, sessionID string) error
|
||||
}
|
||||
```
|
||||
|
||||
### WebSocket Handler 集成
|
||||
|
||||
```go
|
||||
// query 分支
|
||||
case "query":
|
||||
var msg models.WsQuery
|
||||
json.Unmarshal(message, &msg)
|
||||
|
||||
sessionMgr.Touch(ctx, sessionID) // 刷新 TTL
|
||||
sessionMgr.SetActiveRequest(ctx, sessionID, msg.RequestID) // 标记活跃请求
|
||||
|
||||
history, _ := sessionMgr.GetHistory(ctx, sessionID, 20) // 获取对话上下文
|
||||
|
||||
go orchestrator.ProcessQuery(ctx, client, &msg, history) // 异步编排
|
||||
|
||||
// interrupt 分支
|
||||
case "interrupt":
|
||||
reqID, _ := sessionMgr.GetActiveRequestID(ctx, sessionID)
|
||||
if reqID != "" {
|
||||
cancelFunc(reqID) // 取消对应 context
|
||||
sessionMgr.ClearActiveRequest(ctx, sessionID)
|
||||
}
|
||||
|
||||
// 连接断开
|
||||
// 不调用 Destroy,让 session 自然过期(支持重连恢复)
|
||||
```
|
||||
|
||||
### MVP 内存实现
|
||||
|
||||
联调阶段无 Redis 时,用同一接口的内存实现:
|
||||
|
||||
```go
|
||||
type InMemorySessionManager struct {
|
||||
mu sync.RWMutex
|
||||
sessions map[string]*sessionEntry
|
||||
}
|
||||
|
||||
type sessionEntry struct {
|
||||
session models.Session
|
||||
history []models.Message
|
||||
activeReqID string
|
||||
}
|
||||
```
|
||||
|
||||
注入时根据配置切换:
|
||||
|
||||
```go
|
||||
var sessionMgr SessionManager
|
||||
if cfg.Redis.Addr != "" {
|
||||
sessionMgr = NewRedisSessionManager(redisClient, 30*time.Minute, 20)
|
||||
} else {
|
||||
sessionMgr = NewInMemorySessionManager()
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 六、数据模型
|
||||
|
||||
> 注:Go 和 TypeScript 的数据模型定义见下方。AI 服务层的 Go 模型见上方"AI 服务层接口"章节。
|
||||
|
||||
@@ -611,7 +751,7 @@ type ClientMessage =
|
||||
|
||||
---
|
||||
|
||||
## 六、扩展接口设计
|
||||
## 七、扩展接口设计
|
||||
|
||||
通过 Repository 接口隔离存储层,MVP 用内存实现,后续替换为数据库——业务逻辑零改动。
|
||||
|
||||
@@ -687,7 +827,7 @@ func NewApp(cfg *Config) *App {
|
||||
|
||||
---
|
||||
|
||||
## 七、错误码
|
||||
## 八、错误码
|
||||
|
||||
| 错误码 | 含义 | 客户端处理建议 |
|
||||
|--------|------|--------------|
|
||||
@@ -702,7 +842,7 @@ func NewApp(cfg *Config) *App {
|
||||
| `TTS_ERROR` | 语音合成失败 | 静默回退到纯文本回复 |
|
||||
| `INTERNAL_ERROR` | 服务端内部错误 | 提示用户重试 |
|
||||
|
||||
## 八、连接管理
|
||||
## 九、连接管理
|
||||
|
||||
**心跳机制**:客户端每 30 秒发送 `ping`,服务端回复 `pong`。超过 60 秒无 `ping`,服务端判定连接断开并清理会话资源。
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ CamTalk 是一款多模态实时 AI 视觉对话助手。用户通过摄像头
|
||||
|------|------|
|
||||
| [01-项目概述](01-项目概述.md) | 项目目标、核心挑战、交付物 |
|
||||
| [02-系统架构](02-系统架构.md) | 三层架构、技术栈、核心交互流程、前后端模块、存储策略、部署架构 |
|
||||
| [03-接口文档](03-接口文档.md) | WebSocket 协议、REST API、**AI 服务层接口(STT/LLM/TTS)**、**编排器设计**、数据模型、错误码、连接管理(**实现时首先阅读**) |
|
||||
| [03-接口文档](03-接口文档.md) | WebSocket 协议、REST API、**AI 服务层接口**、**编排器设计**、**Session Manager(Redis)**、数据模型、错误码、连接管理(**实现时首先阅读**) |
|
||||
| [04-技术选型](04-技术选型.md) | 持久化层(PostgreSQL)和前端边缘处理层的选型对比与决策理由 |
|
||||
| [05-用户故事](05-用户故事.md) | P0/P1/P2 用户故事、验收标准、优先级决策依据 |
|
||||
| [06-语音交互](06-语音交互.md) | VAD → STT → LLM → TTS 全链路、延迟优化 |
|
||||
|
||||
Reference in New Issue
Block a user