一句话摘要:我的 Education Agent 能用 LLM 自动生成结构化教案,然后让 5 个 AI 评审角色交叉打分,发现问题后自动修改——整个过程无需人工介入。本文拆解它的架构和最关键的”并行提取器”模式。

1. 缘起 — 被催更的 AI 老师

几个月前,我在弄一个软考高项(信息系统项目管理师)的备考系统。需求很简单:把教材知识点转化成结构化的学习教案,每个知识点要有概念讲解、案例、练习题、记忆卡片、常见误区……

一个知识点大概对应教材 1-3 页内容。整本书几百个知识点。手写?不现实。用模板硬套?生成的教案千篇一律,学生看一眼就困。

我需要一个自动备课系统:输入一个知识点,输出一份结构完整、内容扎实、有互动练习的 HTML 教案。而且——它得越写越好,不能原地踏步。

这就是 Education Agent 的起点。

2. 核心方法 — 5 个”老师傅”同时备课

我面对的核心问题是:如何让 LLM 稳定产出高质量的教学内容?

一个大的 LLM 调用(”帮我写一份教案”)往往输出不稳定——有时漏了案例,有时练习题出得太偏。关键是,一个 prompt 里塞太多要求,LLM 会选择性遗忘

解法很简单但很有效:拆成 5 个并行提取器,各管一摊。

2.1 并行提取器管线

1
2
3
4
5
6
7
知识点信息

├─ 🔤 概念提取器 → 概念讲解(text blocks)
├─ 🎯 目标提取器 → 学习目标 + 考试重点
├─ 💡 案例提取器 → 案例 + 应用场景
├─ ⚠️ 误区提取器 → 常见误区 + 对比表格
└─ 📝 习题提取器 → 练习题 + 记忆卡片

每个提取器是一个独立的 LLM 调用,prompt 针对一种内容类型做了深度优化。比如案例提取器的 prompt 要求”贴近生活的类比”、”60-150字”、”必须准确不误导”;习题提取器要求”考查深层理解而非死记硬背”。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 核心代码(简化)
async def generate_for_node(node_id, node):
# 5 个提取器并行执行
tasks = [
_extract_concepts(node),
_extract_objectives(node),
_extract_cases(node),
_extract_misconceptions(node),
_extract_quizzes(node),
]
results = await asyncio.gather(*tasks)

# 合并结果,交叉验证
blocks = merge_blocks(results)
validate_blocks(blocks)

# 编译为 HTML
html = compile_lesson_html(node.name, blocks)
save_lesson_html(html, node_id)
return {"status": "ok", "blocks": blocks}

2.2 为什么并行优于串行?

一开始我试过”串行逐步构建”——先让 LLM 写大纲,再填充每个段落。问题有三:

问题 后果
上下文污染 前一步的错误会传染到后一步
重复内容 案例部分和概念部分可能写了同样的例子
成本高 N 步串行 = N 次推理,而且不能复用中间结果

并行提取器完美解决了前两个问题:每个提取器只看到知识点定义,看不到其他提取器的输出,天然解耦。而且全部 LLM 调用同时发出,延迟只等于最慢的那个,而不是累加。

2.3 从 blocks 到 HTML

提取器输出的是 ContentBlock 列表——一种结构化的中间表示:

1
2
3
4
5
6
@dataclass
class ContentBlock:
type: ContentBlockType # text / quiz / case_study / flash_card / ...
title: str
payload: dict
status: ContentBlockStatus

这层抽象的好处是:内容和渲染分离。同样的 blocks.json,可以编译成 HTML、Markdown、甚至飞书文档。我们目前用 compile_lesson_html() 转成带交互的 HTML 教案,支持折叠、高亮、动态加载题目。

3. 多角色评审 — AI 版的”集体备课”

内容生成只是第一步。真正让这套系统与众不同的是自动评审改进管线

我把真实学校的”集体备课”模式搬到了 AI 里——不是用一个 AI 审教案,而是用 5 个不同角色的 AI 评审者 同时审:

1
2
3
4
5
6
# 5 个评审角色
🎯 学科专家 — 内容准确性、知识点覆盖
📝 教学评审者 — 教学清晰度、阶段匹配
🧠 教育心理学家 — 认知负荷、学生吸引力
🛡️ 安全审查者 — 无敏感/有害内容
🎨 体验评审者 — 可读性、视觉质量

每个角色独立输出发现项(ReviewFinding),包含严重等级(P0 致命~P4 建议)和改进建议。

1
2
3
4
5
6
7
8
@dataclass
class ReviewFinding:
role: ReviewerRole
severity: Severity # P0 ~ P4
dimension: str
description: str
suggestion: str
target_block: int # 指向具体内容块

评审报告汇总后:

  • P0/P1 问题 → 触发自动改进(调用 LLM 修改 blocks.json → 重新编译 HTML → 重新评审)
  • P2/P3 问题 → 记录到改进日志,下次生成时参考
  • P4 建议 → 攒到一定数量后批量优化

核心原则是:不改 HTML,只改 blocks.json 再编译。这样永远不会破坏 HTML 结构。

4. 踩坑记录 — AI 老师也翻过车

4.1 LLM 的”知识幻觉”

第一个版本里,学科专家评审发现某些案例完全是 LLM 编的——教材里根本没有这个例子。解决方案:引入教材原文作为参考上下文(reference text),评审时让学科专家比对原文打分。但这样做增加了 token 消耗,目前只在 P0/P1 场景启用。

4.2 评审管线的过度纠正

有时候评审会提出互相矛盾的要求——教学评审者说”内容太浅”,教育心理学家说”信息密度太高”。改进引擎该如何取舍?

我的做法:按权重排序。学科专家的意见权重最高,教育心理学家次之,体验评审者最低。当意见冲突时,优先级高的角色说了算。

4.3 5 个并行提取器的协调成本

并行提取带来了内容冗余问题——概念提取器和案例提取器可能写了几乎一样的例子。解决方案是在 merge_blocks() 阶段做语义去重:计算每个 text block 的 embedding 相似度,超过 0.85 的只保留一个。

但说实话,这个问题还远没完美解决。目前用了简单的关键词去重,够用但不优雅。

5. 总结

这套架构能做什么

  • 输入:一个知识点(来自知识图谱的 JSON 节点)
  • 输出:结构化的 HTML 教案(含概念、案例、习题、误区、记忆卡片)
  • 质量保障:5 角色自动评审 + 自动改进循环
  • 扩展性:同样的 blocks 管线可以输出多种格式

最关键的三点经验

  1. 拆成独立提取器——每个 LLM 调用只专注一件事,质量远高于一个 prompt 包揽一切
  2. 中间表示(blocks.json)分离内容与渲染——改样式不改内容,改内容不改样式
  3. 多角色评审比单个 AI 评审有效得多——学科专家发现的知识错误,体验评审者永远看不到,反之亦然

相关资源


P.S. 这套系统目前每天自动生成 3-5 份教案,经过评审改进后,质量已经接近我手写的 80%。AI 老师不会取代人类老师——但 AI 教务主任,已经开始上班了。