Skip to content

Cloud-Edge Protocol: events.jsonl

PracticeMate 边端(iOS)与云端之间的数据协议规范。 events.jsonl 是连接学生练习、即时反馈、云端深度评估的唯一数据纽带。


练-评-教 三角架构

PracticeMate 的数据流形成一个三角闭环:

Student (PracticeMate 端)

    │  events.jsonl(练习原始事件流)

Cloud Examiner(云端考官)

    │  Examiner Report(深度评估报告)

Student ← 报告回传至学生端

    │  events.jsonl 聚合(班级维度)

Teacher (全智评 Web 教师后台) ← 班级仪表盘

核心定位

  • PracticeMate 是学生入口——练习发生的地方,事件产生的源头
  • 全智评 是教师后台——查看班级练习数据、发现共性问题、调整教学策略
  • events.jsonl 是纽带——同一份数据格式,既服务学生个体评估,也支撑教师班级视图

即使 MVP 阶段不构建教师仪表盘,架构和数据格式从第一天就为此做好准备。events.jsonl 的 schema 设计确保:单个学生的事件流可以被聚合为班级维度的统计,无需回溯修改数据格式。


Instant Recap vs Examiner Report 层级分离

系统有两层反馈机制,职责清晰分离:

维度Instant Recap(即时回顾)Examiner Report(考官报告)
角色Coach(教练)Examiner(考官)
生成方式规则聚合:按阶段统计 ✓/△/✗ 数量云端 CCAE + 完整 rubric 评分
用户感知温暖、不打分、即时、先说亮点严谨、有分数、证据链、约 30s
网络依赖不需要——纯边端计算需要云端模型
延迟0s(练习结束即出)20-60s(云端处理)

设计原则:Recap 是教练的鼓励性总结,让学生练完立刻有正反馈;Report 是考官的严谨评估,给出可信的成长证据。两者互补,不冲突。

Recap 的数据来源是 events.jsonl 中的事件计数(edge 本地即可完成),Report 的数据来源是完整 events.jsonl 上传后云端 CCAE 流水线处理。


设计原则

  1. Append-only:边端只追加,不修改已写入事件
  2. 离线优先:所有事件先落本地 jsonl,网络恢复后批量上传
  3. 幂等上传:相同 session_id + event_id 组合,云端去重
  4. 正向记录为主:优先记录学生做到了什么(详见下方"正向事件"章节)
  5. 诚实哲学:低置信度事件不隐藏,显式标记并延迟给考官判断

Schema 定义

每行一个 JSON 对象,字段如下:

jsonc
{
  "event_id": "uuid-v4",           // 事件唯一 ID
  "session_id": "uuid-v4",         // 练习会话 ID
  "ts": 0.0,                       // 相对于 session 开始的秒数(float)
  "event_type": "string",          // 事件类型(见下方枚举)
  "phase": "string",               // 当前阶段:preparation | operation | cleanup
  "signal": "string",              // 具体信号名
  "value": {},                     // 信号值(类型因 signal 而异)
  "confidence": 0.0,               // 边端模型置信度 [0, 1]
  "alert_tier": "string",          // "high" | "medium" | "low" — 置信度分层
  "cloud_review_available": false, // 是否标记为需要云端复核
  "transition_source": "string",   // 可选:阶段切换来源(见下方说明)
  "meta": {}                       // 可选:设备信息、模型版本等
}

transition_source 字段

仅出现在 phase_transitionphase_timeout 事件中,标识阶段切换的触发来源:

含义
ai_detectedAI 模型自动检测到阶段完成,触发切换
user_manual用户手动点击按钮切换阶段
timeout阶段超时,系统询问后切换

这体现了混合切换策略:AI 自动检测为主、用户手动为辅、超时兜底。三种来源在数据层面平等记录,供云端分析学生的练习节奏。


事件类型枚举

会话生命周期

event_type说明典型 signal
session_start练习开始session_begin
session_focus仪式层专注引导完成focus_completed
session_end练习结束session_complete
phase_transition阶段切换preparation_to_operation, operation_to_cleanup
phase_timeout阶段超时询问preparation_timeout, operation_timeout

练习观察

event_type说明典型 signal
posture_observation姿态观察bow_hold_check, left_hand_position
audio_observation音频观察pitch_accuracy, rhythm_stability, tone_quality
tempo_observation节奏观察tempo_consistency, tempo_change
technique_observation技术动作观察vibrato_detected, shift_detected

正向事件(Positive Events)

event_type说明典型 signal
achievement达成某个标准intonation_stable_30s, bow_straight_10s
improvement相比上次有进步pitch_improved, rhythm_more_stable
streak连续正确correct_notes_streak_8

