docs: 补充 Session Manager 接口规范与 Redis 数据结构

- 03-接口文档: 新增第五章 Session Manager(Redis Hash+List 数据结构、TTL 策略、接口定义、Handler 集成、MVP 内存实现)
- 03-接口文档: 原五~八章重新编号为六~九章
- 02-系统架构: Session Manager 行补充 Redis 数据结构说明和交叉引用
- README.md: 索引补充 Session Manager 关键词
This commit is contained in:
hhs
2026-06-13 13:24:25 +08:00
parent 87b6407e2e
commit ee557eaa3d
3 changed files with 146 additions and 6 deletions

View File

@@ -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 标记当前正在处理的请求 IDinterrupt 用)。
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`,服务端判定连接断开并清理会话资源。