PLCBench 这类工作要回答的问题非常直接当一个大语言模型LLM驱动的自主 Agent 拿到了 PLC 的访问权它能不能把一次正确的操作变成一段持续稳定的物理控制流程。这个问题并不是把“今天这版模型更会生成代码”平移成“这版模型更会控制设备”而是从符号世界跨入物理世界的一次能力检验。标题里刻意用了 sustained 这个词说明它评估的不是单步动作正确率而是长时间、多步骤、带反馈、有扰动的闭环控制能力。这篇内容会围绕 PLCBench 的标题拆开讲PLC、LLM Agent、持续物理控制这三个词各自意味着什么为什么把它们放在一起之后问题会变难以及如果要在自己环境里搭一个最小验证系统应该从哪些地方入手。对象读者可以是两类人一类是熟悉 PLC 和工业自动化、想了解 LLM Agent 能做什么的工程师另一类是熟悉大模型应用、想往工业控制方向尝试的算法工程师。两边的知识盲区不同所以后面的内容会尽量把概念解释到位同时保留足够的技术细节。1. 先理解标题在问什么从文本工具到物理控制的跨越1.1 LLM Agent 擅长的是符号世界不是物理世界LLM Agent 已经在很多软件场景里证明了价值读取文档、操作数据库、调用外部 API、写自动化脚本。这些场景有一个共同特征就是它们都工作在符号世界里。用户的指令、数据库的记录、API 的返回结果最终都可以转换成文本或结构化数据Agent 的上下文窗口可以容纳错误可以回滚最坏情况下损失的是时间和数据而不是物理设备。物理世界是完全不同的约束。控制一台 PLC 意味着可能在真实设备上打开阀门、启动电机、调节温度。一个逻辑正确但时序错误的动作轻则设备停机重则损坏机械结构或触发安全风险。更麻烦的是物理世界不是静止的当 Agent 读取一个模拟量、经过推理、生成计划、再写回控制字的这段时间里系统的状态可能已经发生了变化。LLM 的慢思考在软件接口里可能只是延迟增加在工业控制里可能直接导致控制失败。这是 PLCBench 这类基准测试存在的第一层原因它考察的不是模型的知识量而是 Agent 在动态、有噪声、不可回滚的环境里做出可靠决策的能力。只有真正在模拟 PLC 环境里跑过一遍才能理解一个看似普通的寄存器读写在物理闭环里意味着什么。1.2 持续控制比单次正确动作难得多很多评测任务属于一次性决策给你一个状态输出一个动作然后看动作是否正确。这种评估方式对代码生成、问答、数学推理都很合理因为环境在评估期间可以被视为静止的。但工业控制不是这样。一个反应釜从开始加热到到达目标温度中间要经历升温、接近、超调、回落的过程一个储罐从低液位补到目标液位中间可能越过上限报警一条输送带启停之间还要考虑顺序逻辑和互锁条件。每一个时刻的动作是否合理取决于上一时刻的动作和当前的状态。Agent 做一次判断是容易的持续几十步甚至几百步地维护系统在目标状态附近才是真正的挑战。sustained 这个表达暗示了评估的时间维度。这类评测通常会规定一个任务窗口比如在 30 分钟内把反应釜温度维持在 90 到 95 度之间评估 Agent 是否持续读取状态、持续调整、并在扰动出现后主动恢复。这个评价尺度比单步正确率更能区分一个 Agent 系统是否真正掌握了控制逻辑。换句话说单步正确率高不代表能在持续控制中不出问题而持续控制稳定才是工业场景真正需要的指标。1.3 PLCBench 评估的是完整 Agent 系统还要注意标题里的另一个词Autonomous LLM Agents。PLCBench 不只是在测试基础模型能不能生成梯形图或结构化文本它测试的是一个包含规划、工具调用、状态读取、动作执行、结果验证、记忆维护在内的完整 Agent 系统。模型能力是其中一环工具设计、上下文管理和错误恢复机制同样重要。这意味着即使同一个模型给它一组合适的工具接口和给它一堆原始寄存器地址最终的持续控制表现会差别很大。好的工具封装可以让 Agent 专注于决策而不是在地址换算和字节序上消耗注意力差的环境抽象会让模型频繁产生非法动作。PLCBench 这类评估框架的价值在于它把模型能力和系统设计放到同一个可重复的测试环境里比较让人看到瓶颈到底在哪一层。对做工业应用的开发者来说这比单纯比较模型排行榜更有参考价值。2. PLC 是 LLM Agent 打开物理世界的一扇门2.1 为什么偏偏是 PLCPLCProgrammable Logic Controller可编程逻辑控制器是工业现场最普及的计算设备之一。它没有通用操作系统那么复杂但有明确的 IO 地址、扫描周期、程序区、寄存器区。相比单片机、工控机PLC 更标准化品牌之间虽有差异但核心模型相似读取输入、执行用户程序、刷新输出按固定周期循环。这让它成为 LLM Agent 接触物理世界相对合适的接口。只要掌握了一类协议的读写方式剩下的工作就是把物理量映射成寄存器地址再把点位表转成结构化文本喂给模型。一台 PLC 的当前状态、报警、过程值几乎都能通过通信协议读出来需要执行的动作也能通过写寄存器或修改程序块写进去。实际工程项目里西门子、三菱、汇川这几个品牌出现频率很高它们的软件环境、地址命名和通信协议差异明显。但无论哪个品牌Agent 要解决的第一个问题都是如何建立可靠的数据通道。这也是为什么很多相关项目在初期会优先选择 Modbus TCP因为它简单、通用、容易排查。2.2 LLM Agent 与 PLC 的完整交互链路典型交互链路可以拆成以下几个环节任务描述转成结构化目标例如把 3 号储罐液位保持在 40% 到 60% 之间。Agent 规划决定需要哪些状态信息。通过通信协议读取 PLC 的输入、输出、寄存器、报警区。把读取到的原始值结合点位表转成当前现场状态。根据状态生成决策要么修改控制参数要么写离散输出要么生成一段新的控制逻辑。执行动作写寄存器或下载程序。等待一段时间后重新读取状态校验动作是否生效必要时修正。每一个环节都有自己的失败模式。状态读取可能因为通信超时失败点位表映射可能因为工程师换过地址而错误动作写入可能被 PLC 的写保护拒绝生成的控制逻辑可能忽略了互锁条件。所以评估 LLM Agent 是否可靠不能只看最后一步动作输出而是要看整条链路在每个环节上的表现。2.3 一个最小交互模型Modbus TCP 示例在本地验证环境里Modbus TCP 是最容易上手的协议。下面是一段读取保持寄存器和写线圈的代码用于理解 Agent 和 PLC 交互的最小模型from pymodbus.client import ModbusTcpClient PLC_IP 192.168.1.10 PLC_PORT 502 client ModbusTcpClient(PLC_IP, portPLC_PORT) client.connect() # 读取保持寄存器起始地址 0数量 10 read_result client.read_holding_registers(0, 10) if not read_result.isError(): print(registers:, read_result.registers) else: print(read error) # 写单个线圈假设地址 1 对应设备启动信号 write_result client.write_coil(1, True) if write_result.isError(): print(write error) client.close()这段代码里地址 0 到 9 的寄存器代表什么地址 1 的线圈控制哪台设备都必须由点位表决定。点位表通常是一张 Excel 表记录每个地址对应的标签名、数据类型、单位、量程、读写属性。对 LLM Agent 来说点位表就是它的地图。如果没有点位表模型即使读到了寄存器原始值也无法理解当前系统状态。2.4 数字量、模拟量与程序下载的差异PLC 的 IO 大致分成两类数字量和模拟量。数字量只有 0 和 1常见于启停按钮、限位开关、继电器输出。接线时还要区分漏型和源型比如热词里提到的输出脉冲接入西门子 PLC 的 NPN 接法PLC 公共端接电源正就属于典型的漏型输入接线。这类信息虽然属于硬件层但 Agent 如果要诊断问题同样需要理解。模拟量是连续值比如压力传感器输出的 4 到 20mA 信号经过 PLC 模块转换后变成 0 到 27648 或 0 到 4000 的整数需要按量程线性换算成工程值。Agent 在读取水位时如果不知道量程转换关系得到的原始整数值毫无意义。因此点位表设计非常关键它决定了模型对现场数据的可读性。更复杂的一类是程序下载。让 Agent 生成梯形图或结构化文本再下载到 PLC能实现更强的人机交互但风险也更高。一个语法正确但时序错误的程序可能比读错寄存器更致命。基础评估里不建议一开始就让 Agent 具备改写程序的能力先跑通寄存器读写和状态反馈闭环再考虑程序生成。3. PLCBench 这类基准测试会如何设计评估框架3.1 任务不是问答而是可验证的物理控制任务从同类工作来看PLCBench 这类基准的任务场景应该是从工业现场常见操作抽象出来的。比较有代表性的有四类启停控制类在满足互锁条件时启动设备停止时按顺序退出。过程调节类把温度、压力、液位调整到目标区间并保持。报警响应类检测到报警后按规则安全处置并恢复。顺序生产类按配方顺序完成多个步骤每步都有前置条件。这些任务的共同点是可以自动判定结果评测不需要人工介入。比如保持液位在 40% 到 60% 这个目标可以直接从寄存器值读取出来逐秒统计是否越界然后算出各项指标。这也是基准测试能够规模化评估的基础。3.2 观测空间与动作空间需要明确约定基准测试必须约定 Agent 能看到什么、能操作什么否则不同 Agent 之间的对比没有意义。观测空间和动作空间可以按层级划分层级观测内容动作内容数字量按钮、限位、报警位、电机反馈启动、停止、复位、开关阀模拟量温度、压力、液位、流量设置目标值、改变阀开度程序块当前程序版本、扫描状态生成并下载新的控制逻辑观测空间决定 Agent 能拿到多少信息动作空间决定它能做哪些事。动作空间太大Agent 容易产生探索性的危险行为动作空间太小又不足以完成复杂任务。一个合理的基准设计会把动作空间收敛到任务必需的最小集合同时在安全层拦截越界动作。3.3 持续物理控制能力如何量化一次动作成功率高不代表持续控制能力强。更好的评估方式是在完整的任务时间窗口内统计以下指标任务完成率在限定时间内达成目标任务的次数占比。越界次数过程量超过安全阈值或被安全层拦截的次数。恢复时间系统进入异常后Agent 恢复到安全或目标状态的耗时。稳定度达到目标后状态偏离目标中心的程度和时间。执行效率完成任务所需的步数、调用轮数或 token 数。把持续这个抽象概念量化之后不同 Agent 策略之间的差异才变得可比。这也意味着想要复现或扩展这套评测最重要的工作就是先把任务场景和指标定义规范化。场景定义模糊评测结果就无法重复。3.4 评测过程本身也要有安全边界即使是在基准评测环境里评测过程也必须考虑安全边界。物理仿真参数设置不合理或者对 Agent 的越界动作不加拦截就可能得到不可复现的失败数据。常见做法是在环境外面加一层模拟联锁保护当 Agent 的动作超过安全范围时环境强制回退该动作同时记录一次越界。这样既能测出 Agent 的问题又不会让评测过程失控。注意评测环境里的安全层通常模拟的是真实 PLC 中的硬件联锁和急停机制。研究阶段可以简化但到了真机阶段独立于 Agent 的物理安全层不能省略。4. 在本地搭一个最小 LLM Agent PLC 控制验证环境4.1 先用仿真 PLC 代替真实设备如果直接在一台真实 PLC 上测试 LLM Agent风险很高。更稳妥的做法是先用仿真环境。可选方案有三个层次Python 模拟从站用 pymodbus 的服务端模拟一组寄存器和线圈适合验证通信和决策逻辑。OpenPLC 运行时开源软件 PLC能运行结构化文本程序支持 Modbus TCP能模拟简单过程。厂商仿真器西门子 PLCSIM、三菱 GX Simulator 等功能接近真机但依赖厂商软件环境。建议从 Python 模拟从站开始因为它启动最快并且方便人为注入故障和噪声。如果目标是贴近真实 PLC 行为再切到 OpenPLC 或厂商仿真器。4.2 用 pymodbus 模拟一个会变化的物理过程下面是一个模拟从站示例。它创建了一个简单环境当前液位会向设定值缓慢靠近同时叠加随机扰动。这样一来Agent 每轮读取的数值都会变化而不是一直停留在初始状态。from pymodbus.server import StartTcpServer from pymodbus.datastore import ModbusSequentialDataBlock, ModbusSlaveContext, ModbusServerContext import threading import time import random # 初始化寄存器地址0为设定液位地址1为当前液位 store ModbusSlaveContext( diModbusSequentialDataBlock(0, [0] * 100), coModbusSequentialDataBlock(0, [0] * 100), hrModbusSequentialDataBlock(0, [100, 35] [0] * 98), irModbusSequentialDataBlock(0, [0] * 100) ) context ModbusServerContext(slavesstore, singleTrue) # 后台线程模拟液位向设定值缓慢靠近 def physics_loop(): while True: ctx context[0] setpoint ctx.getValues(3, 0, 1)[0] level ctx.getValues(3, 1, 1)[0] if level setpoint: level min(level 1, setpoint) elif level setpoint: level max(level - 1, setpoint) level random.uniform(-0.3, 0.3) ctx.setValues(3, 1, [max(0, min(100, round(level)))]) time.sleep(2) threading.Thread(targetphysics_loop, daemonTrue).start() StartTcpServer(context, address(0.0.0.0, 502))这段代码只能用于理解思路。实际使用时要根据自己环境的 pymodbus 版本调整 API 细节比如服务器地址、从站数量、寄存器数量。重点是理解模拟从站可以替 Agent 提供持续变化的状态量。4.3 Agent 主循环决策、过滤、执行、验证Agent 的核心不是让模型自由发挥而是让它在受限的动作空间里工作。下面是一个简洁的结构示意。这里使用伪代码表达流程不绑定具体模型名称def safety_filter(act): # 设定值不能超过量程 if setpoint in act and not (0 act[setpoint] 100): return False # 不能随意关闭联锁 if act.get(action) disable_interlock: return False return True def agent_loop(task, max_steps50): memory [] for step in range(max_steps): state read_plc_state() plan llm_plan(task, state, memory) if not safety_filter(plan): log_abort(plan) return aborted execute(plan) time.sleep(2) new_state read_plc_state() if is_task_done(new_state, task): return completed, step memory.append({plan: plan, state: new_state}) return unfinished, max_steps关键点在于三个函数的分工llm_plan负责推理决策safety_filter负责在物理动作之前拦截风险is_task_done负责客观判定任务是否完成。这样的结构把模型能力和安全机制解耦任意模型输出都必须经过独立于模型的校验层才能到达仿真 PLC。4.4 安全联锁必须独立于 Agent 存在任何让 LLM Agent 直接连接 PLC 的架构都必须把安全联锁设计在 Agent 之外。可以这样理解三级结构LLM Agent 负责建议动作。安全层负责判断动作是否允许。PLC 自身的硬件联锁负责最终保护。这三层不能合并。否则模型幻觉、输出格式错误、上下文污染都可能直接导致物理设备误动作。安全层的规则应该简单、明确、可测试并且最好由懂工艺的工程师编写。比如设定值范围、允许启停的设备清单、互锁条件都不应该由模型在运行时自行推断。注意在真机环境中急停、机械限位、独立安全继电器等硬件级联锁不能由任何软件绕过包括 LLM Agent 生成的程序。仿真阶段可以简化但真机阶段必须严格遵守。5. 常见问题与排查路径5.1 状态读取不到或读到旧值现象Agent 每次读取到的寄存器值都一样或者读取直接超时。可能原因PLC 的 IP 或端口配置错误点位地址映射不正确读取频率比数据刷新频率快字节序或数据类型配置不一致。排查顺序先用 Modbus 调试工具读取同一地址确认链路本身可用。检查点位表的地址换算特别注意 0 起始和 1 起始的区别。检查 32 位寄存器的高低字节顺序。确认 PLC 扫描周期和数据变化频率。处理建议先恢复手动读取通路再让 Agent 接入。在没有可视化工具的情况下直接排查通信问题会比较低效。5.2 写寄存器成功但设备无动作现象写入操作返回成功寄存器值也变了但物理设备没有反应。可能原因写的是数据寄存器而不是控制寄存器控制逻辑要求多个条件同时满足只写一个条件不会动作设备处于手动模式或联锁状态。排查顺序查看设备控制逻辑和互锁条件。对比正常手动操作时哪些寄存器发生变化。查看 PLC 是否处于 RUN 模式。处理建议在 Agent 的可调用工具里增加读取设备状态的操作先确认设备允许动作再执行写入。5.3 Agent 产生非法动作现象模型输出了超出动作空间的内容比如直接生成一段梯形图、写一个负的设定值、或者跳转到一个不存在的工具。可能原因模型输出没有严格受限于 JSON 或动作 schema提示词里没有给出动作白名单没有接入安全过滤层。处理建议把动作空间收敛成固定格式使用结构化输出校验。模型输出必须经过 safety_filter 之后才能执行不能直接透传。5.4 多步执行后状态漂移现象前十几步表现正常后面越来越偏离目标Agent 似乎忘记了最初的任务。可能原因上下文过长早期目标信息被压缩或丢失每次读取状态时没有对比目标值缺少对历史动作结果的归纳。处理建议在 Agent 的上下文里保留简洁的任务目标和最近几步的状态摘要不要把全部原始日志都塞进去。5.5 联锁触发后 Agent 无法恢复现象安全过滤拦截了动作Agent 进入死循环不断生成被拦截的同类动作。可能原因安全过滤只返回拒绝没有给出拒绝原因Agent 没有从拒绝结果里提取约束动作空间里缺少恢复和等待选项。处理建议安全层返回结构化拒绝信息例如{allowed: false, reason: value_out_of_range}让 Agent 能根据原因调整下一步动作。以下是汇总表问题现象常见原因排查方式处理建议状态读不到或不变地址映射错误、字节序错误、刷新频率不匹配用 Modbus 调试工具手动读地址先恢复手动通道再接入 Agent写成功但无动作写错寄存器、互锁条件未满足对比手动操作时的寄存器变化增加设备状态读取工具Agent 产生非法动作动作空间未限定、没有安全过滤检查模型输出是否符合 schema强制结构化和安全过滤多步后状态漂移上下文过长、缺少目标对比查看日志中目标是否仍存在维护任务摘要和最近状态联锁触发后无法恢复拒绝原因未反馈、没有恢复动作检查安全层返回内容返回结构化拒绝原因6. 最佳实践与扩展方向6.1 给 Agent 暴露语义化工具而不是原始寄存器不要直接给模型写寄存器 0x0001 这种底层能力。更好的抽象是启动输送带、设置液位设定值、读取 3 号罐状态这类语义化工具。这样模型不容易产生非法值评测也更容易记录动作含义。工具层封装得越干净Agent 的表现越稳定。6.2 完整记录执行轨迹每一个动作、每一次状态读取、每一次安全拦截都应该记录。这对复现失败、评估效果、审计行为都有价值。记录格式可以使用 JSON 行每条包含时间戳、工具名、参数、返回结果、安全判定。有了完整轨迹才能定位到底是模型推理错误、工具封装错误还是安全规则过严。6.3 从仿真到真机的渐进路线阶段目标典型环境检查点1验证通信和 Agent 主循环Python 模拟从站能自动完成设定值调整2验证控制逻辑和时序OpenPLC 或厂商仿真器能在扰动下维持目标状态3验证单台设备控制单台 PLC 加仿真负载安全联锁全部生效4验证真实工艺场景完整控制柜与现场设备故障注入和恢复演练通过每进入下一阶段之前都要确认上一阶段的指标达标。跨越阶段推进往往会在真机上暴露原型问题排查成本会高很多。6.4 发布前检查清单在把这类系统从研究环境推向工程环境之前至少检查以下内容点位表和寄存器映射是否与现场一致。动作白名单是否覆盖所有必要操作。安全过滤是否对模型输出强制生效而不是只做提示。日志是否完整记录每次读写和拦截。是否有超时和自动回退机制。Agent 模型版本和依赖库版本是否固定。是否有独立于 Agent 的急停和手动模式。是否做过故障注入演练比如通信中断、传感器漂移、联锁触发。回到 PLCBench 的标题真正决定一个 LLM Agent 能否把 PLC 访问变成持续物理控制能力的往往不是单次推理正确率而是环境建模、动作封装、安全层和状态跟踪这些系统设计环节。对想进入这个方向的开发者来说最有价值的起步方式不是先比拼模型效果而是先搭好一套可控、可记录、可复现的仿真闭环把问题和瓶颈量化出来。之后再逐步靠近真实 PLC 和真实工艺在每一层加上足够的安全边界。