0

新一代AI全栈工程师-微服务AI智能面试对话平台

学习园地星课it点top
10天前 13

获课:xingkeit.top/17375/

一、技术选型与架构设计

1.1 核心架构分层

系统采用 Spring Cloud 微服务架构,按业务域拆分为以下核心服务-4

text
复制
下载
┌─────────────────────────────────────────────────────┐
│                    前端层                          │
│           WebRTC语音 / WebSocket实时通信           │
└─────────────────┬───────────────────────────────────┘
                    │
┌─────────────────▼───────────────────────────────────┐
│              API网关 (Spring Cloud Gateway)          │
│           路由 / 鉴权 / 限流 / JWT校验              │
└─────────────────┬───────────────────────────────────┘
                    │
    ┌───────────────┼───────────────┬───────────────┐
    ▼               ▼               ▼               ▼
┌─────────┐   ┌─────────┐   ┌─────────┐   ┌─────────┐
│用户服务  │   │面试服务  │   │题库服务  │   │推理服务  │
│用户/权限 │   │会话管理  │   │RAG检索  │   │LLM推理  │
└─────────┘   └─────────┘   └─────────┘   └─────────┘
    │               │               │               │
    └───────────────┴───────┬───────┴───────────────┘
                            ▼
              ┌─────────────────────────┐
              │  基础设施层              │
              │ Nacos/Redis/Milvus/Kafka │
              └─────────────────────────┘

1.2 技术栈清单

层级技术选型说明
微服务框架Spring Cloud Alibaba + Nacos服务注册发现、配置管理
网关Spring Cloud Gateway路由、鉴权、限流
大模型Ollama + Qwen 本地部署数据安全,避免敏感数据外传-2
向量数据库Milvus / RedisVector存储知识库Embedding,支持RAG检索-3
缓存Redis会话状态、热点数据缓存
消息队列Kafka异步处理面试记录、日志-5
容错Resilience4j熔断、限流、重试-10

二、本地大模型部署与集成

2.1 模型选型与部署

核心原则:数据安全第一。 面试涉及候选人简历、回答等敏感信息,不能调用公有云API。推荐采用 Ollama + Qwen 本地部署方案-2

bash
复制
下载
# 安装 Ollamacurl -fsSL https://ollama.com/install.sh | sh# 拉取并运行千问模型(根据硬件选择版本)ollama pull qwen2:7b
ollama run qwen2:7b

2.2 Spring Boot 集成 Ollama

使用 Spring AI 框架封装模型调用,支持流式输出和同步推理-8-2

xml
复制
下载
运行
<!-- pom.xml 依赖 --><dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-ollama-spring-boot-starter</artifactId>
    <version>0.8.0</version></dependency>

配置类

java
复制
下载
@Configurationpublic class OllamaConfig {
    @Bean
    public OllamaChatModel ollamaChatModel() {
        return new OllamaChatModel(
            OllamaApi.builder()
                .baseUrl("http://localhost:11434")
                .build(),
            OllamaChatOptions.builder()
                .model("qwen2:7b")
                .temperature(0.7)  // 控制输出随机性
                .topP(0.9)
                .build()
        );
    }}

推理服务封装

java
复制
下载
@Service@Slf4jpublic class InterviewInferenceService {
    @Autowired
    private OllamaChatModel chatModel;
    
    /**
     * 同步推理 - 用于评估回答
     */    public String evaluateAnswer(String question, String candidateAnswer) {
        String prompt = String.format(
            "你是一位专业的面试官,请评估候选人对以下问题的回答质量。\n" +
            "问题:%s\n" +
            "回答:%s\n" +
            "请从表达能力、逻辑性、专业性三个维度评分(0-10分),并给出简短评语。",
            question, candidateAnswer        );
        
        ChatResponse response = chatModel.call(
            new Prompt(prompt, OllamaChatOptions.DEFAULT)
        );
        return response.getResult().getOutput().getContent();
    }
    
    /**
     * 流式推理 - 用于面试对话实时生成
     */    public Flux<String> streamChat(String prompt) {
        Prompt chatPrompt = new Prompt(prompt);
        return chatModel.stream(chatPrompt)
            .map(response -> response.getResult().getOutput().getContent());
    }}

