edify 是一个 lesson-first 的 R 学习运行时。
它把课程内容、判题规则、提示层级、rubric、remediation 和可选 AI 反馈放进同一条工作流里,让你先把“老师想怎么教”写清楚,再把它跑起来。
- 用 Markdown lesson + YAML frontmatter 描述课程
- 校验 lesson 结构
- 预览课程与教师审阅报告
- 启动 lesson session
- 支持 expression、object、output 三类判题
- 支持 hint 逐级释放
- 支持 retries
- 支持 task 自动推进
- 支持 session summary
- 支持 rubric 和 remediation
- 支持基于
aisdk的可选解释型 AI 反馈
如果你就在仓库本地试用:
devtools::load_all("E:/YuNotebooks/01_Development/source/yulab-github/edify")
library(edify)如果你想测试 AI 反馈,还需要可用的 aisdk 和默认模型配置。
library(edify)
lesson_templates()
path <- tempfile(fileext = ".md")
new_lesson(path, template = "two_tasks")
print(lint_lesson(path))
print(preview_lesson(path))
print(lesson_report(path))
session <- run_lesson(path, student_id = "demo-user")
run_task(session)
print(next_hint(session))
result1 <- submit_task(session, "subset(mtcars, mpg > 25)")
print(result1)
result2 <- submit_task(session, "subset(mtcars, mpg > 25 & cyl == 4)")
print(result2)
print(session_summary(session))如果你想像学生一样真正“做题”,不要只跑 print(),直接用:
library(edify)
path <- tempfile(fileext = ".md")
new_lesson(path, template = "two_tasks")
learn_lesson(path, student_id = "demo-user")进入后你会看到当前 task,然后可以在控制台里输入:
- 直接写 R 代码做探索,例如
head(mtcars) - 用
/submit subset(mtcars, mpg > 25)正式提交答案 - 用
/ask 我应该先看哪些列?跟教练互动 /hint/task/status/quit
也就是说,交互 loop 里现在区分三类输入:
- 探索代码:默认直接执行,不消耗 attempts
- 答案提交:必须显式写
/submit ... - AI 对话:用
/ask ...
如果你想在交互试用里顺便体验 AI 解释反馈:
learn_lesson(
path,
student_id = "demo-user",
ai_feedback = TRUE
)这时每次提交后,除了规则判题结果,还会返回 AI 解释反馈。
如果你在探索代码时触发了 R error,交互不会退出;开启 ai_feedback = TRUE 后,AI 也会解释错误并给下一步建议。
如果你在 /submit ... 里写错了列名、函数或表达式,也不会直接退出 lesson,而是会把这次提交转成失败结果;开启 AI 后,教练会顺势解释错误。
现在错误反馈还会附带一个简短的 “Next steps” 列表,例如提醒你检查列名、先看 names(...)、使用 /hint 或继续 /ask。
一个最小 lesson 由两部分构成:
- frontmatter
- 一个或多个
## task:区块
最小示例:
---
title: Data frame filtering basics
lesson_id: dplyr-filter-001
audience: Beginner R learners
difficulty: beginner
goals:
- Understand row filtering
runtime:
mode: console
coach:
style: socratic
direct_answer: false
max_hint_level: 2
assessment:
pass_rule: all_required_tasks
retries: 3
---
## task: single-condition
Filter rows where `mpg > 25`.
```edify-check
type: expression
solution: subset(mtcars, mpg > 25)
compare:
mode: data.frame_equallevel1: Think about keeping rows by a condition
level2: You can try subset(mtcars, mpg > 25)
## 内置模板
当前可直接起步的模板有:
```r
lesson_templates()
目前包括:
minimaltwo_tasksoutput_check
创建 lesson:
path <- tempfile(fileext = ".md")
new_lesson(path, template = "minimal")report <- lint_lesson(path)
print(report)你会看到:
- 是否有效
- errors 数量
- warnings 数量
preview <- preview_lesson(path)
print(preview)这里更适合快速看:
- task 数量
- check type
- hint level
- recommendations
teacher_report <- lesson_report(path)
print(teacher_report)这里更适合审阅:
- check 覆盖情况
- hint 覆盖情况
- rubric 覆盖情况
- remediation 覆盖情况
- lesson 风险点
如果你只是想快速感受 learner experience,优先试这个:
learn_lesson(path)这会启动一个 console 交互循环。
推荐你第一次这样试:
head(mtcars)
/ask 我应该关注哪些列来完成这道题?
/hint
/submit subset(mtcars, mpg > 25)session <- run_lesson(path, student_id = "student-001")task <- run_task(session)
task$prompthint <- next_hint(session)
print(hint)hint 会遵守 lesson 中的:
level1,level2, ...coach.max_hint_level
result <- submit_task(session, "subset(mtcars, mpg > 25)")
print(result)返回结果里常见字段包括:
passedstatusattempt_nattempts_remaininghint_levelnext_task_idlesson_completedrubricremediationai_feedback
summary <- session_summary(session)
print(summary)最常见,用表达式比较学生答案与标准答案。
```edify-check
type: expression
solution: subset(mtcars, mpg > 25)
### object
适合直接比较对象结构。
```md
```edify-check
type: object
solution: list(a = 1, b = 2)
compare:
mode: all_equal
### output
适合比较打印输出。
```md
```edify-check
type: output
expected: "[1] \"hello\""
## rubric 与 remediation
如果你希望在“判对/判错”之外再定义更清楚的教学反馈,可以加:
```md
```edify-rubric
pass: Correct and complete
partial: Close, but revise the expression
fail: The answer is still incorrect
retry: Check the expected value and try again
exhausted: Stop and review the lesson note before retrying later
pass: You can move to the next task
然后 `submit_task()` 会把它们接进结果里。
## AI 反馈怎么开
默认不启用 AI:
```r
submit_task(session, "subset(mtcars, mpg > 30)")
如果你已经配置好了 aisdk,可以这样开:
result <- submit_task(
session,
"subset(mtcars, mpg > 30)",
ai_feedback = TRUE
)
result$ai_feedback或者直接用:
result <- coach_respond(session, "subset(mtcars, mpg > 30)")
result$ai_feedback这个阶段 AI 只做:
- 解释为什么错
- 结合 rubric/remediation 给出下一步建议
它不负责:
- 最终判题
- lesson 状态更新
- retry 控制
第一次试用时,建议按这个顺序来:
new_lesson(..., template = "minimal")lint_lesson()preview_lesson()lesson_report()learn_lesson()
第二轮再尝试:
two_tasksoutput_checkedify-rubricedify-remediationcoach_respond()learn_lesson(..., ai_feedback = TRUE)
当前版本已经适合试用,但仍然属于 MVP。
目前更偏:
- console-first
- rule-based checking first
- teacher-authored flow first
还没有重点做:
- Shiny 学习界面
- 更复杂的多轮 AI 会话控制
- learner history 持久化
- 更丰富的 lesson 模板体系
你可以重点感受三件事:
- lesson 结构写起来顺不顺
- runtime 的 hint/retry/task progression 是否符合你的教学直觉
- AI 反馈是否真的“站在老师定义的规则上讲话”
如果你试用过程中遇到问题,再回来迭代会很自然。