SemaPLC: A Project-Grounded, Verification-Gated Agent Harness for PLC Code Generation 精读
论文链接:https://arxiv.org/abs/2608.18565 代码仓库:https://github.com/midea-ai/SemaPLC 发表时间:2026年8月(arXiv 2608.18565v1,2026-08-19提交) 机构:美的AIRC(企业)+ KUKA(企业)+ 上海交通大学 + 浙江大学——典型的企业主导、企业与高校合作模式:企业贡献harness工程、工业场景与基准,高校参与研究。 热度:Hugging Face 每日论文榜当日 115 票,位列前茅,社区关注度相当高。
一、研究背景:让LLM写工厂控制代码,难在哪?
1.1 PLC是什么?为什么它很特殊
如果你用过家里的智能插座,你知道手机点一下就能通断电。现在把这个场景放大一万倍:一条汽车焊装线、一座自来水处理厂、一家炼油厂——里面成百上千台电机、阀门、传感器,全靠一种叫**可编程逻辑控制器(PLC)**的专用计算机在毫秒级循环里做决策。PLC是工业自动化的"大脑",跑在工厂产线、电厂和水厂里,一旦出错,轻则停产,重则设备损毁甚至安全事故。
PLC主要用 IEC 61131-3 标准定义的语言编程,其中结构化文本(Structured Text,ST)是 textual 成员——长得像 Pascal,但语义很不一样:它不是"跑一次就退出"的脚本,而是每个扫描周期(scan cycle)都从头到尾执行一遍的死循环。一个变量该跨周期保持还是每周期重算、一个定时器(TON)的时序怎么推进、两个互斥命令谁优先——这些"时间与状态"的语义,正是PLC代码与普通软件最大的差异。
1.2 LLM已经能写PLC了,但只写到一半
近两年的工作(LLM4PLC、AutoPLC、Agents4PLC等)证明了LLM能生成独立的程序组织单元(POU)——可以理解为PLC世界里的"单个函数/功能块"。编译器反馈修复、形式化属性检查、多智能体迭代、厂商IDE集成……这些技术路线都各自有效。
但论文一针见血地指出:生产环境里的控制逻辑很少是孤立POU。真实部署对生成的代码提出两个额外要求:
- 项目接地(Project Grounding):生成的逻辑必须嵌入一个成熟运转的既有项目——复用它的模块和功能块、尊重它的变量、类型与接口、遵守它的构建/复位/初始化/安全约定。就像你不能往一栋装修好的写字楼里随便砸一面墙,你得知道哪面是承重墙。
- 运行时行为正确:即使程序编译通过、静态检查通过,它仍可能配错一个定时器、走错一次状态转移、漏掉一次复位、破坏一个互锁、用错误的时序驱动输出。编译通过 ≠ 行为正确,这在PLC领域尤其致命。
1.3 核心痛点:“演示过"不等于"测量过”
论文用六个字概括领域现状:Demonstrated, not measured(演示过,没测过)。已有系统会执行生成的代码来"展示它能跑",而不是"测量它跑得多可靠"。基准任务以独立POU为主,项目集成与运行时行为的报告大多停留在少量案例。于是没有人能回答一个跨方法、跨模型的统一问题:生成的逻辑到底有多可靠地满足上面两个部署要求?
这篇论文用一个方法加一套测量来补上这个缺口:
- 方法:一个agent harness(智能体"挽具")——把生成锚定在目标项目里,并且在外部检查确认结果之前,不允许任务结束。
- 测量:在基准规模上,把集成编译、静态行为、动态行为三层分开打分,让每一层的失败都无处藏身。
二、核心思想:把"我觉得写完了"改成"日志证明写完了"
2.1 什么是Harness?为什么关键不是工具
“Harness"直译是马具/挽具——套在马(LLM)身上、约束它往正确方向走的那套装备。SemaPLC的作者在结论区说得很直白:它的新颖性不在工具集,而在支配工具的完成纪律(completion discipline)。
打个比方:普通LLM写代码像实习生说"我写完了,应该没问题”;带自我检查的agent像实习生自查一遍后说"我检查过了";而SemaPLC像一套强制流程——你必须把代码交给三个独立部门(规格审计、编译器、运行测试台)签字盖章,签字记录存档且与你交付的每一行字节对得上,才算完工。模型自己说"pass"不算数。
2.2 三大设计原则
SemaPLC的harness由三条原则撑起:
| 原则 | 解决什么问题 | 一句话理解 |
|---|---|---|
| 项目接地生成 | 逻辑写出来融不进既有工程 | 先读项目树、接口目录、I/O表,再动笔 |
| 多源验证 | 单一检查(如编译)看不出行为错误 | 规格审计 + 编译 + 活运行时验证,三路证据并列 |
| 验证门控迭代 | 模型自我感觉良好就提前交付 | 外部检查不全过,不许结束;失败必须修或如实报失败 |
2.3 完成纪律三条不变量:本文最硬核的贡献
这是全文我最想划重点的部分。验证门(Verification Gate)由三条不变量统治:
- Earned Claims(挣来的声明):只有日志确认的检查才可判定完成。每个检查结果是一个机器可读的哨兵值,与工具调用日志交叉验证——没有日志支撑的"通过"一律降级为"未检查"。模型谎报或幻觉出的pass直接作废。
- Edit Invalidation(编辑失效):任何一次编辑都使旧判定全部失效,所有检查必须重跑。判定附着在精确的字节上——你改了一个字符,之前编译通过、运行正确的结论就全部清零。这堵死了"改了最后一版但没重新测"的经典漏洞。
- Bounded Retries(有界重试):每个检查最多 r=2 轮修复,防止agent在同一个坑里无限打转烧预算。
三条合起来给出一个交付完整性保证(delivery-integrity guarantee):交付的程序与挣得每一项pass的那份候选字节完全一致,且没有任何自报的pass能在没有工具日志的情况下幸存。这就是"验证门控"与"验证增强"的本质区别——后者把检查当加分项,前者把检查当放行的闸门。
三、方法详解:SemaPLC的五个组件如何协作
3.1 整体架构
SemaPLC跑在一个通用的event-driven工具调用核心上(ReAct式),核心本身不含任何PLC专属逻辑。在此之上,harness组织五个组件(对应论文Figure 1):
控制需求 R + 任务上下文 X(POU接口 或 既有项目)
│
▼
┌─────────────────────────────────────┐
│ Project/Task Grounding(接地) │ ← 项目树、FB接口、I/O摘要、约定
│ PLC Skill Library(技能库) │ ← IEC规范、FB模式、定时器/互锁实践
│ Agent Core(规划/生成/编辑/解读) │
│ │ 通过共享 PLC MCP 工具层 │
│ ▼ │
│ 多源验证:SPEC / BUILD / RUN │
│ │ │
│ Verification Gate(验证门)────────┼──→ 全过 → Accept
│ │ │
└───────────┴──→ 失败 → 诊断反馈 → 修复循环
所有组件通过一个单一工具服务器操作环境:既暴露为 MCP(Model Context Protocol)stdio 服务器供agent工具调用,也提供等价的命令行接口供程序化技能脚本使用。工具覆盖语法检查、编译、部署、运行时状态与日志、活变量读取与强制、轨迹采样、脚本化行为检查,共16个MCP工具(如plc_compile、plc_forceVariables、plc_trace、plc_verifyBehavior等)。
3.2 项目接地:先读懂工程,再写代码
在项目轨上,agent先检索项目结构、定位相关模块,然后复用既有变量和功能块、不重定义既有接口、在有界范围内编辑——保持项目约定,而不是重新生成整个项目。接地步骤输出"接地上下文Γ",生成就在Γ上进行。
一个值得借鉴的设计:领域知识放文档而非代码。规则文件说明验证顺序、工具用法、扫描周期语义;策展wiki记录功能块签名、控制模式、编译器陷阱(由PLC工程师从工程实践中蒸馏);过程性技能把多步检查脚本化。这些工件编码通用的IEC 61131-3与验证器语义,不含任何基准答案。
3.3 三源验证:每一路抓不同的bug
| 验证源 | 检查内容 | 抓什么bug |
|---|---|---|
| 规格审计(SPEC) | 逐条对照自然语言需求:每个命名设备/信号/发布变量、阈值与边界、互锁/互斥/优先级、扫描周期状态语义 | 编译器接受但需求禁止的缺陷 |
| 编译(BUILD) | 语法、类型、符号、接口、集成构建;返回源码行号、错误类别、诊断 | 结构性缺陷 |
| 活运行时验证(RUN) | 构建→部署→初始化→注入场景输入→采样外部变量,与运行时断言或金轨迹比对 | 定时器/复位行为、状态演化、互锁、时序输出 |
两个细节很见功力:
- 反馈只给第一条诊断——修复保持局部,避免级联重写把好代码改坏。
- 失败阶段即修复定位:轨迹全平→接线问题;轨迹在变但值错→功能块逻辑;转换太晚→定时器或边沿检测器。这相当于把"运行时调试经验"编码成了修复启发式。
评测隔离也做得干净:agent运行时验证用的场景是自己从任务规格推导的,而打分场景与金轨迹从隐藏参考实现独立推导、从不暴露。两组场景只能通过共同的需求对齐,不可能通过接触打分工件对齐。
3.4 交付门:测试副本与交付文件防漂移
附录里还有个精巧设计:运行时验证操作的是"注入测试副本",交付文件保持原样——但两者可能漂移(比如测试副本里塞了注入用的地址)。交付门要求三个条件才放行:交付文件不含定位地址字面量;交付字节与最后一次成功编译(其输入清单包含该文件)的内容哈希一致;会话日志携带部署与强制输入证据。这正是编辑失效与挣来声明两条不变量在工程上的落地。
四、实验设置:两条互补的赛道,七个模型
4.1 Function Track(功能轨):117个独立POU任务
来自Agents4PLC基准。值得称道的是:作者发现其发布的oracle存在缺陷(验证属性错误、任务描述会冤枉正确实现),于是让PLC工程师审计并修复了117个任务中的43个(附录A详述三轮审计:独立并行标记→暴力真值表/逐步仿真重推→盲审裁决,仅至少两轮确认的缺陷才修,无根据的属性直接删除而非编造阈值),所有方法在相同的修复数据上评测。修复基准本身就是对社区的一份额外贡献。
指标是严格VerifiedPass:held-out judge(任何方法都不得查询)编译候选并用PLCverif(nuXmv后端)对需求导出的属性做模型检查,属性满足比例≥0.80才算过;inconclusive(不支持/翻译失败/超时)计为失败,生成失败留在分母。
4.2 Project Track(项目轨):65个真实工厂任务
来自Spec2Control的十座工业工厂(含焦化炼油厂等),转换为IEC 61131-3 ST项目。每个任务针对一个工段:给定工段叙述、功能块接口目录与库、空入口harness,生成的逻辑必须在完整项目内编译并部署。参考实现、运行时轨迹、原始答案全部隐藏,泄露审计未发现逐字复制。
三层指标(同一65任务分母,逐层独立报告,不丢任何任务):
- 集成编译C:集成程序能否通过RuSTy二值构建;
- 静态行为S(0-100):对程序文本确定性检查断言(子串存在/缺失、必需调用、归一化数值常量、结构引用、任选集);
- 动态行为D(0-100):金轨迹差分——候选与参考在相同harness、活运行时上、最多6个场景下运行,按核心输出端口轨迹一致比例打分;任何一方的编译/部署/超时/缺轨迹失败计0分。
4.3 七个模型、四个对手
- 模型:MiniMax-M2.7、MiniMax-M3、Qwen3.5-Plus、DeepSeek-V4-Flash、DeepSeek-V4-Pro、GLM-5.2、GPT-5.5——五家厂商、两个能力档,所有方法调用相同端点。
- 基线:LLM4PLC、AutoPLC(原框架运行)、Agents4PLC(忠实重实现,自产属性、judge属性保持隐藏),各自按发表预算跑。
- bare:同一个循环剥掉harness(无技能无工具),量化harness本身的贡献。
五、结果一:功能轨全模型登顶,且弱模型受益最大
5.1 主表:七列第一
| 模型 | LLM4PLC | AutoPLC | Agents4PLC | bare | SemaPLC |
|---|---|---|---|---|---|
| MiniMax-M2.7 | 22.2 | 49.6 | 53.8 | 39.3 | 69.2 |
| MiniMax-M3 | 15.4 | 65.0 | 55.6 | 60.7 | 69.2 |
| Qwen3.5-Plus | 13.7 | 67.5 | 67.5 | 62.4 | 75.2 |
| DS-V4-Flash | 41.0 | 54.7 | 54.7 | 34.2 | 67.5 |
| DS-V4-Pro | 43.6 | 61.5 | 62.4 | 55.6 | 69.2 |
| GLM-5.2 | 30.8 | 59.0 | 74.4 | 63.2 | 76.1 |
| GPT-5.5 | 44.4 | 79.5 | 78.6 | 71.8 | 82.1 |
| 均值 | 30.2 | 62.4 | 63.9 | 55.3 | 72.6 |
| 最差 | 13.7 | 49.6 | 53.8 | 34.2 | 67.5 |
三个层次的解读:
- 对最强基线:均值72.6% vs Agents4PLC的63.9%,+8.8pp;对GPT-5.5也赢了最强模型(82.1 vs 79.5)。
- 对bare(去harness):均值+17.3pp(55.3→72.6);每个模型都涨8.5~33.3pp,且弱模型涨得最猛——MiniMax-M2.7 +29.9、DeepSeek-V4-Flash +33.3;跨模型离散度从37.6pp缩到14.6pp;bare编译率均值85.5%→99.2%。这说明harness是模型无关的可靠性层,而不是为某个骨干调的prompt。
- 稳定性的意义:SemaPLC的最差模型(67.5%)高于所有基线的均值;基线分数带宽25~31pp,SemaPLC仅14.6pp。工业落地最怕的不是峰值不够高,而是下限不可控。
为什么赢?作者归因于停止条件的差异:基线在编译器满足、至多加上自派生属性满足后就交付;SemaPLC还要对照规格审计、并在活运行时上验证——需求偏差与语义错误在循环内被修掉,而不是被交付。因为这些检查在模型外部,弱骨干损失更少。
六、结果二:项目轨——动态行为才是照妖镜
6.1 三层分数:编译与静态尚可接近,动态天差地别
| 指标(均值) | LLM4PLC | AutoPLC | Agents4PLC | SemaPLC |
|---|---|---|---|---|
| 集成编译 | 58.7 | 81.5 | 71.2 | 89.4 |
| 静态行为 | 75.7 | 74.0 | 71.7 | 81.6 |
| 动态行为 | 22.4 | 31.4 | 30.3 | 52.2 |
关键观察分三层:
- 集成编译:SemaPLC平均89.4 vs 基线58.7~81.5。接地机制让生成从项目既有接口、声明与约定出发,逻辑天然"合身"。
- 静态行为:SemaPLC在七个模型中五个第一,均值81.6 vs 71.7~75.7——领先存在,但三家基线彼此只差4.0分。
- 动态行为:这是分水岭。SemaPLC均值52.2,七个模型全第一,最差也有31.3;基线均值最高才31.4(AutoPLC),最差模型掉到个位数(LLM4PLC 3.0、AutoPLC 4.0、Agents4PLC 4.5)。
6.2 全文最重要的发现:静态分相近,动态分剧烈分层
把上一节两个观察拼起来,就是论文的核心经验发现:
各方法静态分彼此相差不超过10分(基线71.7~75.7),动态分却从22.4散布到31.4(基线)再到52.2(SemaPLC)。静态评分把方法压缩在一起,运行时层把它们分开——甚至会重新排序。
一个在停止前不执行逻辑的评测,无法把可靠方法与不可靠方法区分开。**执行,而非静态打分,才是生成控制逻辑是否真正可用的忠实检验。**这个结论对整个LLM代码生成评测领域都有警示意义:你的基准如果只考到静态层面,你以为在挑方法,其实可能在抽签。
另一个佐证是SemaPLC的静态-动态落差最小:29.4分(81.6→52.2),基线为41.4~53.3。当然作者也诚实指出:两个分数测的是不同性质,落差不是逐点可靠性损失。即便最强方法,动态分也远低于静态分——运行时PLC生成远未解决。
还有一条诚实的观察:优势随模型变强而收窄。GPT-5.5上,SemaPLC对Agents4PLC动态只领先1.8分(65.4 vs 63.6),静态反而落后(84.1 vs 最高88.8)。动态增益是"模型自身不足处的可靠性补给",不是在前沿模型上恒定的固定加成。
6.3 层消融:因果链条钉死
在DeepSeek-V4-Flash上逐层加检查(项目轨,65任务):
| 累积验证层 | 编译 | 静态 | 动态 | tokens | 请求次数 |
|---|---|---|---|---|---|
| 仅生成 | 64.6 | 71.5 | 23.1 | 34k | 8.9 |
| +规格审计 | 70.8 | 74.0 | 30.3 | 60k | 14.6 |
| +编译 | 83.1 | 77.8 | 43.7 | 74k | 25.5 |
| +运行时(完整) | 84.6 | 78.0 | 54.1 | 129k | 47.8 |
动态分单调爬升:23.1 → 30.3 → 43.7 → 54.1;而静态分仅从71.5动到78.0。编译层贡献最大的单项动态增益(+13.4,因为建不起来的程序运行时直接计0),运行时层其次(+10.4,编译饱和后)。决定性的动态可靠性来自agent被门控的那些检查,而不是生成本身。
配套的Table 4把3590项"场景-端口"值检查按结局分解,非常精彩:结构性失败(未构建/端口缺失)从74.7%降到21.5%,完整harness只留3.3%未构建;这53个点的迁移拆成"新变正确"(23.1%→54.1%)与"新可测的错误值"(2.1%→24.4%)。错误值上升不是退化而是覆盖扩张的副产品——检查必须先能跑才可能错,而观测到的错值恰恰是运行时反馈能修的。残留错值集中在越限场景(17.3% vs 正常工况7.1%),那里正是正确行为最难的地方。
6.4 形式验证的覆盖盲区:为什么必须上运行时
Table 5统计了功能轨held-out形式化管线(PLCverif+nuXmv)在1293份交付程序上的结论覆盖:无REAL/定时器的程序结论率75.7%,带REAL的87.0%,而带TON定时器的32个程序、174条属性,结论率0%——全部落入不支持模式或翻译失败。定时器并非原则上不可验证,但跨扫描周期的有状态时序构造恰好落在该管线的结论覆盖之外,而这恰恰是运行时验证直接锻炼的东西。这就从机理上论证了:形式化与运行时验证是互补关系,不是替代关系。
七、案例研究与成本:一次"检测→修复→再验证"的完整解剖
7.1 焦化炼油厂案例:优先级bug只有运行时暴露得出来
论文Figure 2的案例(炼油厂"Section 8"任务)值得细品,需求是双条件竞争:
低流量(FT-701 < 50 kg/hr)⇒ SlaveSP = 500;变送器故障 ⇒ SlaveSP = 2500
四个方法四种死法:
| 方法 | 结局 | 原因 |
|---|---|---|
| LLM4PLC | ✗ 编译失败 | E007:VAR块前缺分号 |
| AutoPLC | ✗ 编译失败 | E048:未解析引用 PT_701_High_Alarm |
| Agents4PLC | ✓编译 ✗错误 | 两个独立IF都执行:故障先写2500,低流量IF又覆盖成500 |
| SemaPLC | ✓✓ 运行时验证通过 | 中间候选也编译通过但行为错→运行时暴露→按因修复→再验证 |
SemaPLC的中间候选用一个静态手动输出(2500)伺候两种工况——编译干净,缺陷藏在竞争条件下的输出选择里。运行时验证强制FT-701=30 kg/hr,期望500、实测2500,错配现形;失败阶段把修复定位到"按因选输出"而非重写逻辑;再验证确认两个异常工况都对。
这个案例是全文论点的微缩标本:语法与接口层检查对这类缺陷完全失明,只有活运行时的输入-轨迹比对能抓住它。
7.2 交互成本:可靠性是花钱买的
| 赛道 | 方法 | 请求/任务 | 时间/任务 |
|---|---|---|---|
| 功能轨 | Agents4PLC | 6.3 | 454s |
| 功能轨 | SemaPLC | 6.5 | 71s |
| 项目轨 | Agents4PLC | 6.9 | 344s |
| 项目轨 | SemaPLC | 34.1 | 347s |
- 功能轨:请求数相当(6.5 vs 6.3),增益不靠多请求;墙钟反而快6倍——因为Agents4PLC每轮都调PLCverif+nuXmv模型检查,而那主导了它的耗时。
- 项目轨:墙钟相当,但SemaPLC请求数是5倍(34.1 vs 6.9)——动态领先是用模型交互量付账的。差距是架构性的:Agents4PLC固定多智能体工作流,迭代有界,请求数几乎不随模型变(6.8
7.0);SemaPLC开放式循环里每次工具调用都是模型决策,门控让它一直交互到检查通过(16.460.4随骨干浮动)。
这个"可靠性 vs 交互成本"的坦白账,比只报分数的工作诚实得多。
八、讨论:局限、启示与结语
8.1 论文自述的两条局限
- 动态打分只测有界场景集:场景从隐藏参考导出,未见工况下的行为未被测量——分数衡量的是"基准场景上的行为",不是"对未见运行条件的泛化"。
- 最强模型上优势收窄:GPT-5.5上动态仅领先1.8分、静态还落后——验证门控的价值随模型能力提升而稀释。
我再补一条读者视角的观察:层消融是单模型(DeepSeek-V4-Flash)上的,跨模型是否同样单调,论文未验证;以及34.1请求/任务的开销在量产场景是否可接受,取决于工厂对"错一次"的代价容忍度——不过考虑到工业场景里错误的代价(停产、安全事故),这笔账大概率仍然划算。
8.2 对领域的三点启示
- 评测设计的启示:把编译、静态、动态分开报分,且动态用金轨迹差分——这套三层框架可直接迁移到其他"生成即部署"的领域(机器人控制、嵌入式、甚至DevOps的IaC生成)。如果只看静态分,Agents4PLC(71.7)与AutoPLC(74.0)难分高下;动态层一跑,22.4对31.4立刻见真章。
- Harness工程的启示:完成纪律三条不变量(挣来声明、编辑失效、有界重试)是模型无关、领域可移植的机制设计。“字节级判定绑定+日志交叉验证"这套防自欺机制,任何agent系统都值得抄作业。知识放Markdown文档而非硬编码、工具层MCP与CLI双面暴露,也都是可复用的工程决策。
- 人机分工的启示:bare到full的+17.3pp证明,在模型能力之外,外部验证基础设施是可靠性的独立来源;而"弱模型+harness”(如M2.7从39.3到69.2)可以逼近甚至超过"强模型裸奔"(GPT-5.5 bare 71.8)——这对成本敏感的工业落地是个重要选项。
8.3 一句话总结
SemaPLC用一个朴素的洞察做出了扎实的工作:让模型在"自己觉得对"与"外部证明对"之间,只认后者。配上项目接地生成与三源验证,它在功能轨七模型全最高(均值72.6%)、项目轨三层全最高(动态52.2 vs 基线最高31.4),并用层消融钉死了因果:动态可靠性来自门控的那些检查本身。而它留给整个代码生成领域最大的提醒是——执行,而非静态打分,才是检验生成逻辑是否真正工作的忠实标尺。当你的基准停止在执行之前,你以为你在选方法,其实你在掷硬币。
适合谁读:做LLM代码生成/agent harness的研究者(完成纪律可迁移)、工业软件/PLC方向的工程师(接地与运行时验证流程可直接参考)、以及所有关心"agent评测该怎么设计"的人(三层评测与隔离设计是范本)。代码已开源,harness架构与PLC工具套件都可上手。
本文基于arXiv 2608.18565v1全文撰写,所有数据均出自论文正文与附录;观点部分为笔者个人解读,欢迎指正。