☰
DeepTutor:基于大语言模型的启发式AI导师系统解析
2026/11/5 0:02:31 网站建设 项目流程

学习场景里一直有一个很现实的矛盾:学生在遇到难题时,既希望马上得到答案,又担心只是“抄了个答案”而没真正学会。而传统教育软件通常只有两种极端——要么是静态题库,要么是直接给解析文本。随着大语言模型(LLM)的能力逐渐成熟,越来越多团队开始尝试用 AI 做“启发式教学”:不让它直接告诉你结果,而是像老师一样不断提问、引导、纠正思路。今天要聊的DeepTutor,正是这一方向上一个值得关注的开源项目,它由 HKUDS 实验室(香港大学数据科学实验室)提出,聚焦于“深度思考型 AI 辅导系统”。

本文将围绕 DeepTutor 展开,先讲清楚它是什么、要解决什么问题,再拆解其核心设计思路,然后给出一个可运行的实战案例,最后补充部署、评测和工程化落地时容易踩的坑。无论你是做教育产品的后端工程师,还是对大模型智能体(Agent)感兴趣的算法工程师,这篇文章都能提供一个相对完整的参考。

1. DeepTutor 是什么:一个面向深度学习的 AI 辅导智能体

1.1 HKUDS 与 DeepTutor 的背景

HKUDS 是香港大学数据科学实验室的简称,主要研究方向包括大语言模型、数据挖掘、智能体系统等。实验室曾开源过多个在大模型应用层有一定影响力的项目。DeepTutor 是其中比较有代表性的一个教育场景项目,它的定位很简单:用大语言模型构建一个“会追问、会启发、会纠错”的 AI 导师。

传统的在线教育系统里,AI 助教最常见的能力是“学生提问,AI 直接给答案”。这种模式对信息检索效率有帮助,但对学习效果帮助有限。因为真正的学习过程需要学生主动思考、试错、反思。DeepTutor 的设计目标不是做一个“答案生成器”,而是做一个“思维引导器”:它更关注学生是怎么想的,而不是学生要什么结论。

1.2 DeepTutor 要解决的核心问题

我们可以把 DeepTutor 要解决的问题拆成三个层面:

第一层:如何不让 AI 直接泄露答案。
大模型默认行为是“尽量满足用户指令”,学生问“这道题怎么解”,模型往往会把完整解题过程写出来。DeepTutor 需要通过提示词和策略约束模型的输出行为,让它先问学生“你目前是怎么想的”“你卡在哪一步”,再逐步引导。

第二层:如何识别学生的错误思路。
学生给出的回答往往是含糊的,甚至带有错误假设。AI 导师需要从学生的话里抽取关键状态,判断他是在概念理解上出问题,还是在计算过程上出问题,然后针对性地反馈。

第三层:如何做到多轮引导而不是一次性灌输。
教学不是单轮问答。学生可能在一个问题上需要来回讨论七八轮。DeepTutor 需要在每一轮都能基于对话历史调整策略,既要记录学生已经掌握的部分,也要记住哪些点还没讲透。

1.3 与普通 AI 助手的区别

有的同学可能会问:这跟普通 ChatGPT 有什么区别?我完全可以自己写一段提示词:“不要直接告诉我答案,请引导我思考。”

区别在于:提示词只是单点策略,而 DeepTutor 是一套完整的对话状态管理方案。

单靠提示词能约束模型“今天别给答案”,但无法可靠地处理以下问题:

  • 如果学生连续答错,什么时候应该降低难度?
  • 如果学生表现出明显挫败感,要不要先给一点提示?
  • 如何判断学生是真的理解了,还是只是重复了 AI 刚才说过的话?
  • 如何把一次辅导过程沉淀成结构化的学习记录?

这些都需要在系统层面做设计,而不是靠一两句 prompt 就能解决。DeepTutor 的意义在于把“启发式教学”从一个灵感变成了一套可实现的工程方案,包括教学策略、对话管理、状态追踪和评估反馈等模块。

2. 环境准备与项目部署思路

2.1 建议的运行环境

在真正动手运行 DeepTutor 或同类项目之前,我们需要先把环境准备好。由于 DeepTutor 是基于大模型 API 的智能体应用,它本身对硬件要求不高,核心依赖是 Python 环境和一个可用的 LLM API。