诚实标记事件

低置信度事件的处理方式——不隐藏,显式记录:

jsonc
{
  "event_type": "posture_observation",
  "signal": "bow_hold_check",
  "confidence": 0.35,
  "alert_tier": "low",
  "cloud_review_available": true,
  "value": {
    "edge_assessment": "possible_issue",
    "note": "边端不确定,已标记待考官复核"
  }
}

诚实哲学:当边端模型对某个观察不够确定时(confidence < 0.5),不会假装没看到,而是:

  • 显式记录事件,alert_tier 设为 "low"
  • cloud_review_available 设为 true
  • 即时回顾(Recap)中不展示该项(避免误导)
  • 考官报告(Examiner Report)中由云端模型重新评估,给出可信结论

这确保了数据完整性——所有观察都被记录,但反馈的置信度对用户透明。


正向事件设计理念

为什么优先记录正向事件:

  1. 学习动机:正向反馈强化练习意愿,尤其对初学者
  2. 数据平衡:避免 events.jsonl 全是"错误",导致云端报告过于消极
  3. 教练角色:边端扮演教练,教练的首要职责是发现学生做对了什么
  4. 考官补充:严格的问题诊断交给云端考官,它有更强的模型和完整上下文

正向事件不是"降低标准",而是"先看到好的,再改进不足"。


事件语义三元组(Event Semantic Triple)(TD-020)

每个事件从"发生 → 观察 → 判断"经历三个语义阶段,不要混为一谈:

阶段语义event_type 示例说明
check_requested端侧请求检查signal_check_requestedL2 采样到一帧,发起检查请求
observation观察到现象signal_observation模型输出原始观察(如"瓶盖在桌上")
assertion给出判断signal_detected基于观察和 rubric 规则,给出最终断言

为什么要拆开?

  1. 可审计:考官可以看到"AI 看到了什么"和"AI 判断了什么",分别评估感知和推理的准确性
  2. 可打断:用户对 observation 阶段就可以纠正("我手位是对的,你没看到")
  3. 不确定项透明:observation 有但 assertion 置信度低 → 自然进入 Uncertainty Ledger

三元组在 events.jsonl 中的体现

jsonc
// check_requested:端侧发起检查
{"event_type": "signal_check_requested", "signal_id": "hand_position_check", "perception_level": "L2", "ts": "..."}

// observation:模型观察到现象
{"event_type": "signal_observation", "signal_id": "hand_position_check", "detail": "检测到双手位置偏离胸骨中线", "confidence": 0.6, "ts": "..."}

// assertion:给出最终判断
{"event_type": "signal_detected", "signal_id": "hand_position_check", "assertion": false, "confidence": 0.6, "alert_tier": "low", "coach_line": "不太确定,先记下来", "ts": "..."}

三元组不强制三条都产出——如果 assertion 置信度足够高(≥ 0.8),observation 可省略,直接从 check_requested 跳到 assertion。


上传协议

触发时机

  1. 练习结束时:session_end 后立即尝试上传
  2. 后台定时:每 5 分钟检查未上传的 session
  3. 网络恢复时:检测到网络从离线变为在线

上传格式

http
POST /api/v1/sessions/{session_id}/events
Content-Type: application/x-ndjson

{"event_id":"...","session_id":"...","ts":0.0,...}
{"event_id":"...","session_id":"...","ts":1.2,...}
...
  • POST /sessions/:id/summary-card(TD-018)
    • 请求体:{ recap_highlights, uncertainty_count, journey_progress, journey_id }
    • 返回:{ card_id, teacher_view_url } — teacher_view_url 用于生成 QR 码

响应

jsonc
{
  "status": "accepted",
  "session_id": "uuid",
  "events_received": 42,
  "duplicates_skipped": 0
}

重试策略

  • 指数退避:1s → 2s → 4s → 8s → 最大 60s
  • 最多重试 10 次后标记为 pending,等待下次触发

Rubric Runtime 说明

events.jsonl 协议与具体评分标准(Rubric)解耦。同一套事件格式适用于任何 Rubric:

  • 更换 Rubric YAML 文件(如从"CPR/BLS"切换到"OSCE 洗手")
  • 事件类型和 schema 不变
  • 云端 CCAE 流水线根据不同 Rubric 解读相同事件,生成对应报告

这意味着:新增乐器或新增评分维度时,只需新增 Rubric YAML,无需修改客户端事件采集逻辑。


完整 Session 示例(3 分钟练习)

