项目实训(5) - 模拟面试流程改造

56 阅读5分钟

项目实训(5) - 模拟面试流程改造

上次那个“模拟面试”的初步设想,听起来挺美的:开场、技术、项目、行为、提问、结束,AI 像个真正的面试官一样有条不紊。

现实是:AI 它有自己的想法!😂

我之前设计的 System Prompt,虽然写了一大堆规则,让它“严格按照流程”、“一次只进行一个环节”,但实际跑起来,它还是会:

  • 串台:技术提问环节,冷不丁冒出一句行为问题。
  • 忘词:说好这个环节问3-5个问题,它问了1个就想溜,或者直接跳到“你有什么想问我的吗?”
  • 自由发挥过头:有时候开场白能扯半天,就是不进正题。

前端维护的 currentInterviewStage 简直成了摆设,AI 根本不鸟我这个状态。我寻思着,不能光靠一个冗长的 System Prompt 就指望 AI 从头到尾都那么“智能”和“听话”。

新的挣扎方向:强化阶段性指令

我的新思路是,在每个阶段转换时,除了更新前端的 currentInterviewStage 状态,还要给 AI 一个更明确、更即时的“场景指令”。

  1. 初始 System Prompt 简化: 最开始的 System Prompt 主要负责设定 AI 的总体角色(面试官)、告知信息源(比如用户提供的 JD),以及一个非常高阶的流程概述。不再把每个阶段的详细指令都塞进去,免得太长 AI 看不过来。

    // 简化后的初始 System Prompt (示意)
    "你是一位资深面试官。请根据以下职位描述与候选人进行模拟面试。职位描述:\n[JD_TEXT]\n。面试将包含技术探讨、项目经验回顾等环节。请先做一个简短的开场。"
    
  2. 阶段切换时的“幕后指令” : 当一个阶段结束(比如用户点击“进入下一环节”按钮,或者前端根据对话轮数判断),在下一次向 DeepSeek API 发送请求时,我打算在 messages 数组里,用户最新回答的后面,或者在整个 messages 数组的最前面(如果API允许且有效的话),插入一条特殊的 system 角色的消息 (或者 user 角色但内容是指令式的),告诉 AI 现在该干嘛了。这条消息不显示在聊天界面上。

    // 假设用户点击“进入技术提问环节”
    // messages.value 包含了之前的对话历史
    
    const userLatestAnswer = messages.value.findLast(m => m.sender === 'user'); // 可能需要
    
    let apiMessages = messages.value.map(m => ({ role: m.sender === 'user' ? 'user' : 'assistant', content: m.text }));
    
    // 插入阶段性指令
    apiMessages.push({
        role: 'system', // 或者 'user',看哪个效果好
        content: `(指令:现在开始技术提问环节。请根据职位描述中的技术栈,提出2-3个相关问题。)`
        // 这个括号和“指令:”是给我自己看的,实际发给API时可能不需要,或者需要调整措辞让AI更容易理解
    });
    
    // 然后用这个 apiMessages 去调用 fetch ...
    

    这种方式,相当于在每一步都给 AI 一个近期的、明确的上下文和任务。

把职位描述 (JD) 或简历关键点更有效地“喂”给 AI

之前是把整个 JD 塞到初始 System Prompt 里。如果 JD 很长,会不会影响效果?或者 AI 看不全?

  • 尝试:在每个需要参考 JD 的环节(比如技术提问、项目经验回顾),都在阶段性指令里,再次简要提及 JD 的核心内容,或者明确指出“请参考之前提供的职位描述中的XX部分”。 比如:“(指令:进入技术提问。请回顾职位描述中关于 '微服务架构' 和 'Kubernetes' 的要求,并提出问题。)”

遇到的新麻烦:

  • “幕后指令”的干扰:这种插入的指令,会不会让 AI 的回复变得生硬?比如它突然冒出一句“好的,现在我们进入技术提问环节”,然后才开始问问题。这还好。但如果它把我的指令本身也当成对话内容的一部分,那就尴尬了。需要反复调试措辞。
  • DeepSeek API 对多条 system 消息的处理:有些模型对 messages 数组中出现多条 system role 的消息处理方式不同。有的可能只关注第一条,有的会都看。这个得问问后端同学,或者通过实验来确定最佳实践。如果不行,就把阶段性指令伪装成 user role 的消息发过去(比如:“好了,关于上一话题我们先聊到这。接下来,我们谈谈技术方面的问题吧?”)。
  • 用户体验的平衡:过于依赖用户点击“下一环节”来推进,会不会让面试流程度显得不自然?但完全让 AI 控制流程,又怕它失控。这是个两难。可能需要一个折中,比如 AI 完成一个环节的提问后,可以问一句“关于XX方面,你还有什么补充的吗?如果没有,我们就进入下一环节了?”给用户一个反应时间,如果用户没操作,几秒后自动推进。

代码调整(伪代码思路):

// AIChatWindow.vue or InterviewManager.ts

// currentInterviewStage 仍然保留,用于前端展示和逻辑判断

const sendUserReplyAndAdvanceIfNeeded = async (userReplyText: string) => {
    // 1. 添加用户回复到 messages.value
    // 2. 构造基础的 apiMessages (历史对话)
    
    let stageInstruction = "";
    // 判断当前是否需要转换阶段,或者AI上一步的回复是否暗示了阶段结束
    if (shouldAdvanceToNextStage(currentInterviewStage.value, messages.value)) {
        currentInterviewStage.value = getNextStage(currentInterviewStage.value);
        stageInstruction = getInstructionForStage(currentInterviewStage.value, relevantContext); // relevantContext 可能是JD摘要或简历片段
    }

    if (stageInstruction) {
        apiMessages.push({ role: 'system', content: stageInstruction }); // 或者其他注入方式
    }

    // 3. 调用 fetch(apiMessages)
    // 4. 处理回复
}

const getInstructionForStage = (stage: InterviewStage, context?: any): string => {
    switch (stage) {
        case 'technical': return `(指令:现在请针对候选人简历中的技术栈或职位描述中的技术要求进行提问。)`;
        // ... etc.
        default: return "";
    }
}

这个 shouldAdvanceToNextStage 和 getInstructionForStage 的逻辑会很复杂。

目前的状态:  感觉像是在给一个很聪明但又很固执的小孩当家教。你得顺着它的毛摸,用它能理解的方式引导它。直接下命令,它可能就给你撂挑子了。 这种“幕后指令”的方式,感觉比之前纯靠一个大而全的 System Prompt 要灵活一些,但调试起来也更麻烦。继续熬吧。