开源AI家教实战:从教材解析到自动出题判分的完整链路
1. 一个反直觉的教育痛点读完了教材但一考就露馅我知道很多人已经对“AI 家教”这个词脱敏了。市面上的 AI 学习工具不是给你划重点就是帮你秒回作业题本质上还是“你问我答”的搜索引擎式体验。但看到这个开源项目时我还是愣了一下它不做解答反而把你丢过来的几百页教材全部读掉然后像老师一样反过来给你出题。不是那种“本文的中心思想是什么”的弱智题而是基于教材内容、有明确难度层次、能定位回原文的测试题。这个能力听起来很不起眼但它恰好戳中了学习里最容易被忽视的真相读懂教材和能做对题是两种完全不同的能力。前者是被动输入大脑很容易产生“我懂了”的错觉后者是主动提取逼你从记忆里把知识拽出来。认知科学里管这个叫“提取练习效应”说白了就是你越是在考试状态下回忆一个知识点你就越能长期记住它。很多自学的人缺的不是资料也不是时间而是一套会追着你提问、还能判断你答得对不对的机制。这个开源项目正是把“读教材”和“出题考人”这两件事打通了。我把它复现下来跑了一遍又用了不同领域的教材试了几轮今天把整个工作流、部署方案、翻车点都梳理出来希望给想做 AI 教育应用、或者单纯想给自己搞一个“AI 陪练”的人一点可落地的参考。先说它能干什么输入一份或几份 PDF/Markdown 教材项目会自动抽取章节结构、核心概念、定义和关系基于抽取出来的内容生成选择题、填空题、简答题覆盖不同难度在你回答之后它不会只给你一个“对/错”而是会对照教材原文告诉你错在哪、正确推导是什么整个过程可以完全跑在开源模型和开源组件上不需要把教材内容传到闭源商业产品里。它比直接用 ChatGPT 生成几道题的差异在于有一条完整的“教材解析 → 知识关联 → 出题 → 判分 → 反馈”流水线。这篇文章我会把这条流水线拆开讲重点讲每一步为什么必须这么做、不这么做会有什么问题。2. 开源项目里的“教材理解”链路是怎么拆解的我第一次跑这个项目时最想知道的一件事情是AI 到底怎么“读懂”一本教材它不可能真的像人一样从头到尾翻一遍然后总结中心思想但它可以做一套非常工程化的处理把非结构化的文本变成结构化的知识单元。这套处理链路大致分成四步。2.1 文档解析不是简单地把 PDF 里的字提出来大部分 PDF 教材的排版都非常复杂有分栏、页眉页脚、公式、图注、表格。如果直接用最简单的文本抽取工具抽出来的内容往往是乱的正文和页脚混在一起公式变成一堆乱码章节标题夹在段落中间。这个项目在处理时会先做版面分析把页面切成不同的区块区分标题、正文、表格、图注然后再按阅读顺序重组。我自己的经验是PDF 解析这一环的质量直接决定后面所有环节的上限。如果抽出来的文本是乱的再去分段、检索、出题后面的错误会被一层层放大。所以如果你要复现这类项目别在这一步省时间。开源工具可以组合使用PDF 转文本用 PyMuPDF 或 pdfplumber版面分析用 LayoutParser 这类模型辅助表格抽取用 PaddleOCR 的表格识别最终整出一份带层级标记的干净文本。这一步做完你应该得到类似这样一个结构第一章 机器学习基础 1.1 监督学习 定义... 核心概念训练集、测试集、标签、特征 ...这个结构化的文本是后面一切操作的原材料。很多 demo 跑起来效果稀烂第一步就错在原材料上。2.2 切块策略决定了 AI “读”得准不准拿到干净的教材文本之后不能整章扔给大模型。原因有两个一是上下文窗口装不下二是即便装下了大模型对超长文本中间部分的注意力权重也偏低。通俗点说就是“看是看了但没记住重点”。这个项目采用的方式是按语义层级切块。不是单纯按固定的几百字硬切而是优先保留章节标题、段落边界、列表结构等语义边界。每一块文本都会附带它的“位置上下文”比如它是 1.1 节下面的某个段落它的上一级主题是“监督学习”。这个做法非常关键因为检索的时候我们能不仅召回提到“过拟合”的那一段还能知道这段内容属于哪个章节、和哪些前置概念相关。切块大小也没有一个万能值。我测试的时候发现中文教材理论上切成 300 到 500 字左右比较平衡太长了检索时噪音多太短了语义不完整、出题时连题目都组织不起来。项目里一般会提供一个可配置参数建议拿到自己的教材后先抽样几页看看切出来的块是不是都能独立表达一个完整观点再决定参数要不要调。2.3 知识抽取从“说了什么”到“考什么”这是整个项目最核心的地方。只是把文本切块存起来AI 只能做“根据这段话回答问题”没法主动给你出题。要做到“反过来考你”系统必须先识别出这段文本里有哪些值得考的知识点。项目里通常会把切好的文本块交给大模型做一轮结构化的知识抽取。抽取内容包括核心概念及定义概念之间的关系比如“A 是 B 的一种”“C 由 D 和 E 组成”“F 导致 G”公式、定理、条件容易混淆的近似概念典型例子和反例。这一步的输出建议设计成 JSON方便后面直接用于出题。我对接了一套本地部署的模型抽取效果大致是定义类和关系类知识点抽得比较准但公式类经常抽成残缺文本后来我改了提示词要求把公式用 LaTeX 格式输出才明显改善。2.4 向量存储与检索出题前先“找到”相关教材内容知识抽取完成后这些知识点还需要被组织起来。项目采用两层存储结构一层是把切块后的文本做向量化存入向量数据库另一层是把抽取出的知识梳理成适合出题的素材。出题时系统先根据你当前正在学的章节或你输入的学习目标在向量库里做语义检索找到最相关的那几段教材原文然后再把原文和素材一起交给大模型生成题目。这里有一个容易被忽略的细节做向量化用的嵌入模型最好和教材的语言、领域匹配。通用嵌入模型对中文理科教材的语义区分能力不如专门在中文语料上微调过的模型。我实测用 bge-m3 这类中英双语模型就比纯英文模型效果好很多因为很多概念是中文近义词模型分不清就会召回完全无关的段落导致出的题“文不对题”。3. “反过来考你”背后的生成与判分设计如果说教材理解是让 AI 变成“读过书的人”那出题和判分就是让 AI 变成“会教书的老师”。这一步稍微做不好就会沦为一本正经地胡说八道。3.1 出题不是“换着法子给答案”而是要卡在知识点上我看过很多类似功能的 demo题目长得很像那么回事实际上一推敲全是废话“下面哪种方法可以防止过拟合A 数据增强 B 调节学习率 C 增加网络深度 D 以上都是”正确答案甚至能在另一段毫不相关的上下文里找到。这种题练得再多对学习也没有帮助。这个项目处理得比较好的点在于它给大模型的提示词里明确要求了“题目必须能由召回段落中的某个具体知识点直接推导出答案”。换句话说出题不是自由发挥而是有检索结果作为约束。它的提示词大概长这样你是这门课的出题老师。请根据下面的教材片段出一道题。 要求 1. 题目必须能由这段教材内容直接回答不能超纲 2. 选项要有迷惑性迷惑项要来自教材中容易混淆的概念 3. 标注题目考查的知识点 4. 给出正确答案和解析解析里必须引用教材原句。 教材片段 {context}把这段提示词跑了几轮之后我发现最难满足的是第二条“迷惑项要来自教材里的易混淆概念”。纯靠模型自己编的迷惑项往往一眼假因为那些错误选项跟教材没有任何关系。后来我手动检查了一轮输出发现一个规律当系统召回段落里恰好包含“XX 与 YY 的区别”这类对比性描述时生成的选项质量会明显上升。所以你越是想让 AI 出好题越要在前面的知识抽取环节把“易混淆概念对”这类关系提取出来把它作为出题的原料喂回去。3.2 判分是“看起来简单做起来翻车”的重灾区用户答完题之后怎么判断他对不对最简单的做法是对照标准答案做关键词匹配但这个方案几乎必挂。我试过一个很常见的情况问“什么是过拟合”标准答案是“模型在训练集上表现好在测试集上表现差”但用户答“模型把训练数据背下来了遇到新数据就不行了”意思对但用词不同关键词匹配会直接给零分。这个项目用的是“大模型当裁判”的判分方式把标准答案、教材原文片段、用户回答一起交给大模型让它从“知识点是否覆盖”“表述是否准确”“是否有关键错误”几个维度打分并生成反馈。判分提示词里最关键的一条是如果你不确定用户回答的对错就坦率说“无法判断”不要硬给结论。这条约束看起来是在降低系统的“自信”实际上是保护整个产品体验的底线。因为教育场景里一个错误但自信的判分比答不上来更可怕。用户如果被系统误判成错误会开始怀疑自己原本正确的理解如果被误判成正确又会把一个错误认知固化下来。AI 助教在这方面必须比真人老师更谨慎。我还试过把判分结果和前后文联动如果用户上一题答错了下一题就出同一知识点的变形题换个例子再考一次。这就是很多个性化学习产品讲的“错题再练”。这个项目提供了这样的扩展接口我后面会单独讲这个方向可以玩出什么花样。3.3 一套适合个人复刻的“双向”提示词模板整个交互逻辑是“学一段考一段”不是一次性导出一百道题让你刷。你可以把它理解成两个人之间的来回对话每一轮都包含三个步骤定位你当前的学习位置、生成一道针对性的题目、等你回答后判分。我整理了一套简化但能跑通的模板流程按顺序调用即可学习目标输入告诉系统你刚读到教材的 1.2 节主题是“线性回归的损失函数”相关段落召回从向量库中召回和“损失函数”最相关的 3 到 5 个文本块题目生成基于召回的文本块生成 1 道题难度可以指定“基础 / 进阶 / 综合”用户作答用户用自然语言给出答案判分与反馈调用判分模型返回“评分 正确解析 建议重新阅读教材的章节位置”。这套流程也是我在这篇文章里最想让你带走的可复用框架。它不依赖某个具体项目你完全可以用自己手上已有的开源组件拼出一个同款。4. 从零复现这套 AI 家教的本地部署方案既然是开源项目那就得聊怎么把它跑起来。我建议你至少具备 Docker 和 Python 的基础知识不需要会训练模型但得能看懂代码大概在做什么。4.1 整体技术选型哪些组件可以替换我复现的时候把技术栈拆成了五个模块每个模块都有开源替代品自由度很高模块我用的方案可替换方案说明PDF/文档解析PyMuPDF pdfplumberPaddleOCR、LayoutParser中文扫描版教材建议加 OCR文本切块自写按标题层级切分LangChain / LlamaIndex 的 splitter需要保留章节上下文嵌入模型BGE-M3本地text-embedding-3-small 类 API中文场景优先选双语模型向量数据库Chroma / FAISSMilvus、Qdrant教材规模小可用 Chroma对话/出题/判分模型Qwen2.5-14B-Instruct本地DeepSeek API、GLM 系列显存不够就调 API我选 Qwen2.5-14B-Instruct 的原因很简单中文能力够强指令跟随性好出题和判分这种结构化的任务它是拿手项。如果你只是自己玩7B 甚至 4B 也能跑但判分稳定性会下降容易出现“怎么问都对”或者“怎么问都错”的极端情况。4.2 搭建环境时最容易卡住的地方这里直接给一套我在项目复现时用过的可执行流程按照顺序走会少踩很多坑# 1. 创建 Python 虚拟环境 python -m venv .venv source .venv/bin/activate # 2. 安装核心依赖 pip install pymupdf pdfplumber chromadb bge-m3 sentence-transformers pip install vllm # 如果你有独显用 vLLM 跑模型 # 3. 准备模型镜像以 Qwen2.5-14B-Instruct 为例 # vLLM 会自动从 Hugging Face 或 ModelScope 拉取模型第一次跑通最耗时间的不是代码而是下载模型。几个 G 的权重文件网络不好能下一整天。建议提前设好HF_ENDPOINThttps://hf-mirror.com这类国内镜像环境变量可以省掉很多等待时间。显存方面我实际测过的配置如下14B 模型做推理至少需要 16GB 显存半精度加载大概是 14GB 左右24GB 会更舒服如果你的机器只有 8GB 显存就老老实实换 7B 模型或者直接用推理 APICPU 也可以跑14B 模型用 CPU 大概要等半分钟到一分钟才出一个回答出题这种长文本生成会拉到两分钟以上体验比较煎熬。4.3 一条最小可用的“教材导入”代码样例我不会把完整项目代码贴出来但可以给你一个能立刻跑起来的核心片段感受一下“读教材 → 存向量”这一步到底做了什么from pymupdf import open as pdf_open from bge_m3 import BGEM3Embedding import chromadb # 1. 解析 PDF 文本 doc pdf_open(机器学习教材.pdf) pages [] for page in doc: pages.append(page.get_text()) # 2. 简化切块这里只按页切实际建议按章节语义切 chunks [p.strip() for p in pages if len(p.strip()) 100] # 3. 向量化并入库 model BGEM3Embedding() client chromadb.PersistentClient(path./textbook_db) collection client.get_or_create_collection(textbook) embeddings model.encode(chunks)[dense_vecs] collection.add( ids[fchunk_{i} for i in range(len(chunks))], embeddingsembeddings, documentschunks, metadatas[{page: i 1} for i in range(len(chunks))] )这段代码跑完后你的教材就被切成了可以检索的记忆单元。后面出题前的“召回”操作就是在这个 collection 里查语义相似度最高的几个片段然后拼进提示词。5. 实测体验与踩坑记录哪些环节最容易被高估纸面逻辑说得再好也得拿真实教材去撞一撞。我用三份差异很大的教材做了测试一份中文机器学习教材、一份高中物理教辅、一份古典文学选读。结果有惊喜也有不少让我觉得“这个坑以后还会有人踩”的地方。5.1 三个典型翻车场景和应对办法第一个翻车场景是跨章节的考题几乎全军覆没。系统对单章节的知识点出题很稳但一旦我指定“考第三章和第四章的结合”它就会强行把两个不相关的概念捏在一起造出一道人类老师看了会皱眉的题。后来我发现原因是知识抽取阶段没有建模概念之间的跨章节关系两个章节的内容被切成不同的块出题时失去了把它们联系起来的依据。解决办法是引入知识图谱把同一个概念在不同章节的出现位置关联起来但这超出了最小复现范围所以最初版本的项目默认也没做太好。第二个场景是公式类题目输出常乱码。数学教材里的下标、上标、分数结构在 PDF 抽取时经常被拆碎。我明明看到的教材原文是“$E mc^2$”抽出来变成“E mc2”后面生成题目时也把公式写错。后来在解析阶段做了一层 LaTeX 识别把公式区域整体转成 LaTeX 文本情况才好转。如果你打算用 AI 家教来学理科这一关绕不开。第三个场景也是最隐蔽的判分器会“原谅”错误。我故意输入一个和标准答案含义相反的回答判分模型给了我 8 分满分 10理由是“基本意思正确”。我后来检查了判分的提示词发现它被要求“不要过于严苛”这个倾向导致它在模棱两可的时候倾向于给用户过高的分。对学习型产品来说这其实非常危险。我最后在判分提示词里加了一条硬规则只要用户回答的核心结论与教材明显冲突就算表述再流畅得分不能超过 3 分。加完再测违和感少了很多。5.2 别被“效果惊艳”的 demo 骗了失败样本比成功样本更有价值很多开源项目会在 README 里贴几个生成质量高的例子这很正常但容易造成一个错觉这东西全场景都稳。我的态度是测评一个 AI 学习工具不要只看它给出的好题要看它生成的低质量题目是什么样的。我在测试里专门收集了一批失败案例然后反推是哪一环出了问题。比如有一道物理题题干说“一个物体做匀加速直线运动初速度为零求第三秒末的速度”看起来正常但它给出的三个迷惑选项里有两个根本不符合物理常识随便一猜就能排除。问题出在召回阶段模型没有召回匀速直线运动的对比段落所以无法生成真正的区分项。这让我意识到出题质量的上限其实在检索环节就已经决定了。后面再怎么调提示词都只是在一定范围内修补。所以我建议你如果真的想把这个思路做成产品一定要把自己的测试集固定下来每个版本跑一遍统计“无效题目比例”和“判分错误比例”。这两个数字比任何 demo 截图都有说服力。5.3 单机部署的性能瓶颈跑起来之后才发现的资源黑洞我一开始以为最吃资源的是大模型生成题目跑起来之后才发现文档解析和向量化阶段的内存占用同样恐怖。一本 400 页的教材全部解析后放进 Chroma再加载嵌入模型内存直接吃掉了 12GB。再加上 14B 参数模型的显存占用普通 16GB 内存的笔记本基本跑不动。如果你预算有限我比较推荐一个“混合架构”本地跑文档解析、切块、向量检索出题和判分交给云端 API。这样本地只需要一个嵌入模型和向量库压力小很多教材内容是否适合传到外部 API 是你要自己权衡的事情。开源模型和 API 模型完全可以混用关键是每一环要能替换不要让某一个模块成为无法绕开的绑定。6. 顺着这个项目还能往哪个方向扩展跑通这套流程之后下一个自然的问题是除了“读教材、出考卷、判答案”还能在这个骨架上长出什么我自己尝试过两个方向一个相对成熟另一个还在探索中。第一个方向是把静态的题目列表升级成动态的学习路径。前面讲到的知识抽取已经把概念和概念之间的关系存下来了这些关系天然可以组织成一张图。你在图里标出哪些概念是前置知识、哪些是目标知识点AI 就能告诉你要先学哪几章再学哪几章。它已经在用知识图谱的思路做教育效果比单纯按章节顺序学要灵活得多尤其适合补差你哪块弱系统就从图里找到导致你弱的前置概念先补前置再回头学。第二个方向是把问答升级成苏格拉底式对话。不是直接告诉用户“你错了正确答案是……”而是像老师一样反问“你再想想如果学习率等于零梯度下降还会更新参数吗”这种引导式教学对模型的要求更高它得知道用户的知识盲区在哪里得控制信息暴露的节奏。我现在只在很小范围内做了实验效果不稳定但方向是对的。AI 家教如果只能出卷子它还是没有完全摆脱题库软件的影子真正的家教是能在你卡住的地方轻轻推你一把让你自己走到答案边上。这两个扩展方向都不是这个开源项目现成的功能但它的架构留了接口。我的建议是先玩熟基础流程再根据自己的使用场景去改提示词、改判分规则、改知识抽取模板。这类项目的魅力在于你不用从零训练模型所有核心组件都能拿到开源版本你只需要把教育场景里的“分寸感”设计好。最后分享一个我用这个项目时感触最深的小技巧把 AI 出的题当成一面镜子别把它当成权威。它有时候出的题很烂有时候判分很飘我最初产生过“还不如不用”的念头但后来我学会把它的题目拿来当“查漏补缺的线索”哪怕一道题出得不严谨只要它让我重新去翻了教材原文对我来说就已经赚到了。别人开源的是代码你真正要装进脑子里的是这套“被知识反刍”的学习方式。