jsonl
{"event_id":"e001","session_id":"s-abc-123","ts":0.0,"event_type":"session_start","phase":"preparation","signal":"session_begin","value":{"instrument":"violin","piece":"twinkle_twinkle","rubric_version":"v1.2"},"confidence":1.0,"alert_tier":"high","cloud_review_available":false,"meta":{"device":"iPhone15","model_version":"edge-v0.3"}}
{"event_id":"e002","session_id":"s-abc-123","ts":2.5,"event_type":"session_focus","phase":"preparation","signal":"focus_completed","value":{"focus_duration_s":2.5,"ritual_type":"breathing"},"confidence":1.0,"alert_tier":"high","cloud_review_available":false}
{"event_id":"e003","session_id":"s-abc-123","ts":15.0,"event_type":"posture_observation","phase":"preparation","signal":"bow_hold_check","value":{"correct":true,"details":"拇指弯曲适当,小指放松"},"confidence":0.88,"alert_tier":"high","cloud_review_available":false}
{"event_id":"e004","session_id":"s-abc-123","ts":30.0,"event_type":"achievement","phase":"preparation","signal":"preparation_posture_ready","value":{"criteria_met":["bow_hold","left_hand","standing_posture"]},"confidence":0.85,"alert_tier":"high","cloud_review_available":false}
{"event_id":"e005","session_id":"s-abc-123","ts":35.0,"event_type":"phase_transition","phase":"operation","signal":"preparation_to_operation","value":{"from":"preparation","to":"operation","preparation_duration_s":35.0},"confidence":0.92,"alert_tier":"high","cloud_review_available":false,"transition_source":"ai_detected"}
{"event_id":"e006","session_id":"s-abc-123","ts":50.0,"event_type":"audio_observation","phase":"operation","signal":"pitch_accuracy","value":{"measure":1,"accuracy":0.91,"notes_correct":10,"notes_total":11},"confidence":0.87,"alert_tier":"high","cloud_review_available":false}
{"event_id":"e007","session_id":"s-abc-123","ts":65.0,"event_type":"streak","phase":"operation","signal":"correct_notes_streak_8","value":{"streak_length":8,"start_measure":2,"end_measure":3},"confidence":0.83,"alert_tier":"medium","cloud_review_available":false}
{"event_id":"e008","session_id":"s-abc-123","ts":80.0,"event_type":"posture_observation","phase":"operation","signal":"bow_hold_check","value":{"correct":false,"details":"小指僵硬"},"confidence":0.42,"alert_tier":"low","cloud_review_available":true,"value":{"edge_assessment":"possible_issue","details":"小指可能僵硬,但角度遮挡,不确定"}}
{"event_id":"e009","session_id":"s-abc-123","ts":100.0,"event_type":"audio_observation","phase":"operation","signal":"tone_quality","value":{"quality":"good","bow_pressure":"appropriate","bow_speed":"stable"},"confidence":0.79,"alert_tier":"medium","cloud_review_available":false}
{"event_id":"e010","session_id":"s-abc-123","ts":120.0,"event_type":"improvement","phase":"operation","signal":"pitch_improved","value":{"previous_accuracy":0.82,"current_accuracy":0.91,"comparison_session":"s-prev-456"},"confidence":0.80,"alert_tier":"medium","cloud_review_available":false}
{"event_id":"e011","session_id":"s-abc-123","ts":140.0,"event_type":"phase_transition","phase":"cleanup","signal":"operation_to_cleanup","value":{"from":"operation","to":"cleanup","operation_duration_s":105.0},"confidence":0.90,"alert_tier":"high","cloud_review_available":false,"transition_source":"user_manual"}
{"event_id":"e012","session_id":"s-abc-123","ts":155.0,"event_type":"technique_observation","phase":"cleanup","signal":"self_assessment","value":{"student_rating":4,"student_comment":"感觉音准比昨天好了"},"confidence":1.0,"alert_tier":"high","cloud_review_available":false}
{"event_id":"e013","session_id":"s-abc-123","ts":180.0,"event_type":"session_end","phase":"cleanup","signal":"session_complete","value":{"total_duration_s":180,"phases":{"preparation":35,"operation":105,"cleanup":40}},"confidence":1.0,"alert_tier":"high","cloud_review_available":false}

超时示例(preparation 阶段过长)

如果学生在 preparation 阶段停留过久(如超过 90s),系统会产生 phase_timeout 事件:

jsonl
{"event_id":"e-timeout-1","session_id":"s-xyz-789","ts":90.0,"event_type":"phase_timeout","phase":"preparation","signal":"preparation_timeout","value":{"elapsed_s":90,"threshold_s":60,"user_response":"continue"},"confidence":1.0,"alert_tier":"medium","cloud_review_available":false,"transition_source":"timeout"}

系统询问学生是否继续准备或进入演奏,学生的选择记录在 user_response 中。


