RAG 在智能题库中的应用:相似题检索和难度评估方案
RAG 在智能题库中的应用相似题检索和难度评估方案一、搜一元二次方程结果返回了 3000 道题学生挑了最难的开始做在线教育平台最大的资源浪费之一题库里 20 万道题学生却找不到适合自己的那一道。关键词搜索二次函数能返回 3000 条结果但这些题目按照录入时间排序而不是按难度排序导致学生要么做了太简单的题浪费时间要么做了太难的题打击信心直接退出。理想的智能题库需要解决两个问题一是找相似题给定一道题找到与其考察知识点和解题思路相似的题目二是评估难度这道题对当前学生来说有多难。前者用向量检索后者需要结合题目属性、学生历史表现和 IRT项目反应理论来建模。二、相似题检索与难度评估的系统架构核心设计是向量检索 难度预测的双路协同核心公式推荐得分 相似度_score × 0.6 难度适配_score × 0.4。相似度保证找对题难度适配保证适合学生。两者权重可以通过 A/B 测试调优。三、Python 实现相似题检索 IRT 难度模型import numpy as np from typing import List, Dict, Tuple, Optional from dataclasses import dataclass from scipy.special import expit # sigmoid 函数 dataclass class Question: 题库中的题目 question_id: str text: str subject: str knowledge_ids: List[str] question_type: str # choice, fill, proof difficulty_param: float # IRT b 参数难度 discrimination: float # IRT a 参数区分度 guess_param: float 0.25 # IRT c 参数猜测概率 embedding: Optional[np.ndarray] None dataclass class StudentAbility: 学生能力估计 student_id: str theta: float # IRT 能力值 θ theta_std: float # 能力值标准差不确定性 n_questions: int # 已作答题目数 class IRTDifficultyModel: 基于 IRT 的难度评估模型 staticmethod def probability_correct( theta: float, question: Question ) - float: 3PL IRT 模型P(correct|θ) a, b, c ( question.discrimination, question.difficulty_param, question.guess_param, ) return c (1 - c) * expit(1.702 * a * (theta - b)) staticmethod def information( theta: float, question: Question ) - float: 题目信息量用于选择最优下一题 q_val 1.702 * question.discrimination p IRTDifficultyModel.probability_correct( theta, question ) return (q_val ** 2 * (p - question.guess_param) ** 2 * (1 - p) / (p * (1 - question.guess_param))) staticmethod def update_ability( student: StudentAbility, question: Question, correct: bool, ) - StudentAbility: 贝叶斯更新学生能力值简化 EAP 估计 prob IRTDifficultyModel.probability_correct( student.theta, question ) # 似然函数 × 先验简化版 if correct: likelihood prob else: likelihood 1 - prob # 梯度方向更新 learning_rate 0.1 / (1 0.01 * student.n_questions) gradient correct - prob new_theta student.theta learning_rate * gradient return StudentAbility( student_idstudent.student_id, thetanew_theta, theta_stdstudent.theta_std * 0.95, # 随数据增加降低不确定性 n_questionsstudent.n_questions 1, ) class SmartQuestionBank: 智能题库 def __init__(self): self.questions: Dict[str, Question] {} # 倒排索引知识点 - 题目 ID 列表 self.knowledge_index: Dict[str, List[str]] {} # 学生能力模型 self.students: Dict[str, StudentAbility] {} def add_question(self, q: Question): 添加题目到题库 self.questions[q.question_id] q for kid in q.knowledge_ids: self.knowledge_index.setdefault(kid, []).append( q.question_id ) def search_similar( self, query_embedding: np.ndarray, top_k: int 10, min_similarity: float 0.85, ) - List[Tuple[Question, float]]: 向量检索相似题 results [] for q in self.questions.values(): if q.embedding is None: continue sim np.dot(query_embedding, q.embedding) / ( np.linalg.norm(query_embedding) * np.linalg.norm(q.embedding) 1e-8 ) if sim min_similarity: results.append((q, float(sim))) results.sort(keylambda x: x[1], reverseTrue) return results[:top_k] def recommend_by_ability( self, student_id: str, target_knowledge_id: str, top_k: int 5, strategy: str i_plus_1, ) - List[Tuple[Question, float]]: 基于学生能力推荐题目 student self.students.get(student_id) if student is None: # 新学生默认中等能力 student StudentAbility( student_idstudent_id, theta0.0, theta_std1.0, n_questions0, ) self.students[student_id] student # 获取该知识点的所有题目 candidate_ids self.knowledge_index.get( target_knowledge_id, [] ) if not candidate_ids: return [] scored [] for qid in candidate_ids: q self.questions.get(qid) if q is None: continue # 难度适配分 if strategy i_plus_1: # i1 策略推荐略高于当前能力的题 difficulty_match 1.0 - abs( q.difficulty_param - (student.theta 0.5) ) / 3.0 else: # 最近发展区策略 difficulty_match 1.0 - abs( q.difficulty_param - student.theta ) / 3.0 # 信息量加权 info IRTDifficultyModel.information( student.theta, q ) final_score ( 0.4 * difficulty_match 0.3 * info 0.3 * q.discrimination ) scored.append((q, final_score)) scored.sort(keylambda x: x[1], reverseTrue) return scored[:top_k] def hybrid_recommend( self, student_id: str, query_text: str, query_embedding: np.ndarray, top_k: int 10, ) - List[Tuple[Question, float, str]]: 混合推荐相似度 能力匹配 # 1. 向量检索相似题 similar self.search_similar( query_embedding, top_ktop_k * 3 ) # 2. 能力匹配过滤 student self.students.get(student_id) if student is None: # 新学生只按相似度排序 return [(q, sim, similarity) for q, sim in similar[:top_k]] # 3. 综合评分 scored [] for q, sim in similar: ability_score 1.0 - abs( q.difficulty_param - student.theta ) / 3.0 final 0.6 * sim 0.4 * ability_score scored.append((q, final, hybrid)) scored.sort(keylambda x: x[1], reverseTrue) return scored[:top_k]四、边界分析与 Trade-offs向量检索的精度 vs 效率全库做余弦相似度计算在 20 万量级还能撑约 200ms到 100 万题量就需要向量数据库。Milvus 和 Qdrant 都能满足但部署维护成本不低。小规模题库用 FAISS 的 IVF 索引内存中是性价比最高的方案。IRT 模型的数据需求3PL IRT 模型要求每个题目至少有 100-200 次作答数据才能稳定估计 a、b、c 参数。新题没有足够数据时可以用题目属性题型、字数、知识点难度做回归估计初始参数然后用在线学习逐步修正。i1 策略的风险持续推荐略高于能力的题目如果学生连续做错挫败感累积。实践中需要设置错误容忍窗口——连续 3 次错误后策略自动切换为复习模式推荐学生已经掌握的知识点题目来恢复信心。Embedding 模型的领域适配通用 Sentence-BERT 在数学题 Embedding 上效果一般相似度区分度不够。如果能用题库本身的数据做对比学习微调SimCSE 方法Top-10 召回率可以从 72% 提升到 91%。微调需要 5 万对正负样本成本可控。五、总结智能题库的两个核心技术是向量检索找相似题和IRT 模型评估难度。前者保证检索相关性后者保证难度适配性。两者融合的策略权重0.6 : 0.4需要通过实验确定没有通用最优值。工程上需要注意向量检索的索引构建和增量更新、IRT 参数的冷启动估计、以及难度推荐策略的容错机制。最终目标是让学生感觉每道题都刚刚好——既不会太简单觉得无聊也不会太难想要放弃。

