让 AI 写状态机不出 bug 的操作流程!

strongerHuang 2026-10-24 08:00

嵌入式开发中,让 AI 辅助时,只要需求里出现状态两个字——通信协议解析、传感器采集流程、低功耗模式切换、BLE 连接管理、bootloader 流程——AI 就开始表演自由发挥。

生成的代码可能不太符合我们的预期:状态漏了、转移漏了、该报错的地方默默忽略。它跑起来像那么回事,出事在三个月后。

这次分享我们摸出来的四步做法:先表后码 → 穷举事件 → 表驱动 → 从表生成测试。文末有一段可以直接复制的提示词模板。

1. 先表后码:让 AI 先整理思路

不要一上来就让 AI 写代码。第一步永远是:

先不要写代码。把这个状态机的所有状态、所有事件、所有转移列成一张表,包括错误转移和异常处理。我确认之后你再实现。

为什么要这一步?

因为表格比代码好审 10 倍。审代码时,我们的注意力被语法、寄存器操作、边界条件分走了大半;审一张状态转移表时,我们只需要确认四个问题:

  1. 有没有漏掉的状态?
  2. 有没有漏掉的事件?
  3. 有没有漏掉的转移?
  4. 每个转移的目标状态和动作,对不对?

举个例子。一个低功耗传感器采集的状态机,需求里只说了"待机、采集、上传",AI 交上来的表大概长这样(→ 表示转移,— 表示显式忽略,! 表示非法事件,应记录并断言):

状态\事件
启动采集
采集完成
上传完成
总线错误
超时
IDLE
→ SAMP
—
—
!
—
SAMP
—
→ UPLD
—
→ ERROR
→ ERROR
UPLD
—
—
→ IDLE
→ ERROR
→ ERROR
ERROR
→ SAMP
—
—
!
—

表格确认了,代码只是表格的机械翻译。翻译这一步,AI 很擅长。

但先别急着确认。 这张表至少少了三样东西:

  • 动作:→ SAMP 的时候,要不要给传感器上电、清 FIFO?表驱动里,动作才是业务逻辑的落点。
  • 低功耗态和终态:掉电唤醒、低电量休眠走哪条路?错误一直重试,有没有尽头?
  • 错误恢复策略:ERROR 收到"启动采集"就直接回 SAMP,是自动重试还是等外部命令?重试几次放弃?

补齐之后就顺眼了:

状态\事件
启动采集
采集完成
上传完成
总线错误
超时
低电量
IDLE
→ SAMP
—
—
!
—
→ SLEEP
SAMP
—
→ UPLD
—
→ ERROR
→ ERROR
→ SLEEP
UPLD
—
—
→ IDLE
→ ERROR
→ ERROR
→ SLEEP
ERROR
→ SAMP *
—
—
!
—
→ SLEEP
SLEEP
→ IDLE
—
—
—
—
—

2. 穷举,不要举例

给 AI 举例子,它可能只会处理我们举的例子。

"采集流程有待机、采集、上传这几个状态"

如果我们这样描述,AI 大概率不会主动问我们:

  • 掉电唤醒算不算一个事件?

  • I2C NACK 之后是重试还是进错误态?

  • 低电量时是直接休眠还是先把手头的数据存进 Flash?

上一节那张表,最后就是被"低电量 → SLEEP"这种谁都没提过的事件补完整的。嵌入式场景下,要特别把这几类容易被 AI 遗忘的硬件事件写进提示词:

列出所有状态和所有事件。特别注意,事件来源包括但不限于:

  • 命令类:上位机命令、按键(含机械抖动、长按短按)、通信协议包;

  • 硬件类:总线错误(NACK、超时、CRC 错)、传感器异常、掉电/欠压检测(PVD)、复位(含看门狗复位);

  • 时间类:软件定时器超时、协议要求的应答超时、重试间隔;

  • 异步类:中断到达(数据就绪、DMA 完成)、其他任务/线程发来的消息。 每个状态遇到每个事件时的行为(转移 / 显式忽略 / 报错)必须定义,不允许留默认。

输出表格后自查一遍,把你拿不准、需要我确认的格子单独列出来。

最后那句"把拿不准的格子列出来"很关键:AI 的沉默不等于它没有疑问,它只是默认替你做了决定。

3. 表驱动

确认完表格,接下来怎么写代码?

很多人的直觉是让 AI 生成一个大 switch (state),里面嵌套 if (event == ...)。AI 写出来大概是这个样子:

让 AI 写状态机不出 bug 的操作流程!图1

能用,但这是状态机腐烂的开始——switch 分支散落在几个函数里,三个月后需求一变,改了东忘了西。更要命的是 AI 生成的 switch 经常只在部分 case 里更新状态,其余路径的状态保持旧值,这种 bug 审代码时极难发现。

正确姿势是表驱动(table-driven):转移表是数据,执行器是代码。

