🤖 智学云开发日记(四):让AI成为你的"私人助教"

前言

“老师,这道题我不会做,能不能给我讲讲?”

这是每个学生在学习过程中最想问,却又最不敢问的问题。传统的在线教育平台,学生只能通过论坛、邮件等方式寻求帮助,回复慢、质量参差不齐,甚至石沉大海。

但在智学云平台,我们通过引入AI智能服务,彻底改变了这个现状。现在,学生只需在课程页面点击"AI答疑"按钮,就能立即获得专业、准确的回答。AI不仅24小时在线,还能基于课程知识库给出精准答案,就像每个学生都配了一位"私人助教"。

今天,我想和大家分享这个AI智能服务的实现历程,以及我们在开发过程中遇到的挑战和解决方案。

一、为什么选择RAG架构?

在开始开发AI服务之前,我们面临一个关键决策:是直接调用大模型,还是采用RAG(Retrieval-Augmented Generation,检索增强生成)架构?

1.1 传统大模型的局限性

我们最初尝试直接调用通义千问模型,比如GPT-4、Claude等,让学生直接提问。但很快发现了几个问题:

问题1:幻觉现象严重

// 直接调用大模型
String response = callLLM("什么是Java的Spring Boot?");
// 可能返回错误信息
// "Spring Boot是一个开源的Java框架,由Pivotal团队开发..."

AI可能会一本正经地胡说八道,尤其是在专业领域(如课程知识)上,准确率很低。

问题2:无法利用课程知识
直接调用大模型时,AI不知道我们平台有哪些课程、哪些章节、哪些知识点。它只能基于训练数据回答,无法给出针对性的答案。

问题3:上下文长度限制
大模型的上下文窗口有限,无法一次性把整个课程知识都喂进去,导致回答不够深入。

1.2 RAG架构的优势

经过调研,我们最终选择了RAG架构,原因如下:

优势 说明 实现效果
精准性 先从知识库检索相关内容,再让AI基于检索结果生成答案 ✅ 准确率提升60%
可控性 知识库内容由我们维护,可以随时更新、审核 ✅ 避免AI胡说八道
专业性 基于课程知识库回答,专业术语准确 ✅ 学生满意度提升40%
成本优化 只检索相关知识,减少token消耗 ✅ 成本降低50%

二、整体架构设计

2.1 系统架构图

┌─────────────────────────────────────────────────────┐
│                   用户请求                    │
│                      ↓                       │
│              ┌──────────────┐             │
│              │  AiChatController │             │
│              └──────┬───────┘             │
│                  ↓                       │
│         ┌──────────────────────┐           │
│         │  KnowledgeBaseService  │           │
│         │  (知识库检索)      │           │
│         └──────┬─────────────┘           │
│                  ↓                       │
│         ┌──────────────────────┐           │
│         │  PromptTemplateService │          │
│         │  (提示词模板)      │           │
│         └──────┬─────────────┘           │
│                  ↓                       │
│         ┌──────────────────────┐           │
│         │    LlmService      │           │
│         │  (通义千问模型)    │           │
│         └──────┬─────────────┘           │
│                  ↓                       │
│         ┌──────────────────────┐           │
│         │  ContentAuditService │          │
│         │  (内容审核)        │           │
│         └──────┬─────────────┘           │
│                  ↓                       │
│              AI 回答                     │
└─────────────────────────────────────────────┘

2.2 核心组件职责

1. 知识库服务(KnowledgeBaseService)

  • 负责课程知识的存储、检索
  • 支持分块存储(避免单文档过大)
  • 支持向量检索(基于语义相似度)

2. 提示词模板服务(PromptTemplateService)

  • 预设不同场景的提示词模板
  • 支持动态替换变量(如课程名称、问题内容)
  • 提升回答的针对性和准确性

3. 大语言模型服务(LlmService)

  • 对接阿里云通义千问(DashScope)
  • 支持对话模式(多轮对话)
  • 支持流式输出(实时返回)

4. 内容审核服务(ContentAuditService)

  • 审核AI生成的内容
  • 过滤敏感词、违规内容
  • 确保回答安全合规

三、核心功能实现

3.1 课程答疑接口

这是最核心的功能,让学生能够针对课程内容提问。

接口设计:

@RestController
@RequestMapping("/chat")
public class AiChatController {

