psycho-games-hub/docs/SPEC.md

600 lines
18 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 心理咨询室互动终端 — 心理小游戏聚合系统
> **项目代号**Psycho-Games-Hub
> **定位**:青少年/儿童心理辅导互动终端的核心子系统
> **阶段**:架构设计 + 原型阶段v0.1
---
## 一、产品定位
### 1.1 整体场景
```
┌─────────────────────────────────────────────┐
│ 心理咨询室互动终端 │
│ │
│ 🗡️ 数字人入口(语音 + 触摸) │
│ │ │ │
│ Agent 主对话 游戏弹窗 │
│ 策略召回 半透明遮罩 │
│ 风险评估 轻交互 │
│ │ │ │
│ 谈话式量表 ←─── Agent 动态编排 ───→ 激励解读│
└─────────────────────────────────────────────┘
```
- **载体**:一体机 / 触摸屏 kiosk
- **目标用户**:青少年 / 儿童(来访者)
- **核心理念**:数字人是入口,小游戏是「药」,只是吃起来像糖
- **交互方式**:语音对话 + 触摸Agent 主动驱动轻量干预
### 1.2 用户故事
**场景 A游戏触发**
> 来访者:「最近压力好大,考试考砸了。」
> Agent「你这个困扰看起来困扰你很久了。我知道个有效的缓解方式——我给你算个塔罗牌吧。」→ 弹出游戏弹窗 → 抽卡 → 积极方向解读 → 关闭弹窗
**场景 B量表编排**
> Agent 后台监测到近期对话出现「失眠」「焦虑」关键词 → StrategyDispatcher 入队 → Agent 在自然节点插入引导 → 用户同意 → 谈话式问答 → 生成摘要 → 更新风险标签
**场景 C直接入口**
> 用户双指下滑 → 解锁底部工具栏 → 展示所有游戏图标网格 → 主动点击进入
---
## 二、系统架构MVC
### 2.1 模块总览
```
┌──────────────────────────────────────────────────────┐
│ VIEW 层 │
│ AvatarView │ GameModal │ ChatPanel │ ResultCard │
└──────────────────────────────────────────────────────┘
│ 事件 / 回调
┌──────────────────────────────────────────────────────┐
│ CONTROLLER 层 │
│ AgentController │ GameController │ AssessmentCtrl │
│ InterpretationEngine │ StrategyDispatcher │
└──────────────────────────────────────────────────────┘
│ 读写
┌──────────────────────────────────────────────────────┐
│ MODEL 层 │
│ AgentBrain │ GameCatalog │ AssessmentFlows │
│ UserSession │ InterpretationPool │
└──────────────────────────────────────────────────────┘
```
---
## 三、Model 层
### 3.1 AgentBrain
**职责**:维护策略记忆 + 风险词召回
**数据结构**
```javascript
{
// 标注语料库(心理咨询师标注)
corpus: [
{ keyword: "失眠", riskLevel: 3, relatedScale: "SAS", strategy: "soft_inquiry" },
{ keyword: "压力大", riskLevel: 2, relatedGame: "tarot", strategy: "game_offer" },
// ...
],
// 策略路由表
strategies: {
"game_offer": { trigger: "anxiety_level > 2", gameType: "tarot" },
"soft_inquiry": { trigger: "riskLevel >= 3", prompt: "询问近期睡眠状况" },
// ...
},
// 召回方法(当前为规则版,待升级 RAG
recall(text) matchedCorpus[]
}
```
---
### 3.2 GameCatalog
**职责**:游戏配置清单 + 触发条件注册
**数据结构**
```javascript
{
games: [
{
id: "tarot",
name: "塔罗牌占卜",
triggerKeywords: ["压力", "迷茫", "选择", "未来"],
completionKeywords: ["抽卡", "算一算"],
viewComponent: "TarotGame",
difficulty: "low",
estimatedTime: "2min",
icon: "🃏"
},
{
id: "rorschach",
name: "罗夏墨迹",
triggerKeywords: ["看到了什么", "感觉", "想象"],
viewComponent: "RorschachGame",
difficulty: "medium",
estimatedTime: "3min",
icon: "🎭"
},
{
id: "mbti",
name: "人格测试",
triggerKeywords: ["我是谁", "性格", "了解自己"],
viewComponent: "MBTIGame",
difficulty: "medium",
estimatedTime: "5min",
icon: "🔮"
},
{
id: "chimp_memory",
name: "记忆挑战",
triggerKeywords: ["试试", "挑战"],
viewComponent: "ChimpMemoryGame",
difficulty: "low",
estimatedTime: "1min",
icon: "🐵"
}
// 更多游戏...
],
// 查询方法
matchByKeywords(text) games[]
getById(id) game
}
```
---
### 3.3 AssessmentFlows
**职责**:量表的对话化编排
**数据结构**
```javascript
{
flows: [
{
id: "SAS_anxiety",
name: "焦虑自评",
condition: "riskKeywords includes ['焦虑', '失眠', '心慌']",
questionCount: 3, // 精简至 3 题,不做完整量表
questions: [
{
id: "q1",
text: "你最近有没有感到特别紧张或者担心的事情?",
type: "single_choice",
options: ["完全没有", "偶尔", "经常", "一直都在"],
scores: [1, 2, 3, 4]
},
// ...
],
scoringMethod: "sum",
resultRanges: {
low: { min: 0, max: 5, label: "状态良好", interpretation: "positive" },
medium: { min: 6, max: 8, label: "轻度波动", interpretation: "neutral" },
high: { min: 9, max: 12, label: "值得关注", interpretation: "caution" }
}
}
// 更多量表...
],
// 查询方法
matchByCondition(riskKeywords) flows[]
getQuestions(flowId) questions[]
}
```
---
### 3.4 UserSession
**职责**:维护当前来访者会话上下文
**数据结构**
```javascript
{
sessionId: "uuid-xxx",
startTime: "2026-05-31T10:00:00Z",
userProfile: {
age: 14, // 年龄(首访时采集)
gender: "M", // 性别
firstVisit: true
},
riskTags: [], // 动态风险标签,如 ["焦虑", "压力", "学业"]
riskScore: 0, // 综合风险评分0-100
gameHistory: [
{ gameId: "tarot", timestamp: "...", result: "positive_outlook" }
],
assessmentResults: [
{ flowId: "SAS_anxiety", score: 5, timestamp: "..." }
],
recentUtterances: [
{ role: "user", text: "最近压力好大", timestamp: "..." },
{ role: "agent", text: "...", timestamp: "..." }
]
}
```
---
### 3.5 InterpretationPool
**职责**:积极心理学话术库,按游戏类型 × 情境分组
**数据结构**
```javascript
{
pools: {
"tarot": {
"压力": [
"你抽到的这张牌显示,你正在经历一个重要的转变期。压力其实是身体在告诉你,它愿意为你付出更多,只是需要一点喘息的空间。",
"这张牌提醒你:不是所有事情都需要马上解决。有时候,『放下』也是一种前进的方式。",
],
"迷茫": [
"牌面显示你正处于一个探索期,迷茫不是坏事——它意味着你还在寻找答案,而答案正在来的路上。",
]
// ...
},
"rorschach": {
"学业压力": [
"你在这张墨迹中看到了很多变化的形状,这说明你的内心正在经历很多调整。你比自己想象的更有弹性。",
]
// ...
}
// 更多游戏...
},
// 查询方法
get(gameType, contextTags) interpretations[]
}
```
---
## 四、View 层
### 4.1 AvatarView
**职责**:数字人主界面
- 全屏占位,作为系统主页背景
- 实现方式Live2D / 3D 虚拟人 / 纯 2D 立绘 + 表情差分(待选)
- 接收 AgentController 的表情指令(`setExpression("happy")`、`speak("你好呀")`
- 触摸响应区域:点击数字人触发语音输入
### 4.2 GameModal
**职责**:游戏弹窗遮罩
**展示规格**
- 层级:覆盖在 AvatarView 上方z-index 最高
- 样式:`backdrop-filter: blur(8px)` + 半透明黑底(`rgba(0,0,0,0.6)`
- 尺寸:宽度 90vw高度 80vh不超出屏幕居中
- 关闭行为:允许用户点击关闭按钮退出(游戏中途关闭记录为「中断」)
**子区域**
```
┌─────────────────────────┐
│ [游戏名称] [× 关闭] │ ← 顶栏
├─────────────────────────┤
│ │
│ 游戏内容区 │ ← 动态组件 slot
│ │
├─────────────────────────┤
│ [进度指示] │ ← 底栏(如有需要)
└─────────────────────────┘
```
### 4.3 ChatPanel
**职责**:对话气泡流
- 底部/侧边展开,可折叠
- 展示最近 N 条对话记录
- Agent 消息和来访者消息气泡区分样式
- 接入 AgentController 的实时消息流
### 4.4 AssessmentCard
**职责**:量表对话式问答
- 每题一屏,全屏卡片流
- 选项以卡片按钮形式展示(触摸友好)
- 支持进度条展示1/N
- 动画过渡切换
### 4.5 ResultCard
**职责**:结果展示
**内容**
- 游戏结果解读(来自 InterpretationEngine
- 雷达图/进度条(可选)
- 鼓励文案(来自 InterpretationPool
- 建议下一步行动
---
## 五、Controller 层
### 5.1 AgentController主控协调器
**职责**:系统中央调度
**核心流程**
```
1. 监听对话输入(用户 utterance
2. 追加到 UserSession.recentUtterances
3. 触发 AgentBrain.recall() → 策略匹配
4. 根据匹配结果:
a. 若匹配到 game_offer → 触发 GameController
b. 若匹配到 soft_inquiry → 直接生成对话回复
c. 若风险等级高 → 触发 StrategyDispatcher
5. 将回复追加到 ChatPanel
6. 若 AgentController 内部有 StrategyDispatcher 队列非空 → 插入引导语
```
### 5.2 GameController
**职责**:游戏生命周期管理
**状态机**
```
IDLE → LOADING → PLAYING → RESULT → CLOSING → IDLE
```
**核心方法**
```javascript
{
// 触发游戏
trigger(gameId) 弹出 GameModal加载 viewComponent
// 收集游戏结果
collectResult(data) 传递给 InterpretationEngine
// 关闭游戏
close(interrupt: boolean) 写回 UserSession.gameHistory 关闭 GameModal
}
```
### 5.3 AssessmentController
**职责**:量表执行器
**核心流程**
```
1. 接收 AgentController 的激活指令flowId
2. 从 AssessmentFlows 加载 questions
3. 按顺序展示 AssessmentCard每题一屏
4. 收集 answers + 计算 scores
5. 生成摘要 → 传递给 InterpretationEngine
6. 结果写回 UserSession.assessmentResults
7. 更新 UserSession.riskScore
```
### 5.4 InterpretationEngine
**职责**:解读编排引擎(最体现积极心理学设计的模块)
**核心流程**
```
1. 接收 GameController 或 AssessmentController 的结果数据
2. 查询 UserSession 获取当前上下文riskTags / recentUtterances
3. 从 InterpretationPool 按 gameType + contextTags 获取候选解读
4. 拼接上下文敏感内容(注入来访者提到过的关键词)
5. 选取最积极的解读变体interpretation = "positive" 优先)
6. 生成 ResultCard 内容
7. 决定是否在 ResultCard 中插入下一个游戏/量表建议
```
### 5.5 StrategyDispatcher
**职责**:策略分发队列
**数据结构**
```javascript
{
queue: [
{
id: "strategy_001",
type: "assessment",
scale: "SAS_anxiety",
priority: 2,
reason: "检测到焦虑风险词 3 次",
suggestedQuestions: ["失眠情况", "紧张频率"],
createdAt: "..."
},
{
id: "strategy_002",
type: "game",
gameId: "chimp_memory",
priority: 3,
reason: "缓解轻度压力的轻量游戏"
}
],
// 方法
enqueue(strategy),
dequeue() strategy, // 优先级最高者出队
peek() strategy, // 只查看不下队
isEmpty() boolean
}
```
**入队触发条件**
- AgentBrain 后台监测到风险关键词累计 N 次
- 用户在对话中主动提到相关话题
- 游戏/量表完成后自动推荐下一个
---
## 六、关键交互流
### 流 1游戏触发核心
```
用户说"最近压力好大"
AgentController.utterance()
AgentBrain.recall("最近压力好大")
→ 匹配 corpus: { keyword: "压力大", strategy: "game_offer" }
AgentController 决策 → StrategyDispatcher.enqueue({ type: "game", gameId: "tarot" })
AgentController 在对话中插入引导语:
"你这个困扰,看起来困扰你很久了。我知道个有效的缓解方式——我给你算个塔罗牌吧。"
用户确认 / 自然延续
GameController.trigger("tarot")
→ 弹出 GameModal → TarotGame 组件加载
用户抽卡 → TarotGame 交互完成
GameController.collectResult({ card, userChoice })
InterpretationEngine.generate({ gameType: "tarot", result: {...}, context: UserSession })
→ 从 InterpretationPool 选取积极解读
→ 生成 ResultCard
展示 ResultCard解读文案 + 鼓励 + 建议)
GameController.close()
→ 写回 UserSession.gameHistory
AgentController 追加对话:"感觉怎么样?塔罗牌给你的启示有没有帮到你?"
```
### 流 2量表编排PSI 等)
```
AgentBrain 后台监测:
recentUtterances 检测到 "焦虑"/"失眠"/"心慌" 关键词累计 3 次
StrategyDispatcher.enqueue({
type: "assessment",
scale: "SAS_anxiety",
priority: 2,
reason: "检测到焦虑风险词 3 次",
suggestedQuestions: ["你最近睡眠状况如何?", "有没有经常感到紧张?"]
})
AgentController 感知队列非空
在对话自然节点插入:
"我注意到你说最近睡得不太好,我有个小工具能帮你整理一下现在的状态,愿意试试吗?"
用户同意
AssessmentController.activate("SAS_anxiety")
→ 从 AssessmentFlows 加载 3 道题目
逐题展示 AssessmentCard → 用户作答
收集评分 → 计算总分
InterpretationEngine.generate({ flowType: "assessment", score, context })
展示 ResultCard + 更新 UserSession.riskScore
AgentBrain 更新 riskTags加入 "焦虑"
影响后续 StrategyDispatcher 召回权重
```
### 流 3直接入口用户主动触发
```
数字人下方手势区域(双指下滑 / 长按)
解锁底部工具栏 ToolBar
展示游戏图标网格 GridView
用户点击图标 → GameController.trigger(gameId)
(与流 1 的后半段一致)
```
---
## 七、项目结构(原型阶段)
```
psycho-games-hub/
├── docs/
│ ├── SPEC.md # 本文档
│ ├── RESEARCH.md # GitHub 调研报告(稍后补充)
│ └── PROTOTYPE_NOTES.md # 原型实现笔记
├── src/
│ ├── models/
│ │ ├── AgentBrain.js
│ │ ├── GameCatalog.js
│ │ ├── AssessmentFlows.js
│ │ ├── UserSession.js
│ │ └── InterpretationPool.js
│ ├── views/
│ │ ├── AvatarView.html # 数字人主界面(单文件原型用)
│ │ ├── GameModal.vue # 游戏弹窗
│ │ ├── ChatPanel.vue
│ │ └── ResultCard.vue
│ ├── controllers/
│ │ ├── AgentController.js
│ │ ├── GameController.js
│ │ ├── AssessmentController.js
│ │ └── StrategyDispatcher.js
│ ├── components/ # 各游戏独立组件
│ │ ├── TarotGame.vue
│ │ ├── RorschachGame.vue
│ │ └── MBTIGame.vue
│ └── App.vue
└── README.md
```
---
## 八、待决策问题(悬置)
| # | 问题 | 选项 | 当前倾向 |
|---|------|------|---------|
| 1 | 数字人技术路线 | A: Live2D / B: 3D 虚拟人 / C: 2D 立绘+差分 | C最轻量 |
| 2 | 策略召回引擎 | A: 规则版(关键词匹配)/ B: RAG向量化召回 | A先行B后续 |
| 3 | 第一批游戏优先级 | 塔罗牌 / MBTI / 罗夏墨迹 | 塔罗牌优先 |
| 4 | 游戏关闭策略 | A: 可随时关闭 / B: 完成才关闭 | A |
| 5 | 遮罩样式 | A: blur + 黑底 / B: 纯黑底半透明 | A |
| 6 | Agent 接入方式 | 接入 MiniMax / 本地小模型 | 待确认 |
---
## 九、版本记录
| 版本 | 日期 | 变更 |
|------|------|------|
| v0.1 | 2026-05-31 | 初稿MVC 模块划分 + 交互流设计 |
---
*本文档为架构设计文档,随着原型开发推进会持续更新。*
*关键决策待在大头确认后锁定。*