三、微服务核心实现

3.1 服务注册与发现(Nacos)

yaml
复制
下载
# application.ymlspring:
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
        enabled: true
        service: ${spring.application.name}

3.2 服务间通信(Feign Client)

AI推理服务需要调用题库服务和用户服务,通过 Feign 实现声明式调用,配合 Hystrix 熔断降级-4

java
复制
下载
@FeignClient(
    name = "question-bank-service",
    fallback = QuestionBankFallback.class)public interface QuestionBankClient {
    @GetMapping("/api/questions/random")
    ResponseEntity<QuestionDTO> getRandomQuestion(
        @RequestParam("skill") String skill,
        @RequestParam("level") String level    );}@Component@Slf4jpublic class QuestionBankFallback implements QuestionBankClient {
    @Override
    public ResponseEntity<QuestionDTO> getRandomQuestion(String skill, String level) {
        log.warn("题库服务不可用,使用降级题库");
        // 返回默认题目
        return ResponseEntity.ok(
            QuestionDTO.builder()
                .content("请介绍一下你的技术栈和项目经验")
                .difficulty("medium")
                .build()
        );
    }}

3.3 服务容错(Resilience4j)

大模型推理可能耗时较长或超时,必须配置熔断和限流-9-10

yaml
复制
下载
resilience4j:
  circuitbreaker:
    instances:
      inferenceService:
        failureRateThreshold: 50   # 失败率阈值
        slowCallRateThreshold: 50
        slowCallDurationThreshold: 5s        waitDurationInOpenState: 10s        permittedNumberOfCallsInHalfOpenState: 3
        slidingWindowType: TIME_BASED        slidingWindowSize: 60
java
复制
下载
@Servicepublic class InferenceServiceWithResilience {
    @CircuitBreaker(name = "inferenceService", fallbackMethod = "fallbackInference")
    public String infer(String prompt) {
        // 调用大模型推理
        return ollamaChatModel.call(prompt);
    }
    
    public String fallbackInference(String prompt, Throwable t) {
        log.error("推理服务熔断降级: {}", t.getMessage());
        return "系统繁忙,请稍后重试。您的回答已保存,将由人工复核。";
    }}

四、核心难点攻克

4.1 问题一:AI 幻觉导致瞎编答案

场景:候选人问「请评价我的回答」,AI 可能凭空捏造评分。

解决方案:RAG 检索增强生成。将面试评估标准、岗位能力模型等知识文档向量化,推理时先检索相关内容作为上下文-2

知识库构建

java
复制
下载
@Componentpublic class KnowledgeBaseLoader {
    @Autowired
    private EmbeddingModel embeddingModel;
    @Autowired
    private VectorStore vectorStore;  // Milvus
    
    public void loadKnowledge() throws IOException {
        // 1. 加载评估标准文档
        String text = loadFile("interview-standards.pdf");
        
        // 2. 文档分片(每500字符,重叠50字符)
        Document document = new Document(text);
        DocumentSplitter splitter = DocumentSplitters.recursive(500, 50);
        List<TextSegment> segments = splitter.split(document);
        
        // 3. 向量化并存入Milvus
        List<Embedding> embeddings = embeddingModel.embedAll(segments);
        vectorStore.add(segments, embeddings);
    }}

推理时检索

java
复制
下载
public String evaluateWithRAG(String question, String answer) {
    // 1. 构建查询文本
    String query = String.format("问题:%s\n回答:%s", question, answer);
    
    // 2. 向量检索 TOP-3 相关评估标准
    List<EmbeddingMatch<TextSegment>> matches = 
        vectorStore.search(embeddingModel.embed(query), 3);
    
    // 3. 拼接 Prompt(强制基于资料回答)
    StringBuilder context = new StringBuilder();
    context.append("请根据以下评估标准严格评分,不要编造标准之外的维度:\n");
    for (EmbeddingMatch<TextSegment> match : matches) {
        context.append(match.getEmbedded().text()).append("\n");
    }
    context.append("\n候选人回答:").append(answer);
    
    // 4. 调用模型
    return chatModel.call(context.toString());}