    @GetMapping("/course")
    public Mono<R<String>> courseQa(
            @RequestParam @NotBlank String question,
            @RequestParam(required = false) Long courseId) {
        
        // 1. 从知识库中查找相关内容,最多找5条
        List<String> context = knowledgeBaseService.retrieveContext(question, 5);
        String contextText = context.stream()
                .limit(5)
                .collect(Collectors.joining("\n\n"));
        
        // 2. 获取问答模板,如果没有就用默认模板
        PromptTemplate template = promptTemplateService.getByCode("COURSE_QA");
        String tpl = template != null ? template.getContent() :
                "你是在线课程答疑助手,请根据给定的课程知识回答学生问题,回答使用中文。\n" +
                        "【课程知识】:\n{{context}}\n\n【问题】:\n{{question}}\n\n请给出清晰分点回答。";
        
        // 3. 把知识库内容和问题填入模板,生成最终的提示词
        String prompt = tpl.replace("{{context}}", contextText)
                .replace("{{question}}", question);
        
        // 4. 调用AI模型生成回答
        return llmService.chat(prompt)
                .map(R::ok);
    }
}

实际效果:

学生提问:"Java的Spring Boot是什么?"

知识库检索结果:
【课程知识】:
1. Spring Boot是由Pivotal团队提供的开源框架
2. 它简化了基于Spring的应用开发
3. 提供了自动配置和"约定优于配置"的理念
4. 内置了Tomcat、Jetty等Servlet容器
5. 支持自动监控和健康检查

【问题】: Java的Spring Boot是什么?

提示词(填充后):
你是在线课程答疑助手,请根据给定的课程知识回答学生问题,回答使用中文。
【课程知识】:
1. Spring Boot是由Pivotal团队提供的开源框架
2. 它简化了基于Spring的应用开发
3. 提供了自动配置和"约定优于配置"的理念
4. 内置了Tomcat、Jetty等Servlet容器
5. 支持自动监控和健康检查
【问题】: Java的Spring Boot是什么?

请给出清晰分点回答。

AI回答:
Spring Boot是由Pivotal团队(现已被VMware收购)开发的一个开源Java应用框架,旨在简化基于Spring的应用开发过程。

主要特点:
1. 简化配置:通过自动配置和"约定优于配置"的理念,大大减少了XML配置文件的编写
2. 内嵌容器:内置了Tomcat、Jetty等Servlet容器,无需手动部署WAR包
3. 自动依赖管理:提供了"starter"依赖,自动管理版本兼容性
4. 生产就绪特性:内置了健康检查、指标监控等生产环境必需的功能
5. 生态系统丰富:拥有庞大的社区支持和丰富的第三方集成

在智学云平台中,我们使用Spring Boot 3.2.0作为基础框架,它为AI服务提供了稳定、高效的运行环境。

3.2 知识库管理

知识库是RAG架构的核心,我们采用了以下设计:

分块策略:

@Data
@TableName("knowledge_chunk")
public class KnowledgeChunk {
    private Long id;
    private Long documentId;      // 所属文档ID
    private Integer chunkIndex;     // 分块索引
    private String content;         // 分块内容(500-1000字符)
    private String embedding;        // 向量表示
    private Integer status;          // 状态:0待处理 1已处理
}

为什么分块?

  • 避免单文档过大,超出向量检索的上下文窗口
  • 提高检索精度(只检索最相关的分块)
  • 支持增量更新(只需更新修改的分块)

向量存储:

@Service
public class VectorStoreServiceImpl implements VectorStoreService {

    public List<KnowledgeChunk> search(String query, int topK) {
        // 1. 将查询文本转换为向量
        float[] queryVector = embeddingService.embed(query);
        
        // 2. 在向量数据库中检索最相似的向量
        List<KnowledgeChunk> chunks = vectorRepository.search(queryVector, topK);
        
        return chunks;
    }
}

3.3 内容审核机制

为了确保AI回答的安全性,我们实现了内容审核:

@Service
public class ContentAuditServiceImpl implements ContentAuditService {

    @Override
    public String audit(String content) {
        // 1. 敏感词检测
        if (containsSensitiveWords(content)) {
            return "内容包含敏感词,请修改后重试";
        }
        
        // 2. 违规内容检测
        if (containsIllegalContent(content)) {
            return "内容涉及违规信息,已被拒绝";
        }
        
        // 3. 调用AI审核
        return llmService.audit(content);
    }
}

四、技术挑战与解决方案

4.1 挑战1:向量检索的精度问题

问题描述:
在早期测试中,我们发现向量检索的精度不够高。比如学生问"如何配置Spring Boot的数据库连接?“,检索结果可能包含"Spring Boot配置”、"数据库连接池"等内容,但不包含具体的配置步骤。

解决方案:混合检索策略

public List<KnowledgeChunk> retrieveContext(String question, int topK) {
    // 1. 关键词检索(BM25算法)
    List<KnowledgeChunk> keywordResults = keywordSearch(question, topK / 2);
    
    // 2. 语义检索(向量相似度)
    List<KnowledgeChunk> semanticResults = vectorSearch(question, topK / 2);
    
    // 3. 融合结果(去重、排序)
    return mergeAndRerank(keywordResults, semanticResults, topK);
}

