作品集 | AI 编程教学平台 — 从 RAG 到 Agentic RAG 的全栈实战
项目概述AI 编程教学平台 是一个面向高校 C 语言课程的智能教学辅助系统,由我独立完成全栈开发(后端 + 前端 + AI 集成 + 运维部署)。项目从 2025 年 9 月启动,持续迭代至今。 核心功能 模块 功能描述 作业批改 学生提交 C 代码 → AI 自动评分 + 错误分析 + 改进建议 RAG 知识库 教师上传教学资料 → 智能分块 → 向量检索 → AI 精准答疑 AI 对话 SSE 流式对话,KaTeX 数学公式渲染,代码高亮 学情分析 成绩分布、知识掌握热力图、学生成长曲线、教案生成 QQ 机器人 OneBot 协议接入,作业截止提醒、成绩推送、群内 AI 答疑 班级管理 教师创建班级、邀请学生、发布作业任务、查看提交情况 架构总览1234567891011121314151617181920┌──────────────────────────────────────────────────────────┐│ Vue 3 前端 (SPA) ││...
手写 Agent 循环到 LangChain4j:一场代码减半、能力翻倍的迁移
背景:710 行的「手工耿」AgentEduMind 项目的 Agent 层经历了三代: 代 实现 Agent 循环 工具调用 HTTP 客户端 状态 1 OpenClaw 网关 网关托管 网关路由 RestClient 已删除 2 AgentLoopServiceImpl 手写 while 循环 手动 JSON Schema RestClient/WebClient 本文主角 3 LangChain4jAgentService AiServices 内置 @Tool 注解 ChatModel 当前 第二代 AgentLoopServiceImpl 是一个 714 行的单体类,核心逻辑大概长这样: 123456789101112131415161718192021222324// 手写 Agent 循环(简化版)while (step < maxSteps) { step++; // ① 手写请求体(含手动构建的 tools JSON Schema) Map<String, Object> body ...
告别 OpenClaw:从 AI 网关依赖到自研 Agent 编排
背景EduMind 是一个 AI 驱动的智能教学平台,技术栈是 Spring Boot 4 + Vue 3,核心功能包括 RAG 知识库检索、作业批改、课堂实时互动和 QQ 机器人答疑。 从项目初期开始,所有 LLM 调用都经过 OpenClaw——一个开源的 AI Agent 框架(38 万 star,2026 年仍然极度活跃)。它负责:接收 QQ 消息、调用 MCP 工具、管理会话、路由 LLM 请求。 用了三个月后,我们决定把它从项目里彻底移除。这篇文章记录了为什么、怎么做、以及做完之后的架构变成了什么样。 为什么要移除 OpenClaw?1. 品类错配OpenClaw 是一个聊天机器人框架——它的核心价值是多频道消息(QQ/微信/Discord/Telegram)、Skill 插件系统、多 Agent 工作流。但 EduMind 只用了它最小的一块功能:作为一个 HTTP 代理把请求转发给 DeepSeek。 这就像租了一整层办公楼,只用了两间房,其中一间还漏水。 2. 问题积累三个月的使用中,OpenClaw 带来的问题逐渐超过了它提供的便...
实时课堂模块安全加固与 AI 教学材料生成——EduMind 暑期冲刺记录
一次针对 EduMind 实时课堂模块的集中攻关,横跨安全、性能、可靠性和 AI 生成能力四个维度,一天内完成 16 项修复与功能新增。 一、安全纵向加固:学生身份防冒用问题/api/live/join 是公开接口,学生自报学号就能拿到合法 JWT。WebSocket Handler 又直接信任消息体中的 studentId,导致学生 A 可以任意冒用学生 B 的身份答题、举手、提问。 方案:四层纵深防御 Join 入口验证 — 在 LiveSessionService.joinSession 中增加班级花名册校验:如果教师已导入学生名单,则不在名单内的学号拒绝加入 WebSocket Handler 覆盖身份 — InteractionHandler、ReactionHandler、QASessionHandler 全部改为从 STOMP Session Attributes(CONNECT 阶段 JWT 验证后存储)读取学生身份,忽略 payload 中的 studentId/studentName REST 端点修复 — markConfusion 从 JWT 提取身份...
课堂直播系统 × OneBot QQ 整合 + 备课学情仪表盘
概述本次迭代围绕课中互动 → 课后反馈 → 课前备课三个环节,打通了课堂直播系统与 OneBot QQ 机器人的消息推送,并新建了备课学情仪表盘与预习任务系统,形成”备课 → 上课 → 复盘”的完整闭环。 一、OneBot QQ × 课堂直播 整合已实现功能 功能 触发时机 推送方式 🔔 未答题提醒 互动关闭时(手动/倒计时) QQ 私聊未作答学生 + 群内汇总 📊 课堂总结 教师结束课堂 群消息(互动数/正确率/MVP/缺席名单)+ 私聊缺席学生 📢 开课通知 教师创建课堂 群消息(课堂码 + 加入方式) 📖 预习任务推送 教师发布预习任务 群消息(主题 + 知识点) 技术实现新建 LiveNotificationService,注入已有的 OneBotHttpService(调 NapCat HTTP API)和 StudentQqBindingMapper(学号 → QQ 号映射),在以下切面织入: 1234LiveSessionService.createSession() → notify...
EduMind 项目源码深度解析 —— 从 RAG 到 MCP 的全链路知识点复盘
前言这篇文章源自我在维护 EduMind(AI 教学平台)时的一次逐文件代码审查。一个下午,从 SecurityContextHolder 问到 Self-Attention,从 EmbeddingService 追问到 RerankerService。现在把沿途学到的知识点整理成一篇结构化复盘,方便自己复习,也方便其他接手这个项目的开发者快速建立全局理解。 本文按架构分层组织,而不是按文件顺序。 一、RAG 管线:从文本到检索结果的全过程这是整个项目最核心的模块,位于 edumind/.../rag/ 下。 1.1 管线全景1234567891011121314151617181920用户提问 → RagService.search() │ ├─ ① EmbeddingService.embedQuery() │ 文本 → Tokenizer 分词 → ONNX → Mean Pooling → L2 归一化 → float[512] │ ├...
RAG 底层探秘:从文本到向量的全过程——Embedding、Tokenizer、Reranker 与 Self-Attention 科普
引言:一个传统 Java 开发者的困惑最近在维护 EduMind 这个 AI 教学平台时,我盯着 EmbeddingService.java 和 OnnxEmbeddingTranslator.java 看了很久——里面没有一个方法是我在业务代码里显式调用的,但它们确实在跑。更让我好奇的是:为什么需要两个模型(Embedding + Reranker)先后处理同一批数据?”加几句话”为什么就能让排序变准? 这篇文章从我最困惑的几个问题出发,用尽可能通俗的方式讲清楚 RAG 检索管线里那几段”看不懂但又确实在跑”的代码。 如果你是一个传统后端开发者,对深度学习不太熟,这篇文章是写给你的。 一、EmbeddingService:看起来像下载器,实际上是个翻译官EmbeddingService.java 有 230 行代码,其中约 120 行在下载模型文件(model.onnx, tokenizer.json 等),看起来像个下载工具。但它的核心功能只有三个方法: 123float[] embedQuery(String query); // 把用户问题转成向量float[...
EduMind 生产级加固实录 — 从培训班项目到可上线水平
背景EduMind 是一个 AI 驱动的智能教学助手,技术栈是 Spring Boot 4 + Vue 3 + PostgreSQL + Redis。经过多轮功能迭代后,代码规模达到 170 个 Java 源文件、15 个 Vue 组件。 功能是完善的——但离”能正经上线”还有一段距离。最近做了一次全面的生产就绪度审计,从 6 个维度逐项定位差距,然后一次性补齐。 审计的 6 个维度:安全(C+)、可靠性(B)、CI/CD(C+)、可观测性(B-)、数据(D)、测试(D+)。总体评分 C+。 以下按改动的重要程度逐一记录。 一、全局异常处理 — 从用户看不懂到一眼定位改之前只有 5 个异常处理器。大部分异常落到兜底 catch(Exception) 返回: 1{"code": 500, "message": "系统错误"} 实际效果: JSON 少个引号 → 500 “系统错误” 缺少必填参数 → 500 “系统错误” 文件超过 50MB → 500 “系统错误” ?classId=a...
用单词喂养一只桌面猫——我把背单词做成了一款桌宠游戏
你有没有这样的困扰?打开背单词 APP → 刷 5 分钟 → 切到 B 站 → 两小时过去了。 不是你不努力,而是背单词这件事本身就缺乏正反馈。对勾 ✅、积分、排行榜——这些东西冷冰冰的,无法让人产生真正的牵挂。 如果,你的屏幕上住着一只需要用单词喂养的猫呢? 这不是一个背单词软件,而是一只需要你的猫CatPet 是一只住在你电脑桌面上的橘猫。她会饿、会开心、会撒娇、会生气。而你唯一能养活她的方式,就是——背单词。 1234567891011┌─────────────────────────────────┐│ 🐱 小橘 ││ ⭐ Lv.5 🪙 120 猫粮币 ││ 饱腹度 ██████░░░░ 62/100 ⚠️ ││ 心情 ████████░░ 78/100 ││ 经验值 ████░░░░░░ 45/100 ││ ││ "好饿... 喵~ 快喂我 😿" ...
从零到一:给 Spring Boot 项目装上可观测性三件套
前言:一次”盲飞”式排查前段时间给 EduMind(一个基于 Spring Boot 4 + Vue 3 的 AI 教学助手)做了一轮生产级差距审计。结果让我后背发凉——整个项目没有任何可观测性。 唯一和”监控”沾边的配置就一行: 1management.endpoints.web.exposure.include=health 没有指标、没有追踪、没有结构化日志、没有告警。出问题只能靠 docker compose logs 人肉翻,排查一次线上问题的时间够写三个 feature。 审计结束后,我花了半天补齐了这块。本文记录这个过程。 一、为什么可观测性不是”可选”很多开发者(包括以前的我)对可观测性的态度是:“等项目大了再说”。 但可观测性不是锦上添花,它解决三个你绕不开的问题: 问题 没有可观测性 有可观测性 用户说”好慢” 翻代码猜、改完祈祷、等用户反馈 Grafana 一看,p99 延迟在哪段一目了然 凌晨报警 你是报警系统——用户打电话/P0 issue Alertmanager → 钉钉,起床处理,其他时间安心睡觉 排查线上错误 d...