关键细节:给 Prompt 加上「不要编造」约束,实际项目中能显著降低幻觉率-2

4.2 问题二:面试对话上下文丢失

解决方案:Redis 存储会话状态 + Kafka 异步持久化-5-9

java
复制
下载
@Servicepublic class InterviewSessionService {
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    @Autowired
    private KafkaTemplate<String, String> kafkaTemplate;
    
    private static final String SESSION_PREFIX = "interview:session:";
    private static final long SESSION_TTL = 3600; // 1小时超时
    
    /**
     * 保存对话上下文
     */    public void saveContext(String sessionId, String role, String content) {
        String key = SESSION_PREFIX + sessionId;
        List<Map<String, String>> history = getHistory(sessionId);
        
        Map<String, String> turn = Map.of(
            "role", role,           // candidate / interviewer
            "content", content,
            "timestamp", String.valueOf(System.currentTimeMillis())
        );
        history.add(turn);
        
        // 只保留最近20轮,避免上下文过长
        if (history.size() > 20) {
            history = history.subList(history.size() - 20, history.size());
        }
        
        redisTemplate.opsForValue().set(key, history, SESSION_TTL, TimeUnit.SECONDS);
        
        // 异步发送到Kafka持久化
        kafkaTemplate.send("interview-logs", sessionId, 
            JsonUtils.toJson(turn));
    }
    
    @SuppressWarnings("unchecked")
    public List<Map<String, String>> getHistory(String sessionId) {
        String key = SESSION_PREFIX + sessionId;
        Object value = redisTemplate.opsForValue().get(key);
        if (value == null) {
            return new ArrayList<>();
        }
        return (List<Map<String, String>>) value;
    }}

4.3 问题三:向量库重启数据丢失

开发环境用 InMemoryEmbeddingStore 很方便,但生产环境重启后所有知识库全丢-2

解决方案:生产环境使用 Milvus/Redis 持久化向量库

java
复制
下载
@Configuration@ConditionalOnProperty(name = "vector.store.type", havingValue = "milvus")public class MilvusVectorStoreConfig {
    @Bean
    public VectorStore vectorStore() {
        return new MilvusVectorStore(
            MilvusVectorStoreConfig.builder()
                .host("milvus-service")
                .port(19530)
                .collectionName("interview_knowledge")
                .embeddingDimension(1536)
                .build(),
            embeddingModel()
        );
    }}

五、面试流程核心逻辑

5.1 动态出题策略

根据岗位技能标签和候选人回答动态抽取题目,避免重复-3-7

java
复制
下载
@Servicepublic class QuestionStrategy {
    @Autowired
    private QuestionBankClient questionClient;
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    
    /**
     * 三级随机化出题
     * 1. 按难度分层(初级40% / 中级40% / 高级20%)
     * 2. 按技能标签匹配
     * 3. 去重(Redis BloomFilter)
     */    public QuestionDTO nextQuestion(String sessionId, String skill, int level) {
        // 计算题目难度分布
        String difficulty = level <= 3 ? "junior" : 
                           (level <= 7 ? "medium" : "senior");
        
        // 调用题库服务获取题目
        QuestionDTO question = questionClient.getQuestion(skill, difficulty);
        
        // 去重检查:使用 Redis 记录已出题目
        String askedKey = "asked:" + sessionId;
        Boolean isDuplicate = redisTemplate.opsForSet().isMember(askedKey, question.getId());
        if (Boolean.TRUE.equals(isDuplicate)) {
            // 重新获取
            return nextQuestion(sessionId, skill, level);
        }
        redisTemplate.opsForSet().add(askedKey, question.getId());
        
        return question;
    }}

5.2 回答评估与评分