相关新闻

Python 学习行为分析:学生作答数据的特征工程与模型训练

Python 学习行为分析:学生作答数据的特征工程与模型训练

Python 学习行为分析:学生作答数据的特征工程与模型训练 一、平台存了 500 万条做题记录,却不知道学生为什么会放弃 一个在线教育平台每天产生几十万条学生作答记录——什么时候开始做题、答了哪道题、花了多少秒、是对是错、错了之后有没有看解析。这些…

2026/10/1 18:58:22 阅读更多 →
MSPM0微控制器SPI模块配置与DMA高效数据传输实战指南

MSPM0微控制器SPI模块配置与DMA高效数据传输实战指南

1. 项目概述与SPI核心价值 如果你在嵌入式开发中打过交道,尤其是用过像MSPM0这样的微控制器,那么对SPI(Serial Peripheral Interface)这个名字一定不会陌生。它就像电路板上的“高速公路”,负责在微控制器和各种传感器…

2026/10/1 18:57:58 阅读更多 →
找不到创新点怎么办?实用方法帮你快速梳理思路高效挖掘核心创新方向

找不到创新点怎么办?实用方法帮你快速梳理思路高效挖掘核心创新方向

对于科研人员来说,文献工作往往伴随着两个极端的痛苦:一是搜索时的大海捞针,为了几篇核心文献,不得不花费数小时翻阅成百上千条琐碎的摘要;二是阅读时的翻译折磨,在专业术语和复杂的 LaTeX 公式间反复推敲&…

2026/9/28 21:45:04 阅读更多 →

最新新闻

Python3数据类型转换避坑指南:字符串拼接、Decimal精度与pandas批量转换实战