建议环境如下:

项目建议配置说明
操作系统Linux / macOS / Windows(WSL2)推荐 Linux 服务器,部署更稳定
Python3.9 及以上大部分 LLM 项目已适配新版本
模型服务OpenAI 兼容 API 或本地部署模型需确认服务地址和密钥
依赖管理pip + venv / conda避免污染全局环境
代码仓库Git用于克隆项目源码

版本需要根据你的项目实际情况调整,本文示例以常见环境为例,重点演示配置思路。如果你的机器支持 CUDA 且显存足够,也可以考虑本地部署量化模型来替代远程 API,但这样会增加部署复杂度,建议新手先从 API 模式开始。

2.2 获取与部署开源项目

DeepTutor 以开源项目的形式发布,通常托管在 GitHub 上。获取代码的通用方式如下:

git clone https://github.com/HKUDS/DeepTutor.git cd DeepTutor

进入项目目录后,一般需要创建虚拟环境并安装依赖:

python -m venv venv source venv/bin/activate # Windows 下执行 venv\Scripts\activate pip install -r requirements.txt

这里需要提醒的是,不同项目的依赖文件命名可能不同,常见的有requirements.txt和pyproject.toml。如果你看到的是pyproject.toml,可以通过pip install -e .来安装项目本身及其依赖。

2.3 模型服务与密钥配置

大模型应用几乎都需要配置 API 密钥。无论 DeepTutor 内部封装得多好,最终都需要调用某个 LLM 服务。常见的配置方式是在项目根目录创建.env文件:

# 通用配置模板,具体字段以项目 README 为准 LLM_API_KEY=your-api-key LLM_BASE_URL=https://api.example.com/v1 LLM_MODEL=your-model-name

配置完成后,可以通过环境变量加载工具读取。例如 Python 中常用的python-dotenv:

from dotenv import load_dotenv import os load_dotenv() api_key = os.getenv("LLM_API_KEY") base_url = os.getenv("LLM_BASE_URL") model = os.getenv("LLM_MODEL")

一个常见的错误是:直接把 API 密钥硬编码在代码里,然后提交到 Git 仓库。这会导致密钥泄露,轻则产生额外费用,重则影响账号安全。正确做法是使用.env文件,并在.gitignore中把它忽略掉。

3. 核心原理拆解:如何让 AI 学会“启发式教学”

前面说过,DeepTutor 的价值在于把教学策略工程化。下面我们逐一拆解它的核心模块。这几块内容不仅适用于 DeepTutor 本身,也适用于任何想构建“AI 导师”类应用的开发者。

3.1 从“给答案”到“引导思考”:教学策略提示词

要让大模型不直接给答案,最基础的手段是提示词设计。但这里的提示词并不是简单写一句“别告诉我答案”,而是要给模型一套可执行的规则。

一个典型的“引导式教学”提示词可能长这样:

你是一名耐心的高中数学老师。你的目标不是帮学生直接解出题目,而是通过提问和提示,引导学生自己找到解题思路。 规则: 1. 当学生问你题目时,先不要给出答案,也不要展示完整解题过程。 2. 先询问学生对这道题的理解:“你读完题后,觉得题目在考察什么知识点?” 3. 根据学生的回答判断他的基础水平,再决定下一步引导的深度。 4. 如果学生卡住太久,可以给出一个小提示,但只给下一步思路,不给答案。 5. 如果学生给出正确答案,让他再解释一遍思路,确认他是否真的理解。

这里的关键点是:行为约束要具体,不能只给抽象指令。大模型对“启发式教学”的理解取决于训练数据,如果不做规则约束,它很容易退化成直接给答案。像上面第五点提到的“让学生复述思路”,就是很有效的防止“假装学会”的手段。

3.2 多轮对话状态管理

大模型的对话接口本身是无状态的——每次调用都是一次独立推理。为了让 AI 导师记住学生上一轮说了什么,需要在系统层面维护对话上下文。

最简单的方式是直接把完整历史拼接到 prompt 中,例如:

对话历史: 学生:这道题我不会做。 AI:你觉得这道题考的是什么知识点? 学生:可能是二次函数吧。 当前问题:请根据上面的对话,决定下一步怎么引导。

