Prompt 状态机:AI 面试越级率 0% 的工程化

做 AI 模拟面试,最大的技术难点不是流式、不是计费,是让 LLM 老老实实按流程走:开场 → 自我介绍 → 基础题 → 追问 → 评分,一步都不能跳。

初版产品被用户吐槽最多的就是:面试官(LLM)聊着聊着突然跳到"恭喜你通过面试"——流程越级。我们把越级率从 20% 压到 0%,靠的不是调参,是 Prompt 状态机

一、为什么 LLM 会越级

LLM 没有"程序计数器",它是按概率生成下一个 token。长对话里:

  1. 上下文漂移:聊了 20 轮后,模型忘了现在在第几步
  2. 用户诱导:用户说"我觉得我答得不错,是不是该给我过了?",模型容易顺着答
  3. 指令稀释:Prompt 里写了 10 条规则,越靠后的越容易被忽略(注意力衰减)

解决思路:把流程状态"焊死"在每一轮对话里,而不是让模型自己记。

二、三层 Prompt 结构

第 1 层:System 强元规则(会话级)

1
2
3
4
5
6
7
8
9
你是资深技术面试官,面试流程共 5 步:
STEP1 开场 → STEP2 自我介绍 → STEP3 技术基础题 →
STEP4 项目深挖 → STEP5 评分总结。

硬性规则:
1. 每轮回复开头必须输出当前状态标记 [STATE: STEPn]
2. 只有在用户完成当前步骤的所有问题后,才能进入下一步
3. 用户主动要求跳步时,回答"我们先完成当前环节"并继续提问
4. 任何情况下不得提前输出最终评分

关键:把规则写成"命令式约束",并且给一个可验证的格式要求(每轮输出 [STATE: STEPn])——让模型自己每轮"汇报"自己在哪一步,漂移能被立即发现。

第 2 层:User 变量(每轮注入)

每轮对话,后端把当前状态拼进 User 消息:

1
2
[当前状态] 你在 STEP3(技术基础题),已完成 2 个问题,用户正在回答第 3 题。
[用户消息] {user_message}

状态不在 System 里躺着,而是在每轮 User 消息里刷新——模型的注意力永远能看到最新的状态行。

第 3 层:Assistant 预填开场(Prefill Injection)

这层最关键也最容易被忽略。不要等模型自己想下一句,后端预填 Assistant 的开头:

1
assistant: [STATE: STEP3] 好的,第 3 题是:请谈谈 Go 的 GC 机制。

模型在预填内容后面续写,很难推翻已经"说出口"的状态。预填 = 给模型一个"既成事实",让它顺着走。

三、校验层:输出必须可验证

三层 Prompt 是"引导",校验层是"兜底":

1
2
3
4
5
6
7
// 解析模型回复开头的状态标记
state := parseState(reply)   // [STATE: STEPn]
if state != expectedState {
    // 越级:截断回复,强制回到当前状态
    reply = truncateToState(reply, expectedState)
    return "请先完成当前环节:" + currentQuestion
}

越级不是"接受"或"忽略",是直接拦截重写——模型输出到了 STEP5,我们就截掉那部分,重新生成或提示用户继续。这就是越级率 0% 的机制来源。

四、实战效果

指标 初版(单层 Prompt) 三层状态机
流程越级率 ~20% 0%
用户中途"求通过" 部分被模型顺走 100% 拦截
每轮状态可追踪 [STATE] 标记可入日志
面试完整完成率 60% 92%

五、踩坑记录

坑 1:别把"下一步"写死在 System

初版把流程描述写进 System 让模型"记住",20 轮后全忘。状态必须每轮刷新(User 变量),System 只放不变的规则。

坑 2:预填会"抢话"

预填如果写了完整的问句,模型可能直接开始"自问自答"。预填只写状态标记 + 半句话,留一半给模型续,既焊死状态又不抢戏。

坑 3:评分步骤要独立会话

评分总结时如果还在同一会话,模型会受前面对话影响。评分用新会话,只传"完整问答记录",让模型基于记录评分,不基于"聊天情绪"。

坑 4:中文状态下状态标记要统一

[STATE: STEP3] 的括号形式必须固定,解析器才稳。格式是协议,不是文案——模型可能输出全角/半角括号混用,解析器要做归一化。

总结

AI 应用里的流程控制,本质是把状态从模型的记忆里搬到系统的数据里

  1. System 放不变的规则 + 输出格式约束(状态标记)
  2. User 每轮刷新当前状态,对抗注意力衰减
  3. Assistant 预填 用既成事实焊死下一步
  4. 校验层 解析状态标记,越级直接拦截

不要指望模型"自觉"遵守流程——把流程变成可校验的协议,0% 才可能。