你在学一门课时有没有遇到过这种挫败感同一个问题向通用 AI 助手追问得到的回答总是“标准但不够对味”——它讲得没错却和你手里的教材、老师的强调重点、考试风格对不上。“Show HN: Learn Leap, an AI tutor that teaches from your own material”这个项目标题正好指出了一个被很多人忽略的方向AI 教育产品不一定需要“什么都知道”它更需要“围绕你提供的材料来教”。学习者把讲义、课件、笔记、错题本传上去AI 再基于这些私有资料回答问题、讲解概念、生成测验。这篇文章会拆解这个方向为什么值得关注并以一个最小可运行的“私有材料 AI 辅导原型”为例讲清楚背后的技术链路、实现步骤和上线前容易踩的坑。1. 这篇文章要真正解决的问题AI 教育缺少的是“私有材料”不是“模型”先看一个常见场景。同样是 Python 课的“参数传递”不同教材的讲法可能完全不同。有的教材说“引用传递”有的教材强调“对象引用本质上仍然是值传递”。如果学生去问通用大模型得到的往往是业界主流表达但未必和他所在课程的教材口径一致。考试时阅卷标准通常依据本课程的教材和方法论而不是某个大模型的“平均知识”。这种知识源上的不一致是通用 AI 助教无法成为“合格私教”的根本原因。所以一个真正可用的 AI 老师第一任务不是“显得更聪明”而是“先读学生指定的材料并只在材料语境内回答问题”。Learn Leap 这类产品的核心价值就在这里它把 AI 的“知识边界”刻意收窄收窄到用户上传的私有文档中从而保证讲解口径、案例风格、重点分布都与课程本身一致。但实现起来有一个现实约束大模型的上下文窗口是有限的学生不可能每次提问都把整本教材贴进去。过去有人尝试把资料全文复制进 Prompt几万字的材料很快就会撞上长度限制而且还会引入大量无关信息干扰模型输出。现在更通用的方案是 RAGRetrieval-Augmented Generation检索增强生成先把材料切片、向量化、建索引提问时只检索出最相关的若干片段再让大模型基于这些片段回答。于是AI 教育产品的竞争焦点发生了转移从“谁的模型更大、参数更多”转向“谁能更好地组织、检索、编排用户的私有材料”。这个判断是理解 Learn Leap 这类产品的一把钥匙。本文后面的内容都围绕这个转变展开。2. Learn Leap 的产品逻辑从“AI 问答”到“私有材料教学”从产品公开定位来看Learn Leap 解决的是“用你自己的材料来教学”。它的核心链路通常包括四个环节准备材料、建立知识库、交互式学习、评估反馈。第一步用户上传自己的学习资料。常见的输入包括 Markdown 笔记、PDF 讲义、Word 文档、课程 PPT、网页链接等。第二步系统把这些资料转成统一格式的纯文本做切片和向量化形成一份“私有知识库”。第三步学生向 AI 提问时系统先从知识库检索相关内容再让模型基于检索结果生成教学回答。第四步AI 可以根据材料生成测验题再根据学生的答题表现推荐下一步学习内容。这个流程听起来不复杂但每一步里面都有产品决策。例如“切片”看起来是纯技术细节实际直接影响教学效果切得太细模型缺乏上下文切得太粗检索准确率下降。“出题”看起来只是 Prompt 技巧但题目必须严格落在材料覆盖的知识点内否则又退化成通用题库失去了“基于学生自己的材料”的初衷。为了更直观地理解可以把“直接用 ChatGPT 学习”和“用私有材料 AI 教学”做一个对比对比维度直接用通用 AI 学习私有材料 AI 教学知识来源大模型训练时得到的通用知识用户上传的讲义、笔记、教材答案口径行业主流表达贴合具体课程的教材与讲师口径案例与例题随机生成风格不稳定可以按讲义中的例题风格出题生僻内容容易产生幻觉有出处可追溯可定位到切片使用成本零准备直接提问需要先整理并提供材料典型场景概念解释、发散讨论备考、课程复习、企业培训、错题巩固从使用场景看这类产品最适合的人有三类一是正在备考的学生他们希望 AI 的知识口径与自己的教材保持一致二是教师他们想快速把讲义变成可交互的“数字助教”用来制作辅导材料三是企业内部培训负责人他们需要新员工在知识问答中只接触公司标准文档而不是网上混杂的信息。相反它不适合“没有任何准备资料只想头脑风暴”的场合也不适合“需要了解最新学术前沿”的场景因为私有材料可能滞后。明确这些边界比只看功能列表更重要。3. AI Tutor 背后的关键技术RAG 与课程编排理解了产品逻辑接下来看技术实现。一个私有材料 AI 辅导系统通常由四部分构成文档解析、文本切片、向量检索、生成输出。如果要做成完整教学产品还需要第五部分教学编排与评估。文档解析是最容易被低估的一环。不同格式的解析难度完全不同纯文本和 Markdown 最简单直接读入即可PDF 和 Word 涉及版式、表格、图片处理起来坑很多。很多项目早期只支持 Markdown 和纯文本不是开发者懒而是这个选择能避开大量解析问题。对于 PDF可以用 pypdf、pdfplumber 这类库读取但如果是扫描版 PDF还需要 OCR成本会明显上升。一个务实的建议是优先让用户上传 Markdown、TXT、HTML 等易于解析的格式并在产品说明里引导用户转换文档。文本切片决定了检索的上限。常见的做法是按固定字符数切块比如每 800 字一块相邻块之间保留 100 字重叠。这样做的好处是实现简单坏处是可能切断一个完整知识点。更好的办法是先按段落分组再在段落组之间找边界尽量让每个切片在语义上完整。切片大小也需要权衡太小检索结果缺乏上下文语义太大多个知识点混在一起既浪费向量维度也容易让模型被无关信息干扰。向量检索是 RAG 的核心。系统把每个切片送入 Embedding 模型得到向量表示存入向量索引提问时把问题也转成向量通过余弦相似度找出最相似的几个切片。这里有一个常见误解向量检索并不一定优于关键词检索。对于代码、公式、专有名词混合检索往往更可靠。所谓混合检索是同时使用关键词检索BM25和向量检索再把两路结果合并排序。课程材料往往包含大量专有名词因此在教学场景中混合检索比单纯向量检索更稳妥。生成输出是整个链路中“最像 Prompt 工程”的部分但它的目标不只是生成通顺回答而是“忠实于给定材料”。通常做法是在 System Prompt 中要求模型优先依据参考材料回答如果材料不足必须明确承认而不是编造回答尽量给出材料里的事实和例子。此外把温度参数调低比如 0.2 到 0.3可以减少创造力让答案更稳定。再往上是教学编排层。这里要做的不只是“回答问题”还包括把一门课拆成知识点按顺序讲解根据学生答题情况动态选择下一题用间隔重复算法安排复习记录常见错题。这层已经超出纯 RAG 的范畴但它才是“AI 辅导”区别于“AI 问答机器人”的关键。Learn Leap 这类产品如果想做出深度最终一定会在编排层建立壁垒。4. 从零搭建一个最小可用的 Learn Leap 原型理解了概念我们来做一个可以跑起来的最小原型。这个原型不追求完整产品功能而是演示“上传自己的讲义 - 建索引 - 围绕材料问答”的核心链路。4.1 环境准备建议准备一个 Python 3.9 以上的环境安装两个核心依赖openai 用于调用 Embedding 和对话模型numpy 用于计算向量相似度。你也可以把 Embedding 模型换成本地开源模型或自建服务这里用 OpenAI SDK 做演示重点在流程而不是具体厂商。pip install openai numpy export OPENAI_API_KEY你的密钥注意不要把 API Key 硬编码进代码仓库。本机调试用环境变量是基本习惯生产环境应改用密钥管理服务。4.2 完整代码下面是一个单文件原型文件名为learn_leap_mini.py。它先读取一个 Markdown 或 TXT 讲义按段落切片生成向量索引然后进入命令行对话循环。每次提问时系统会检索最相关的切片并把它们作为参考资料交给大模型生成回答。# 文件路径learn_leap_mini.py Learn Leap Mini - 一个基于自有材料教学的 AI 辅导原型。 依赖 pip install openai numpy 环境变量 OPENAI_API_KEY 用法 python learn_leap_mini.py 你的讲义.md import os import re import sys from typing import List import numpy as np from openai import OpenAI client OpenAI(api_keyos.environ.get(OPENAI_API_KEY)) EMBED_MODEL text-embedding-3-small CHAT_MODEL gpt-4o-mini CHUNK_SIZE 800 TOP_K 5 SYSTEM_PROMPT 你是一位耐心的 AI 辅导老师。在回答学生问题时要严格遵守以下要求 1. 优先依据给定的参考资料讲解先给出直接答案再用材料中的概念解释原因。 2. 如果参考资料不足以回答请明确说“材料中没有覆盖这一点”再补充通用知识。 3. 回答要简明多用例子控制在 300 字以内。 4. 不要编造参考资料中不存在的公式、数据或结论。 def read_text(path: str) - str: with open(path, r, encodingutf-8) as f: return f.read() def split_into_chunks(text: str, chunk_size: int CHUNK_SIZE) - List[str]: paragraphs [p.strip() for p in re.split(r\n\s*\n, text) if p.strip()] chunks: List[str] [] buf for p in paragraphs: if len(buf) len(p) 1 chunk_size and buf: chunks.append(buf.strip()) buf p else: buf buf \n p if buf else p if buf.strip(): chunks.append(buf.strip()) return chunks def embed_texts(texts: List[str]) - List[List[float]]: resp client.embeddings.create(modelEMBED_MODEL, inputtexts) return [item.embedding for item in resp.data] def build_index(chunks: List[str]): return embed_texts(chunks) def retrieve(query: str, chunks: List[str], vectors) - List[str]: qvec embed_texts([query])[0] arr np.array(vectors) qarr np.array(qvec) # 归一化后计算余弦相似度 arr arr / np.linalg.norm(arr, axis1, keepdimsTrue) qarr qarr / (np.linalg.norm(qarr) 1e-10) scores arr qarr idxs np.argsort(scores)[::-1][:TOP_K] return [chunks[i] for i in idxs] def ask_tutor(question: str, context_chunks: List[str], history: List[dict]) - str: context \n\n---\n\n.join(context_chunks) messages [{role: system, content: SYSTEM_PROMPT}] history messages.append({ role: user, content: f参考资料\n{context}\n\n学生提问{question}, }) resp client.chat.completions.create( modelCHAT_MODEL, messagesmessages, temperature0.3, ) return resp.choices[0].message.content def main(path: str) - None: print(f[1/4] 读取讲义{path}) text read_text(path) print([2/4] 文本切片) chunks split_into_chunks(text) print(f共生成 {len(chunks)} 个切片) print([3/4] 构建向量索引) vectors build_index(chunks) print([4/4] 开始教学对话输入 exit 退出) history: List[dict] [] while True: question input(\n学生问题).strip() if question.lower() in {exit, quit}: break if not question: continue related retrieve(question, chunks, vectors) answer ask_tutor(question, related, history[-6:]) print(\nAI 老师, answer) history.append({role: user, content: question}) history.append({role: assistant, content: answer}) if __name__ __main__: if len(sys.argv) 2: print(用法python learn_leap_mini.py 讲义路径) sys.exit(1) main(sys.argv[1])4.3 代码拆解与关键逻辑read_text负责读取本地讲义。这个原型只支持 UTF-8 编码的文本或 Markdown 文件如果要支持 PDF 和 Word需要在这一步增加格式判断和对应解析库。split_into_chunks是切片函数。它先按空行把文本切成段落再把段落拼装成不超过 800 字的块。这里的思路是“优先保持段落完整其次控制长度”比纯按字符硬切更接近语义边界。课程材料里如果经常出现长代码块或长公式可以适当调大CHUNK_SIZE。embed_texts调用 Embedding 模型把文本转成向量。build_index返回所有切片的向量列表在生产项目中这一步会把向量和原始文本一起存入向量数据库。这个原型为了演示流程直接把向量保存在内存中代价是每次重启都要重新计算。遇到较大的讲义可以把向量序列化到本地文件或者使用 Redis 等缓存。retrieve是关键检索函数。它先把问题向量化再与所有切片向量做余弦相似度计算最后返回相似度最高的TOP_K个切片。代码中做了向量归一化归一化后点积等于余弦相似度省去手动计算。ask_tutor把检索到的切片拼接到 Prompt 中再调用对话模型。这里刻意把“参考资料”放在“学生提问”之前并设置了三个约束优先用材料回答、材料不足要承认、不得编造。temperature0.3是为了让回答更稳定。history 只保留最近 3 轮对话避免上下文无限膨胀。main串起整个流程。入口从命令行读取讲义路径然后依次完成读取、切片、建索引、交互问答。5. 运行与效果验证准备一份测试讲义比如一份名为操作系统讲义.md的文件里面写清楚“死锁”“进程调度”“虚拟内存”等几个知识点。然后运行python learn_leap_mini.py 操作系统讲义.md预期交互效果类似下面这样[1/4] 读取讲义操作系统讲义.md [2/4] 文本切片 共生成 12 个切片 [3/4] 构建向量索引 [4/4] 开始教学对话输入 exit 退出 学生问题什么是死锁 AI 老师死锁是指多个进程在并发执行过程中因互相等待对方占有的资源而无法继续推进的一种状态。 结合讲义来看死锁产生的四个必要条件是互斥、持有并等待、不可剥夺、循环等待...判断原型是否“学会了”你的材料不能只看回答是否通顺而要检查三点第一答案是否使用了材料中的表述。如果讲义里把某个概念定义为一种独特说法AI 的回答应该包含这个说法而不是换成通用的同义表达。第二如果问到一个材料没有覆盖的问题AI 是否明确说“材料中没有覆盖这一点”而不是硬编一个答案。第三当你追问“这个知识点在哪一章”时系统能否通过检索定位到具体切片。检索质量决定了这个系统是否可靠。如果运行失败第一步看 API Key 是否正确第二步看网络是否能访问模型服务第三步把 Embedding 和 Chat 模型的返回结果分别打印出来确认是哪一段出了问题。常见错误通常是模型名或请求参数写错其次才是网络问题。6. 常见问题与排查思路问题现象可能原因排查方向解决思路AI 回答明显偏离讲义检索到的切片不相关或不够先打印retrieve返回的切片内容调大TOP_K或改用混合检索BM25 向量回答经常说“材料中没有”切片过碎检索到的内容不足以回答问题查看切片数量与长度调大CHUNK_SIZE增加上下文内容模型仍然编造材料外内容Prompt 约束不够强检查系统提示词是否被覆盖强制要求模型引用原文并在输出模板中增加“来源切片”字段PDF 或 Word 解析乱码格式兼容问题查看解析后的纯文本是否正常优先转成 Markdown/TXT扫描版 PDF 需接入 OCR问答时上下文越聊越乱历史消息无限制增长查看请求体大小只保留最近几轮或对历史做摘要压缩API 费用增长过快每次问答都重复计算全部切片向量查看日志中的调用次数缓存 Embedding 结果改用批量索引构建上传材料包含敏感信息数据安全设计不足审查第三方服务的数据协议按最小权限原则控制访问敏感材料脱敏有条件时使用本地模型这几个问题里最值得重视的是第一个。因为 RAG 系统的上限由“检索质量”决定而不是由大模型决定。如果检索不到正确切片模型再强也没用。实际项目中建议在开发早期就给检索环节做“人工评测”准备 20 道基于材料的题目检查每题能否在 Top 5 切片中命中正确答案。这个步骤越早做后面越省心。7. 最佳实践与工程化建议如果你准备在真实项目里落地“私有材料 AI 教学”下面这些建议来自同类产品的常见实践值得在使用前先想清楚。先控制知识库规模。一门课一个知识库不要把所有材料都堆在一起。边界清晰的知识库不仅检索更准也方便做权限隔离。每门课再拆成“讲义”“题库”“错题本”等子库让不同类型数据的切片策略不同。讲义可以切得比较大错题本则应该每题独立。建立评估集是投入产出比最高的事。不要靠感觉判断一个 AI 助教好不好而是准备一组基于材料的“标准问题”每道问题标注期望答案来自哪一段材料。每次调整切片策略或 Prompt 后都跑一遍评估集记录命中率和回答质量。没有评估集的系统很难持续迭代。强制让 AI 给出“来源”。在 Prompt 中要求模型在回答后面标注“以上内容参考了讲义第 X 部分”或者直接让系统把检索到的切片编号追加到回答末尾。这样做有三重好处学生能回到原文核对老师能检查 AI 有没有讲偏产品团队能收集问题样本。教学编排要渐进式设计。不要一开始就要求 AI 自动生成整门课程而是先做一个“限定材料范围的口语问答助手”。跑通之后再增加知识点拆解、测验生成、错题复习。这不仅是产品迭代路线也是技术复杂度上升的路径问答只依赖 RAG测验需要更稳定的输出结构错题复习则要引入状态管理。安全与权限要提前设计。用户上传的材料可能包含未公开的课件、企业内部培训文档甚至个人笔记。必须明确告知用户数据会被如何使用、存储在哪里、何时删除。如果材料敏感优先考虑本地向量库加本地模型方案。模型服务调用时尽量在服务端转发而不是让客户端直接持有密钥。还要注意版权合规。用户上传的教材可能受版权保护产品不应把它们公开传播或用于训练模型。作为开发者要给用户提供下载和删除自己资料的入口并做好数据隔离。这一点既是法律要求也是建立用户信任的基础。最后是定位问题。让 AI 扮演“全天候助教”而不是“替代老师”。课程目标、教学大纲、重难点判断仍然要由人类教师设计AI 的价值是随时解答问题、批改练习、根据材料反复讲解。这个定位能避免产品面对过高的期望值也更容易设计出可落地的功能。8. 总结与下一步方向Learn Leap 这个名字本身已经说清了产品的核心让学生借助一个“跳跃”进入知识体系的辅助工具而不是让 AI 代替学生思考。从技术角度看这类产品没有使用什么神秘模型核心链路就是文档解析、文本切片、向量检索、生成回答再叠加教学编排。真正难的地方是如何让 AI 始终忠实于学生的私有材料并且根据学生的掌握情况动态调整讲解方式。本文给出的最小原型能帮你在一份讲义上跑通“私有材料问答”的完整链路。你可以用它作为起点先解决两个问题一是你自己的讲义是否适合切片和向量化二是当前 Prompt 能多大程度抑制幻觉。在此基础上下一步值得深入的方向包括引入混合检索提高生僻术语命中率给每个知识点附加测试题维护学生错题状态接入本地模型以支持敏感材料离线处理。如果下次再看到类似的 AI 教育产品你可以快速判断它是否解决了“私有材料和教学口径”这个问题如果只是接了一个通用模型又换了一层聊天界面那它的护城河还很浅如果它能把用户的上传材料变成真正可检索、可评估、可追踪的教学资源那才是值得持续投入的方向。接下来建议收藏这篇文章按第 4 节代码跑一次最小原型再结合你自己的课程材料做 20 道评估题。你很快就会感受到AI 教育从“会聊天”到“会教你的东西”之间到底差了多少步。