Files
EzVibe/docs/v2_design/ARCHITECTURE.md
e2hang 96cb28fe08 feat: multi-layer eventFilter for window drag + text input fix + Qt platform xcb
- Fix window drag: install eventFilter on live2d_container, central, and
  _live2d_widget; fix super() call in dynamic class
- Fix text input: remove WA_TransparentForMouseEvents from _chat_container
- Force QT_QPA_PLATFORM=xcb on Linux (wayland has mouse event issues)
- Add HealthTracker module, update AgentBrain with health integration
- Update scheduler and memory modules
- Add v5_modify documentation

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-19 23:36:58 +08:00

415 lines
13 KiB
Markdown
Raw Permalink 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.
# EzVibe v2 架构设计文档
> 本文档描述 EzVibe 系统当前v1.x的整体架构设计。
---
## 1. 系统概览
EzVibe 是一个运行在用户桌面上的 AI 桌宠系统,核心目标是**健康监测与提醒**(久坐提醒、喝水提醒)。
**技术栈**
- Python 3.10+
- PySide6 / PyQt6Qt 图形界面)
- SQLite + NumPy本地持久化 + 向量检索)
- Ollama / OpenAILLM 推理)
- pynput全局键鼠监听
**运行模式**
- 完整 GUI 模式(`python main.py`
- Headless Dummy 模式(`python main.py --dummy`
- API Server 模式(`python main.py --server`
---
## 2. 分层架构
```
┌─────────────────────────────────────────────┐
│ 表现层 (UI) │
│ ui/pet_window.py │
│ - PetWindow / DummyPetWindow │
│ - 情绪动画渲染、右键菜单、托盘 │
└────────────────────┬────────────────────────┘
┌────────────────────▼────────────────────────┐
│ 智能层 (Agent) │
│ │
│ ┌─────────┐ ┌─────────┐ ┌──────────────┐ │
│ │ brain │ │ emotion │ │ scheduler │ │
│ │ .py │ │ .py │ │ .py │ │
│ │ LLM决策 │ │ 状态机 │ │ 行为调度 │ │
│ └────┬────┘ └────┬────┘ └──────┬───────┘ │
│ └───────┬──┴────────────┘ │
│ ┌──────▼──────┐ │
│ │ memory │ │
│ │ .py │ │
│ │ RAG向量记忆 │ │
│ └─────────────┘ │
└────────────────────┬────────────────────────┘
┌────────────────────▼────────────────────────┐
│ 感知层 (Perception) │
│ perception/keyboard_mouse_monitor.py │
│ - 键鼠事件监听、活跃度检测 │
│ - ScreenCapture截图+OCR
└─────────────────────────────────────────────┘
```
---
## 3. 模块职责
### 3.1 表现层 — `ui/pet_window.py`
**职责**
- 渲染桌宠窗口(无边框、置顶、透明背景)
- 情绪状态驱动动画idle/happy/focused/annoyed/sleepy
- 提醒通知弹窗(健康喝水/伸展提醒)
- 拖拽移动、右键菜单、最小化到托盘
**关键类**
- `PetWindow`PySide6/PyQt6 实现,延迟构造避免导入冲突
- `DummyPetWindow`headless 测试替代,不依赖 Qt
**图像资源**
```
assets/pet/
├── idle/
├── happy/
├── focused/
├── annoyed/
└── sleepy/
```
每个情绪目录下存放 16 帧 PNG 动画180×180px。无图像时回退到 emoji 显示。
**设计亮点**
- `_make_pet_window_class()` 使用 `type()` 动态构造类,避免模块级导入 QtWidgets
- `create_pet_window()` 工厂函数,支持 `force_dummy` 强制降级
---
### 3.2 智能层 — `agent/`
#### 3.2.1 `brain.py` — AgentBrainLLM 推理引擎)
**职责**
- 整合记忆上下文 + 情绪状态 + 用户输入
- 调用 LLMOllama/OpenAI/Dummy生成回复
- 决策是否触发主动行为
- 管理会话历史(短期上下文窗口)
**LLM 后端适配器(策略模式)**
```
LLMBackend (基类)
├── OllamaBackend — http://localhost:11434
├── OpenAIBackend — OpenAI API / 兼容第三方
└── DummyLLMBackend — 测试用固定回复
```
**核心方法**
- `think(user_input)`:接收用户输入,返回 `{"text", "emotion_state", "action"}`
- `decide_action()`:异步决策是否触发主动行为
- `_parse_action()`:从 LLM 回复中解析 `[ACTION: type:description]` 标签
**System Prompt 模板**
```python
DEFAULT_SYSTEM_PROMPT = """你是「EzVibe」一个运行在用户桌面上的 AI 桌宠。
【当前情绪状态】{emotion_display}
【性格设定】友善、活泼,偶尔会犯懒或闹小脾气...
【主动行为能力】可以提醒喝水/休息,或做出可爱小动作。
请用自然对话风格回复。如果想触发主动行为,在回复末尾加上:
[ACTION: <action_type>:<description>]
"""
```
#### 3.2.2 `emotion.py` — EmotionEngine情绪状态机
**状态集合**`S = {idle, happy, focused, annoyed, sleepy}`
**核心机制**
- 5×5 状态转移矩阵 P
- 上下文调制因子(事件驱动增益)
- 蒙特卡洛随机采样
- 最小驻留时间限制(防止抖动)
**状态转移矩阵**(行=当前状态,列=目标状态):
```
→ idle happy focused annoyed sleepy
idle │ 0.4 0.2 0.2 0.1 0.1
happy │ 0.2 0.5 0.1 0.1 0.1
focused │ 0.1 0.2 0.5 0.1 0.1
annoyed │ 0.1 0.1 0.1 0.6 0.1
sleepy │ 0.2 0.1 0.1 0.1 0.5
```
**事件增益**`ContextBoost.EVENT_BOOSTS`
```python
"long_work_session" sleepy +2.0, focused +0.8
"user_focused" focused +2.5
"reminder_ignored" annoyed +3.0
"user_praise" happy +3.0
"user_healthy_action" happy +2.0
```
**关键方法**
- `update(event)`:根据事件触发状态转移
- `tick()`:时钟推进,触发 `time_passes` 事件
- `force_state(state)`:强制设置状态(测试用)
#### 3.2.3 `scheduler.py` — BehaviorScheduler行为调度器
**行为优先级定义**
- `PRIORITY_HIGHEST = 0`:健康/高危提醒(打断所有)
- `PRIORITY_USER_INPUT = 1`:用户主动输入响应
- `PRIORITY_PROACTIVE = 2`:系统主动闲聊/行为
- `PRIORITY_LLM_TRIGGER = 3`LLM 自触发
**内置行为**
| 行为 | 优先级 | 冷却 | 说明 |
|------|--------|------|------|
| `remind_water` | 0 | 1800s | 喝水提醒 |
| `remind_stretch` | 0 | 3600s | 久坐伸展提醒 |
| `idle_nudge` | 2 | 300s | 空闲闲聊触发 |
| `happy_nudge` | 2 | 600s | 开心时主动搭话 |
**核心逻辑**
- 活跃度限制极度专注activity < 0.15)时禁止 P2/P3 打扰
- 情绪调制focused 状态概率×0.2sleepy 状态概率×0.3
- 提醒队列:`Reminder` 延迟执行任务
#### 3.2.4 `memory.py` — VectorMemory向量记忆系统
**数据模型**
```python
@dataclass
class MemoryEntry:
text: str # 记忆文本
embedding: list[float] # 向量嵌入
tags: list[str] # 标签
metadata: dict # 元数据
created_at: float # 时间戳
id: str | None # UUID
```
**存储层**`SQLite` + `MemoryStore`
```sql
CREATE TABLE memories (
id TEXT PRIMARY KEY,
text TEXT NOT NULL,
embedding BLOB NOT NULL, -- numpy 序列化
tags TEXT NOT NULL DEFAULT '[]',
metadata TEXT NOT NULL DEFAULT '{}',
created_at REAL NOT NULL
);
```
**嵌入适配器**
```
make_embedder(backend)
├── OllamaEmbedder — nomic-embed-text
├── OpenAIEmbedder — text-embedding-3-small
└── DummyEmbedder — TF-IDF开发/测试用)
```
**RAG 工作流**
1. Query → Embedding
2. 向量检索 Top-k
3. 格式化上下文
4. 注入 System Prompt
---
### 3.3 感知层 — `perception/`
#### 3.3.1 `keyboard_mouse_monitor.py` — KeyboardMouseMonitor
**职责**:全局键盘/鼠标监听,使用 pynput 全局钩子。
**核心组件**
- `ActivityDetector`:滑动窗口活跃度统计
- `KeyboardMouseMonitor`pynput listener + queue
- `ScreenCapture`mss 截图 + pytesseract OCR
**活跃度计算**
```python
baseline = window_seconds / 60.0 * 30.0 # 30 events/min = normal
activity = min(raw / baseline, 1.0)
```
**阈值定义**
- activity < 0.15:极度专注(可能深度工作/游戏)
- activity < 0.3:比较专注
- 0.3 ≤ activity < 0.7:适度活跃
- activity ≥ 0.7:非常活跃
**全局单例**
```python
_global_monitor: KeyboardMouseMonitor | None = None
def get_global_monitor(...) KeyboardMouseMonitor
def stop_global_monitor() None
```
---
## 4. 主入口 — `main.py`
### 4.1 EzVibeApp 初始化流程
```python
def _init_components(self):
1. EmotionEngine()
2. VectorMemory(embedder_backend="dummy") # 避免依赖 Ollama
3. AgentBrain(llm_backend=...)
4. KeyboardMouseMonitor + ScreenCapture
5. BehaviorScheduler(emotion_engine, activity_detector)
6. PetWindow延迟到 QApplication 之后
```
### 4.2 运行模式
**Dummy 模式**headless 测试):
```python
def _run_dummy(self):
# 初始化后直接打印状态摘要,模拟行为触发
```
**Qt 模式**
```python
def _run_qt(self):
app = QtWidgets.QApplication(sys.argv)
self._window = create_pet_window(...) # QApplication 之后才能创建
# QTimer 20ms 驱动 asyncio 轮询(临时方案,待改进)
timer.timeout.connect(lambda: self._loop.run_until_complete(asyncio.sleep(0)))
app.exec()
```
---
## 5. API 服务器 — `api/server.py`
FastAPI 服务器,提供 REST/WebSocket 接口:
| 端点 | 方法 | 说明 |
|------|------|------|
| `/status` | GET | 返回系统状态 |
| `/emotion` | GET/POST | 获取/设置情绪状态 |
| `/remind` | POST | 添加提醒 |
| `/memory/search` | POST | RAG 检索 |
| `/memory/add` | POST | 添加记忆 |
| `/ws` | WebSocket | 实时事件流 |
---
## 6. 数据流
### 6.1 用户交互流程
```
用户输入文本
AgentBrain.think()
┌─ 注入情绪状态到 System Prompt
├─ RAG 检索相关记忆VectorMemory.search
├─ 追加对话历史
└─ 调用 LLMOllama/OpenAI/Dummy
解析 [ACTION: ...] 标签
返回 {"text": "...", "action": {...}, "emotion_state": "..."}
PetWindow 显示回复 + 动画
```
### 6.2 健康监测流程
```
定时调度(每 10s
BehaviorScheduler.check_and_trigger()
┌─ 冷却时间检查
├─ 活跃度限制检查(极度专注时禁止打扰)
├─ 概率触发(结合情绪调制)
└─ 执行 action_fn()
show_reminder() → 气泡通知
记录到记忆VectorMemory.add
```
### 6.3 感知数据流
```
pynput 全局钩子(独立线程)
queue.Queue 传递事件
_worker_loop 消费队列
ActivityDetector.record() 记录到滑动窗口
get_activity() → 0.0~1.0 活跃度
```
---
## 7. 文件结构
```
EzVibe/
├── main.py # 主入口EzVibeApp
├── requirements.txt # 依赖列表
├── setup_project.py # 项目初始化脚本
├── agent/
│ ├── __init__.py
│ ├── brain.py # AgentBrain + LLM后端
│ ├── emotion.py # EmotionEngine 状态机
│ ├── scheduler.py # BehaviorScheduler + ActivityDetector
│ ├── memory.py # VectorMemory + MemoryStore + VectorEngine
│ └── test_*.py # 单元测试
├── perception/
│ ├── __init__.py
│ ├── keyboard_mouse_monitor.py # KeyboardMouseMonitor + ActivityDetector
│ └── test_perception.py
├── ui/
│ ├── __init__.py
│ ├── pet_window.py # PetWindow + DummyPetWindow
│ └── test_pet_window.py
├── api/
│ ├── __init__.py
│ └── server.py # FastAPI 服务器
├── data/ # SQLite 数据库目录
├── assets/ # 桌宠图像资源
└── docs/
├── v2_design/
│ ├── ARCHITECTURE.md # 本文档
│ ├── ARCHITECTURE_REVIEW.md # 架构评审
│ ├── EVOLUTION_ROADMAP.md # 演进路线
│ ├── HEALTH_TRACKER_SPEC.md # HealthTracker 规格
│ └── DESIGN_DECISIONS.md # 设计决策
└── *.md # 其他文档
```
---
## 8. 已知限制与改进方向
| 问题 | 现状 | 改进方向 |
|------|------|----------|
| Qt + asyncio 融合 | QTimer 轮询(不稳定) | 引入 qasync |
| OCR 性能消耗 | mss + pytesseract 每分钟执行 | 轻量级焦点窗口提取 |
| LLM 延迟 | 同步等待 5 秒 | 解耦动作与文案Fallback 缓存 |
| annoyed 状态屏蔽 P0 | 完全禁止打扰 | 柔性降级(安静模式) |
| 健康数据缺乏结构化 | RAG 模糊检索 | HealthTracker 结构化数据库 |
| 奖惩机制无闭环 | 单向提醒 | 隐式确认 + 正向反馈 |
详见 `ARCHITECTURE_REVIEW.md`