这种方式实现简单,但存在两个问题:

一是 token 消耗会随对话轮次线性增长。对话越长,每次请求的输入 token 就越多,费用和延迟都会上升。

二是上下文过长会稀释模型注意力。模型可能忘记早期的信息,或者对最新指令的遵循度下降。

更工程化的做法是把对话历史整理成结构化的“会话状态”,只保留关键信息。例如:

{ "student_id": "stu_1001", "topic": "二次函数", "difficulty_level": 3, "key_questions": [ { "question": "求函数 y = x^2 - 4x + 3 的顶点坐标", "student_answer": "不会", "hint_given": true, "status": "in_progress" } ], "known_points": ["能识别二次函数的一般形式"], "weak_points": ["不会配方", "不确定顶点公式"] }

每次对话结束后,从模型输出中抽取结构化信息,更新这个状态对象。下一轮调用时,把状态摘要和用户最新输入一起传给模型。这比单纯拼接历史更可控,也更节省 token。

3.3 个性化与学生画像

每位学生的基础不同。同样是“二次函数”这个知识点,有的学生是没记住顶点坐标公式,有的是前面一元二次方程没学扎实。AI 导师如果能记录学生的知识薄弱点,就可以更有针对性地出题和引导。

具体实现上,可以在会话状态里维护一张“知识掌握情况表”:

{ "mastery_map": { "一元一次方程": "mastered", "配方法": "learning", "二次函数图像": "not_started" } }

当学生触发某个知识点时,AI 根据当前的掌握等级调整互动策略。例如mastered状态可以快速跳过,learning状态需要多给提示,not_started状态需要先补基础概念。这个思路跟很多人熟悉的“自适应学习系统”一脉相承,只不过 DeepTutor 的做法是利用大模型来动态判定学生掌握度,而不是依赖预设题库。

3.4 评估与反馈闭环

没有评估的教学是不完整的。DeepTutor 作为 AI 导师,也需要回答一个核心问题:这次辅导到底有没有效果?

常规做法是,在辅导结束后让 AI 生成一份结构化总结:

{ "session_score": 0.78, "num_questions": 5, "num_correct_first_try": 2, "main_difficulty": "配方步骤不熟练", "suggested_next_topics": ["二次函数图像平移", "二次函数最值问题"] }

这份总结既可以展示给学生,也可以沉淀到学习档案中,供老师或系统做后续学习路径规划。评估指标不必追求复杂,重点在于“是否能反映学生的真实状态变化”。如果想做更精细的评估,可以引入人工标注样本,对 AI 生成的总结做定期抽检。

4. 实战:搭建一个 DeepTutor 风格的辅导对话服务

接下来我们进入实战环节。这里我不直接贴 DeepTutor 官方仓库的完整代码,而是带大家手动搭建一个“DeepTutor 风格”的最小实现。这样做的目的是帮助你理解核心链路——当你回头再去看官方源码时,会轻松很多。

4.1 项目结构

先规划一下项目文件结构:

tutor-demo/ ├── main.py ├── prompts.py ├── tutor_state.py ├── requirements.txt └── .env

用一个简单的模块划分来模拟 DeepTutor 的关键模块:prompts.py负责提示词定义,tutor_state.py负责对话状态管理,main.py负责主流程。

4.2 定义教学角色提示词

先创建prompts.py:

SYSTEM_PROMPT = """你是一位专注于启发式教学的 AI 导师。 你的目标是帮助学生自己找到解题思路,而不是直接给出答案。 教学策略: 1. 当学生提问时,先询问他的思考过程,例如“你目前是怎么想的?” 2. 当学生给出部分正确的回答时,先肯定正确部分,再指出不足。 3. 当你需要提示时,请使用提问的方式给出“下一步思路”,不要直接给完整过程。 4. 如果学生连续三次答错,可以适当降低问题难度,换一个更基础的例子。 5. 如果学生最终得出正确答案,请他用自己的话解释一遍过程。 始终使用中文回复。 """

这段提示词定义了 AI 导师的基本人设和行为规则。它没有绑定具体学科,可以通用于数学、物理、编程等多种学习场景。如果你希望限定在某个学科,可以在提示词中追加学科要求。