效果对比:

检索策略 准确率 平均响应时间
纯向量检索 65% 800ms
混合检索 82% 600ms

4.2 挑战2:提示词工程

问题描述:
最初我们使用简单的提示词:“请回答以下问题”。但AI的回答往往不够结构化,学生需要追问才能得到完整答案。

解决方案:结构化提示词模板

@Data
@TableName("prompt_template")
public class PromptTemplate {
    private String code;           // 模板代码
    private String name;           // 模板名称
    private String content;         // 模板内容
    private List<String> variables; // 可替换变量
    
    // 模板示例
    // 你是在线课程答疑助手,请根据给定的课程知识回答学生问题,回答使用中文。
    // 【课程知识】:\n{{context}}\n\n【问题】:\n{{question}}\n\n请给出清晰分点回答。
}

提示词优化技巧:

  1. 明确角色定位:告诉AI它是什么角色(课程答疑助手)
  2. 提供上下文:明确告诉AI知识库内容是什么
  3. 要求格式:要求AI给出清晰分点回答
  4. 限制范围:要求AI只基于知识库内容回答,不要胡编

4.3 挑战3:并发性能问题

问题描述:
在高峰期(比如晚上8-10点),大量学生同时提问,AI服务的响应时间明显变慢,甚至出现超时。

解决方案:多级缓存策略

@Service
public class LlmServiceImpl implements LlmService {

    private final CacheManager cacheManager;
    
    @Override
    public Mono<String> chat(String prompt) {
        // 1. 生成缓存key
        String cacheKey = "llm:chat:" + DigestUtils.md5Hex(prompt);
        
        // 2. 尝试从缓存获取
        String cached = cacheManager.get(cacheKey);
        if (cached != null) {
            return Mono.just(cached);
        }
        
        // 3. 缓存未命中,调用AI
        return webClient.post()
                .bodyValue(body)
                .retrieve()
                .bodyToMono(String.class)
                .cache(cacheKey, Duration.ofMinutes(30));  // 缓存30分钟
    }
}

性能优化效果:

优化措施 缓存命中率 平均响应时间
无缓存 0% 1200ms
L1缓存 45% 400ms
L2缓存 75% 150ms

五、实际效果与数据

5.1 使用数据统计

上线一个月后,我们统计了AI服务的使用数据:

指标 数值 说明
总提问次数 156,789次 学生提问热情高
平均响应时间 380ms 性能表现良好
准确率(人工抽检) 82% RAG架构效果显著
学生满意度 4.2/5.0 满意度高
成本(token消耗) 降低50% 知识库检索优化

5.2 学生反馈

我们收集了学生的真实反馈:

正面反馈:

  • “AI回答很专业,比论坛回复快多了!”
  • “24小时在线,再也不用等老师回复了!”
  • “基于课程知识库,回答很准确!”
  • “分点清晰,学习效率提升!”

负面反馈:

  • “有时候回答不够深入,需要追问”
  • “对于新课程,AI回答不够准确”
  • “希望能支持语音提问”

改进措施:

  1. 增加知识库内容的深度和广度
  2. 优化提示词模板,提高回答的针对性
  3. 引入多模态支持(文本、语音、图片)
  4. 增加AI对话历史记录,支持上下文理解

六、未来规划

6.1 短期优化(1-3个月)

1. 多轮对话支持

@Data
public class ChatSession {
    private String sessionId;
    private Long userId;
    private List<ChatMessage> messages;  // 对话历史
    private LocalDateTime createTime;
    private LocalDateTime updateTime;
}

2. 个性化推荐
基于学生的学习行为,推荐相关课程、知识点:

  • 学习历史分析
  • 错题记录分析
  • 学习时长统计
  • 个性化知识库推送

3. 实时流式输出
让学生看到AI"思考"的过程,提升交互体验:

  • 逐步展示AI的回答
  • 支持中断和重新生成
  • 展示引用的知识库来源

6.2 长期规划(3-6个月)

1. 知识图谱构建
将知识库中的知识点构建成知识图谱,实现:

  • 知识点关联
  • 推理能力
  • 多跳问答

2. 多模态AI
支持更多交互方式:

  • 语音问答
  • 图片识别
  • 代码生成
  • 视频讲解

3. AI助教系统
打造更智能的学习助手:

  • 主动学习提醒
  • 作业批改
  • 学习进度跟踪
  • 个性化学习路径推荐

七、技术总结

7.1 核心技术栈

技术组件 版本 用途
Spring Boot 3.2.0 基础框架
Spring WebFlux 3.2.0 响应式编程
阿里云DashScope 通义千问 大语言模型
Redis 7.0 缓存和会话管理
向量数据库 Milvus 知识库向量存储
Elasticsearch 8.11.0 全文检索

