多智能体面试调度中的状态机冲突:从代码审查到规则统一
在构建多智能体面试系统时,真正难处理的往往不是单个 Agent 的提示词,而是各阶段之间的状态契约。当转换规则、执行步骤和可视化状态图分别描述同一条流程时,任何一处漏改都会让执行器面对歧义。最近在审查 AI 面试天团项目时,就遇到了这样一个典型问题。
问题现象
Issue #375 指向 Skills/interview-orchestrator/SKILL.md 中三套互相冲突的描述:
- 状态转换规则规定,收到
CONTROL_RETURN后只能从CHAT_ACTIVE进入TECH_ACTIVE,随后依次进入HR_ACTIVE和ASSESSMENT_ACTIVE。 - 阶段执行步骤却在第 157、170、183 行先把状态重置为
IDLE:CHAT_ACTIVE -> IDLE、TECH_ACTIVE -> IDLE、HR_ACTIVE -> IDLE。 - 状态图又写成
CHAT_ACTIVE -> IDLE -> TECH_ACTIVE -> IDLE -> HR_ACTIVE -> IDLE -> ASSESSMENT_ACTIVE。
三条信息看起来都在描述同一个流程,实际上却定义了两套状态机。
为什么会影响执行
如果执行 Agent 严格按状态规则做前置校验,Phase 3、4、5 从 IDLE 启动时就会被判定为非法转换;如果它按步骤继续执行,又会绕过状态规则。更隐蔽的问题是,不同模型、不同上下文压缩或不同重试路径可能选择不同的解释方式,最终表现为流程偶发阻塞、阶段跳转异常,或者状态字段与实际进度不一致。
这类问题不适合靠“让 Agent 自己判断”解决。多智能体系统的可靠性应来自明确的数据契约和可验证的转换逻辑,而不是依赖模型对文档的语义猜测。
两种修复路径
方案 A:保留 IDLE
把 *_ACTIVE -> IDLE -> *_ACTIVE 明确定义为合法路径,并为 IDLE -> TECH_ACTIVE、IDLE -> HR_ACTIVE、IDLE -> ASSESSMENT_ACTIVE 补充前置条件。这种方式适合阶段间确实需要暂停、恢复或异步调度的场景。
方案 B:移除阶段间 IDLE
把主链路统一为 CHAT_ACTIVE -> TECH_ACTIVE -> HR_ACTIVE -> ASSESSMENT_ACTIVE,同时调整 Phase 3 至 Phase 5 的状态前置检查和状态图。如果阶段之间没有并发或恢复需求,这条路径更简单,也更容易验证。
无论选择哪一种,都应该让规则、步骤、状态图和代码使用同一份状态定义。
工程化建议
第一,建立单一来源的状态转换表。可以用一个结构化配置表达每条边的起点、事件、终点和守卫条件:
const transitions = {
CHAT_ACTIVE: { CONTROL_RETURN: "TECH_ACTIVE" },
TECH_ACTIVE: { TECH_COMPLETE: "HR_ACTIVE" },
HR_ACTIVE: { HR_COMPLETE: "ASSESSMENT_ACTIVE" },
ASSESSMENT_ACTIVE: { ASSESSMENT_COMPLETE: "COMPLETED" }
};
function transition(current, event) {
const next = transitions[current]?.[event];
if (!next) throw new Error("invalid transition: " + current + " + " + event);
return next;
}
第二,在状态写入前统一校验事件和前置条件,避免各 Agent 自己维护一套分支判断。第三,补充状态机单测,至少覆盖合法主链路、非法事件、重复事件和失败重试。第四,将状态图从转换表生成,或在 CI 中校验文档与代码是否一致。
结论
这次审查暴露的不是一个孤立的文档笔误,而是状态契约缺少单一来源的问题。对多智能体系统而言,清晰的提示词只是起点;把状态转换变成可执行、可校验、可测试的规则,才能让不同 Agent 在同一套流程上稳定协作。
- 点赞
- 收藏
- 关注作者
评论(0)