4.3 对话管理核心逻辑

接下来创建tutor_state.py:

import json class TutorState: """保存一次辅导会话的核心状态""" def __init__(self, student_id: str, topic: str): self.student_id = student_id self.topic = topic self.wrong_count = 0 self.correct_count = 0 self.history = [] self.weak_points = [] def add_exchange(self, student_msg: str, tutor_msg: str): self.history.append({ "student": student_msg, "tutor": tutor_msg }) def record_wrong(self): self.wrong_count += 1 def reset_wrong_count(self): self.wrong_count = 0 def to_summary(self) -> str: """将状态摘要成文本,供模型继续推理时使用""" return json.dumps({ "student_id": self.student_id, "topic": self.topic, "wrong_count": self.wrong_count, "correct_count": self.correct_count, "recent_history": self.history[-4:], "weak_points": self.weak_points }, ensure_ascii=False)

这个类负责记录:

  • 学生连续答错的次数(用于触发降难度策略)。
  • 最近几轮对话内容(用于上下文拼接)。
  • 已经识别出的薄弱点。

这里的关键设计是:不要把全量历史都传给模型,保留最近几轮即可。这样既节省 token,又能维持模型对对话语境的把握。

4.4 主流程:调用大模型实现引导式对话

现在编写main.py,这是整个示例的核心:

from openai import OpenAI from prompts import SYSTEM_PROMPT from tutor_state import TutorState def create_client(): """根据环境变量创建 OpenAI 兼容客户端""" import os from dotenv import load_dotenv load_dotenv() return OpenAI( api_key=os.getenv("LLM_API_KEY"), base_url=os.getenv("LLM_BASE_URL") ) def tutor_once(client, state: TutorState, student_input: str) -> str: """ 调用大模型进行一次辅导交互。 返回 AI 导师的回复文本。 """ # 将系统提示词、状态摘要、学生输入拼成消息列表 messages = [ {"role": "system", "content": SYSTEM_PROMPT}, {"role": "system", "content": f"当前会话状态:{state.to_summary()}"}, {"role": "user", "content": student_input} ] resp = client.chat.completions.create( model=os.getenv("LLM_MODEL"), messages=messages, temperature=0.4 ) return resp.choices[0].message.content if __name__ == "__main__": client = create_client() state = TutorState(student_id="demo_001", topic="二次函数") print("AI 导师已就绪。输入题目开始学习,输入 exit 退出。") while True: student_input = input("\n学生: ") if student_input.lower() == "exit": break reply = tutor_once(client, state, student_input) print(f"\nAI 导师: {reply}") # 简单模拟:这里把模型回复存进历史,方便下一轮引用 state.add_exchange(student_input, reply)

这里的消息组织方式值得注意:我们用了两个system消息。第一个定义 AI 导师的全局人设,第二个提供当前会话状态。在大部分 OpenAI 兼容接口中,多个 system 消息会被合并处理,这种方式可以避免把状态摘要直接拼进用户问题里,语义上更清晰。

4.5 运行与效果验证

在项目目录下先安装依赖:

pip install openai python-dotenv

然后确认.env文件中已经配置好:

LLM_API_KEY=你的密钥 LLM_BASE_URL=你的模型服务地址 LLM_MODEL=你的模型名称

运行:

python main.py

我在这里给出一个简化但真实感很强的交互演示:

学生: 二次函数 y = x^2 - 4x + 3 的顶点坐标怎么求? AI 导师: 你之前学过配方法吗?如果学过,可以先试着把 x^2 - 4x + 3 配成完全平方的形式。你觉得应该怎么配? 学生: 是不是 x^2 - 4x + 4 - 1? AI 导师: 没错,你已经做对了一部分!x^2 - 4x + 4 可以写成 (x - 2)^2,那么原来的式子应该写成什么形式?还剩下什么需要处理呢?

你可以看到,AI 导师并没有直接说出“顶点坐标是 (2, -1)”,而是沿着学生的思路一步步往下引。如果学生答错,state 中的wrong_count会累积,达到阈值后,可以在后续的 prompt 中要求模型降低难度。这就是一个最简单的“策略动态调整”雏形。