7.2 关键代码示例

1. LLM配置类

@Data
@Configuration
@ConfigurationProperties(prefix = "ai.dashscope")
public class LlmConfig {
    private String apiKey;      // API密钥
    private String model;        // 模型名称(qwen-plus)
}

2. 知识库检索服务

@Service
public class KnowledgeBaseServiceImpl implements KnowledgeBaseService {

    @Override
    public List<String> retrieveContext(String question, int topK) {
        // 1. 向量化查询
        float[] queryVector = embeddingService.embed(question);
        
        // 2. 向量检索
        List<KnowledgeChunk> chunks = vectorStoreService.search(queryVector, topK);
        
        // 3. 提取文本内容
        return chunks.stream()
                .map(KnowledgeChunk::getContent)
                .collect(Collectors.toList());
    }
}

3. AI对话服务

@Service
public class LlmServiceImpl implements LlmService {

    private Mono<String> chat(String prompt) {
        Map<String, Object> body = Map.of(
            "model", config.getModel(),
            "input", Map.of("messages", new Object[]{
                Map.of("role", "user", "content", prompt)
            })
        );
        
        return webClient.post()
                .bodyValue(body)
                .retrieve()
                .bodyToMono(String.class)
                .map(this::extractContentSafely);
    }
}

八、心得体会

8.1 技术选型的重要性

在开发AI服务的过程中,我深刻体会到技术选型的重要性

教训1:不要盲目追求最新技术

  • 通义千问模型更新很快,但稳定性和成本更重要
  • 我们选择了成熟稳定的DashScope,而不是最新的模型
  • 这保证了服务的稳定性和成本可控

教训2:架构设计要考虑扩展性

  • RAG架构虽然增加了复杂度,但带来了巨大的价值
  • 知识库可以独立更新,不影响AI服务
  • 为未来引入多模态、知识图谱等打下了基础

8.2 用户体验至上

核心原则:

  1. 响应速度:AI回答必须在3秒内返回
  2. 准确性:基于知识库的准确率要达到80%以上
  3. 可用性:服务可用性要达到99.9%以上
  4. 安全性:严格的内容审核,确保回答安全合规

8.3 持续优化的必要性

AI技术发展迅速,我们需要持续优化:

  • 定期更新知识库内容
  • 优化向量检索算法
  • 调整提示词模板
  • 收集用户反馈,不断改进

8.4 实战经验与最佳实践

经验1:知识库质量决定AI回答质量

  • 知识库内容必须经过人工审核和结构化处理
  • 每个知识块控制在500-1000字符,避免过长或过短
  • 定期清理过期或错误的知识内容
  • 建立知识库版本管理机制

经验2:提示词工程需要反复打磨

  • 不要使用一次性提示词,要建立模板库
  • 提示词要包含:角色定位、任务描述、输出格式、约束条件
  • 通过A/B测试验证不同提示词的效果
  • 记录每次提示词优化的效果数据

经验3:监控和日志至关重要

  • 记录每次AI调用的输入、输出、耗时、token消耗
  • 建立异常报警机制(如响应时间超过3秒)
  • 定期分析日志,发现潜在问题
  • 保存用户反馈与对应回答,用于后续优化

经验4:渐进式上线策略

  • 先在小范围用户中测试(如10%用户)
  • 收集反馈并快速迭代
  • 逐步扩大使用范围
  • 始终保留人工审核通道

经验5:成本控制技巧

  • 合理设置上下文窗口大小
  • 使用缓存减少重复调用
  • 对简单问题使用小模型,复杂问题使用大模型
  • 定期清理无用的对话历史

九、总结

AI智能服务的实现,是智学云平台从"传统在线教育"向"智能教育"转型的重要里程碑。通过引入RAG架构,我们成功解决了传统在线教育平台的痛点:

解决了什么问题:

  1. 学生提问无人回复 → AI 24小时在线答疑
  2. 回答质量参差不齐 → 基于知识库的精准回答
  3. 响应速度慢 → 平均380ms的快速响应
  4. 成本高昂 → 知识库检索降低50%成本

🎯 核心价值:

  • 让每个学生都配了一位"私人助教"
  • 24小时在线,随时随地答疑
  • 基于课程知识,专业准确回答
  • 提升学习效率,降低学习成本

📈 下一步计划:

  • 支持多轮对话,理解上下文
  • 引入语音问答,提升交互体验
  • 构建知识图谱,实现推理能力
  • 打造AI助教系统,主动服务学生

智学云开发日记系列文章持续更新中,敬请关注!

下一篇预告: 📡 智学云开发日记(五):实时互动服务的实现与思考

#AI智能服务 #RAG架构 #知识库检索 #大语言模型 #在线教育 #技术分享

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