通话式课程改造设计 v0.1(待审)
日期:2026-09-18
状态:待用户审。本稿只描述改造方案,不代表已实现。
1. 为什么要改
用户原话(2026-09-18):
它就是 APP,孩子一开始,连着以后就开始,相当于就开始打电话了。这个时候就相当于开了一个网上课程,老师就一直引导孩子,两个人在对话。老师也可以用 Function Calling 不断地去调整桌面上——有可能是几个图片让孩子选,也有可能直接就又变成了课件。就这样时间就往前推进。
对照立项文档 [[08-宏观产品方案-v0.1-待审]],这个描述与原文一致:
| 立项文档原话 |
位置 |
| 「建议先测试每次约 5–15 分钟的完整小活动,也允许多个活动连续进行」 |
第 82 行 |
| 「孩子可以改变角色、物品或故事走向,AI 在预制素材及允许动作内回应」 |
第 67 行 |
| 「孩子说"老虎也要来" → AI 可接两轮故事,再自然邀请继续」 |
第 78 行 |
当前实现把这三条都丢了。
2. 问题定位(已核对代码)
2.1 指令层明确禁止变通(最严重)
server/app/upstream.py 的 _teaching_instruction() 默认分支下发给模型的最后一句是:
现在用一句话带孩子执行已呈现的任务。读出当前英文目标 X,…不能只说中文,不再改成别的题。
- 「执行已呈现的任务」= 念台词,不是对话
- 「不再改成别的题」= 明确禁止跟随孩子 —— 直接违反立项文档第 67、78 行
孩子听到的 I choose the dog. Your turn! 之后接不上话,根因就在这里:模型手里只有这一句剧本,且被禁止变通。
2.2 黑板内容锁死在当前活动的固定词表
server/app/session.py 的 showChoices / presentTask 校验:
allowed = set(self.content.activity(self.activity_id).items)
if not set(choices).issubset(allowed):
raise InvalidSessionAction("choices 包含当前活动未注册的内容。")
老师不能显示它想显示的内容,只能从当前预制活动的 items 里挑。所以「随时变成课件」做不到。
2.3 活动是「必须完成的关卡」
存在 completeActivity(结束活动)与 advanceActivity(进入下一个)两个工具,活动有 completed 状态。想要「连续进行」,却要先打卡。
2.4 完全没有课时概念
现在与时间有关的只有「90 秒无互动暂停」。用户要求的一节课 20–30 分钟,代码里不存在。
3. 目标交互模型
孩子打开 App
↓
一次接通 = 一节课(20–30 分钟)
↓
AI 老师持续引导对话 ──────────┐
↓ │
Function Calling 双向: │
├─ 改黑板(图片/选项/课件) │
└─ 记学情(独立/提示/待复习)│
↓ │
时间自然往前推进 ←────────────┘
↓
到点结束
要点:
- 一通话,不是一轮一轮。中途不因「活动完成」而中断。
- AI 主导:它决定此刻呈现什么、问什么、要不要接孩子的话。
- 黑板是它的教具:随时可改,不受「当前活动词表」限制。
- 学情照记:Function Calling 继续产出结构化证据,家长侧不变瞎。
4. 改造项
4.1 指令层:从「逐轮台词」改成「教学目标 + 引导原则」
用户明确(2026-09-18):
指令是灵活的。我们定的只是「要学什么东西」「要怎么去引导这些」;定了之后,就根据小朋友的状态去引导就行了。
这不是改几句文案,是改服务端的角色定位:
|
现在 |
应该 |
| 服务端给什么 |
逐轮台词(「读出当前英文目标 X」「不再改成别的题」) |
教学目标 + 可用引导手段 + 边界 |
| 具体怎么说 |
服务端写死 |
模型根据孩子当下状态现场组织 |
| 服务端的角色 |
编剧 |
教研 |
类比:给老师一份教案大纲(今天教什么、孩子卡住时有哪些手段、哪些不能做),而不是给老师逐字台词本。
改什么:
- 移除逐轮台词式指令:不再告诉模型「读出目标 X」这种具体措辞
- 移除「不再改成别的题」
- 保留并前置教学要素,让模型自己组织语言:
- 本节点的目标与成功标准(来自活动上下文)
- 可用的引导手段:示范、图片、中文支架、降低难度、换情境
- 边界:不在
helpLevel=0 时透露答案、不替代孩子说、不把热闹当掌握
- 把「孩子当前状态」作为输入:已有证据、刚才说了什么、是否卡住、有没有求助
依据:立项文档第 67、78 行要求「孩子可以改变故事走向」「AI 可接两轮故事再自然邀请继续」;用户 2026-09-18 明确指令要灵活、只定目标与引导原则。
4.2 黑板内容:从「当前活动词表」放开到「内容注册表」
改什么:session.py 的 choices / item 校验白名单。
改成:白名单从 activity.items 放宽为整个 StarterContentRegistry 已注册素材。
保留:仍然校验「必须是已注册内容」——防止模型编造不存在的图片或单词(这条防线不能撤)。
收益:老师可以随时换素材;孩子提到别的东西时,老师能把它显示到黑板上。
4.3 活动:从「关卡」降级为「教学上下文」
改什么:completeActivity / advanceActivity 的语义。
改成:
- 活动仍然存在,但只作为「当前教学目标 + 素材 + 观察标准」的上下文,用于学情锚定
- AI 可以自然过渡到下一个上下文,不需要先显式
completeActivity
- 「完成」不再是课程推进的必要条件
必须保留:活动携带的 successCriteria(成功标准)与 skill 绑定关系 —— 这是学情证据的锚点,丢了学情就散架。
4.4 课时框架(新增)
新增:一节课的时间框架。
- 记录本节课开始时间
- 按 20–30 分钟规划
- 待定(见第 7 节):到点是自动结束,还是提醒后允许继续
4.5 学情:保持不变量
以下不改:
- 独立 / 提示后 / 待复习 分维度记录
- 点击不算会说;一次成功不算掌握
- 家长报告的字段与含义
- 原始对话单独保存
5. 不变量与边界(改造中不能破的)
- 学情证据必须仍然可锚定:每条观察要能说清是哪个技能、什么标准、有无帮助。
- 不能变成自由聊天:立项文档第 25 行明确「保留预制内容和主动带领,不将产品默默改成任意自由聊天」。
- 家长侧不能变瞎:改造后家长报告的内容量不应减少。
- 模型不能自评等级:不能因为聊得热闹就写「已达 B1」。
6. 验证方式
改造后需要能验证(不只是跑通测试):
- 孩子自由引入话题(如「老虎也要来」)时,老师能接住并自然引回,不中断通话
- 老师能显示当前活动之外的素材(黑板不被拒)
- 连续 20 分钟不出现「活动完成」导致的断线或重置
- 一节课结束后,家长报告里能看到这节课的观察记录
7. 已定决策(2026-09-18 用户确认)
- 课时到点行为:C —— 不打断进行中的内容,等它自然收尾。不设下课铃,不做超时惩罚。
- 活动过渡对家长可见:要体现。一节课里换过几次教学上下文,家长报告里应能看到。
- 改造顺序:先做 4.1(指令层),改动最小、最可能直接改善对话手感;验证方向后再动黑板、活动、课时三块。
7.1 仍然未定
- 课时「自然收尾」由谁判断:模型感知到孩子疲倦主动收,还是服务端给时长信号由模型决定收尾时机?
- 家长报告里「教学上下文切换」的呈现粒度:按次数统计,还是列出依次练了什么?
8. 影响面
| 层 |
文件 |
改动量 |
| 指令层 |
server/app/upstream.py |
小(改文案 + 约束) |
| 黑板校验 |
server/app/session.py |
中(白名单来源) |
| 活动语义 |
server/app/session.py、upstream.py |
中(状态机) |
| 课时 |
server/app/main.py、mobile/lib/main.dart |
中(新增) |
| 客户端黑板 |
mobile/lib/child/child_blackboard.dart |
小——已支持 diagnostic/picture/letter_sound/word_picture/dialogue 五种模式,不需要新增呈现类型 |
附:与当前修复工作的关系
本轮(2026-09-18)已完成的全项目扫描修复不冲突,其中若干项正是这次改造的前提:
- 结束通话要求「孩子明确说结束」——保证通话不会因普通答题中断
- 音频失败不再挂断整通话——保证持续通话的稳定性
- 事件链异常不再静默——保证长会话不哑
改造要在这些基础上做,而不是推倒重来。