作品集 | AI 编程教学平台 — 从 RAG 到 Agentic RAG 的全栈实战
项目概述
AI 编程教学平台 是一个面向高校 C 语言课程的智能教学辅助系统,由我独立完成全栈开发(后端 + 前端 + AI 集成 + 运维部署)。项目从 2025 年 9 月启动,持续迭代至今。
核心功能
| 模块 | 功能描述 |
|---|---|
| 作业批改 | 学生提交 C 代码 → AI 自动评分 + 错误分析 + 改进建议 |
| RAG 知识库 | 教师上传教学资料 → 智能分块 → 向量检索 → AI 精准答疑 |
| AI 对话 | SSE 流式对话,KaTeX 数学公式渲染,代码高亮 |
| 学情分析 | 成绩分布、知识掌握热力图、学生成长曲线、教案生成 |
| QQ 机器人 | OneBot 协议接入,作业截止提醒、成绩推送、群内 AI 答疑 |
| 班级管理 | 教师创建班级、邀请学生、发布作业任务、查看提交情况 |
架构总览
1 | ┌──────────────────────────────────────────────────────────┐ |
技术亮点详解
一、完整 RAG 检索链路(7 步管线)
这不是调包 Demo——从 Embedding 到精排全链路自研:
1 | 文档上传 → 智能分块 → 本地向量化 → pgvector 存储 |
1. 智能文档切割
- 自动识别 Markdown / 代码 / 对话 / 通用 4 种文档类型
- 按结构(标题层级、函数定义、对话轮次)+ 语义边界(余弦相似度 < 0.6 判定为主题切换)双重切割
- 滑动窗口 + 上下文引用保留语义连贯性
2. 本地 ONNX Embedding
- DJL 加载 bge-small-zh-v1.5,ONNX Runtime 纯 CPU 推理
- 384 维向量,单条 30ms,无 GPU 依赖、无外部 API 费用
- 多源镜像自动下载 + SHA-256 哈希降级保证模型高可用
3. pgvector 向量检索
- PostgreSQL 原生 pgvector 扩展 + IVF-Flat 索引加速近似最近邻搜索
- 支持用户级隔离(
WHERE user_id = ?),防止知识库越权
4. 双路召回 + RRF 融合
- 向量检索 + PostgreSQL
tsvector全文检索双路并行 - Reciprocal Rank Fusion 归一化:
score = Σ 1/(k+rank),k=60 - 比线性加权更稳定,不依赖不同检索路的绝对分数量纲
5. Cross-Encoder Reranker 精排
- 本地 ONNX 部署 bge-reranker-base,对 RRF Top-N 逐条精排
- Query-Document 联合编码,比 Bi-Encoder 更精准
- 单条 80ms,候选集控制在 20 条内,延迟可控
6. LLM Query 改写
- 短 query(<15 字)或包含指代词(”这个””上次那个”)时触发
- LLM 将口语化问题改写为检索友好的关键词
- 失败时降级为原始 query,不影响主流程
7. RagTrace 全链路可观测
- 每一步耗时、召回量、精排 Top-N 文档名和分数记录为结构化 JSON
- 数据模型对齐 RAGAS 评估标准(Context Precision / Context Recall),可无缝对接 LangFuse
二、MCP 工具协议实现
基于 Anthropic MCP (Model Context Protocol) 规范,自研工具注册与调用机制:
| 工具名 | 功能 | Agent 使用场景 |
|---|---|---|
queryClassStatus |
查询班级学习概况 | “C101 班学得怎么样?” |
queryHomeworkTasks |
查询作业任务列表 | “最近有什么作业?” |
queryStudentStats |
查询学生成绩 | “张三成绩怎么样?” |
searchKnowledge |
知识库语义检索 | “指针和数组有什么区别?” |
getCurrentTime |
获取当前时间 | “今天是几号?” |
LLM 自主决策何时调用哪个工具,工具返回结果后 LLM 基于实时数据生成回答,实现 Agentic RAG。
三、分布式系统基础设施
缓存穿透防护链
- Redis BloomFilter 预加载全量班级 ID(启动时加载,误判率 3%)
- Cache-Aside 模式 + Redisson 分布式锁控制 Miss 单源回源
- Caffeine 本地缓存 + Redis 远程缓存两级架构
Bucket4j 分布式令牌桶限流
- 基于 Redis 的接口级限流,AOP 切面无侵入
- 匿名/认证用户差异化策略,
/api/homework/submit单独 5次/分钟 - 令牌桶 vs 滑动窗口——突发流量友好,允许短时超发
Redis Stream 异步批改队列
- 学生提交 → 入库(PENDING) → 入队 → 秒回”已收到”
- 消费者异步调用 LLM 批改 → 写结果 → 状态流转为 COMPLETED
- 接口响应时间从 30~300s 优化到 200ms 以内
Java 21 Virtual Threads
- 启用
spring.threads.virtual.enabled=true - IO 密集型任务(LLM 调用、DB 查询、Redis 操作)吞吐量显著提升
- Tomcat 请求线程、
@Async方法、WebFlux 调度线程全部切换为虚拟线程
四、工程化实践
数据库
- Flyway 版本化迁移,SQL 脚本可追溯可回滚
- PostgreSQL + pgvector 向量索引 +
tsvector全文索引 - Schema 设计含完整字段注释(
COMMENT ON TABLE/COLUMN)
安全
- Spring Security + JWT 无状态认证
- 路由级权限控制(教师端/学生端分离)
- API 请求频率限制
前端
- Vue 3 + TypeScript + Element Plus + Pinia 状态管理
- KaTeX 数学公式实时渲染(支持 LaTeX 在线编辑)
- SSE 流式对话 + Markdown 渲染 + 代码高亮
- 路由守卫 + 登录拦截 + AI 回复中断确认
运维
- Docker 容器化部署
- JMeter 压力测试
- Swagger/Knife4j API 文档
踩坑与收获
1. LangChain4j 框架坑
从 Spring AI 叛逃到 LangChain4j 经历五连坑:
- Jackson 双版本冲突(
tools.jacksonvscom.fasterxml.jackson) - BOM 覆盖 Netty 版本导致 Spring Boot 4 不兼容
- API 大换血(
ChatLanguageModel→ChatModel) - JDK HttpClient 发 HTTP/2 Upgrade 头被 OpenClaw Gateway 拒绝
- 流式调用超时不稳定
最终方案:LangChain4j 只做 OpenAI 协议兼容的薄封装,核心逻辑(Tool Calling 循环、RAG 管线)全部自研,不依赖框架黑盒。
2. 知识库越权 Bug
RAG 检索无 user_id 过滤 → 私人知识库内容被学生搜到。修复方案:
document_chunk表加user_id列 + Flyway 迁移回填- 检索 SQL 加权限过滤条件
- 共享知识库与个人知识库独立隔离
3. QQ 机器人消息丢失
OpenClaw OneBot 插件每次处理消息时重载 → dispatcher 回调被销毁 → Agent 回复无法投递。定位到是插件加载时机问题,不是超时问题。
技术栈总结
| 分层 | 技术 |
|---|---|
| 后端框架 | Spring Boot 4.0.4 + Java 21 |
| ORM | MyBatis-Plus 3.5.15 |
| 数据库 | PostgreSQL 16 + pgvector + Flyway |
| 缓存 | Redis + Redisson + Caffeine |
| AI 框架 | LangChain4j 1.13.0 + DJL 0.28.0 + ONNX Runtime |
| AI 模型 | bge-small-zh-v1.5 (Embedding) + bge-reranker-base (Reranker) |
| 限流 | Bucket4j-Redis |
| 文档解析 | Apache Tika 2.9 |
| 前端 | Vue 3 + TypeScript + Element Plus + Pinia + KaTeX |
| 消息推送 | OneBot / Napcat QQ 机器人 |
| API 文档 | SpringDoc OpenAPI + Knife4j |
| 部署 | Docker |
| 测试 | JMeter |
项目链接
- 博客:www.lkl-zero.top
- 本作品集持续更新,欢迎交流讨论。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 LKL-ZREO!