4.6 给示例增加策略控制

上面的代码还没有真正用到record_wrong和reset_wrong_count。一个更完善的版本应该在解析学生回答后,根据内容做简单判断并更新状态。我们可以这样增强:

def judge_and_update(state: TutorState, student_input: str, tutor_reply: str): """ 基于简单的规则判断学生上一轮回答是否正确。 生产环境可改用模型自动判断。 """ # 这里只是示例:包含“不对”“不会”“不知道”时视为回答不理想 negative_markers = ["不对", "不会", "不知道", "不懂", "没思路"] if any(marker in student_input for marker in negative_markers): state.record_wrong() print(f" [状态更新] 连续答错次数: {state.wrong_count}") if state.wrong_count >= 3: # 达到阈值后,向模型追加一条降难度提示 state.weak_points.append("需要降低难度") else: state.reset_wrong_count()

这里的判断逻辑虽然简单,但它展示了策略引擎的核心思想:AI 的回复质量取决于我们是否能让状态参与决策。生产系统中,你可以用更复杂的方式判断学生状态,比如让模型输出结构化 JSON,再解析到 state 对象中。

5. 常见问题与排查思路

在实际部署和二次开发 DeepTutor 或类似项目时,大家会遇到不少问题。这里梳理几个高频场景:

问题现象常见原因解决思路
调用 API 报 401 错误API 密钥配置错误或 .env 未加载检查 .env 文件和 load_dotenv 顺序
模型总是直接给答案提示词约束不足增加具体规则,采用 few-shot 示例强化约束
对话几轮后效果变差历史消息过长,模型注意力被稀释只传最近 3-5 轮;或用状态摘要替代原始历史
运行时报缺少依赖requirements.txt 版本不匹配按项目文档指定版本,避免大版本升级
高并发时延迟明显多次串行调用大模型引入缓存、异步并发、批量处理
学生回答判断不准字符串规则太简单改用模型结构化输出,让模型返回状态标签

5.1 模型总是直接给答案怎么办

这是 DeepTutor 类应用最容易遇到的问题。仅仅在 system prompt 里写“不要直接给答案”往往不够,因为大模型对负向指令的遵循不如正向指令稳定。

更有效的做法是:

提供负面示例(few-shot)。在提示词中给模型一个“错误示范”和“正确示范”,模型会更容易模仿正确行为。例如:

错误示范: 学生:这道题怎么做? AI:先用公式 x = -b/(2a) 求出顶点横坐标,然后代入得到纵坐标,答案是 (2, -1)。 正确示范: 学生:这道题怎么做? AI:你以前见过“顶点式”这个概念吗?如果 y = x^2 - 4x + 3,你觉得有没有办法把它变得更容易看出顶点?

增加后置检查。在主流程中接一个判断模型输出是否包含“答案句”的过滤器。如果检测到模型直接给出了完整答案,可以通过二次调用要求它改成提问式引导。这相当于给 AI 导师增加了一层“审核机制”。

5.2 状态管理导致越跑越偏怎么办

我在前面的示例中提到了“状态摘要”方案。有些同学照着实现后会发现,模型生成的反馈跟实际情况有点脱节。比如状态里写着“学生连续答错 3 次”,但 AI 导师的回复还是在讲很难的内容。

这种情况通常是因为状态信息在 prompt 中的权重不够高。可以尝试:

  1. 将状态摘要放到user消息开头,而不是system消息。
  2. 明确要求模型“必须根据当前会话状态调整回应方式”。
  3. 在状态摘要中删除无关字段,只保留与当前决策相关的字段。

5.3 如何评估 AI 导师的水平

评估 AI 导师不是简单测“准确率”,因为启发式对话没有唯一标准答案。常用的思路是用一套“教学行为检查单”来做人工评测:

  • 是否在连续 3 条回复中都没有直接给出完整答案?
  • 是否在给出提示前先询问了学生的思路?
  • 当学生答错时,是否给出了针对性反馈而不是泛泛重讲?
  • 是否在最后确认了学生的理解?

这套检查单可以作为打分表,也可以让另一个更强的模型来打分。评估体系建议尽早建立,否则很难判断提示词改动到底是变好还是变差。

6. 工程化与教育场景落地建议

