diff --git a/.gitignore b/.gitignore index 767da6e..d9924a6 100644 --- a/.gitignore +++ b/.gitignore @@ -61,10 +61,13 @@ platform_blocklist.json *.exe~ .claude/ -# ========== 文档 (项目规范:docs/ 不纳入版本管理,docs/api/ 为例外) ========== +# ========== 文档 (项目规范:docs/ 不纳入版本管理,以下为例外) ========== docs/* !docs/api/ !docs/deploy/ +!docs/dev-plan/ +!docs/cyrene-project-architecture-analysis.md +!docs/dev_must_read.md # ========== 调试临时文件 (项目规范:debug/cache/ 为临时脚本目录) ========== debug/cache/ diff --git a/docs/cyrene-project-architecture-analysis.md b/docs/cyrene-project-architecture-analysis.md new file mode 100644 index 0000000..960185f --- /dev/null +++ b/docs/cyrene-project-architecture-analysis.md @@ -0,0 +1,857 @@ +# Cyrene AI 项目架构与功能分析文档 + +> **日期**:2026-07-07(原稿 2026-05-23,已更新反映近期变动) +> **分支**:`dev` +> **项目根目录**:`d:\Project\Code\Uni\Cyrene` +> **近期变更摘要**:详见 [15-june-july-2026-fixes.md](dev-plan/15-june-july-2026-fixes.md) + +--- + +## 目录 + +1. [项目概览](#一项目概览) +2. [总体架构](#二总体架构) +3. [后端服务详解](#三后端服务详解) + - [AI-Core (8081) — 对话引擎](#31-ai-core-8081--对话引擎) + - [Gateway (8080) — API 网关](#32-gateway-8080--api-网关) + - [Memory-Service (8091) — 记忆系统](#33-memory-service-8091--记忆系统) + - [工具系统 (pkg/plugins + AI-Core)](#34-工具系统-pkgplugins--ai-core-集成) + - [IoT-Debug-Service (8083) — 模拟设备](#35-iot-debug-service-8083--模拟设备) + - [Voice-Service (8093) — 语音服务](#36-voice-service-8093--语音服务) + - [Proto (占位)](#37-proto-占位) +4. [前端详解](#四前端详解) + - [技术栈](#41-技术栈) + - [状态管理](#42-状态管理) + - [组件树](#43-组件树) + - [自定义 Hooks](#44-自定义-hooks) + - [API 模块](#45-api-模块) + - [WebSocket 消息流](#46-websocket-消息流) +5. [ethend (9090) — 调试工具](#五ethend-9090--调试工具) +6. [对话管线详解](#六对话管线详解) +7. [数据库设计](#七数据库设计) +8. [安全性](#八安全性) +9. [已知限制与改进方向](#九已知限制与改进方向) + +--- + +## 一、项目概览 + +Cyrene(昔涟)是一个 AI 数字伴侣系统,以 React SPA 为前端,Go 微服务集群为后端,通过 PostgreSQL 持久化数据和 pgvector 向量搜索实现长期记忆。系统以虚拟角色"昔涟"的固定人格与用户对话,支持 IoT 智能家居操控、定时提醒、知识库管理、自动化规则引擎、语音识别/合成、图片分析、互联网搜索 (SearXNG) 等功能。 + +| 维度 | 数据 | +|------|------| +| 后端语言 | Go 1.24 | +| 前端框架 | React 18.3 + TypeScript 5.6 + Vite 6.0 | +| 数据库 | PostgreSQL (pgvector 向量扩展) | +| LLM 模型 | 多模型配置系统 (models.json),支持多 Provider/多用途路由回退链 | +| WebSocket 库 | gorilla/websocket (Go), 原生 WebSocket (浏览器) | +| HTTP 框架 | Gin (Gateway), net/http (其他服务) | +| 状态管理 | Zustand 4.5 | +| CSS 框架 | Tailwind CSS 3.4 | +| 包管理器 | pnpm | +| Go 代理 | GOPROXY=https://goproxy.cn,direct | + +--- + +## 二、总体架构 + +``` +┌──────────────────────────────────────────────────────────────┐ +│ Browser (React SPA) │ +│ localhost:5173 (dev) / 生产由 Gateway 托管静态文件 │ +└───────────┬──────────────────────────────────┬───────────────┘ + │ WebSocket (ws://gateway:8080/ws/chat) + │ + REST API (gateway:8080/api/v1/*) + ▼ +┌──────────────────────────────────────────────────────────────┐ +│ Gateway (:8080) │ +│ Gin Router → JWT Auth → Rate Limiter → Handlers │ +│ WebSocket Hub: 会话状态/消息缓存/IoT广播 │ +│ 规则引擎: 定时/事件触发自动化 │ +└───┬──────────┬──────────┬──────────┬─────────────┘ + │ SSE │ HTTP │ HTTP │ HTTP + ▼ ▼ ▼ ▼ +┌────────┐ ┌────────┐ ┌────────┐ ┌──────────────┐ +│AI-Core │ │Memory │ │Voice │ │IoT Debug │ +│ :8081 │ │:8091 │ │:8093 │ │ :8083 │ +│ │ │ │ │ │ │ │ +│编排器 │ │PGVector│ │whisper │ │8个模拟设备 │ +│意图分析 │ │语义搜索│ │edge-tts│ │toggle/set/ │ +│子会话 │ │去重衰减│ │TTS回退│ │history API │ +│人格系统 │ │ │ │ │ │传感器波动 │ +│思考引擎 │ │ │ │ │ │ │ +│工具调用 │ │ │ │ │ │ │ +└────┬───┘ └────┬───┘ └────┬───┘ └──────────────┘ + │ │ │ │ + └──────────┴──────────┴──────────┘ + │ + ┌───────▼───────┐ + │ PostgreSQL │ + │ + pgvector │ + └───────────────┘ +``` + +**核心数据流**:用户消息 → Gateway WebSocket → AI-Core SSE → 编排器并行处理(意图分析 → 子会话分派 → LLM 合成 → 审查拆分) → Gateway 解析 → WebSocket 逐条返回前端。 + +--- + +## 三、后端服务详解 + +### 3.1 AI-Core (:8081) — 对话引擎 + +**目录**:`backend/ai-core/` +**入口**:[cmd/main.go](backend/ai-core/cmd/main.go) +**包数量**:11 个内部包,约 40 个 `.go` 文件 + +#### 3.1.1 启动流程 + +1. 加载 `.env` 环境变量 +2. 初始化人格加载器(`persona.NewLoader`)——从 `internal/persona/` 目录读取 YAML 配置 +3. 初始化 LLM 适配器:优先加载 `models.json` → `ModelSelector`;无配置文件时回退到 `.env` +4. 初始化记忆系统(`memory.NewStore` + `NewRetriever` + `NewExtractor`)——PostgreSQL 持久化 +5. 初始化会话历史存储(`context.NewConversationStore`)——内存缓存,上限 50 条 +6. 初始化 IoT 客户端(`tools.NewIoTClient`)——连接 IoT Debug Service +7. 注册 13 个 LLM 可调用工具(`tools.NewRegistry`) +8. 启动后台思考引擎(`background.NewThinker`) +9. 构建编排器 v2.0(`orchestrator.NewOrchestrator`) +10. 注册 HTTP 端点:`/api/v1/chat`(SSE)、`/api/v1/memory/search`、`/api/v1/memory`(CRUD)、`/api/v1/health` + +#### 3.1.2 包结构 + +| 包 | 文件 | 职责 | +|----|------|------| +| `orchestrator/` | `orchestrator.go`, `intent_analyzer.go`, `synthesizer.go` | 对话编排 v2.0:意图分析→子会话分派→综合生成 | +| `subsession/` | `manager.go`, `registry.go`, `general_provider.go`, `memory_provider.go`, `iot_provider.go`, `review_provider.go` | 子会话框架:4 个提供者并行执行 | +| `llm/` | `adapter.go`, `openai.go`, `stream.go`, `selector.go` | LLM 抽象层:OpenAI 兼容协议、流式输出、断句器、多模型路由选择器 | +| `config/` | `loader.go` | 模型配置加载器:只读加载 models.json | +| `memory/` | `store.go`, `retriever.go`, `extractor.go`, `client.go` | 记忆系统:存储/检索/提取/HTTP 客户端 | +| `persona/` | `loader.go`, `injector.go` | 人格管理:YAML 加载、系统提示构建、风格注入 | +| `tools/` | `registry.go`, `calculator_tool.go`, `datetime_tool.go`, `crypto_tool.go`, `file_tool.go`, `http_tool.go`, `iot_client.go`, `iot_control_tool.go`, `iot_tools.go`, `json_tool.go`, `markdown_tool.go`, `random_tool.go`, `text_tool.go`, `web_fetch.go`, `web_search.go` | 工具系统:13 个 LLM 可调用工具 + IoT 客户端 | +| `context/` | `builder.go` | 上下文构建器:会话历史/人格/子会话结果组合为 LLM 提示 | +| `background/` | `thinker.go` | 后台思考引擎:事件驱动(chat 后/沉默)自主思考 | +| `model/` | `message.go`, `session.go`, `sub_session.go`, `memory.go` | 共享数据模型:消息、会话、子会话、记忆 | + +#### 3.1.3 Orchestrator v2.0 管线 + +``` +用户输入 → ProcessInput() + ├─ 1. 意图分析 (intentAnalyzer.Analyze) + │ ├─ isStrongIoTCommand() 快速通道 (0s) + │ ├─ isGreeting() 快速通道 (0s) + │ └─ LLM 意图分析 (fallback) + ├─ 2. 加载人格配置 → BuildSystemPrompt + ├─ 3. 子会话分派 (subManager.Dispatch) + │ ├─ general_provider (通用对话意图) + │ ├─ memory_provider (记忆检索) + │ ├─ iot_provider (IoT 设备查询/操控) + │ └─ review_provider (审查拆分) + │ 快速通道: greeting/纯聊天 → 跳过所有子会话 + ├─ 4. 200ms 超时等待子会话结果 + ├─ 5. Synthesizer 流式生成 (ChatWithTools + 最多5轮工具调用循环) + ├─ 6. 流式输出 delta → SSE + ├─ 7. parseReviewMessages() 审查拆分 → StreamReview SSE + ├─ 8. 断句信息 → StreamSegments SSE + ├─ 9. StreamDone → [DONE] + └─ 10. 后处理: 缓存回复 + 异步记忆提取 +``` + +**快速通道条件**: +- IoT 命令:`controlWords ∩ msg AND deviceWords ∩ msg` → 跳过 LLM 意图分析(节省 2-3s) +- 纯问候/聊天无 IoT 无 Memory:跳过所有子会话分派 + +**`parseReviewMessages()`** — 括号匹配状态机: +- 输入:`"(歪着头看你) 叶酱,客厅灯早就开着啦♪..."` +- 输出:`[{type: "action", content: "歪着头看你"}, {type: "chat", content: "叶酱,客厅灯早就开着啦♪..."}]` +- 支持 `()` 和 `()` 两种括号 +- `splitReviewLongMessage()`:80 字符智能断句(句号/感叹号/问号/逗号边界) + +#### 3.1.4 Intent Analyzer + +**文件**:[intent_analyzer.go](backend/ai-core/internal/orchestrator/intent_analyzer.go) + +**快速通道关键词**: +```go +controlWords = ["打开", "关闭", "关掉", "关上", "调到", "设置", "开关", "调节", "调高", "调低", "开一下", "关一下"] +deviceWords = ["灯", "空调", "窗帘", "电视", "风扇", "加湿器", "插座", "门锁", "传感器"] +``` + +**意图类型**:`iot_control`, `iot_query`, `greeting`, `chat`, `story`, `memory_trigger`, `knowledge`, `task` + +#### 3.1.5 IoT Provider (子会话) + +**文件**:[iot_provider.go](backend/ai-core/internal/subsession/iot_provider.go) + +- `Execute()`:收集所有 device-action 对 → 批量执行 +- 上下文窗口:±30 字节 + 全文回退逻辑 +- 操作检测:`hasOpen`/`hasClose` 布尔值判断 +- 通过 `personaDir` 字段加载 IoT 回复人格配置 + +#### 3.1.6 后台思考引擎 + +- 事件驱动:`TriggerPostChatThink()` 在每次对话后触发 +- 沉默触发:用户长时间不活动 +- 思考内容可持久化到 memory-service + +--- + +### 3.2 Gateway (:8080) — API 网关 + +**目录**:`backend/gateway/` +**入口**:[cmd/main.go](backend/gateway/cmd/main.go) +**包数量**:8 个内部包,约 30 个 `.go` 文件 + +#### 3.2.1 启动流程 + +1. 加载配置 (`config.Load`) +2. 确保上传目录 `./uploads/` 存在 +3. 初始化 7 个持久化 Store(降级:连接失败不影响启动) +4. 种子数据:自动创建 admin 用户 + 清理旧 admin 用户 +5. 初始化 WebSocket Hub + 闲置会话清理 + IoT 广播 +6. 初始化规则引擎 +7. 配置 Gin 路由 → 启动 HTTP 服务 +8. 启动提醒/简报调度器 + +#### 3.2.2 路由表 + +**公开路由**: +| 方法 | 路径 | 说明 | +|------|------|------| +| GET | `/api/v1/health` | 健康检查 | +| POST | `/api/v1/auth/register` | 注册(限流) | +| POST | `/api/v1/auth/login` | 登录(限流) | + +**需认证路由** (JWT + Rate Limit): +| 方法 | 路径 | Handler | +|------|------|---------| +| POST | `/api/v1/auth/refresh` | authHandler | +| POST | `/api/v1/sessions` | sessionHandler.Create | +| GET | `/api/v1/sessions` | sessionHandler.List | +| DELETE | `/api/v1/sessions` | sessionHandler.DeleteAll | +| GET | `/api/v1/sessions/:id` | sessionHandler.Get | +| DELETE | `/api/v1/sessions/:id` | sessionHandler.Delete | +| GET | `/api/v1/sessions/:id/messages` | sessionHandler.GetMessages | +| DELETE | `/api/v1/sessions/:id/messages` | sessionHandler.ClearMessages | +| GET | `/api/v1/sessions/:id/export` | sessionHandler.ExportSession | +| GET | `/api/v1/messages/search` | sessionHandler.SearchMessages | +| GET | `/api/v1/memory/search` | memoryHandler.Query | +| GET | `/api/v1/memory` | memoryHandler.List | +| POST | `/api/v1/memory` | memoryHandler.Add | +| DELETE | `/api/v1/memory` | memoryHandler.Delete | +| POST | `/api/v1/notifications/push` | notificationHandler.Push | +| GET/POST/PUT/DELETE | `/api/v1/reminders*` | reminderHandler | +| GET/POST | `/api/v1/briefings*` | briefingHandler | +| POST/GET | `/api/v1/voice/*` | voiceHandler | +| POST/GET/DELETE | `/api/v1/files/*` | fileHandler | +| GET/POST/PUT/DELETE | `/api/v1/automation/rules*` | automationHandler | +| GET/POST/PUT/DELETE | `/api/v1/automation/scenes*` | automationHandler | +| POST/GET/PUT/DELETE | `/api/v1/knowledge/*` | knowledgeHandler | +| POST/GET | `/api/v1/images/*` | imageHandler | + +**WebSocket**: +| 路径 | 说明 | +|------|------| +| `GET /ws/chat?token=xxx&session_id=xxx` | WebSocket 升级(仅限 admin 用户) | + +**内部服务** (Internal Service Token): +| 方法 | 路径 | 说明 | +|------|------|------| +| POST | `/api/v1/internal/notify` | 内部通知推送 | + +**Webhook** (Webhook Auth): +| 方法 | 路径 | 说明 | +|------|------|------| +| POST | `/api/v1/webhook/generic` | 通用 Webhook | +| POST | `/api/v1/webhook/discord` | Discord Webhook | + +#### 3.2.3 WebSocket Hub + +**文件**:[hub.go](backend/gateway/internal/ws/hub.go) + +核心数据结构: +- `clients map[*Client]bool` — 所有活跃连接 +- `userClients map[string]map[*Client]bool` — 按用户索引 +- `sessions map[string]*SessionState` — 会话状态追踪 +- `conversationCache sync.Map` — 对话缓存(最多 50 条/session) + +功能: +- 客户端注册/注销(优雅清理,两阶段广播) +- 按用户/会话精准推送 +- 闲置会话自动标记(超过 idleTimeout 无活动 → state="idle") +- IoT 设备状态广播:每 10 秒轮询 IoT Debug Service 并推送给所有客户端 +- 对话缓存:`CacheMessage()` / `GetConversation()` / `GetSessionHistory()` + +#### 3.2.4 消息持久化 + +**WebSocket handler** ([chat_handler.go](backend/gateway/internal/handler/chat_handler.go)) 的 `streamResponse()`: + +1. 用户消息**立即**持久化到 DB(在 WebSocket 发送前) +2. AI 回复**流式**接收 SSE,逐 delta 转发 WebSocket +3. `review_messages` 解析后每条独立持久化(role="action"/"assistant") +4. 最终完整文本也持久化一次 + +#### 3.2.5 Store 层 + +| Store | 文件 | 功能 | +|-------|------|------| +| `SessionStore` | `session_store.go` | 会话 CRUD、消息持久化、搜索 | +| `UserStore` | `user_store.go` | 用户注册/查询/列表/删除 | +| `ReminderStore` | `reminder_store.go` | 提醒 CRUD | +| `BriefingStore` | `briefing_store.go` | 每日简报 CRUD | +| `AutomationStore` | `automation_store.go` | 自动化规则/场景 CRUD | +| `FileStore` | `file_store.go` | 文件上传/管理 | +| `KnowledgeStore` | `knowledge_store.go` | 知识库/文档管理 | + +#### 3.2.6 规则引擎 + +**文件**:[rule_engine.go](backend/gateway/internal/engine/rule_engine.go) + +- 事件驱动自动化:定时触发 / Webhook 触发 +- 场景执行:一组规则的批量触发 +- 通过 WebSocket 向用户推送通知 + +--- + +### 3.3 Memory-Service (:8091) — 记忆系统 + +**目录**:`backend/memory-service/` +**入口**:[cmd/main.go](backend/memory-service/cmd/main.go) +**文件数**:6 个 Go 文件 + +#### 3.3.1 包结构 + +| 包 | 文件 | 职责 | +|----|------|------| +| `cmd/` | `main.go` | HTTP 服务入口 | +| `internal/config/` | `config.go` | 配置加载 | +| `internal/model/` | `memory.go` | 记忆数据模型 | +| `internal/store/` | `store.go` | PostgreSQL + pgvector 存储层 | +| `internal/service/` | `memory_service.go` | 业务逻辑层 | +| `internal/handler/` | `memory_handler.go` | HTTP 处理器 | + +#### 3.3.2 记忆数据模型 + +``` +MemoryEntry { + ID, UserID, Content, Category, Priority, + Embedding (pgvector 1536维), + CreatedAt, UpdatedAt, DecayFactor, AccessCount, LastAccessedAt +} +``` + +#### 3.3.3 核心功能 + +- **语义搜索**:pgvector 余弦相似度检索 top-N 相关记忆 +- **去重**:Jaccard 相似度检测,合并高相似度记忆 +- **衰减机制**:`DecayFactor` 随时间衰减,低权重记忆被清理 +- **记忆巩固**:高访问频率记忆自动提升优先级 +- **CRUD API**:创建/查询/列表/删除 + +#### 3.3.4 HTTP API + +| 端点 | 方法 | 说明 | +|------|------|------| +| `/api/v1/memories` | POST | 创建记忆 | +| `/api/v1/memories?user_id=xxx` | GET | 列表 | +| `/api/v1/memories/:id` | GET | 获取 | +| `/api/v1/memories/:id` | DELETE | 删除 | +| `/api/v1/memories/search?user_id=xxx&q=xxx&limit=10` | GET | 语义搜索 | +| `/api/v1/thinking/logs` | POST | 记录思考日志 | +| `/api/v1/health` | GET | 健康检查 | + +--- + +### 3.4 工具系统 (pkg/plugins + AI-Core 集成) + +> **迁移说明:** tool-engine (8092) 已移除。工具注册与调用整合到 `pkg/plugins` 共享模块,由 AI-Core 直接管理。 + +**目录**:`backend/pkg/plugins/` +**核心**:[pkg/plugins/manager/registry.go](backend/pkg/plugins/manager/registry.go) +**插件数**:11 个共享插件 + 5 个 AI-Core 专属工具 + +#### 3.4.1 16 个 LLM 可调用工具 + +**共享插件** (`pkg/plugins/`): + +| 工具 | 目录 | 功能 | +|------|------|------| +| calculator | `calculator/` | 数学表达式求值 | +| datetime | `datetime/` | 日期时间计算/格式化 | +| text | `text/` | 文本处理(统计/转换/截断) | +| crypto | `crypto/` | 哈希/加解密 | +| random | `random/` | 随机数/字符串生成 | +| markdown | `markdown/` | Markdown 渲染 | +| json | `json/` | JSON 解析/查询/格式化 | +| file | `file/` | 文件读写/列表 | +| http | `http/` | HTTP 请求(GET/POST 等) | +| web_search | `web_search/` | SearXNG 网络搜索 (DuckDuckGo 兜底) | +| web_fetch | `web_fetch/` | 网页内容提取 | + +**AI-Core 专属工具** (`ai-core/internal/tools/`): + +| 工具 | 功能 | +|------|------| +| iot_query | IoT 设备状态查询 | +| iot_control | IoT 设备操控 | +| host_exec | 主机命令执行 (沙箱) | +| host_file | 主机文件操作 (沙箱) | +| host_system | 主机系统信息 | +| vision_analyze | 图片视觉分析/OCR | +| knowledge_search | 知识库 RAG 检索 | +| knowledge_ingest | 知识库文档导入 | + +#### 3.4.2 ToolRegistry 调用审计 + +[registry.go](backend/pkg/plugins/manager/registry.go) — 内存环形缓冲区 (500 条) 记录工具调用的参数/结果/耗时/成功率。API 端点: +- `GET /api/v1/tools/calls` — 分页查询,支持按工具名过滤 +- `GET /api/v1/tools/calls/stats` — 按工具聚合的成功率/平均耗时 + +#### 3.4.3 主聊天流程工具调用 + +`Synthesizer` 通过 `ChatWithTools` 向 LLM 传递工具定义,支持最多 5 轮工具调用循环。后台思考器使用相同机制。 + +--- + +### 3.5 IoT-Debug-Service (:8083) — 模拟设备 + +**目录**:`backend/iot-debug-service/` +**单文件服务**:[cmd/main.go](backend/iot-debug-service/cmd/main.go)(626 行) + +#### 3.5.1 模拟设备列表 + +| ID | 名称 | 类型 | 可操作性 | +|----|------|------|---------| +| `light-livingroom` | 客厅灯 | light | toggle, brightness, color | +| `light-bedroom` | 卧室灯 | light | toggle, brightness, color | +| `ac-livingroom` | 客厅空调 | ac | toggle, temperature, mode | +| `ac-bedroom` | 卧室空调 | ac | toggle, temperature, mode | +| `curtain-livingroom` | 客厅窗帘 | curtain | toggle, position | +| `sensor-temperature` | 温度传感器 | sensor | 只读 | +| `sensor-humidity` | 湿度传感器 | sensor | 只读 | +| `lock-door` | 智能门锁 | lock | toggle, battery | + +#### 3.5.2 API + +| 端点 | 方法 | 说明 | +|------|------|------| +| `/api/v1/devices` | GET | 列出所有设备(不含历史) | +| `/api/v1/devices/{id}` | GET | 获取单个设备(含最近 10 条历史) | +| `/api/v1/devices/{id}/toggle` | POST | 切换开关状态 | +| `/api/v1/devices/{id}/set` | POST | 设置属性 `{field, value}` | +| `/api/v1/devices/{id}/history` | GET | 获取操作历史 | + +#### 3.5.3 特性 + +- **线程安全**:`sync.RWMutex` 保护所有设备操作 +- **传感器波动**:每 30 秒自动模拟温度 ±0.2°C / 湿度 ±1% 随机波动 +- **属性设置**:声明式控制,支持中文值("开"/"关")和布尔值 +- **操作历史**:记录每次变更的字段、旧值、新值、时间戳 + +--- + +### 3.6 Voice-Service (:8093) — 语音服务 + +**目录**:`backend/voice-service/` +**入口**:[cmd/main.go](backend/voice-service/cmd/main.go) +**文件数**:6 个 Go 文件 + +#### 3.6.1 STT (语音识别) + +- **引擎**:whisper.cpp(本地运行) +- **前处理**:ffmpeg 音频格式转换 +- **支持语言**:中文(`zh`) + +#### 3.6.2 TTS (语音合成) + +三级回退策略: +1. **edge-tts**(首选)— Microsoft Edge TTS API,音质最好 +2. **espeak-ng**(回退)— 离线 TTS,无需网络 +3. **静默 WAV 生成器**(最终回退)— 生成等长静音音频,保证用户体验不中断 + +--- + +### 3.7 Proto (占位) + +`backend/proto/` — 目前仅包含 `.gitkeep`,为未来的 Protobuf/gRPC 通信预留。 + +--- + +## 四、前端详解 + +**目录**:`frontend/web/` +**入口**:[main.tsx](frontend/web/src/main.tsx) → [App.tsx](frontend/web/src/App.tsx) + +### 4.1 技术栈 + +| 技术 | 版本 | 用途 | +|------|------|------| +| React | 18.3 | UI 框架 | +| TypeScript | 5.6 | 类型系统 | +| Vite | 6.0 | 构建工具 | +| Zustand | 4.5 | 状态管理 | +| Tailwind CSS | 3.4 | 样式 | +| 原生 WebSocket | — | 实时通信 | +| SpeechSynthesis API | — | TTS 朗读 | +| SpeechRecognition API | — | STT 语音输入 | + +### 4.2 状态管理 (Zustand) + +| Store | 文件 | 职责 | +|-------|------|------| +| `authStore` | `authStore.ts` | 用户认证状态、token 管理 | +| `chatStore` | `chatStore.ts` | 消息列表、流式状态、IoT 设备状态、后台思考状态、历史分页 | +| `sessionStore` | `sessionStore.ts` | 会话列表、当前会话、消息加载、导出 | +| `notificationStore` | `notificationStore.ts` | 站内通知列表、已读管理 | +| `personaStore` | `personaStore.ts` | 昔涟人格配置、心情状态 | + +### 4.3 组件树 + +``` +App +├── ErrorBoundary +└── AppLayout + ├── Header (Logo, 连接状态, 搜索按钮) + ├── Sidebar (会话列表, 新建对话) + ├── ChatContainer + │ ├── MessageList + │ │ ├── MessageBubble (用户/助手消息) + │ │ │ ├── CyreneAvatar (昔涟头像) + │ │ │ ├── ImageLightbox (图片灯箱) + │ │ │ ├── AIMessageActions (朗读按钮) + │ │ │ └── ActionMessageBubble (动作消息: 居中/斜体/灰色) + │ │ └── TypingIndicator (输入中动画) + │ ├── IoTStatusBar (设备状态条) + │ └── ChatInput (输入框/附件/发送) + ├── AutomationPanel (自动化规则管理) + ├── BriefingPanel (每日简报) + ├── FilePanel (文件管理) + ├── KnowledgePanel (知识库管理) + ├── ReminderPanel (提醒管理) + └── SearchModal (全局搜索) +``` + +### 4.4 自定义 Hooks + +| Hook | 文件 | 功能 | +|------|------|------| +| `useWebSocket` | `useWebSocket.ts` | WebSocket 连接生命周期、指数退避自动重连、消息路由 | +| `useChat` | `useChat.ts` | 消息发送逻辑 | +| `useAuth` | `useAuth.ts` | 认证状态管理 | +| `useSession` | `useSession.ts` | 会话切换、历史加载 | +| `useSpeechRecognition` | `useSpeechRecognition.ts` | 浏览器语音识别封装 | +| `useSpeechSynthesis` | `useSpeechSynthesis.ts` | 浏览器 TTS 封装 | +| `usePWA` | `usePWA.ts` | PWA 安装/更新 | + +#### 4.4.1 WebSocket 重连策略 + +- **指数退避**:初始 1s,每次翻倍,最大 30s +- **jitter**:在 `[delay/2, delay]` 范围内随机,避免惊群 +- **最大重试**:10 次后放弃并提示用户刷新 +- **会话恢复**:重连后自动发送 `history` 消息恢复后端上下文 + +### 4.5 API 模块 + +| 模块 | 文件 | 对应后端 | +|------|------|---------| +| `client` | `client.ts` | Axios 实例、JWT 拦截器 | +| `auth` | `auth.ts` | `/api/v1/auth/*` | +| `sessions` | `sessions.ts` | `/api/v1/sessions/*` | +| `memory` | `memory.ts` | `/api/v1/memory/*` | +| `reminders` | `reminders.ts` | `/api/v1/reminders/*` | +| `briefings` | `briefings.ts` | `/api/v1/briefings/*` | +| `voice` | `voice.ts` | `/api/v1/voice/*` | +| `files` | `files.ts` | `/api/v1/files/*` | +| `automation` | `automation.ts` | `/api/v1/automation/*` | +| `knowledge` | `knowledge.ts` | `/api/v1/knowledge/*` | + +### 4.6 WebSocket 消息流 + +**客户端 → 服务端**: +```typescript +{ type: "message", content: "你好", mode: "text", session_id: "xxx", timestamp: 123 } +{ type: "history", session_id: "xxx" } +{ type: "voice_input", audio_data: "base64..." } +``` + +**服务端 → 客户端**: +| type | 触发时机 | 前端处理 | +|------|---------|---------| +| `stream_chunk` | AI 流式逐字输出 | `appendToLastMessage` 累积 | +| `stream_end` | 流式输出结束 | `finishStreaming` 标记完成 | +| `response` | 审查后的独立消息 (action/chat) | `addMessage` 添加独立气泡 | +| `history_response` | 会话恢复/历史请求 | 仅在无消息时加载 | +| `review` | 旧版审查消息 | 逐条 `addMessage` | +| `multi_message` | 多段消息 | 逐段 `addMessage` | +| `stream_segments` | 断句信息 | 逐段 `addMessage` | +| `device_update` | IoT 设备状态广播 (10s) | `setIoTDevices` 更新状态栏 | +| `background_thinking` | 后台思考状态变化 | `setBackgroundThinkingStatus` | +| `notification` | 系统通知/提醒 | `addNotification` + 浏览器桌面通知 | +| `error` | 服务端错误 | 系统消息气泡 | + +--- + +## 五、ethend (:9090) — 调试工具 + +**目录**:`ethend/` +**类型**:Node.js Express 应用 + +### 5.1 服务管理 + +| 端点 | 方法 | 功能 | +|------|------|------| +| `/api/services` | GET | 列出所有服务状态 | +| `/api/services/:id/build` | POST | 编译服务 (go build -o main.exe) | +| `/api/services/:id/start` | POST | 启动服务 | +| `/api/services/:id/stop` | POST | 停止服务 | +| `/api/services/:id/restart` | POST | 重启服务 | +| `/api/services/:id/logs` | GET | 获取服务日志 | +| `/api/services/:id/memory` | GET | 获取进程内存 | + +### 5.2 其他功能 + +- **IoT 管理**:设备列表/状态切换 +- **记忆管理**:记忆搜索/CRUD +- **性能监控**:CPU/内存使用率 +- **数据库管理**:表结构检查、迁移执行 +- **WebSocket 状态**:连接数/会话列表 +- **健康检查轮询**:每秒检测所有服务可达性 + +### 5.3 关键配置 + +**构建命令**([config.js](ethend/src/config.js)): +```javascript +buildCommand: 'go', +buildArgs: ['build', '-o', isWin ? 'main.exe' : 'main', './cmd/main.go'], +goBin: GO_BIN +``` + +所有 Go 服务统一编译为 `main.exe`(Windows),ethend 通过 `./main` 启动。**自定义二进制名称不会被 ethend 识别。** + +--- + +## 六、对话管线详解 + +### 6.1 完整请求时序 + +``` +Browser (React) Gateway AI-Core + │ │ │ + ├─ WebSocket: {type:"message"} ──┤ │ + │ ├─ POST /api/v1/chat ──────►│ + │ │ (SSE streaming) │ + │ │ ├─ 意图分析 (0-1.4s) + │ │ ├─ 并行子会话 + │ │ │ ├─ memory (检索) + │ │ │ ├─ iot (查询/操控) + │ │ │ └─ general (意图) + │ │ ├─ LLM 合成 (3-4s) + │ │ ├─ parseReviewMessages + │ │ │ + │ │◄── SSE: delta ────────────┤ + │◄── WS: stream_chunk ──────────┤ │ + │◄── WS: stream_chunk ... ──────┤ │ + │ │◄── SSE: review_messages ──┤ + │◄── WS: response (action) ─────┤ (200ms delay) │ + │◄── WS: response (chat) ───────┤ │ + │ │◄── SSE: [DONE] ──────────┤ + │◄── WS: stream_end ────────────┤ │ +``` + +### 6.2 性能数据 + +| 场景 | 总响应 | 意图分析 | 子会话 | LLM 合成 | +|------|--------|---------|--------|---------| +| "你好呀" | ~3.9s | 0s | 跳过 | 3.9s | +| "打开客厅灯" | ~2.6s | 0s | IoT+Memory | ~2.6s | +| "关掉客厅灯" | ~2.6s | 0s | IoT+Memory | ~2.6s | +| "打开卧室灯和卧室空调" | ~3.0s | 0s | IoT+Memory | ~3.0s | +| "看看设备状态" | ~5.3s | 1.4s | IoT+Memory | ~3.9s | +| "你还记得我喜欢什么吗?" | ~4-5s | LLM | Memory+General | ~3-4s | + +LLM 合成(deepseek-v4-flash)是主要延迟来源,约占 60-80% 的总响应时间。 + +### 6.3 E2E 消息流示例 + +``` +用户: "帮我把客厅灯打开" + → Gateway WS → AI-Core SSE + → Intent: iot_control (快速通道, 0s) + → Dispatch: memory + general + iot + review (并行) + → IoT: 查询 8 个设备 → 匹配客厅灯 → 已开状态 + → Synthesize: 综合上下文 → LLM 生成回复 + → parseReviewMessages: + action: "歪着头看你" + chat: "叶酱,客厅灯早就开着啦♪ 你是不是工作太累看花了眼呀?" + → Gateway: 200ms 间隔逐条推送 WebSocket response + → Frontend: ActionMessageBubble + MessageBubble 分别渲染 +``` + +--- + +## 七、数据库设计 + +### 7.1 PostgreSQL 连接 + +所有服务共用 PostgreSQL 数据库 `cyrene_ai`,通过 `DB_URL` 环境变量配置: +``` +postgres://cyrene:cyrene_pass@localhost:5432/cyrene_ai?sslmode=disable +``` + +### 7.2 主要表结构 + +| 表 | 管理方 | 用途 | +|----|--------|------| +| `users` | Gateway | 用户认证 | +| `sessions` | Gateway | 会话记录 | +| `messages` | Gateway | 对话消息(role, content, timestamp) | +| `memories` | Memory-Service | 记忆存储(含 pgvector embedding) | +| `reminders` | Gateway | 定时提醒 | +| `briefings` | Gateway | 每日简报 | +| `automation_rules` | Gateway | 自动化规则 | +| `automation_scenes` | Gateway | 自动化场景 | +| `files` | Gateway | 文件元数据 | +| `knowledge_bases` | Gateway | 知识库 | +| `knowledge_documents` | Gateway | 知识文档 | +| — (工具调用日志) | AI-Core (内存) | 环形缓冲区 500 条,无 DB 持久化 | + +### 7.3 已知缺项 + +- `messages` 表 `msg_type` 通过后端 ServerMessage 自动填充(含 markdown/code),但数据库层面未持久化该字段,历史消息查询依赖 role 判断 + +--- + +## 八、安全性 + +| 层面 | 实现 | +|------|------| +| 认证 | JWT (HS256),默认永不过期 | +| 密码存储 | bcrypt 哈希 | +| 会话隔离 | 按 userID + sessionID 双重隔离 | +| 限流 | 认证端点:5次/分钟/IP;API 端点:10 req/s + 突发 20 | +| CORS | 可配置的来源白名单 | +| HTTP 框架 | Gin 的生产模式(ReleaseMode)+ Recovery 中间件 | +| WebSocket 安全 | JWT token 验证 + admin-only 主对话 | +| 内部服务 | Internal Service Token 认证 | + +--- + +## 九、已知限制与改进方向 + +### 当前限制 + +1. **LLM 合成延迟**(3-4s):LLM 调用是主要瓶颈,合成阶段无法被快速通道绕过 +2. **"开" 字歧义**:无法将单独的 "开" 加入快速通道("开心"/"开始" 产生误判),"开灯" 等短命令仍走 LLM +3. **嵌入 API 依赖**:DeepSeek 等不提供 `/embeddings` 端点的 API 需额外配置 `EMBEDDING_API_URL` 或使用本地 n-gram 降级 +4. **跨群记忆混合**:后台思考 (Thinker) 仍将各频道记忆混合生成统一摘要,尚未完全隔离 +5. **流式审查**:`parseReviewMessages()` 需要等 LLM 合成完成后才能执行,无法实时拆分 + +### 建议改进方向 + +1. **LLM 响应缓存**:对相似问候/常见 IoT 命令引入语义缓存 +2. **Ollama 本地嵌入**:配置 `EMBEDDING_API_URL=http://localhost:11434/v1` + `EMBEDDING_MODEL=bge-m3` 启用真实向量检索 +3. **跨群聊记忆隔离**:Thinker 按频道独立维护记忆上下文 +4. **流式审查**:在 LLM 合成过程中实时识别并分段发送 action/chat +5. **本地工作助手插件**:承载代码/长文生成等聊天平台不适合的能力 +6. **前端集成测试**:Playwright/CDP 端到端测试 + +--- + +## 附:快速参考 + +### 服务端口一览 + +| 服务 | 端口 | 技术 | +|------|------|------| +| Gateway | 8080 | Gin + WebSocket | +| AI-Core | 8081 | net/http + SSE | +| IoT Debug | 8083 | net/http | +| Platform Bridge | 8095 | net/http + WebSocket (OBv11/Telegram适配器) | +| Memory | 8091 | net/http + pgvector | +| Voice | 8093 | net/http + whisper.cpp | +| Frontend (dev) | 5173 | Vite | +| ethend | 9090 | Express | + +### 常用命令 + +```bash +# 构建所有 Go 服务 +cd backend/ai-core && GOWORK=off go build -o main.exe ./cmd/main.go +cd backend/gateway && GOWORK=off go build -o main.exe ./cmd/main.go +# ... 其他服务同理 + +# 或通过 ethend API +curl -X POST http://localhost:9090/api/services/ai-core/build +curl -X POST http://localhost:9090/api/services/gateway/build + +# 启动前端开发服务器 +cd frontend/web && pnpm dev + +# E2E 测试 +node test/test_final_e2e.mjs +``` + +### 环境变量 (.env) + +位于 `.env`,基础设施与 LLM 回退配置: +``` +POSTGRES_HOST=localhost +POSTGRES_PORT=5432 +POSTGRES_USER=cyrene +POSTGRES_PASSWORD=cyrene_pass +POSTGRES_DB=cyrene_ai +JWT_SECRET=xxx +ADMIN_USERNAME=admin +ADMIN_PASSWORD=xxx + +# Phase 6: 以下 LLM 变量作为 models.json 不存在时的回退 +LLM_API_URL=https://api.deepseek.com/v1 +LLM_API_KEY=sk-xxx +LLM_MODEL=deepseek-v4-flash +LLM_FALLBACK_MODEL=deepseek-v4-flash +``` + +### 模型配置 (models.json) + +Phase 6 新增,位于 `backend/models.json`(`.gitignore` 已排除)。格式: + +```json +{ + "version": "1.0", + "providers": { + "deepseek": { + "name": "deepseek", + "base_url": "https://api.deepseek.com", + "api_key": "sk-xxx", + "timeout_sec": 120, + "max_retries": 3 + } + }, + "models": { + "primary_chat": { + "id": "primary_chat", + "name": "deepseek-v4-flash", + "provider": "deepseek", + "description": "主对话模型", + "tags": ["chat", "fast"], + "params": { "temperature": 0.8, "max_tokens": 2048 }, + "enabled": true + } + }, + "routing": { + "chat": { + "purpose": "chat", + "fallback_chain": ["primary_chat", "fallback_chat"], + "required": false + } + } +} +``` + +**配置管理 API**(Gateway admin,ethend 代理提供 UI): + +| Method | Path | Description | +|--------|------|-------------| +| GET/POST/DELETE | `/api/v1/admin/models/providers/:name` | Provider CRUD | +| GET/POST/DELETE | `/api/v1/admin/models/models/:id` | Model CRUD | +| GET/POST/DELETE | `/api/v1/admin/models/routing/:purpose` | Routing CRUD | + +**向后兼容**:如果 `models.json` 不存在,`ModelSelector` 自动回退到 `.env` 的 4 个 LLM 变量,行为与 Phase 5 及之前完全一致。 diff --git a/docs/dev-plan/15-june-july-2026-fixes.md b/docs/dev-plan/15-june-july-2026-fixes.md new file mode 100644 index 0000000..8ec53bd --- /dev/null +++ b/docs/dev-plan/15-june-july-2026-fixes.md @@ -0,0 +1,126 @@ +# 2026年6-7月功能升级与修复汇总 + +> **日期**:2026-07-07 +> **时期**:2026年6月下旬 - 7月上旬 +> **分支**:`dev` + +--- + +## 一、Platform Bridge — 多平台接入 + +### 多账号 QQ 适配器 +- 平台桥接 (`platform-bridge`) 负责统一管理所有第三方平台适配器 +- 支持同一平台类型多个实例(如 `obv11` 和 `obv11-main`),通过 config name 区分 +- 110+ 条官方 QQ Bot API 表情映射,支持表情名称解析 +- WebSocket 连接管理:client/server 双模式、自动重连、禁言检测 + +### 群聊行为控制 +- **消息发送间隔**:群聊 ≥3 秒/条,最多 2 条/轮,单条 ≤500 字自动截断防封控 +- **禁言检测**:通过 `group_ban` notice 实时跟踪禁言状态,发送循环内逐条重检 +- **审查模式 (group_ambient)**:非 @ 消息由 LLM 自主判断是否插话 +- **管理员审查模式**:管理员消息在 group_ambient 下仍保留工具使用权 +- **消息日志**:每配置独立日志文件,按 `AdapterName` 命名 + +### 主动消息平台推送 +- 后台思考生成的主动消息可通过 QQ 适配器推送到群聊/私聊 +- 支持 `【QQ私聊:QQ号】` 和 `【QQ群聊:群号】` 目标格式 +- `ProactiveGuard` 统一频控,跨 Web/QQ 双通道 + +--- + +## 二、记忆系统升级 + +### 嵌入模型两级降级 +| 级别 | 方案 | 配置 | +|------|------|------| +| L1 | OpenAI 兼容 `/embeddings` API (如 Ollama bge-m3) | `EMBEDDING_API_URL` + `EMBEDDING_MODEL` | +| L2 | 本地 n-gram FNV 哈希向量 (0依赖) | 默认,L1 不可用时自动启用 | + +- 启动时自动测试嵌入 API 可用性 +- DeepSeek 等不提供 embedding 的 API 不会静默失败 +- 保存记忆时同步生成向量嵌入 + +### 检索增强 +- 向量检索 + n-gram 滑动窗口关键词匹配,按分数排序 +- 2-4 字中文分词窗口匹配 content/summary/keywords +- pgvector `<=>` 余弦距离检索 8 条 + 关键词匹配 100 条去重合并 + +### 记忆归属 +- persona 规则:记忆不全是开拓者的,需分辨发送者再归因 +- 群聊规则:不要把群友的事说成开拓者做的 + +--- + +## 三、后台思考系统 (Thinker) + +### 死锁修复 (11+ 轮) +- **根因**:Go `sync.Mutex` 不可重入,`defer` 是函数作用域非块作用域 +- `defer t.muUnlock()` 在 for 循环和跨 LLM 调用时导致 self-deadlock +- 修复函数:`performThink`, `lightThinkLoop`, `performLightThink`, `storeThought`, `UpdatePresence`, `TriggerReminderMessage`, `PushPlatformMessage`, `resetSilenceTimer`, `buildThinkingUserPrompt` + +### 上下文隔离 +- `thinkSessionID` 绑定思考周期触发时的会话,防止跨群串台 +- 思考过程中其他群的消息不再覆盖 activeSessionID +- convHistory 和 thought push 均使用绑定的 session + +### 轻量思考 + 平台观察 +- `lightThinkLoop`:高频轻量轮询(~60s),简短状态确认/话题发起 +- `platformThink`:定期(~600s)聚合各频道记忆生成平台观察摘要 + +--- + +## 四、对话引擎 (Orchestrator + Synthesizer) + +### 群聊人格强化 +- **#1 审查模式**:非 @ 消息由 LLM 判断是否回复,支持 `【不发送】` 自我审查 +- **#2 回复长度**:最多 1-2 句,允许多段落但需双换行分隔 +- **#3 闭嘴服从**:识别"别说话""闭嘴"等指令,持续遵守 +- **#4 发送者识别**:根据消息前缀中的昵称称呼对方 +- **#5 简体中文**:强制输出简体中文,防止群友繁体昵称传染 +- **#6 拒绝长内容**:禁止生成代码/长文,告知等待本地工作助手插件 +- **#7 记忆归因**:不同人的言行分清,不张冠李戴 +- **#8 禁用数字 ID**:用昵称而非 QQ 号称呼人 + +### 管理员功能 +- **多层防御**:`AdminOnly` 字段 → plugin manager 自动拦截 → IoT provider 执行级检查 +- **身份提示**:管理员以名字标注,数字 UID 从昵称中移除 +- **权限区分**:设备控制/系统管理等 admin-only 工具对非管理员温柔拒绝 + +### 工具系统 +- 后台工具结果自动推送(成功/失败),失败结果不再触发 LLM 跟进避免噪音 +- 工具名称输出过滤(`vision_analyze`, `web_search` 等) +- 双换行消息拆分 + +--- + +## 五、搜索与其他 + +### web_search (SearXNG) +- 引擎精简为 `bing` + `sogou`(移除 baidu 安全验证拦截 + 360 不稳定) +- 超时 25s,SearXNG 内部 timeout=20s +- 添加 User-Agent + +### LLM API +- HTTP 连接池:`MaxIdleConns=100`, `MaxIdleConnsPerHost=20`, `IdleConnTimeout=90s` +- `TLSHandshakeTimeout=15s` 防止握手卡死 + +### 降级回复 +- 仅在管理员私聊时发送降级消息,群聊静默避免怪话 + +--- + +## 六、新增环境变量 + +| 变量 | 默认值 | 说明 | +|------|--------|------| +| `EMBEDDING_API_URL` | `LLM_API_URL` | 嵌入 API 地址,可指向 Ollama 等独立服务 | +| `EMBEDDING_MODEL` | `text-embedding-3-small` | 嵌入模型名 | +| `PLATFORM_BRIDGE_URL` | `http://localhost:8095` | platform-bridge 地址 | + +--- + +## 七、已知待办 + +- [ ] 嵌入 API 接入真实模型(Ollama bge-m3)后验证向量检索准确率 +- [ ] 本地工作助手插件(承载长文本/代码生成等能力) +- [ ] 跨群聊记忆完全隔离(当前后台思考仍会将各频道记忆混合后统一生成摘要) diff --git a/docs/dev-plan/README.md b/docs/dev-plan/README.md new file mode 100644 index 0000000..42543f1 --- /dev/null +++ b/docs/dev-plan/README.md @@ -0,0 +1,28 @@ +# Cyrene 开发规划文档索引 + +> **日期**:2026-07-07 +> **当前版本**:v1.7-alpha +> **当前阶段**:v1.8-alpha 开发中 + +--- + +## 当前计划 + +| 文档 | 说明 | +|------|------| +| [00-next-test-plan.md](00-next-test-plan.md) | **← 当前** — 测试版开发计划 (v1.7 → v2.0) | +| [14-humanization.md](14-humanization.md) | 人性化改进 — 语言和行为更像真人 | +| [15-june-july-2026-fixes.md](15-june-july-2026-fixes.md) | **← 新增** — 2026年6-7月功能升级与修复汇总 | + +## 活跃设计文档 + +| # | 文档 | 对应版本 | 内容 | +|---|------|---------|------| +| 4 | [语音系统方案](04-voice-system-plan.md) | v1.8 | 专属 TTS 模型、流式合成、实时通话 | +| 5 | [多模型配置系统](05-model-config-system.md) | v1.6 | models.yaml、多 Provider、ModelSelector | +| 7 | [IoT 与宿主机操控](07-host-control-iot-evolution.md) | v1.9 | Home Assistant 集成、安全沙箱 | +| 11 | [STT 修复与优化](11-stt-fix-and-optimization.md) | v1.8 | DashScope/Whisper 缺陷修复、流式管道 | + +## 已归档 + +`archived/` 目录:架构进化、插件系统、多平台接入、对话流程、OS 环境、DevTools、平台观察、Phase 7 优化等已完成的设计文档。