外观
AI 面试教练项目
目录
- 1. 项目摘要
- 2. 背景、目标与约束
- 3. 系统架构与调用链
- 4. 核心技术方案
- 5. 关键权衡
- 6. 实现难点与故障处理
- 7. 评测、监控与验证
- 8. 实施路线与复盘
- 9. 面试表达
- 10. 递进追问
- 11. 证据与关联文档
- 12. 简明总结
1. 项目摘要
- 项目类型:学习型生产项目设计;
- 一句话目标:根据岗位和候选人的实时回答,一次提出一道问题,动态追问并给出有证据的多维评分与复习计划;
- 主要用户:准备 AI 应用、AI 后端、算法或系统设计面试的学习者;
- 核心技术:LLM、RAG、Agent、结构化评分、状态机、评测集和可观测性;
- 最关键难点:追问质量、评分稳定性、事实证据、长对话状态、安全边界和效果验证;
- 核心设计:外层使用确定性面试状态机,内层只在“分析回答和选择追问”环节使用 Agent;
- 当前边界:本文是可实施设计,不代表系统已上线,也不声明任何未经实测的准确率或业务效果。
1.1 30 秒项目结论
我设计的不是一个“让模型随便提问”的聊天机器人,而是一套由能力图谱、题库、RAG、评分 Rubric 和受控 Agent 组成的面试训练系统。外层状态机保证一次一题、轮次、预算和结束条件,Agent 根据用户回答中的正确点、遗漏和错误选择下一道追问,评分器必须输出证据片段和分维度理由,最终把失败样本沉淀为复习任务和回归评测集。
1.2 为什么适合作为面试项目
该项目能同时展示:
- 如何把 LLM 的自然语言能力变成结构化产品流程;
- 为什么 RAG、Agent 和 Workflow 各自承担不同职责;
- 如何处理评分漂移、幻觉、提示注入和长对话;
- 如何设计离线评测、线上指标、成本与降级;
- 如何用状态、证据和日志排查“主流程成功但质量失败”。
2. 背景、目标与约束
2.1 业务背景
传统题库只能展示固定答案,普通聊天模型又容易一次问多题、提前泄露答案、重复追问或给出没有证据的分数。学习者真正需要的是:回答后立即暴露知识缺口,并通过连续追问检验是否理解原理和工程边界。
2.2 功能目标
- 根据目标岗位、级别、主题和时间创建面试;
- 一次只展示一个主要问题;
- 从回答中抽取事实点、推理链、项目证据、错误和遗漏;
- 根据缺口选择追问、提示、讲解、切换主题或结束;
- 从准确性、原理深度、工程意识、项目表达和沟通结构五个维度评分;
- 每个分数提供引用用户回答的证据和改进建议;
- 生成主题掌握图、错题清单和间隔复习计划;
- 支持暂停、恢复、退出、删除记忆和导出复盘。
2.3 成功标准
不能用“模型回答看起来不错”作为验收。至少定义:
- 题目是否与岗位、主题和难度匹配;
- 是否保持一次一题且追问来自上一轮缺口;
- 评分是否能引用真实回答证据;
- 同一答案多次评分是否在可接受范围内;
- 知识引用是否来自允许且有效的文档版本;
- 是否能在服务重启后恢复会话;
- 是否能识别退出、拒答和需要人工澄清的场景;
- 延迟、成本和敏感数据是否符合产品约束。
具体阈值必须通过标注集、基线和实测确定,本文不虚构数值。
2.4 输入、输出与主要数据
输入:
- 目标岗位、级别、知识主题和面试时长;
- 用户回答、代码片段和项目描述;
- 题库、知识文档、评分 Rubric 和历史薄弱点;
- 用户对数据保存、难度和反馈方式的偏好。
输出:
- 当前问题、必要提示和动态追问;
- 分维度评分、证据、错误和遗漏;
- 更好的 30 秒与 3 分钟回答;
- 主题覆盖、薄弱点、复习任务和面试复盘;
- 完整但受控的执行轨迹。
2.5 非功能约束
- 交互延迟:问题生成和反馈适合流式返回;
- 一致性:题目、评分和知识引用需要版本化;
- 隐私:用户项目经历和答案按租户隔离并可删除;
- 安全:用户输入与检索文本不能修改系统评分规则;
- 成本:限制每轮上下文、工具和反思次数;
- 可恢复:状态不能只保存在模型上下文或浏览器;
- 可解释:最终分数必须有可定位证据。
3. 系统架构与调用链
3.1 组件职责
| 组件 | 职责 | 不能承担的职责 |
|---|---|---|
| 面试会话 API | 鉴权、创建、暂停、恢复、事件输出 | 不直接决定面试内容 |
| 面试状态机 | 控制轮次、阶段、预算和终止 | 不自由生成追问 |
| 能力图谱与题库 | 定义主题、难度、前置和覆盖 | 不保存用户私密答案 |
| 回答分析器 | 抽取事实点、错误、遗漏和项目证据 | 不直接写最终分数 |
| RAG 服务 | 检索可靠知识和参考答案 | 不决定用户是否通过 |
| 追问 Agent | 根据缺口选择下一动作 | 不绕过状态机和预算 |
| Rubric 评分器 | 分维度评分并引用证据 | 不执行真实副作用 |
| 状态与报告服务 | 保存轮次、分数、薄弱点和报告 | 不把调试日志当用户记忆 |
| 评测与观测 | 回归、Trace、指标和告警 | 不替代业务验收 |
3.2 技术栈、框架、库与组件清单
| 技术点 ID | 技术点/环节 | 类型 | 采用方案 | 链路职责 | 版本/证据边界 |
|---|---|---|---|---|---|
| TP-01 | 会话编排与恢复 | 状态机/工作流模式 | 持久化面试状态机 + 幂等事件 + 检查点 | 控制轮次、预算、暂停、恢复、终止和唯一状态迁移 | 当前是示例项目设计;框架选型需由恢复演练、并发与运维约束验证 |
| TP-02 | 知识证据检索 | RAG 服务 + 索引组件 | 权限与版本过滤的混合召回、融合和 Rerank | 为回答分析和评分提供带来源、版本的知识证据 | 是否需要向量库和 Rerank 由真实题库、查询集及 Recall/引用指标决定 |
| TP-03 | 回答评分与追问 | Schema、Rubric + 受控 Agent | 独立 Rubric 评分器;Agent 只选择下一动作 | 抽取缺口、生成可解释分数,并在预算内追问/讲解/结束 | 模型输出不是事实;须用重复评分、专家标注、越权和恢复测试验证 |
3.3 横向选型对比
| 技术点 ID | 候选方案 | 优点 | 缺点/代价 | 适用场景 | 不适用场景 | 选择结论与依据 |
|---|---|---|---|---|---|---|
| TP-01 | 模型上下文或进程内会话状态 | 实现快、链路短、原型成本低 | 重启丢失、并发覆盖、恢复和审计困难 | 单用户演示、短会话、允许重新开始 | 多租户、长会话、暂停恢复与计费 | 只用于原型;需要恢复、幂等或审计时切换持久化状态机 |
| TP-01 | 持久化状态机/工作流 | 生命周期、版本冲突和恢复边界明确 | 状态设计、迁移和运维复杂度更高 | 正式面试、跨设备恢复、异步报告 | 一次性无状态问答 | 通过断连、重复提交和 Worker 重启演练后采用 |
| TP-02 | 固定题库/关键词检索 | 可解释、成本低、专有术语稳定 | 同义问法和开放知识覆盖弱 | 题目范围小、知识变化低 | 项目追问、自然语言变体和大量资料 | 早期基线保留;检索失败切片证明语义缺口后升级 |
| TP-02 | 混合检索 + Rerank | 兼顾精确词和语义召回,排序可优化 | 索引、延迟、版本和评测治理更复杂 | 知识量大、问法多样、要求引用 | 资料很少或没有可靠评测集 | 以离线 Recall、排序和端到端引用正确率共同决定 |
| TP-03 | 单次 LLM 自由评分并直接追问 | 原型快、表达灵活 | 分数漂移、证据弱、状态和权限边界不清 | 低风险练习、只给建议不做结论 | 招聘决策、稳定评分、审计场景 | 不能作为高风险最终评分;只保留为探索性建议 |
| TP-03 | 结构化 Rubric + 受控 Agent | 分数与动作职责分离,证据和停止条件清晰 | Schema、标注、评测和编排成本更高 | 可解释训练、连续追问、质量回归 | 无 Rubric、无专家样本的开放闲聊 | 重复评分一致性和专家相关性达到门禁后使用 |
3.4 系统架构图
图:架构|AI 面试教练组件职责与治理边界
替代文本: 会话 API 把请求交给 TP-01 状态机,状态机编排能力图谱、回答分析、TP-02 RAG、TP-03 Rubric 与受控 Agent,最终把轮次状态和证据写入存储;评测、权限和观测作为横向治理能力覆盖链路。
图表加载中…
读图结论: LLM 和 Agent 是可替换能力组件,确定性状态机、Rubric、证据存储、权限和评测共同守住业务结果。
图中每个生成组件只能在状态机分配的输入、动作和预算边界内工作;最终状态和分数必须由可审计服务提交。
3.5 端到端调用链
图:技术调用流程|一次回答从提交到下一轮追问
图表加载中…
替代文本: 用户回答先经过轮次与版本校验,再进入分析、知识检索、Rubric 评分和受控追问;成功时状态机事务保存并返回下一轮,旧轮次、依赖超时或结果不可验证时记录冲突/检查点,并返回同一 Run 的降级或恢复入口,避免重复创建轮次。
读图结论: 追问由 Agent 动态决定,但评分、预算、状态和终止由确定性服务掌握。
图中回答分析器负责抽取缺口,RAG 提供可追溯证据,追问 Agent 只给出候选动作;真正提交状态变更的是状态机,并在事务保存成功后才向用户返回下一题或复盘结果。
3.6 状态机
图 2:面试会话从创建、追问到中断恢复和终止的生命周期
替代文本: 会话从创建、配置、提问、等待回答、分析、评分进入下一步决策;决策可继续提问、解释缺口或正常结束。任一非终态都可暂停、等待外部输入、进入可重试失败、不可恢复失败或取消,其中恢复和重试分别回到持久化的原状态或检查点。
图表加载中…
读图结论: 正常面试路径可以动态循环,但暂停、外部输入、失败、重试和取消都必须通过显式状态迁移;只有 FINISHED、FAILED_FINAL、CANCELLED 能结束生命周期。
图中的 任一非终态(图示汇总) 不是数据库中的真实枚举,而是把所有可中断工作状态的公共迁移集中展示。PAUSED 和 WAITING_FOR_INPUT 依赖 resume_state 回到被打断的位置,FAILED_RETRYABLE 依赖 checkpoint_state 从安全检查点重跑;不可恢复失败与主动取消则直接进入终态,不能原地恢复。
resume_state 和 checkpoint_state 必须随事件持久化,不能由模型自由填写。FINISHED、FAILED_FINAL、CANCELLED 是终态;恢复失败时要重新打开会话或创建新会话。
| 当前状态 | 允许的外部命令 | 关键校验 | 下一状态 |
|---|---|---|---|
CONFIGURING | SAVE_CONFIG | 岗位、主题、预算合法 | ASKING |
WAITING_FOR_ANSWER | SUBMIT_ANSWER | 当前 round、session version、轮次唯一 | ANALYZING |
PAUSED | RESUME | 操作者与会话一致,resume_state 可恢复 | resume_state |
WAITING_FOR_INPUT | PROVIDE_INPUT | 输入类型和请求 ID 匹配 | resume_state |
FAILED_RETRYABLE | RETRY | 错误可重试、预算未耗尽、检查点存在 | checkpoint_state |
| 任一非终态 | PAUSE / CANCEL | 权限与当前版本 | PAUSED / CANCELLED |
其他状态收到旧答案或不允许命令时返回冲突,不靠 Prompt 猜测是否接受。每次迁移携带 version 和事件唯一键,拒绝旧请求覆盖新轮次。
3.7 上下游依赖
- 上游:身份、岗位配置、用户授权和知识库;
- 下游:模型供应商、向量/关键词索引、报告服务和通知;
- 横向:模型网关、预算、缓存、Trace、审计和评测集;
- 降级:固定题库、规则评分、延迟生成完整复盘。
4. 核心技术方案
4.1 能力图谱与题目模型
每道题不是孤立字符串,至少包含:
topic_id、难度和岗位适用范围;- 前置知识和可追问能力点;
- 合格答案要点、加分项和常见错误;
- 可引用的一手知识来源;
- 最大追问深度和结束条件;
- 题目、Rubric 和 Prompt 版本。
能力图谱用于保证覆盖和难度递进,避免模型只围绕熟悉词语随机出题。
4.2 回答分析 Schema
json
{
"claims": [{"text": "...", "status": "correct|wrong|uncertain"}],
"covered_points": ["..."],
"missing_points": ["..."],
"project_evidence": [{"quote": "...", "strength": "weak|medium|strong"}],
"ambiguities": ["..."],
"suggested_followup_capability": "...",
"citations": [{"document_id": "...", "version": "..."}]
}所有字段需要 Schema 校验。uncertain 不能被悄悄转成错误或正确,必要时通过追问确认。
4.3 RAG 方案
检索 Query 由当前题目、目标能力和回答中的关键 Claim 共同构成,而不是直接使用整段回答。过滤条件包括主题、文档状态、岗位、语言和权限。返回结果经过重排,并保留原文片段、来源和版本。
检索失败时:
- 不以模型记忆替代事实来源;
- 将事实评分标记为证据不足;
- 可以继续考察表达结构或请求澄清;
- 把空召回记录到评测样本。
4.4 评分模型
五个维度各 0-5 分,但分数不是单一模型直觉。完整 0~5 锚点以 AI 面试冲刺题库与复盘的五维评分 为单一事实源,QuestionVersion 保存所用 rubric_version。每个维度包含:
text
score = rubric_level(answer_evidence, expected_points, error_severity)若第
默认等权只是初始配置;权重、阈值和 Rubric 必须共同版本化。严重错误使用硬门禁,不能被其他维度平均掩盖:核心事实反向时 accuracy 不高于 1;虚构项目贡献时 project 为 0 且禁止标记 mastered;建议直接执行越权或重复副作用时 engineering 不高于 1。门禁命中、证据不足和 Judge 不一致都要进入人工复核。
评分输出必须包含:
- 引用用户回答的原句;
- 对应 Rubric 等级;
- 评分理由和命中的严重错误门禁;
- 未覆盖的关键点;
- 严重错误和不确定项;
- 如何提升到下一级,以及下一次复测动作。
最终分数必须连同 rubric_version、weight_version、证据和门禁结果保存,才能重放和解释。
4.5 Agent 决策空间
追问 Agent 只能从有限动作中选择:
ASK_FOLLOWUP(capability_id);ASK_CLARIFICATION(reason);GIVE_HINT(level);EXPLAIN_GAP(point_ids);MOVE_TO_NEXT_TOPIC(topic_id);FINISH(reason)。
状态机检查问题是否重复、主题是否允许、预算是否足够以及是否触发结束条件。模型不能自行修改分数、用户权限或最大轮次。
4.6 状态与数据模型
| 实体 | 关键字段 | 一致性要求 |
|---|---|---|
InterviewSession | user、role、level、state、resume/checkpoint_state、version | 乐观锁更新 |
Round | question、answer_hash、analysis、score、revision、analysis_status、worker/lease/attempt | (session_id, round_id) 唯一;分析任务原子认领;修改走显式 revision |
QuestionVersion | topic、rubric_version、prompt、sources | 不可变版本 |
RubricVersion | 0~5 锚点、权重版本、严重错误门禁 | 可重放、不可原地覆盖 |
Evidence | answer span、document span、source | 可追溯 |
Weakness | capability、confidence、first/last seen | 用户隔离与 TTL |
AgentRun | model、tools、steps、termination | 可审计、可恢复 |
EvalCase | input、expected、labels、versions | 固定回归 |
OutboxEvent | event_id、round_id、type、published_at | 与业务事务原子写入、至少一次投递 |
4.7 最小伪代码
python
def accept_answer(session_id, round_id, answer, expected_version):
answer_hash = stable_hash(answer)
with transaction() as tx:
session = tx.lock_session(session_id)
existing = tx.find_round(session_id, round_id)
if existing:
if existing.answer_hash != answer_hash:
raise Conflict("round already has a different answer; create revision")
return existing # 完全相同的重放
require(
session.state == "WAITING_FOR_ANSWER"
and session.current_round_id == round_id
and session.version == expected_version
)
round_record = tx.insert_round_unique(
session_id=session_id,
round_id=round_id,
answer=answer,
answer_hash=answer_hash,
status="ANALYSIS_PENDING",
)
tx.transition_session(session, "ANALYZING", expected_version)
tx.insert_outbox_unique("ROUND_ANALYSIS_REQUESTED", round_record.id)
return round_record
def analyze_round(round_id, worker_id):
# ANALYSIS_PENDING/RETRYABLE -> RUNNING 使用条件更新原子认领。
claim = claim_round_for_analysis(
round_id=round_id,
worker_id=worker_id,
lease_seconds=300,
)
if claim is None:
return # 已被其他有效租约认领或已经完成
# 慢调用在事务和数据库锁之外执行;长调用期间续租。
snapshot = claim.immutable_snapshot
question = load_immutable_question(snapshot.question_version_id)
try:
analysis = analyze_answer(question, snapshot.answer)
evidence = retrieve_evidence(question, analysis.claims)
score = grade_with_rubric(
question.rubric_version, snapshot.answer, analysis, evidence
)
action = enforce_policy(
snapshot.session_state,
decide_next_action(snapshot, analysis, score),
)
except Exception as error:
mark_retryable_if_lease_owner(round_id, claim.lease_token, error)
raise
with transaction() as tx:
# 只有仍持有有效租约的 Worker 能提交同一个分析版本。
completed = tx.complete_round_once_if_lease_owner(
round_id,
claim.lease_token,
analysis,
evidence,
score,
action,
)
if not completed:
raise LeaseLost("analysis lease expired or ownership changed")
advanced = tx.advance_session_if_current(
snapshot.session_id,
snapshot.session_version_after_accept,
action,
)
if not advanced:
raise Conflict("session version changed; rollback round completion")接收答案的短事务只做状态校验、(session_id, round_id) 唯一占位、版本迁移和 Outbox 写入;相同轮次只有一个主答案,重复 Payload 返回已有结果,不同 Payload 返回冲突,修改必须走显式 revision。
Outbox 是至少一次投递,所以 Worker 在任何模型调用前必须把 ANALYSIS_PENDING/RETRYABLE -> RUNNING 与 worker_id、lease_until、attempt 条件更新为原子认领。有效租约避免两个 Worker 并发产生模型费用;长任务定期续租,过期后由看门狗在核对现有调用状态后回收,并受最大 attempt/预算限制。提交阶段必须在同一数据库事务中完成“验证租约 → 完成 Round → 推进 Session”;丢失租约时抛错并回滚整笔事务,绝不能继续推进旧 Action。对支持幂等请求键或结果查询的模型供应商复用稳定调用 ID;供应商不支持时,进程在响应落库前崩溃仍可能产生重复费用,必须记录为残余的至少一次边界,不能宣称 exactly-once。
5. 关键权衡
| 决策 | 选择 | 备选方案 | 原因 | 代价与风险 |
|---|---|---|---|---|
| 外层控制 | 状态机 | 完全自由 Agent | 保证一次一题、预算和恢复 | 需维护状态与动作协议 |
| 评分 | Rubric + 证据 | 模型直接给总分 | 可解释、可评测 | Rubric 建设成本 |
| 题目来源 | 题库 + 动态变体 | 完全临时生成 | 覆盖稳定且可追溯 | 题库维护与版本 |
| 知识来源 | RAG + 一手资料 | 仅模型参数知识 | 降低事实漂移 | 检索失败和索引治理 |
| 对话历史 | 结构化状态 + 摘要 | 全量消息回放 | 控制 Token 与噪声 | 摘要可能丢信息 |
| 多 Agent | 初期单 Agent + 工具 | 多专家 Handoff | 降低协调复杂度 | 单 Agent 提示更复杂 |
5.1 性能与成本
- 轻量模型完成结构抽取,复杂评分或追问按需升级;
- RAG 只在事实判断需要证据时执行;
- 题目和 Rubric 缓存按版本复用;
- 完整报告异步生成,不阻塞下一题;
- 每会话设置 Token、轮次、工具和费用预算;
- 记录每阶段成本,不能只看模型总账单。
5.2 安全、权限与隐私
- 用户答案和项目经历按租户与用户隔离;
- 检索文档是外部数据,不能覆盖系统规则;
- Trace 默认不保存不必要的敏感原文;
- 长期薄弱点记忆需用户可见、可删除;
- 导出和分享报告使用短期签名与明确授权;
- 管理员查看训练数据需要独立审计。
5.3 可维护性
- 模型、Prompt、题目、Rubric、文档和索引分别版本化;
- 业务状态使用内部枚举,不复制供应商状态;
- 模型响应通过适配层归一化;
- 新岗位通过能力图谱和 Rubric 扩展,不复制整套流程;
- 失败样本进入回归集,防止修复只停留在 Prompt 热补丁。
5.4 技术难点清单
| 技术难点 | 为什么难 | 核心矛盾 | 可落地抓手 |
|---|---|---|---|
| 评分正确、稳定与可解释同时成立 | 自然语言答案允许多种正确表达,模型评分又会随上下文、随机性和版本变化 | 语义判断需要模型弹性,用户申诉与产品验收需要确定性证据 | 版本化 Rubric、答案原文 Span、知识证据、严重错误门禁、重复评分与人工一致性评测 |
| 动态追问与面试流程控制 | 高质量追问必须承接上一轮缺口,但自由 Agent 容易重复、越级、泄露答案或无法结束 | 个性化探索与一次一题、预算、覆盖和终止约束相互牵制 | 能力图谱、有限动作枚举、状态机校验、问题指纹、最大追问深度 |
| RAG 证据冲突与不可信输入 | 检索结果可能为空、过期、互相矛盾或包含间接 Prompt Injection | 需要外部知识核验事实,又不能让外部文本改变系统评分规则 | 来源白名单、权限与版本过滤、指令/数据隔离、引用 Schema、证据不足状态与人工复核 |
| 异步分析的一致性与重复费用 | 模型响应慢且不可放在长事务中;Worker 在响应落库前崩溃会留下结果不确定区间 | 数据库状态希望原子推进,外部模型调用无法参与本地事务 | 短事务占位、Outbox、租约认领与续租、稳定调用 ID、提交阶段所有权校验 |
| 长对话状态与可删除记忆 | 全量回放会增加噪声、延迟和成本,摘要又可能丢掉关键证据;长期记忆还涉及租户隔离和删除 | 个性化需要历史,评分重放与隐私要求又限制历史使用 | 原始 Round、结构化状态、阶段摘要分层保存;证据回指原文;记忆 TTL、作用域和删除审计 |
| 质量改进的因果归因 | 模型、Prompt、题库、Rubric、语料和索引可能同时变化 | 指标变化容易被误归因,回滚时也无法定位责任版本 | 固定 EvalCase、全链路版本快照、单变量灰度、影子评测和失败样本回归 |
5.5 方案亮点的证据化表达
以下亮点仍是待实现、待验证的设计主张。面试表达应同时给出验证材料;没有代码、测试、Trace 或评测结果时,只能说“设计了验证方案”,不能说“已经解决”。
| 问题 | 关键决策 | 证据或验证方式 | 适用边界 |
|---|---|---|---|
| 自由 Agent 容易破坏一次一题和结束条件 | 外层由状态机掌握状态、预算和终止,Agent 只从有限动作空间建议下一步 | 重放重复题、越权改分、多问一题和超预算动作,核对策略层拒绝记录与状态不变 | 开放式陪练可放宽动作,但计分面试、考试或高影响反馈仍需确定性控制 |
| 总分看似合理却无法解释 | 分数必须绑定回答 Span、Rubric 等级、知识来源、版本和门禁命中 | 对每个分数执行证据完整性检查;用同一答案重复评分并与人工区间比较 | 主观表达维度无法完全变成客观事实,仍需置信度、申诉和人工复核 |
| Worker 重试可能重复调用模型并推进两轮 | 接收答案、异步分析和状态提交分段;使用 Outbox、租约所有权与乐观锁控制提交 | 注入重复消息、租约过期、响应后崩溃和并发提交,核对调用 ID、Round 唯一约束与 Session 版本 | 供应商不支持幂等或查询时,仍可能产生重复费用,不能承诺端到端 exactly-once |
| RAG 不可用时系统容易编造事实判断 | 将“证据不足”作为显式结果,只继续结构评分或请求澄清,不用模型记忆冒充来源 | 注入空召回、过期索引和冲突文档,核对事实分数降级、引用为空和用户提示 | 结构、沟通等不依赖外部事实的维度可继续评估,但不能借此判定技术 Claim 正误 |
| Prompt 热修复容易反复引入旧问题 | 将失败 Round 连同输入、期望、证据和版本固化为 EvalCase,发布前影子回放 | 对模型、Prompt、Rubric 或索引变更运行固定回归并比较分项差异 | EvalCase 只能覆盖已知分布,仍需持续采样新岗位、口语和恶意输入 |
6. 实现难点与故障处理
6.1 问题矩阵
| 现象 | 根因 | 解决 | 验证 |
|---|---|---|---|
| 追问与上一回答无关 | Agent 只看到摘要、缺口 Schema 为空 | 保存证据片段;动作绑定 capability | 人工标注追问相关集 |
| 重复问相似问题 | 无问题指纹和覆盖状态 | 语义去重、能力覆盖图、最大深度 | 长会话回归 |
| 同一答案分数变化大 | Rubric 模糊、随机性、证据不同 | 固定 Rubric、低随机性、版本和示例锚点 | 重复评分方差 |
| 错误答案获高分 | 只评价表达,不核对事实 | RAG 证据、严重错误门槛、反例集 | 错误样本召回测试 |
| 检索内容操纵评分 | 间接 Prompt Injection | 指令/数据隔离、来源白名单、结构化引用 | 恶意文档红队集 |
| 上下文越来越慢 | 全量对话和工具结果回放 | 结构化状态、阶段摘要、按需原文 | 长度与延迟曲线 |
| 提交后一直处理中 | 状态只在 Worker 内存 | 事件、检查点、看门狗、可重试状态 | Worker 重启测试 |
| 同一回答生成两轮 | 客户端重试无幂等 | 轮次版本 + answer hash 唯一约束 | 重放请求测试 |
| 用户间记忆串线 | 查询缺少 tenant/user 过滤 | 强制作用域、行级权限、审计 | 跨用户渗透测试 |
| 模型不可用导致面试中断 | 无降级路径 | 固定题库、规则反馈、异步复盘 | 故障注入和切换测试 |
6.2 排查顺序
- 查询
session_id当前状态、版本和最近事件; - 确认问题版本、回答哈希和本轮是否已提交;
- 查看回答分析、检索证据、Rubric 和 Agent 动作;
- 区分模型失败、检索失败、状态冲突和客户端重复;
- 检查 Prompt/模型/索引/Rubric 版本是否发生变化;
- 将可复现失败加入固定评测集,再修复和回归。
6.3 超时、重试与降级
- 回答分析超时:使用规则抽取或请求稍后重试;
- RAG 超时:标记证据不足,继续结构评分;
- 评分失败:不伪造分数,保存本轮并异步补评;
- Agent 决策失败:按能力图谱选择固定下一题;
- 报告生成失败:面试状态不回滚,只重试报告任务;
- 状态提交冲突:重新加载最新版本,禁止覆盖新轮次。
6.4 生产易发问题闭环
当前项目没有线上事故和实测报告,所以下表用于实现评审、故障演练和未来复盘。表中的“证据”是必须采集的定位材料,“根因”是常见候选而非已经发生的事实。
| 现象 | 影响 | 证据 | 根因 | 止损 | 修复 | 验证 | 预防 |
|---|---|---|---|---|---|---|---|
| 同一答案在发布后分数整体漂移 | 用户前后结果不可比,掌握度和复习计划被污染 | Answer hash、评分明细、证据 Span、模型/Prompt/Rubric/索引版本及发布批次 | 多个评分依赖同时升级,Rubric 锚点变化或检索证据集合变化 | 暂停新评分展示;切回上一版本;保留原结果并标记待复评,不直接覆盖历史分数 | 评分快照版本化,依赖单变量灰度;对必要样本创建显式 revision | 用冻结答案集做新旧版本盲评,比较分维度变化、严重错误门禁和人工区间 | 发布前影子评测;为漂移、门禁反转和证据变化设告警;禁止无版本热改 |
| 接口成功但追问无关、重复或突然跳级 | 会话仍可用但训练质量失败,用户无法暴露真实缺口 | Round Trace、回答分析 Schema、缺口列表、候选动作、问题指纹、能力覆盖状态 | 分析器漏抽取,摘要丢失证据,Agent 未绑定 capability 或去重只按字面 | 暂停动态追问,回退到固定题库或请求澄清;不让错误动作继续污染覆盖图 | 强制动作绑定缺口能力;语义去重;保存证据 Span;调整追问深度和终止规则 | 用标注的相关/重复/难度样本跑长会话回归,并人工检查动作链 | 单独监控追问相关率、重复率和回退率;失败 Round 自动进入评测候选池 |
| 一次提交产生两次分析费用或会话跳过一轮 | 增加成本,分数与下一题竞争写入,状态不可解释 | Outbox 消费记录、Worker/lease/attempt、供应商调用 ID、Round 唯一键、Session version | 至少一次消息重复投递、租约过短或丢失所有权后旧 Worker 仍提交 | 冻结该 Session 推进;撤销过期 Worker 提交权;保留唯一主 Round 并对账外部调用 | 原子认领与续租;提交时校验 lease token;Round 唯一约束和 Session 乐观锁放入同一事务 | 注入重复消息、长模型调用、租约过期和并发提交,确认只有所有者能完成与推进 | 监控单 Round 多调用和 lease lost;租约按长尾设置且受最大 attempt/预算约束 |
| RAG 返回内容却把错误答案判为正确 | 错误知识被强化,评分公信力和复习内容受损 | Query、召回与重排结果、document/version、引用 Span、门禁命中和评分 Prompt | 召回文档过期或冲突,评分器只看语义相似,检索文本注入系统指令 | 将该事实维度标记证据不可信并暂停发布分数;切换允许来源或交人工复核 | 来源与状态白名单、冲突检测、引用蕴含校验、指令/数据隔离和严重错误反例集 | 用过期、冲突、恶意和“表述相似但结论相反”的文档做红队回归 | 文档、索引和引用版本可追溯;监控来源分布、空召回、冲突与引用失配 |
| 暂停恢复后重复上一题或丢失当前答案 | 用户进度受损,旧请求可能覆盖新状态 | Session 事件序列、resume/checkpoint_state、current_round_id、客户端 expected_version、流式连接记录 | 只保存页面或模型上下文,状态与响应流不同步,恢复时未校验版本 | 停止接受该会话新答案;按持久化事件重建状态并向用户确认当前题 | 状态迁移事务化;响应携带 session/round/version;恢复只使用服务器检查点 | 在 ASKING、ANALYZING、SCORING 和流式中断点分别重启,验证恢复位置与幂等提交 | 定期执行会话恢复演练;对状态年龄、版本冲突和重复题告警 |
| 用户看到其他人的薄弱点、项目经历或报告片段 | 严重隐私与租户隔离事故 | tenant/user 查询条件、授权决策、缓存键、向量过滤、Trace 和导出审计 | 查询漏作用域、共享缓存键、索引元数据缺失或后台任务丢失身份上下文 | 立即关闭受影响查询/分享入口,撤销链接与缓存,保全审计并启动通知流程 | 在 Repo、缓存、RAG、对象存储和导出层统一强制租户作用域;后台任务携带不可伪造身份 | 跨租户渗透测试、缓存碰撞、异步任务和删除后检索回归 | 行级权限与策略测试进入 CI;敏感 Trace 最小化;对跨租户命中零容忍告警 |
6.5 可复用经验积累
| 可复用经验 | 适用信号 | 推荐做法 | 使用边界 |
|---|---|---|---|
| “接口成功”与“质量成功”必须分开观测 | 请求无报错但追问、评分或引用明显变差 | 技术成功率之外,单独记录相关性、重复、证据完整性、门禁和人工纠错 | 质量指标需要标注口径,不能只凭用户停留时长推断 |
| 模型输出是建议,不是业务事实或状态源 | LLM 能生成分数、动作、记忆和终止理由 | Schema 校验后交给策略层;权限、状态、预算和终止由代码决定 | 低风险文案生成可以更自由,但涉及分数、权限和副作用必须受控 |
| 评分链要能从结果反向追到原文和规则 | 用户申诉时只能看到一句“模型认为” | 保存 Answer Span、知识 Span、Rubric/权重/Prompt/模型版本和门禁结果 | 可追溯不等于结论必然正确,仍需人工复核和纠错 revision |
| 按至少一次语义设计外部调用 | 队列、网络和 Worker 都可能重试 | 业务唯一键、Outbox、原子认领、幂等提交、所有权校验与补偿 | 外部供应商无幂等时只能控制内部状态,不能消除所有重复费用 |
| 降级时要同时降低结论强度 | RAG 或评分器失败后仍想保持会话可用 | 可以继续固定题或结构反馈,但显式标记证据不足、延迟评分或转人工 | 不得用模型参数知识伪装成已检索的一手证据 |
| 长期记忆必须有完整生命周期 | 个性化数据不断累积且会进入后续 Prompt | 定义来源、用途、作用域、置信度、TTL、用户可见性、删除与审计 | 调试日志不是用户记忆;删除业务数据也要处理索引、缓存和备份策略 |
| 每次质量修复都要转化为评测资产 | 问题靠改 Prompt 暂时消失,升级后再次出现 | 将失败输入、期望能力、证据、版本和判定规则固化为 EvalCase | 回归集会老化,需抽样线上新分布并防止针对测试集过拟合 |
7. 评测、监控与验证
7.1 离线评测集
评测样本至少包含:
- 完全正确、部分正确、概念混淆和自信错误回答;
- 只会背定义但不会项目落地的回答;
- 项目完整但缺少原理的回答;
- 中英文混合、口语、代码和长回答;
- Prompt Injection、复制标准答案和无关内容;
- 同义表达、矛盾表达和主动承认不知道。
每个样本由人工标注覆盖点、严重错误、合理分数区间、推荐追问能力和证据。
7.2 核心指标
质量指标:
- 题目岗位匹配、追问相关、关键遗漏发现和严重错误识别;
- 分维度评分与人工评分的一致性;
- 同一答案重复评分稳定性;
- 引用正确、问题不重复和结束条件正确。
工程指标:
- TTFT、每轮端到端延迟和长尾;
- 模型、检索、评分和 Agent 各阶段成功率;
- 重试、状态冲突、恢复和降级次数;
- 单轮 Token、成本和上下文长度;
- 敏感数据和安全策略命中。
7.3 线上验证
- 先影子评测,不向用户展示新评分;
- 再小流量灰度,保留旧版本回滚;
- 对低置信度和高影响结果人工抽检;
- 将用户纠错与申诉关联到原始证据;
- 质量、延迟、成本和安全同时达标才扩大流量。
7.4 监控与 Trace
图 3:Round Trace 从输入快照到状态提交的证据与版本链
替代文本: 每轮以不可变输入快照开始,依次形成回答分析、检索证据、Rubric 评分、候选动作和策略校验,再以事务提交 Round、Session 与 Outbox;各阶段同时把模型、Prompt、题目、Rubric、文档、索引、策略和会话版本汇入同一条 Trace。
图表加载中…
读图结论: Round Trace 不能只记录调用顺序;它要把“基于什么输入和证据得到什么分数、选择什么动作、最终提交到哪个状态版本”连成可重放、可归因的证据链。
输入快照冻结本轮题目和答案身份,证据节点保留来源 Span 与文档/索引版本,评分节点绑定回答 Span、Rubric、门禁和模型版本,动作节点同时记录 Agent 建议与策略层裁决。只有状态事务提交成功后才形成新的 session_version 并输出响应;所有节点共享 trace_id、round_id 和版本快照,才能区分模型漂移、检索变化、规则变化与并发覆盖。
每个 Span 还应记录耗时、错误类型和非敏感摘要。原始回答是否进入 Trace 由数据策略控制;即使不保存原文,也应保留受控的哈希、Span 标识或脱敏摘要,避免可观测性破坏隐私边界。
8. 实施路线与复盘
8.1 第一阶段:固定题库与状态机
- 建立能力图谱、题目和 Rubric;
- 一次一题、暂停恢复和固定追问;
- 保存 Round 事件和评分证据;
- 不引入自由 Agent。
验收:状态稳定、题目可追溯、固定评分流程可回归。
8.2 第二阶段:RAG 与结构化评分
- 引入知识索引和权限过滤;
- 回答分析、事实核验和分维度评分;
- 建设人工标注评测集;
- 保存模型、Prompt、索引和 Rubric 版本。
验收:评分能引用证据,失败可归因到检索或评分。
8.3 第三阶段:动态追问 Agent
- 将动作限制为有限枚举;
- 增加重复检测、预算和终止;
- 动态调整难度和追问方向;
- 建立恶意输入和长对话回归。
验收:追问质量优于固定基线,且不破坏状态与安全边界。
8.4 第四阶段:报告与个性化
- 生成薄弱能力图和间隔复习;
- 用户可查看、修改和删除长期记忆;
- 建设岗位级评测、灰度和反馈闭环;
- 优化模型路由、缓存和异步报告成本。
8.5 当前未验证边界
- 尚无真实标注集和人工一致性基线;
- 尚无实际用户完成率、延迟和成本数据;
- 不应将规划中的模型、框架或指标写成既成事实;
- 实现后必须用测试、Trace、数据库状态和用户反馈更新本文。
9. 面试表达
9.1 30 秒项目介绍
我把 AI 面试教练设计成“确定性状态机 + RAG 证据 + 受控追问 Agent”。系统一次只问一道题,先结构化分析回答,再检索知识证据,用固定 Rubric 给出分维度评分,Agent 只能在有限动作中选择下一道追问。这样既保留动态追问能力,又能控制轮次、预算、重复、安全和恢复,并通过固定评测集验证评分与追问质量。
9.2 2~3 分钟完整表达
- 背景:固定题库没有动态追问,普通聊天模型评分又不稳定;
- 约束:一次一题、证据可追溯、长对话恢复、用户隔离和成本;
- 架构:会话 API、状态机、题库、分析器、RAG、评分器、Agent 和评测观测;
- 关键决策:外层固定 Workflow,Agent 只选择下一动作;
- 难点:评分漂移、重复追问、注入、上下文和幂等;
- 验证:人工标注集、重复评分、恶意样本、重启和重复请求;
- 演进:岗位图谱、个性化记忆、多模型路由和灰度评测。
9.3 个人贡献表达规则
实际实现后,只陈述自己真实完成的边界,例如状态机、RAG、评分评测或观测。使用代码、接口、测试、Trace 或数据作为证据,不把团队结果全部归为个人贡献。
10. 递进追问
- 为什么这个项目不能完全使用固定 Workflow?
- 为什么又不能让 Agent 自由控制整个流程?
- 如何证明分数稳定,而不是模型“看起来合理”?
- 检索正确但评分错误,调用链上如何定位?
- 服务在模型成功后、状态提交前崩溃,如何避免重复一轮?
- 如何防止知识库中的恶意文本改变评分规则?
- 如果并发扩大十倍,模型、检索、数据库和报告谁先成为瓶颈?
- 如果重新设计,哪些能力应先做确定性基线再引入 Agent?
11. 证据与关联文档
11.1 当前证据状态
- 当前只有项目设计文档和关联知识文档;
- 尚未创建代码、数据库迁移、测试、Trace 或实测报告;
- 因此
doc_status保持draft,不能声明项目已经完成。
11.2 关联文档
11.3 一手参考资料
以下资料于 2026-07-10 核对:
- OpenAI Agents SDK - Tools
- OpenAI Agents SDK - Guardrails
- OpenAI Agents SDK - Tracing
- OpenTelemetry Documentation
- OWASP Top 10 for LLM Applications 2025
12. 简明总结
一句话记忆: AI 面试教练用确定性状态机守住流程,用 RAG 提供证据,用受控 Agent 选择真正有价值的下一问。
- 一次一题、轮次、预算、评分和终止由代码控制;
- Agent 只在有限动作空间中根据回答缺口动态追问;
- 每个分数必须绑定 Rubric、用户回答证据和知识来源;
- 评分漂移、重复追问、注入和状态丢失都要进入固定回归集;
- 没有代码和实测证据前,本项目只能标记为设计草案。