1. 从“聊天”到“干活”:一个教育智能体项目的时间都去哪了
去年年底,我们几个做教育产品的朋友凑在一起,想做一个真正能帮学生解决学习问题的AI智能体。最初的设想特别简单:接个大模型,套一个对话界面,把教材内容喂进去,学生问什么它答什么,这不就完事了吗?按照这个思路,我们甚至乐观地觉得,两周就能出个能用的版本。
结果真正动手之后才发现,整个项目里最花时间的部分,跟“聊天”这件事本身几乎没什么关系。对话界面搭起来只用了两天,模型接入调通也就一个下午,但后面整整三个月,我们都在处理一些看起来“不智能”的事情:怎么把一份PDF教材拆成模型能理解的结构、怎么判断学生问的问题到底属于哪个知识点、怎么保证同一个问题在不同章节里给出的答案不打架、怎么在模型胡说八道的时候把它拉回来。
这篇文章不是要讲什么宏大的教育理念,也不是要吹嘘我们的智能体有多厉害。我想把这段经历里真正耗时间、真正踩坑的地方拆开来讲清楚。如果你也在做类似的教育类智能体,或者打算做一个垂直领域的对话应用,这些经验应该能帮你少走一些弯路。文章会涉及知识库构建、意图识别、答案一致性、幻觉抑制、评测体系这几个核心环节,每个环节我都会说明我们为什么这么做、具体怎么做的、以及实测下来哪些做法有效哪些是白费力气。
2. 知识库构建:把教材变成模型能“吃”的结构,比想象中难十倍
2.1 为什么不能直接把PDF丢给模型
我们最开始的做法非常粗暴:把教材PDF转成纯文本,按固定字数切块,每块加上向量索引,学生提问时检索最相似的几块拼进提示词里。这个方案在Demo阶段看起来能用,但一放到真实场景就崩了。
问题出在“固定字数切块”这个操作上。教材里的一个完整知识点,往往跨越好几个段落,中间还夹杂着公式、图表、例题。你按500字一刀切下去,很可能把一个定理的证明切成两半,前半段在块A,后半段在块B。学生问这个定理怎么证明,检索出来的块A只有前提没有结论,模型就只能靠猜,猜出来的答案自然错得离谱。
我们后来统计了一下,在最初的切块方案下,有将近四成的检索结果是不完整的。这意味着模型有40%的概率拿到的是残缺信息,它再聪明也变不出正确答案。
2.2 我们最终采用的分层切块策略
经过反复试验,我们改成了一套分层切块的方法。核心思路是:不要按字数切,要按知识结构切。
具体来说,我们先把教材按章节、小节、知识点三级拆解。每个知识点作为一个独立的检索单元,但这个单元里包含完整的信息:定义、公式、推导过程、例题、常见误区。如果某个知识点内容太长,超过模型上下文窗口的限制,我们再按语义段落做二次切分,但切分点必须落在段落边界,绝不从句子中间断开。
这里有个关键操作:我们在每个知识点的开头加了一段“摘要锚点”,用两三句话概括这个知识点讲的是什么。检索的时候先匹配锚点,命中之后再取完整内容。这样做的好处是检索精度大幅提升,因为锚点是高度浓缩的语义表示,比拿整段文本去算相似度要准得多。
实测数据:改用分层切块加摘要锚点之后,检索完整率从原来的61%提升到了94%,模型拿到残缺信息的概率降到了6%以下。
2.3 公式和图表的处理:最容易被忽略的坑
教材里大量的公式和图表,是另一个让人头疼的地方。纯文本转换会把公式变成一堆乱码,图表直接丢失。我们试过用OCR识别公式再转成LaTeX,但识别准确率只有七成左右,错误率太高,不敢直接用。
最后的方案是:公式和图表不参与文本检索,而是单独建一个“多媒体索引”。每个公式和图表都关联到它所属的知识点ID。当学生的问题涉及某个知识点时,系统会把该知识点下的公式和图表一并取出来,以结构化数据的形式传给模型,而不是让模型去“读”图片。
这个做法有个额外好处:模型不需要理解图片内容,只需要知道“这里有一个公式,它描述的是XX关系”,然后基于文本描述来组织答案。这样既避免了OCR错误,又保证了信息的完整性。
注意:如果你的教材里公式特别多,建议在项目初期就建立公式与知识点的关联关系,不要等到后期再补。后期补录的工作量是前期建立的五倍以上,而且容易漏。
3. 意图识别:学生问的到底是不是你以为的那个问题
3.1 同一个问题,十种问法
做教育智能体,绕不开的一个问题是:学生不会用标准术语提问。一个关于“一元二次方程求根公式”的问题,学生可能会问“那个求根公式是什么”、“方程怎么解”、“b方减4ac那个公式”、“二次方程怎么算根”,甚至直接拍一道题过来问“这个怎么做”。
我们最初的做法是纯靠向量检索,把学生问题向量化,去知识库里找最相似的。但实测下来,这种做法的准确率很不稳定。因为学生的口语化表达和教材的书面语之间,语义鸿沟比想象中大。向量模型能捕捉到“求根公式”和“二次方程”的关联,但很难区分“求根公式”和“判别式”这两个相邻但不同的知识点。
3.2 两级意图识别架构
我们后来改成了一套两级识别架构。第一级是粗分类,判断学生的问题属于哪个学科、哪个章节。这一级用的是一个轻量级的文本分类模型,输入是学生问题,输出是章节标签。这个模型是我们用教材目录和历年真题标题训练出来的,准确率能到92%左右。
第二级是细粒度的知识点匹配。在粗分类确定的章节范围内,再用向量检索去匹配具体的知识点。因为检索范围从整本教材缩小到了一个章节,候选集小了很多,精度自然就上去了。
这套架构的关键在于:第一级分类必须足够准,否则后面全错。我们为了保证第一级的准确率,专门做了一个“兜底策略”:如果分类模型对某个问题的置信度低于阈值,就不强行分类,而是把问题抛给一个更通用的检索流程,同时记录下这个case,后续人工review后补充到训练数据里。
3.3 多轮对话中的意图漂移问题
教育场景里,学生很少只问一个问题就结束。通常是连续追问:“这个公式怎么来的”、“那如果a等于0呢”、“有没有例题”。每一轮追问的意图,都依赖于上一轮的上下文。
我们踩过的坑是:早期版本每一轮都独立做意图识别,结果学生问“那如果a等于0呢”,系统识别成“一元一次方程”,因为“a等于0”这个表述在一元一次方程的语料里出现频率更高。但实际上学生是在追问上一轮的一元二次方程。
修复方案是在意图识别模块里加入对话历史。具体做法是把最近三轮的问答拼成一个上下文向量,和当前问题一起送进分类模型。这样模型能“看到”学生之前问了什么,从而正确理解当前问题的指向。
实测下来,加入对话历史后,多轮追问的意图识别准确率从74%提升到了89%。这个提升非常关键,因为多轮追问在教育场景里占比超过六成。
4. 答案一致性:同一个知识点,不能今天一个说法明天另一个
4.1 模型“自由发挥”带来的麻烦
大模型有个特点:同一个问题,换个问法,它可能给出不同的答案。这在闲聊场景里无所谓,但在教育场景里是致命的。学生今天问“勾股定理怎么证明”,模型给了一个证明方法;明天换个问法再问,模型给了另一个证明方法,而且两个方法里的符号约定还不一样。学生就懵了:到底哪个是对的?
我们做过一个测试:用同一个知识点的十个不同问法去问模型,统计答案的核心结论是否一致。结果一致性只有68%。这意味着有三分之一的概率,学生得到的答案和之前的不一样。
4.2 用“答案模板+模型填充”来锁定核心结论
我们的解决方案是:对于每个知识点,预先定义一个“答案骨架”。这个骨架规定了答案必须包含哪些部分:定义、公式、推导步骤、注意事项、例题。模型的任务不是自由生成整个答案,而是在骨架的约束下填充具体内容。
举个例子,对于“一元二次方程求根公式”这个知识点,骨架是这样的:
- 定义:只含一个未知数且未知数最高次数为2的方程
- 标准形式:ax² + bx + c = 0 (a≠0)
- 求根公式:x = [-b ± √(b²-4ac)] / (2a)
- 判别式:Δ = b²-4ac,Δ>0有两个不等实根,Δ=0有两个相等实根,Δ<0无实根
- 推导方法:配方法
- 常见误区:忘记讨论a≠0的情况
模型在生成答案时,必须按照这个骨架来组织内容。骨架里的核心公式和结论是硬编码的,模型不能修改,只能用自己的语言去解释和展开。这样一来,无论学生怎么问,答案的核心结论都是一致的。
4.3 符号和术语的统一
另一个容易被忽略的问题是符号和术语的统一。不同教材可能用不同的符号表示同一个概念,比如判别式有的用Δ,有的用D。如果模型在不同回答里混用,学生会困惑。
我们的做法是建立了一个“术语映射表”,把同一个概念的不同表述统一到一个标准术语上。模型在生成答案前,会先经过这个映射表做一次术语标准化。这个工作看起来琐碎,但对教育产品来说非常重要,因为学生很容易被不一致的表述搞晕。
提示:术语映射表建议在项目初期就建立,并且随着知识库的扩充持续维护。我们后来发现,术语不一致是学生反馈里排名前三的困惑来源。
5. 幻觉抑制:当模型开始“编造”知识点
5.1 教育场景对幻觉的容忍度是零
闲聊场景里,模型说错一句话,用户可能一笑而过。但在教育场景里,模型编造一个不存在的定理,或者给出一个错误的公式,学生信了,后果很严重。我们对幻觉的容忍度必须是零。
但现实是,大模型在遇到知识库覆盖不到的问题时,会倾向于“编造”一个看起来合理的答案,而不是承认自己不知道。我们内部管这个叫“自信地胡说八道”。
5.2 三层防御机制
我们最终搭建了三层防御机制来抑制幻觉。
第一层是检索置信度过滤。当学生的问题在知识库里检索不到足够相似的內容时,系统不直接让模型回答,而是返回一个“这个问题我暂时没有找到相关资料”的提示。这个阈值我们调了很多次,太低会导致大量问题被拒答,太高又会放过一些本该拒答的问题。最终定在相似度0.75,实测下来拒答率在8%左右,其中大部分确实是知识库没覆盖的内容。
第二层是答案溯源校验。模型生成答案后,系统会把答案里的关键结论和知识库里的原文做比对。如果某个结论在知识库里找不到支撑,就标记为“待审核”,不直接返回给学生。这个校验用的是文本蕴含模型,判断答案是否被知识库内容所蕴含。
第三层是人工抽检。我们每周会随机抽取一定比例的问答记录,人工检查答案的准确性。发现幻觉案例后,分析原因,如果是知识库缺失就补充知识库,如果是模型理解偏差就调整提示词或骨架。
5.3 一个真实的幻觉案例
有一次学生问“三角形内角和是多少”,模型回答“三角形内角和是180度,但在非欧几何中可能大于或小于180度”。这个答案本身没错,但超出了初中数学的范围,学生看不懂。更麻烦的是,模型还补充了一句“在球面几何中,三角形内角和大于180度”,这个结论是对的,但学生问的是初中几何,这个补充信息反而造成了困惑。
这个案例让我们意识到,幻觉不一定是“编造错误信息”,也可能是“提供了超出范围的信息”。对于教育产品来说,后者同样有害。我们后来在提示词里加了一条约束:答案的深度和范围必须与学生的学段匹配,不要引入超纲内容。
6. 评测体系:怎么知道智能体到底“教”得好不好
6.1 传统NLP指标在这里不够用
做对话系统,常用的评测指标是BLEU、ROUGE这些,衡量生成文本和参考答案的相似度。但在教育场景里,这些指标意义不大。因为同一个问题,可以有多种正确的解释方式,措辞不同但都对。用BLEU去衡量,反而会把一些措辞不同但内容正确的答案判为低分。
我们试过用人工评测,但成本太高,一天只能评几百条,根本跟不上迭代速度。
6.2 我们搭建的三维评测框架
后来我们设计了一套三维评测框架,分别从准确性、完整性、适龄性三个维度来评估。
准确性:答案的核心结论是否正确。这个用规则+模型结合的方式判断。规则部分检查关键公式和结论是否与知识库一致,模型部分判断语义是否等价。
完整性:答案是否覆盖了骨架里要求的所有部分。这个用骨架匹配的方式,检查答案里是否包含了定义、公式、推导、例题等必要模块。
适龄性:答案的深度和表述是否适合目标学段。这个用的是一个分类模型,判断答案的词汇难度和知识深度是否超出学段范围。
每个维度打分后,加权得到一个综合分。我们每周跑一次全量评测,跟踪综合分的变化。实测下来,这套评测框架和人工评测的相关性能到0.85左右,足够指导迭代方向了。
6.3 评测集的建设:比评测本身更重要
评测框架再好,没有好的评测集也是白搭。我们花了很大力气建设评测集,核心原则是:评测集必须覆盖真实场景里的各种问法。
具体做法是:从线上真实问答记录里采样,覆盖不同章节、不同难度、不同问法类型(直接问定义、问推导、问例题、追问、对比问等)。每个问题都由教研老师标注了标准答案和评分要点。目前评测集有2000多条,还在持续扩充。
经验:评测集不要一次性建完就放着不动。我们每个月都会从线上采样新的case补充进去,特别是那些模型表现不好的case。评测集越贴近真实场景,评测结果越有指导意义。
7. 一些零散但重要的实操心得
7.1 提示词工程不是写一次就完事
我们的提示词模板改了不下五十版。每一版都是针对具体问题做的调整。比如发现模型喜欢在答案开头加“这是一个很好的问题”,我们就在提示词里明确禁止;发现模型在解释公式时喜欢跳步,我们就在提示词里要求“每一步推导都必须写出依据”。
提示词维护是个持续工作,不是一劳永逸的。建议把提示词当成代码来管理,每次修改都记录原因和效果,方便回溯。
7.2 缓存策略能省不少钱
教育场景里,高频问题是集中的。同一个知识点,可能一天被问几百次。如果每次都走完整的检索+生成流程,成本很高。我们加了一层缓存:对于高频问题,直接返回缓存答案;对于低频问题,才走完整流程。缓存命中率大概在35%左右,省了将近四成的模型调用成本。
但缓存有个坑:知识库更新后,缓存必须失效。我们早期忘了这茬,结果知识库改了,缓存里还是旧答案,学生拿到的信息是过时的。后来加了一个缓存版本号机制,知识库每次更新,版本号加一,缓存自动失效。
7.3 日志记录要足够细
做智能体,日志是排查问题的生命线。我们记录了每一次问答的完整链路:学生原始问题、意图识别结果、检索到的知识点、模型输入提示词、模型原始输出、经过后处理后的最终答案、用户反馈。这些日志在排查问题时非常有用。
有一次学生反馈答案错误,我们查日志发现是检索环节匹配错了知识点,但模型基于错误的知识点给出了一个看起来合理的答案。如果没有详细日志,我们可能一直以为是模型的问题,实际上根因在检索。
7.4 用户反馈要主动收集
我们最初只在答案下面放了一个“有帮助/没帮助”的按钮,但点击率很低。后来改成在答案末尾加一句“如果这个回答没解决你的问题,可以点这里告诉我们哪里不对”,反馈率提升了好几倍。
收集到的反馈里,最有价值的是“答案不对”和“答案看不懂”这两类。前者帮我们发现知识库和检索的问题,后者帮我们优化答案的表述方式。
8. 如果重新来过,我会在哪些地方省下时间
回头看这三个月,有些时间花得值,有些确实走了弯路。如果重新做一个教育智能体,我会在几个地方调整优先级。
第一,知识库的结构化一定要在项目最开始就做。我们前期为了快速出Demo,用了粗糙的切块方案,后面返工重构花了大量时间。如果一开始就按知识点分层切块,能省下至少两周的返工时间。
第二,意图识别的对话历史一定要早加。我们是在多轮追问出问题之后才补上的,如果一开始就考虑多轮场景,能少踩很多坑。
第三,评测集的建设要和开发同步进行。我们前期只顾着开发,评测集是后期才补的,导致中间有一段时间不知道模型到底进步了还是退步了。如果开发的同时就积累评测集,迭代方向会清晰很多。
第四,幻觉抑制的阈值不要拍脑袋定。我们最开始凭感觉定了一个相似度阈值,结果要么拒答太多要么放过太多。后来基于真实数据做了统计分析,才找到合适的阈值。这个分析工作应该在定阈值之前就做。
教育智能体这个方向,技术上的挑战其实不在“聊天”本身,而在于怎么把教育场景的特殊性——知识的严谨性、学生的认知水平、教学的一致性——转化成工程上可落地的约束和流程。聊天界面只是冰山一角,水面下的知识库、意图识别、答案控制、评测体系才是真正决定产品能不能用的东西。我们踩过的这些坑,希望能给后来者一些参考。