如果产品已经过了 demo 阶段,准备在生产环境落地,那么下面这些方向值得提前规划。

6.1 提示词版本管理

DeepTutor 的核心能力高度依赖提示词。不同版本的提示词可能导致完全不同的教学风格。因此,提示词应该像代码一样纳入版本管理,并记录每次改动的效果对比。

常见的做法是:

  • 将每个版本的提示词单独命名,例如math_tutor_v3。
  • 在评估系统中记录使用该版本时的会话质量分数。
  • 采用灰度发布策略:先让 10% 的用户用新提示词版本,对比效果后再全量推送。

6.2 内容安全与未成年人保护

教育场景往往面向未成年人,内容安全是最高优先级。这里要特别强调几个边界:

第一,AI 导师不得输出与学习无关的敏感内容。即使学生故意问一些与学科无关的话题,AI 导师也应该礼貌拒绝并引导回学习主题。这可以通过提示词约束,也可以在外层加内容过滤服务。

第二,AI 导师不应给出医疗、心理、法律等专业建议。学生可能趁机倾诉心事,AI 不能越界充当心理咨询师。常规做法是在系统提示词中明确职责边界,必要时输出固定话术:“如果你感到不舒服,建议告诉家长或老师。”

第三,数据隐私保护。学生的对话数据应加密存储,访问权限要遵循最小权限原则。尤其是未成年人数据,上线前务必完成合规评估。

6.3 性能优化思路

DeepTutor 类的应用本质上是一个“多轮交互系统”,性能瓶颈主要在 LLM 推理。优化手段包括:

  • 结果缓存:对高频知识点问题,可以缓存 AI 导师的引导步骤,学生多次提问时不必每次都调用模型。
  • 异步接口:将辅导过程拆分为“接收用户输入 -> 异步生成回复 -> 前端轮询结果”,避免用户长时间等待 HTTP 响应。
  • 小模型前置路由:先用一个轻量模型判断用户的意图和知识点分类,再让大模型做深度辅导,可以一定程度上降低成本。

6.4 从原型到生产的完整链路

演示项目可以只关注“对话质量”,但生产环境还需要考虑:

学生提问 -> 内容安全检查 -> 知识点识别 -> AI 导师对话 -> 对话记录落库 -> 会话总结生成 -> 学习效果评估

每一步都要有日志、监控和异常处理。尤其是 AI 导师的回复,如果出现模型超时、输出格式异常、内容不合规等情况,要有兜底策略。简单场景下,可以在异常时返回“老师暂时走神了,请重新说一遍”,并把错误信息记录到日志中。

7. 总结与下一步学习方向

通过本文的梳理,我们可以看到 DeepTutor 并不是一个简单的“大模型套壳”项目,而是一个把教育学策略和 LLM 能力结合起来的智能体系统。它的核心贡献在于提出了“AI 导师应该如何引导学生思考”这一套可工程化的交互范式,包括教学策略提示词、会话状态管理、学生画像追踪、学习效果评估等模块。

我在实战部分搭建的 demo 虽然简化了很多细节,但已经覆盖了 DeepTutor 风格应用的主干链路。你可以在此基础上继续做这样几件事:

  1. 把字符串规则升级为模型判断:让模型输出结构化 JSON,自动更新学生状态,实现更精确的答题正误判断。
  2. 接入学科知识库:在学生与 AI 导师对话时,利用 RAG(检索增强生成)从教材、题库中检索相关内容作为参考,避免模型胡编乱造。
  3. 尝试接入不同的基座模型:不同模型对“启发式教学”提示词的遵循能力差异很大,值得做一个横向测评。
  4. 完善前端交互:将命令行 Demo 改造成 Web 界面,增加学生答题提交、过程记录展示、学习报告导出等功能。

教育场景的 AI 应用有一个天然优势:反馈链路短且明确——学生到底有没有学会,很快就能通过测验体现。这给算法迭代提供了很好的依据。DeepTutor 的方向给教育智能体的发展提供了一个很务实的样本,如果你也在做类似的学习产品,建议直接 clone 一份源码看看,从提示词设计开始逐步改造,会比自己从零搭一套要快很多。希望这篇文章能帮你少走一些弯路。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询