让 AI 写状态机不出 bug 的操作流程!图2
让 AI 写状态机不出 bug 的操作流程!图3
让 AI 写状态机不出 bug 的操作流程!图4

(三张图依次是转移表定义、动作函数、只查表的执行器。)

这套结构对嵌入式的额外好处:

  • const 转移表落进 .rodata,只要链接脚本把它指向 Flash,就不占 RAM(函数指针数组、状态变量、事件队列仍然占 RAM,别把这句话理解成"整套机制零开销")。
  • 加状态、加事件,只改表,不动执行器。
  • 表可以独立审查,甚至可以当作接口文档发给同事。

4. 从表生成测试,再让 AI 反向对表

第一,从表生成穷举测试。

让 AI 写状态机不出 bug 的操作流程!图5

好处是联动:表改了,测试跟着变,漏掉的格子立刻变红。

第二,让 AI 反向输出一张表来对。

这是最便宜、也最有效的一招:

读一遍你刚才实现的执行器和转移表,反向输出一张"状态 × 事件"表,格式与第一步完全一致。然后把它和第一步的表逐格 diff,逐条列出不一致的格子,先不要修改代码。

为什么有效?因为正向生成时,AI 顺着表格机械翻译;反向生成时,它必须真的去读代码。

5. 提示词模板

把上面几条串起来,就是这样一个完整的工作流提示词:

环境:____(裸机 / RTOS / 嵌入式 Linux)
我要在 MCU 上实现一个状态机,
请严格按以下步骤来,每一步完成后
停下来等我确认,不要跳步。

【第一步】只输出一张状态转移表,
不写代码。表头:状态 × 事件 →
目标状态 + 动作。要求穷举:
1. 所有状态,含错误态、低功耗态、终态;
2. 所有事件,至少包括:
   - 命令类:上位机命令、按键(含抖动、
     长按短按)、通信协议包;
   - 硬件类:总线错误(NACK / 超时 /
     CRC 错)、传感器异常、掉电欠压(PVD)、
     复位(含看门狗复位);
   - 时间类:软件定时器超时、协议应答
     超时、重试间隔;
   - 异步类:中断就绪(数据就绪 / DMA
     完成)、其他任务或线程发来的消息。
3. 每个 (state, event) 组合的行为:
   转移、显式忽略、或报错,不留默认。
4. 输出后自查一遍,把拿不准、
   需要我确认的格子单独列出来。

【第二步】等我确认表格后,
用 C 表驱动风格实现:
- 转移表用 const 二维数组(进 Flash),
  动作用函数指针;
- 执行器只查表,无业务判断;
- ISR 只往事件队列入队,状态修改
  只发生在唯一执行上下文,共享数据
  用临界区 / 原子操作保护;
- 禁止 malloc、禁止 C++ 异常,
  栈和队列全部静态分配。

【第三步】生成 PC 端可跑的穷举测试
(Unity / CppUTest):
- 每个状态 × 每个事件,
  断言结果与表一致;
- mock 所有 action,验证副作用;
- 覆盖事件队列的满 / 空边界。

【第四步】反向校验:
读一遍你写的实现,反向输出同样
格式的状态 × 事件表,与第一步的
表逐格 diff,列出所有不一致的格子,
先不要改代码。

(____ 处换成自己的运行环境;粘贴给 AI 时不用管这里的折行。)

6. 总结

AI 不会替我们把需求想清楚,但它非常擅长把想清楚的东西机械地翻译成代码和测试。我们要做的,是先把那张表逼出来。

------------ END ------------





关于科技区角:国内科技展会垂直内容策划服务商,提供从论坛内容全案策划、会展市场化IP打造到精准专业观众一站式邀约服务,以产业内容吸引高质量B端人群,打通展会从议题设计、演讲嘉宾邀约、宣传预热、精准邀观到供需对接全链路。
声明:内容取材于网络,仅代表作者观点,如有内容违规问题,请联系处理。
AI
more
王兴兴:物理AI已经看到被击穿的苗头;全世界对AI的信仰都不够
Kimi K3.1 Pro发布,超GPT-6杀回前4/首部「龙标」AI电影上映/国办:减缓人工智能应用就业替代影响
「恨不得卸载患者手机里的AI」,第一批大战AI的医生已经快疯了
OpenAI 紧急“断网”:前沿大模型因不可控风险被迫转入沙箱训练
赔麻了?首部国产 AI 院线电影上映!
PHP“后门”惊魂:两大漏洞险些瘫痪全球网络,AI助纣为虐还是技术预警?
中科创达发布滴水AIOS 3.0,汽车、机器人、AI眼镜都要「自主智能」
AI热潮下的冷思考:初创企业如何破解“伪增长”迷局,重获产品市场契合度
科大讯飞“1024”开发者节观察 以国产AI赋能千行百业
聚焦AI应用驱动新纪元|2026 WAIAC世界人工智能应用大会即将启幕
Copyright © 2025-成都区角科技有限公司
蜀ICP备2025143415号-1
  
川公网安备51015602001305号