Python3数据类型转换避坑指南:字符串拼接、Decimal精度与pandas批量转换实战

先讲一个我实际踩过的坑。某次项目里从数据库读出一批订单金额,代码里直接用total fee计算合计数,结果数据全部变成了字符串拼接,比如"199" "1" "1991",不是 200。查了半天才发现,数…

2026/10/1 19:03:58 阅读更多 →
WorkBuddy接入自定义MCP连接器:SSE长连接实战与排查指南

WorkBuddy接入自定义MCP连接器:SSE长连接实战与排查指南

1. 为什么要在 WorkBuddy 里接一个自定义 MCP 连接器WorkBuddy 这类 AI 工作台用久了,你会发现一个很现实的问题:内置能力再全,也覆盖不了你手头那些"私有工具链"。比如团队内部的设计素材库、自研的图片生成服务、某个只在公司内网…

2026/10/1 19:03:58 阅读更多 →
[光学原理与应用-651]:低频电磁波走电路介质,超高频电磁波走光学介质,所谓光电差异,只是频率跨越了多个数量级、换了一套传输介质,底层物理体系完全统一。

[光学原理与应用-651]:低频电磁波走电路介质,超高频电磁波走光学介质,所谓光电差异,只是频率跨越了多个数量级、换了一套传输介质,底层物理体系完全统一。

详解:低频电磁波走电路介质,超高频电磁波走光学介质核心观点:电信号与光信号都属于电磁波。二者之间的光电差异,本质并不是两套完全不一样的物理,主要是频率跨越十几个数量级,传输与调控介质发生切换&#…

2026/10/1 19:03:58 阅读更多 →
杭州前端工程师如何度过职业发展的瓶颈期?

杭州前端工程师如何度过职业发展的瓶颈期?

对于大多数Web前端工程师来说, 职业瓶颈这个问题几乎是每个人都会碰到的。但是每个人具体的情况不一样, 所以这个瓶颈会出现在不同的工作时期和具体的时间点上。针对这种情况, 比较推荐的处理办法就是主动离开自己那个习惯的区域, 打破原有的思考方式, 并且从提高自身的业务水平…

2026/10/1 19:03:58 阅读更多 →
Agent记忆系统实战:从存储选型到混合检索与安全防护

Agent记忆系统实战:从存储选型到混合检索与安全防护

做Agent开发的人,几乎都会在某个阶段被同一个问题卡住:系统越做越像一个“对话接口”,而不是一个有记忆、能成长的个体。用户上一轮刚说过“我现在搬到上海了”,下一轮问“我上次说的地址你记得吗”,Agent只能沉默——…

2026/10/1 19:03:58 阅读更多 →
Agent上生产:系统接入才是拦路虎,MCP与适配层实战复盘

Agent上生产:系统接入才是拦路虎,MCP与适配层实战复盘

这个项目上线那天,我们在会议室里等第一个真实工单。演示环境里模型表现得像个十年老员工,能总结、能推断、能把完整执行计划列得清清楚楚。但生产环境里,它要做的第一件事,是把 OA 里一张审批单读进来,再对着 ERP 里的…

2026/10/1 19:02:58 阅读更多 →

日新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/1 0:00:30 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/1 0:00:30 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/1 1:01:17 阅读更多 →

周新闻

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解 【免费下载链接】spirula-studio Cross-vendor 3D Gaussian Splatting trainer - video to splat to mesh, Vulkan or CUDA. 项目地址: https://gitcode.com/GitHub_Trending/sp/spirula-studio Sp…

2026/9/30 13:14:22 阅读更多 →
SEO怎么推广速查手册新手避坑实战指南

SEO怎么推广速查手册新手避坑实战指南

SEO怎么推广速查手册新手避坑实战指南 模板网站太丑不够用?别急着加滤镜,那是治标不治本。很多老板盯着后台流量掉得眼红,却还在纠结首页Banner的圆角是不是3像素。这就像穿着西装去挖土,姿势不对,努力白费。我整理这份 速查手册…

2026/9/30 18:13:06 阅读更多 →
FireRed-OpenStoryline少样本仿写深度解析:AI Agent如何复刻你的独特文案风格与节奏

FireRed-OpenStoryline少样本仿写深度解析:AI Agent如何复刻你的独特文案风格与节奏

FireRed-OpenStoryline少样本仿写深度解析:AI Agent如何复刻你的独特文案风格与节奏 【免费下载链接】FireRed-OpenStoryline FireRed-OpenStoryline is an AI video editing agent that transforms manual editing into intention-driven directing through natural language …

2026/9/30 13:14:49 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/1 0:00:30 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/1 0:00:30 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/1 1:01:17 阅读更多 →