资讯动态

基于Neo4j与Qwen-Plus的智能出题与错题分析系统设计

发布时间:2026/8/31 11:04:34 来源:尧图企业网站定制
毕业设计里把“智能生成题目系统”做成一个真正调用了大模型接口的工程项目比只做一套题库增删改查更能体现综合能力。这里给出一个小型闭环方案用 Neo4j 维护知识点知识图谱通过 Qwen-Plus 大模型生成题目再结合答题记录做错题分析和薄弱点路径推荐。整套代码可以按本文结构复现既适合作为毕设核心功能也能改造成教学平台的自适应练习模块。先明确这条技术主线题目不是从数据库里随机抽取而是由知识图谱提供“当前要练哪个知识点、前置知识是什么”的状态再由大模型根据知识点和难度要求生成题目最后通过错题数据反向更新学生的薄弱知识点。相比传统题库系统这种设计把“出题”和“学情分析”打通了答辩时也更容易讲清楚为什么需要引入大模型和知识图谱。1. 为什么智能出题系统需要知识图谱和大模型配合1.1 传统题库出题方式的主要问题很多在线考试系统在做智能组卷时其实只是从题库里按题型、知识点、难度打乱抽取。这种方案在题目数量足够多时能跑通但存在几个明显问题题库是静态的新增题目完全依赖人工录入出题速度慢。题目和知识点之间往往只做简单关联无法表达“学完一阶导数才能学二阶导数”这类前置关系。错题分析只能统计“哪道题错了”很难定位到学生真正没掌握的知识点。推荐复习内容时没有依赖关系做支撑容易推荐学生还没有前置基础的题目。这些问题恰好是知识图谱和大模型擅长解决的。知识图谱负责表达知识点以及知识点之间的依赖关系大模型负责按需生成高质量题目。1.2 知识图谱在这里到底承担什么职责知识图谱本质上是“实体-关系-实体”的图结构。在题目生成场景里实体是“知识点”关系可以包括“前置要求”“属于同一章节”“常考组合”等。例如知识点A二元一次方程知识点B代入消元法关系B 的前置知识点包含 A当系统要给学生推荐“代入消元法”相关题目时先通过知识图谱检查该学生是否掌握前置知识点 A。如果未掌握系统就优先举一反三练习 A而不是直接出 B 的题目。这样一来出题逻辑就从“随机抽题”变成了“按学习路径出题”。1.3 大模型扮演的“出题员”角色Qwen-Plus 是一个可以接收文本指令并返回结构化内容的大语言模型。把知识图谱里查到的知识点、难度、题型和前置约束拼进 Prompt模型就能生成题目文本、选项、正确答案和解析。与人工出题相比模型出题速度快且可以每次生成不同变体适合构造大量练习数据。需要清醒认识的是大模型生成的题目不一定百分百正确。因此工程上不能只做“拿到结果就存库”必须加入答案校验、难度抽检和人工审核状态。这也是毕设系统里值得展开讲解的点。1.4 系统整体功能拆解围绕“智能生成题目系统”这个核心可以将完整功能拆成四个模块模块核心功能关键技术知识图谱模块知识点、题目、前置关系维护Neo4j、Cypher智能出题模块按学生状态和知识点生成题目Qwen-Plus API、Prompt 工程答题与错题模块记录答题结果、聚合错题知识点MySQL/JSON 存储、离线统计学情分析模块薄弱点定位、复习路径推荐图遍历、路径计算毕设可以围绕这四个模块展开也可以先做前三个模块跑通闭环再扩展第四个模块。2. 系统架构与核心工作流设计2.1 分层架构与模块划分为了后面好写文档和答辩建议把系统分成三层数据层Neo4j 保存知识图谱MySQL 或 SQLite 保存题目缓存、学生信息、答题记录、错题本。服务层负责知识图谱读写、调用大模型、题目存储、错题聚合、学习路径计算。展示层提供 REST API给前端或小程序端调用。这个分层的好处是大模型接口如果更换只要改动出题服务内部实现不影响知识图谱和错题模块。答辩时问“如何解耦”可以直接用这个回答。2.2 核心工作流一次完整的“生成练习”请求链路如下前端传入学生 ID 和知识点 ID。后端从 Neo4j 查询该知识点是否包含未掌握的前置知识点。如果没有前置未掌握项则携带知识点名称、难度、题型等参数调用 Qwen-Plus。大模型返回 JSON 格式题目内容。后端解析并做基础校验落库。学生提交答案后后端记录答题结果。错题模块根据错题关联的知识点在图谱里找出薄弱节点。分析模块生成复习路径下次出题优先选择路径中的知识点。这个流程把“缓存题目”“推荐题目”“错题本”串成一条线避免每个功能点各自独立。2.3 学习环境与生产环境的差异如果是学习或毕设阶段Neo4j 和数据库可以全部跑在本地API 调用使用开发环境的 Key。生产环境需要考虑代码外置配置、接口鉴权、日志采集、数据库备份和大模型费用控制。具体差异可以参考下面表格环境模型调用知识图谱配置管理异常处理学习/毕设每道题直接请求单机 Docker环境变量基础 try-except生产环境结果缓存、限量、熔断集群或备份库配置中心重试、告警、降级后面讲代码时我会先给学习环境能跑通的写法再指出生产环境需要补哪些能力。3. 用 Neo4j 构建知识点知识图谱3.1 先理解图数据模型在智能出题系统里最小规模的图模型可以这样设计节点类型KnowledgePoint知识点属性包括 name、subject、grade、difficulty。Question题目属性包括 content、type、answer、analysis。关系类型(KnowledgePoint)-[:REQUIRES]-(KnowledgePoint)表示某个知识点依赖另一个知识点作为前置知识。(Question)-[:TESTS]-(KnowledgePoint)表示题目考察某个知识点。先建这三类节点和两种关系已经足够支持“根据知识点出题”和“薄弱点回溯”。如果后续要扩展章节、教材版本再加入章节节点和“BELONGS_TO”关系。3.2 Neo4j 环境准备Neo4j 的使用方式有两种桌面版和 Docker 容器。毕设阶段推荐 Docker 方式环境统一且不会污染本机。docker run -d \ --name neo4j-demo \ -p 7474:7474 \ -p 7687:7687 \ -e NEO4J_AUTHneo4j/your_password \ neo4j:5.20.0启动后浏览器访问 http://localhost:7474使用 neo4j / your_password 登录。Python 连接 Neo4j 推荐使用官方驱动neo4j不需要额外使用 py2neo。pip install neo4j这里要注意py2neo 更新较慢新版本 Neo4j 兼容性不如官方驱动。直接使用neo4j驱动更稳。3.3 写入知识点和前置关系下面的代码演示如何建立知识点节点和 REQUIRES 关系。from neo4j import GraphDatabase class KnowledgeGraph: def __init__(self, uri, user, password): self.driver GraphDatabase.driver(uri, auth(user, password)) def close(self): self.driver.close() def create_knowledge_point(self, name, subject, grade, difficulty): cypher MERGE (kp:KnowledgePoint {name: $name}) SET kp.subject $subject, kp.grade $grade, kp.difficulty $difficulty RETURN kp with self.driver.session() as session: session.run(cypher, namename, subjectsubject, gradegrade, difficultydifficulty) def add_requires(self, kp_name, pre_kp_name): cypher MATCH (k:KnowledgePoint {name: $kp_name}) MATCH (p:KnowledgePoint {name: $pre_kp_name}) MERGE (k)-[:REQUIRES]-(p) with self.driver.session() as session: session.run(cypher, kp_namekp_name, pre_kp_namepre_kp_name) graph KnowledgeGraph(bolt://localhost:7687, neo4j, your_password) graph.create_knowledge_point(函数, 数学, 高一, 基础) graph.create_knowledge_point(函数单调性, 数学, 高一, 中等) graph.add_requires(函数单调性, 函数) graph.close()这里使用MERGE而不是CREATE是为了避免重复执行脚本时产生重复节点。add_requires同样使用MERGE让关系幂等。3.4 查询前置知识点和薄弱路径查询某个知识点的所有直接前置知识点def get_prerequisites(self, kp_name): cypher MATCH (k:KnowledgePoint {name: $kp_name})-[:REQUIRES]-(pre) RETURN pre.name AS name, pre.difficulty AS difficulty with self.driver.session() as session: result session.run(cypher, kp_namekp_name) return [{name: record[name], difficulty: record[difficulty]} for record in result]查询某个学生薄弱知识点到目标知识点的最短前置路径可以结合错题节点MATCH (target:KnowledgePoint {name: $target_name}) MATCH (weak:KnowledgePoint {name: $weak_name}) MATCH path shortestPath((weak)-[:REQUIRES*]-(target)) RETURN [node IN nodes(path) | node.name] AS path这里的思路是如果学生错了“函数单调性”这道题且之前“一次函数”也错过那么图谱里“一次函数 - 函数 - 函数单调性”的路径可能就是薄弱链条。复习时先补路径最前面的节点。4. 接通 Qwen-Plus 大模型实现智能出题4.1 接入方式和认证准备Qwen-Plus 可以通过 DashScope 提供的服务调用。在本地开发时建议把 API Key 放到环境变量里不要写死在代码中。export DASHSCOPE_API_KEYyour_api_keyPython 调用时可以使用 OpenAI SDK 兼容模式也可以直接使用 HTTP 请求。为了减少依赖这里使用requests调用兼容接口。pip install requests参考调用方式import os import json import requests API_KEY os.environ[DASHSCOPE_API_KEY] MODEL_NAME qwen-plus def generate_question(knowledge_point: str, question_type: str choice, difficulty: str 简单, num_questions: int 1): url https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions headers { Authorization: fBearer {API_KEY}, Content-Type: application/json } prompt build_prompt(knowledge_point, question_type, difficulty, num_questions) payload { model: MODEL_NAME, messages: [ {role: system, content: 你是教学题库编辑只输出 JSON。}, {role: user, content: prompt} ], temperature: 0.7, response_format: {type: json_object} } resp requests.post(url, headersheaders, datajson.dumps(payload), timeout60) resp.raise_for_status() data resp.json() content data[choices][0][message][content] return json.loads(content)这里使用了response_format指定 JSON 输出。需要注意的是大模型接口版本不同参数命名可能有差异落地前要查一下当前版本是否支持该字段。如果不支持也可以靠 Prompt 里的“只输出 JSON”来约束。4.2 Prompt 设计是出题质量的核心同样的接口不同 Prompt 得到的题目质量差别很大。推荐在 Prompt 里写清楚角色、任务、格式要求和示例。def build_prompt(knowledge_point, question_type, difficulty, num_questions): prompt f 你是一个严谨的学科教师。请围绕知识点“{knowledge_point}”生成 {num_questions} 道{question_type}题。 难度要求: {difficulty}。 题目要求: 1. 知识点覆盖准确不出现超纲内容。 2. {question_type}必须有四个选项。 3. 正确答案必须唯一。 4. 每题包含题目、选项、答案、解析。 输出 JSON 格式如下: {{ questions: [ {{ content: 题目文本, options: [A. ..., B. ..., C. ..., D. ...], answer: A, analysis: 解析文本 }} ] }} 只输出 JSON不要输出其他文字。 return prompt这里的核心技巧是“给模型一个固定的 JSON 骨架”。如果只告诉模型“输出题目”模型容易返回 Markdown 或额外解释解析时要写很多兼容逻辑。4.3 返回结果校验与落库即使是 JSON 格式模型也可能生成解析后缺字段、选项不是四项、答案不在选项范围等情况。因此解析后要加一层校验。def validate_question(item): if content not in item: return False, 缺少题目 if options not in item or len(item[options]) ! 4: return False, 选项必须为四个 if answer not in item or item[answer] not in [A, B, C, D]: return False, 答案格式错误 if analysis not in item: return False, 缺少解析 return True, ok通过校验的题目可以写入题目表。这里用 SQLite 做示例生产环境可替换为 MySQL。CREATE TABLE IF NOT EXISTS question_cache ( id INTEGER PRIMARY KEY AUTOINCREMENT, knowledge_point TEXT NOT NULL, question_type TEXT NOT NULL, content TEXT NOT NULL, options TEXT NOT NULL, answer TEXT NOT NULL, analysis TEXT NOT NULL, status TEXT DEFAULT pending, created_at DATETIME DEFAULT CURRENT_TIMESTAMP );status字段建议保留后续可以加人工审核流程。未经审核的题目不在正式考试中展示只用于练习场景。4.4 并发与超时处理大模型接口不是本地函数耗时几秒到几十秒都很正常。不能在后端接口里同步等待太久否则前端容易超时。常见做法有两种同步调用加长超时适合毕设演示前端请求设置 60 秒超时。异步任务把出题请求写入队列后端轮询结果。适合生产环境。另外批量出题时要控制并发调用数量。如果一次生成 10 道题可以循环请求接口但每道题之间加time.sleep(0.5)避免触发限流import time def batch_generate(knowledge_point, count5): questions [] for _ in range(count): item generate_question(knowledge_point, num_questions1) questions.extend(item[questions]) time.sleep(0.5) return questions这种方式打印日志时也能看清每个请求的耗时和状态便于排查。5. 从出题到错题分析闭环逻辑实现5.1 题目与知识点的关联落库大模型生成题目后只存题库还不够。出题时传入了知识点所以可以建立题目到知识点的关联。可以简单地在 question_cache 表里记录 knowledge_point也可以把关联关系写入 Neo4jMERGE (q:Question {id: $question_id}) MERGE (kp:KnowledgePoint {name: $knowledge_point}) MERGE (q)-[:TESTS]-(kp)这里question_id是题库表的主键。关联关系也可以直接用关系数据库实现但在展示“某个知识点下有哪些题、哪些题容易被答错”时图查询更直观。5.2 错题记录与薄弱知识点聚合学生答题后记录结果。推荐使用统一答题记录表CREATE TABLE IF NOT EXISTS answer_record ( id INTEGER PRIMARY KEY AUTOINCREMENT, student_id TEXT NOT NULL, question_id INTEGER NOT NULL, is_correct INTEGER NOT NULL, student_answer TEXT, answered_at DATETIME DEFAULT CURRENT_TIMESTAMP );当is_correct 0时该题进入错题本。错题模块要做的是按学生和知识点聚合错误次数def aggregate_weak_points(student_id): query SELECT q.knowledge_point, COUNT(*) AS wrong_count FROM answer_record r JOIN question_cache q ON r.question_id q.id WHERE r.student_id ? AND r.is_correct 0 GROUP BY q.knowledge_point ORDER BY wrong_count DESC # 假设使用 sqlite3 return cursor.execute(query, (student_id,)).fetchall()注意这里统计的是知识点而不是题目这样才不会因为某道题太难而被误解为知识点不会。5.3 基于图谱生成复习路径拿到薄弱知识点列表后系统要给出复习建议。简单做法是对每个薄弱知识点查询其前置知识点把前置中尚未掌握或错误率高的节点放在复习计划最前面。def build_review_path(weak_point): pre_list graph.get_prerequisites(weak_point) if not pre_list: return [weak_point] review_path [] for pre in pre_list: if pre[name] in weak_point_set: review_path.append(pre[name]) review_path.append(weak_point) return review_path如果学生薄弱点不止一个可以使用上文提到的shortestPath找到知识链最终返回一个按依赖顺序排列的知识点数组。前端拿到数组后逐个知识点出题练习就形成了闭环。5.4 分析结果展示思路展示层不需要过度复杂能画出两个维度就足够知识点掌握度柱状图按错误次数排序颜色区分薄弱程度。复习路径步骤条展示“一次函数 - 函数 - 函数单调性”这样的路径。如使用 Vue 或 React只需要请求/api/student/{id}/weak-points和/api/student/{id}/review-path返回 JSON 渲染即可。这个接口设计也可以写进毕设文档。6. 环境准备、项目结构与运行验证6.1 依赖清单与版本选择建议先整理一份最小依赖清单依赖用途建议版本neo4j连接 Neo4j5.xrequests调用模型接口2.31Flask / FastAPI提供 REST APIFlask 3.x 或 FastAPI 0.111sqlite3Python 内置不需要单独安装Neo4j 建议使用 5.x 系列因为官方驱动和文档都比较成熟。如果你的操作系统是 Windows 且不想用 Docker也可以下载 Neo4j Desktop但要注意 Java 版本要求。6.2 项目目录结构一个适合毕设展示的项目结构如下intelligent-question-system/ ├── app.py # Flask/FastAPI 入口 ├── config.py # 读取环境变量 ├── models/ │ ├── graph.py # Neo4j 操作类 │ └── question.py # 题目数据库操作 ├── services/ │ ├── generator.py # 大模型出题服务 │ ├── reviewer.py # 错题聚合服务 │ └── recommender.py # 复习路径推荐服务 ├── prompts/ │ └── question.json # Prompt 模板 ├── requirements.txt └── README.md这种划分不复杂但能体现分层思想。答辩时可以直接画包图。6.3 运行步骤环境准备完成后按顺序执行启动 Neo4j 容器。运行python init_graph.py初始化知识点。启动服务python app.py。请求出题接口。使用 FastAPI 的示例接口from fastapi import FastAPI from pydantic import BaseModel app FastAPI() class GenerateRequest(BaseModel): student_id: str knowledge_point: str difficulty: str 简单 question_type: str choice app.post(/api/questions/generate) def generate(req: GenerateRequest): pre graph.get_prerequisites(req.knowledge_point) # 简化为直接出题实际应结合学生掌握情况 result generate_question(req.knowledge_point, req.question_type, req.difficulty) save_question(result, req.knowledge_point) return {code: 0, data: result}启动 FastAPI 开发服务器uvicorn app:app --reload --host 0.0.0.0 --port 80006.4 验证方式和预期结果验证项可以写成自查清单[ ] Neo4j 中能查到已创建的知识点节点。[ ] 调用/api/questions/generate后返回 JSON 格式题目。[ ] 题目入库后question_cache表新增记录。[ ] 提交错误答案后aggregate_weak_points能统计出错误知识点。[ ]build_review_path返回路径包含前置知识点。预期返回的大模型出题结果示例{ questions: [ { content: 函数 yf(x) 在区间 [a,b] 上单调递增则下列正确的是, options: [ A. f(a) f(b), B. f(a) f(b), C. f(a) f(b), D. 无法判断 ], answer: A, analysis: 单调递增表示随 x 增大函数值增大因此 f(a) f(b)。 } ] }如果返回结果频繁出现奇数个选项、答案不在范围内就要检查 Prompt 和校验函数。7. 常见问题排查与避坑指南7.1 大模型返回 JSON 解析失败现象接口返回成功但json.loads(content)抛出异常。原因模型输出中可能带有多余的 Markdown 代码块例如 json 包裹或者模型截断了输出。排查方式打印原始content确认是完整 JSON 还是被截断。如果内容被截断调大max_tokens参数。如果内容带代码块做一个清洗函数去掉首尾的json。import re def extract_json(text): text text.strip() if text.startswith(): text re.sub(r^(?:json)?, , text) text re.sub(r$, , text) return text.strip()7.2 Neo4j 连接失败或 Cypher 语句执行异常现象执行graph.get_prerequisites时报连接拒绝或语法错误。原因容器未启动。端口映射错了bolt 端口应为 7687。驱动版本与 Neo4j 版本不匹配。属性名大小写写错例如name写成Name。排查方式检查容器状态docker ps。确认连接串是bolt://localhost:7687不是 http。在 Neo4j 浏览器里手动执行 Cypher先验证语句本身正确。7.3 知识图谱数据稀疏推荐结果不完整现象加了大量的知识点但路径计算经常查不到路径。原因REQUIRES 关系没有充分录入或录入时漏掉了中间节点。解决方案可以先从教材目录抽取两层关系。第一层是章节关系第二层是知识点前置关系。即使数据量不大只要把链条补完整就能跑通最短路径演示。不要一开始追求大而全。7.4 答辩容易被问的几个问题为什么不用传统随机抽题回答重点随机抽题无法处理知识点前置关系也没有能力动态生成新题。大模型生成错了怎么办回答重点设置了 JSON 校验、答案格式检查和人工审核状态正式考试场景可以关掉 AI 自动生成的题目。知识图谱为什么用 Neo4j 而不用 MySQL回答重点前置知识链需要多跳查询Neo4j 的遍历和shortestPath更自然且关系可以动态扩展。8. 最佳实践与扩展方向8.1 工程化落地清单如果要把这个系统从毕设演进成真正可用的教学工具至少要补这些能力能力说明题目审核流模型生成的题目先落pending状态人工审核后再可见用户权限学生、教师、管理员三种角色接口加鉴权结果缓存相同知识点和难度的生成结果缓存一段时间节省模型费用限流熔断使用 Redis 计数器或网关限流避免单个学生请求打爆 API日志追踪每次模型调用记录耗时、返回状态、失败原因数据扩展把题目难度和学生掌握度建模到图里后续可以做个性化推荐8.2 可复用的设计经验这个项目最值得记住的设计是“知识图谱决定学什么大模型负责生成练什么错题分析决定下次练什么”。三个环节可以独立替换。如果把 Qwen-Plus 换成其他模型只需要改generator.py的调用方式和 Prompt 模板。如果把 Neo4j 换成阿里云图数据库或别的图引擎只需替换graph.py内部实现。如果后续要做推荐系统可以在KnowledgePoint上增加“掌握度”属性用答题正确率动态更新。8.3 后续功能扩展方向在现有闭环上可以继续扩展自适应练习根据最近答题正确率动态调整下一题难度。试卷自动生成从知识图谱中选择一组覆盖多个知识点的题目组装成试卷。题目质量评估用同班同学的答题通过率评估题目难度是否合理。多学科支持把subject属性作为一级维度不同学科分别建模。对于毕设来说完成“知识图谱构建 - 大模型出题 - 错题分析”这条完整链路已经足够体现综合能力。剩下的扩展方向可以作为文档里的“未来展望”部分来写答辩时也更有余裕。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价