考官报告示例(Examiner Report)

云端处理完成后返回的报告结构:

jsonc
{
  "report_id": "r-001",
  "session_id": "s-abc-123",
  "generated_at": "2025-01-15T10:05:30Z",
  "processing_time_s": 28,
  "rubric_version": "v1.2",

  // 边端即时回顾(Recap)— 练习结束时立即生成,无需网络
  "recap_summary": {
    "generated_by": "edge",
    "tone": "coach",
    "highlights": [
      "音准比上次进步了 9%",
      "连续 8 个音符准确无误",
      "准备阶段姿态一次到位"
    ],
    "phase_summary": {
      "preparation": {"positive": 2, "uncertain": 0, "issue": 0},
      "operation": {"positive": 3, "uncertain": 1, "issue": 0},
      "cleanup": {"positive": 1, "uncertain": 0, "issue": 0}
    }
  },

  // 云端考官报告 — 上传后 20-60s 生成
  "examiner_assessment": {
    "overall_score": 78,
    "dimension_scores": {
      "intonation": 82,
      "rhythm": 85,
      "tone_quality": 75,
      "posture": 70
    },
    "evidence_chain": [
      {
        "dimension": "intonation",
        "score": 82,
        "evidence_events": ["e006", "e010"],
        "narrative": "第一小节音准 91%,相比上次提升 9 个百分点,进步明显。"
      },
      {
        "dimension": "posture",
        "score": 70,
        "evidence_events": ["e003", "e008"],
        "narrative": "准备阶段持弓正确;演奏中段有一次疑似小指僵硬。",
        "low_confidence_items": [
          {
            "event_id": "e008",
            "edge_confidence": 0.42,
            "cloud_review_available": true,
            "cloud_assessment": "经视频帧分析,确认小指在第 80s 时有短暂僵硬,但 3s 后自行恢复。",
            "note": "教练标记为不确定,考官经复核确认为轻微问题"
          }
        ]
      }
    ],
    "growth_indicators": [
      {
        "metric": "pitch_accuracy",
        "trend": "improving",
        "sessions_compared": 5,
        "detail": "近 5 次练习音准从 72% 提升至 91%"
      }
    ],
    "recommendations": [
      "继续保持音准练习节奏",
      "注意演奏中段右手小指放松",
      "下次可尝试稍快速度(♩=72 → ♩=80)"
    ]
  }
}

低置信度项在报告中的呈现

当边端标记了 cloud_review_available: true 的事件,考官报告会:

  1. evidence_chain 中显式列出该事件
  2. 标注 edge_confidence 原始值
  3. 给出云端复核后的结论(cloud_assessment
  4. 添加 note: "教练标记为不确定,考官经复核确认/排除" 说明

这让学生和教师都能看到:哪些判断是确定的,哪些经过了二次确认,体现评估的诚实与透明。


数据量估算

单次练习(3 分钟)

  • 事件数:10-20 条
  • 单条事件大小:200-500 bytes
  • 单次 session 文件大小:2-10 KB

日常使用(每天练习 30 分钟)

  • 约 100-200 条事件
  • 文件大小:20-100 KB
  • 月累计:600 KB - 3 MB

存储策略

  • 本地保留最近 30 天原始 events.jsonl
  • 云端永久存储(用于长期成长分析)
  • 超过 30 天的本地文件压缩归档或删除(云端已有备份)

第四轮重构新增字段(v0.5)

Events schema 新增字段:

字段类型说明
journey_idstring (uuid)跨会话技能旅程 ID,同一技能的多次练习共享
perception_levelenum: L0 / L1 / L2产出该事件的感知层级
primitiveenum: presence / sequence / timing / quality / safetyRubric Primitive 信号原语类型

Report schema 新增字段:

字段类型说明
journey_contextobject技能旅程上下文(journey_id + 历史 session 摘要)
summary_cardobjectPractice Summary Card(练-评-教三角轻量闭合卡片,含 QR 码 URL)

Event Semantic Triple(三元组事件拆分):

每个检测事件拆为三步语义:check_requested(Planner 发出检测请求)→ observation(感知层产出原始观察)→ assertion(Confidence Router 产出最终断言)。三步共享同一 correlation_id,支持审计日志回溯。

版本演进

版本变更
v0.1初始 schema,基础事件类型
v0.2增加 confidence 和 alert_tier 字段
v0.3增加正向事件类型(achievement/improvement/streak)
v0.4增加 session_focus、phase_timeout 事件;transition_source 字段;诚实哲学标记
v0.5增加 journey_id、perception_level、primitive 字段;Event Semantic Triple;report 新增 journey_context + summary_card

PracticeMate — Rubric Runtime