java
复制
下载
@Servicepublic class AnswerEvaluator {
    @Autowired
    private InferenceServiceWithResilience inferenceService;
    
    public EvaluationResult evaluate(String sessionId, String question, String answer) {
        String prompt = buildEvaluationPrompt(question, answer);
        String result = inferenceService.infer(prompt);
        return parseEvaluationResult(result);
    }
    
    private String buildEvaluationPrompt(String question, String answer) {
        return String.format("""
            你是一位资深技术面试官,请评估候选人的回答。
            
            【面试问题】
            %s
            
            【候选人回答】
            %s
            
            【评估要求】
            1. 从以下维度评分(每项0-10分):技术深度、逻辑清晰度、表达能力
            2. 给出简短评语(50字以内)
            3. 给出综合推荐意见:通过 / 待定 / 不通过
            
            请按JSON格式输出。
            """, question, answer);
    }}

六、部署与运维

6.1 Docker Compose 一键部署

yaml
复制
下载
# docker-compose.ymlversion: '3.8'services:
  nacos:
    image: nacos/nacos-server:v2.2.0    ports:
      - "8848:8848"
    environment:
      MODE: standalone  
  redis:
    image: redis:7-alpine    ports:
      - "6379:6379"
  
  milvus:
    image: milvusdb/milvus:v2.2.0    ports:
      - "19530:19530"
    environment:
      ETCD_ENDPOINTS: etcd:2379
  
  ollama:
    image: ollama/ollama:latest    ports:
      - "11434:11434"
    volumes:
      - ./models:/root/.ollama    command: serve  
  interview-service:
    build: ./interview-service    ports:
      - "8080:8080"
    depends_on:
      - nacos      - redis      - milvus      - ollama    environment:
      SPRING_CLOUD_NACOS_DISCOVERY_SERVER_ADDR: nacos:8848

6.2 监控与告警

集成 Prometheus + Grafana 监控关键指标-3-4

指标告警阈值说明
推理服务 P99 延迟> 5s模型响应过慢
推理服务错误率> 5%可能模型异常
向量检索耗时> 200ms向量库性能问题
会话超时率> 10%候选人体验下降

七、面试官高频追问

Q1:为什么要用本地大模型,而不是调用 OpenAI API?

数据安全是招聘系统的生命线——候选人简历、面试回答属于敏感个人信息,不得出网。本地部署虽然模型效果稍逊,但符合企业合规要求-2

Q2:如何保证系统高可用?

三管齐下:Nacos 服务注册实现多实例部署、Resilience4j 熔断防止雪崩、Kafka 异步削峰应对突发流量-9

Q3:AI 瞎编答案怎么办?

RAG 检索增强生成 + 规则兜底。关键数据(如候选人评分)通过代码逻辑计算,不让 AI 凭空生成-2。对于知识类回答,强制 AI「基于检索到的资料回答,不要编造」。


八、总结与演进方向

本文完整实现了一个 Spring Cloud 微服务 + 本地大模型 的 AI 面试系统,核心要点:

  1. 架构分层:网关 → 微服务 → 基础设施,清晰解耦

  2. 模型本地化:Ollama + Qwen 保障数据安全

  3. RAG 防幻觉:向量检索 + 知识库约束 AI 输出

  4. 容错机制:熔断、降级、重试保障稳定性

下一步演进方向

  • 语音交互:集成 WebRTC + ASR/TTS 实现全语音面试-3-7

  • 多模态评估:分析候选人表情、语速等非语言信号

  • 自动总结:面试结束后自动生成评估报告

10 个网页


本站不存储任何实质资源,该帖为网盘用户发布的网盘链接介绍帖,本文内所有链接指向的云盘网盘资源,其版权归版权方所有!其实际管理权为帖子发布者所有,本站无法操作相关资源。如您认为本站任何介绍帖侵犯了您的合法版权,请发送邮件 [email protected] 进行投诉,我们将在确认本文链接指向的资源存在侵权后,立即删除相关介绍帖子!
最新回复 (0)

    暂无评论

请先登录后发表评论!

返回
请先登录后发表评论!