Industrial AIOps 工业数据
连接用户现场的 OPC-UA、Modbus、MQTT 等工业协议,采集设备数据并进行本地诊断、审计和结构化导出。分析引擎不要求国外模型 API。
安装到
uvx --from iaiops iaiops-mcp
MCP 配置仅供参考,请检查权限、命令和远端服务后自行配置。
README
Industrial AIOps 工业数据
连接用户现场的 OPC-UA、Modbus、MQTT 等工业协议,采集设备数据并进行本地诊断、审计和结构化导出。分析引擎不要求国外模型 API。
安装与连接
使用本地 stdio 连接,在 MCP 客户端填写以下启动命令,并按项目文档完成所需配置。
uvx --from iaiops iaiops-mcp
需要 Python 3.11+。根据现场协议安装 iaiops 对应的依赖扩展,并按中文文档配置 IAIOPS_MCP 和设备端点;物理设备支持须结合现场验证。
使用示例
根据上文用途,先针对你已授权的本地项目、数据库或国内数据源执行一次查询,再按结果继续操作。
项目来源
本页说明已核对项目资料和安装入口;不同设备、浏览器和第三方数据源的实际运行仍需在你的环境确认。
上游中文使用文档
<!-- mcp-name: io.github.industrial-aiops/iaiops -->Industrial-AIOps(工业 AIOps)
English · 中文
让 AI 说清楚产线为什么停了 —— 而且每句结论都带证据引用。
一个厂商中立、读优先的现场数据 tap。它讲 14 种现场协议,把跨协议的证据在时间上对齐, 交给智能体的是带引用的裁决,不是猜测。每次调用都留审计;读取路径绝不回连。
pip install "iaiops[opcua]" # 按现场装,或 [all]
iaiops init # 生成 ~/.iaiops/config.yaml
iaiops doctor # 先自检,再谈信任
也可以直接跑容器 —— cosign 签名、非 root。它以 stdio 讲 MCP,所以要保持 stdin 打开,并挂一个卷存审计库:
cosign verify --key deploy/margo/cosign.pub ghcr.io/industrial-aiops/iaiops:0.28.0-factory
docker run -i --rm -v iaiops-state:/home/iaiops/.iaiops \
ghcr.io/industrial-aiops/iaiops:0.28.0-factory
要加固部署或离线部署(只读根文件系统、cap_drop: ALL、no-new-privileges、可选端侧 LLM),
见 deploy/margo/compose.yaml 与 deploy/airgap/。
分析引擎不需要 GPU、不需要模型 API —— 它是确定性算法;LLM 可选,且只负责把结论讲成人话。
它能干什么
| 读 | OPC-UA(含 HDA 历史访问、tag 自动发现)· Modbus TCP/RTU · S7comm · 三菱 MC · 欧姆龙 FINS · MTConnect · MQTT/Sparkplug B · EtherNet/IP · EtherCAT · PROFINET · SECS/GEM · HART-IP · BACnet/IP · IO-Link —— 另有两层只读 REST 面:BAS 监控器(Metasys / Niagara)与 Ignition Gateway |
| 查得清 | scan 现场勘察(零发包预览,给人签字的那份)· readiness 这个站点今天能跑什么、还差什么(零联网)· collect 有界评估采集 + 断点续跑 · store 留存与剪枝 |
| 想明白 | 停机根因 copilot(旗舰;四级结论 + 假设账本 + 时序排除)、从采集历史实测的 OEE(可用率/性能/质量 + 六大损失,可出自包含 HTML 报告)、报警洪泛分析(ISA-18.2)、数据流断点定位、数据可信度打分、资产台账、老 PLC 程序讲解(ST/AWL/L5X) |
| 查得完 | investigate 八步证据闭环 —— 定义事件 → 取证 → 归一校验 → 压缩排序 → 关联时间线 → 验假设 → 知识校验 → 结论闭环;每一步走不通时说清是你没给还是产品给不了 · tags 点表语义确认(导出表 / 静态页 / 产出 config 补丁) |
| 越用越准 | case 事故案例闭环 —— 标签从审计轨迹自动来,确认只需一次点选,学出本站自己的原因权重 |
| 管得住 | 审计 · 预算 · 风险分级 · 回滚 —— 每一次调用都过,MCP 与 CLI 两条前端走同一引擎 |
| 归你自己 | 无遥测、不回连。有六个工具按设计可以把数据发出去(stream_publish、stream_publish_event、uns_publish、historian_push、mqtt_publish、rca_narrate)—— IAIOPS_NO_EGRESS=1 会把这六个一并摘除,形成离线姿态 |
本包内含十个行业版:fab · factory · process · building · water · warehouse · clinical ·
pharma · renewables · plcnext,各自带只读的行业建议检查。变电/电力(IEC-104 · DNP3 · IEC-61850)为独立包
iaiops-energy。
头五分钟
四条命令。其中只有一条会碰设备,而且它在发出任何东西之前,先把要发的内容原样打印出来。
pip install "iaiops[modbus]" # 选你真有的那个协议,或者 [all]
iaiops init # 交互式配一个端点
iaiops doctor # 配置、凭据、连通性 —— 以及版本号
iaiops onboard status # ← 先跑这条:走哪条路、第几步、下一条命令。零联网。
iaiops readiness # 这个站点今天能跑哪些场景,每个缺口还差什么
readiness 只读你的配置和本地库,回答一个问题:这个站点今天能跑哪些场景,每个缺口还差什么?
每个缺口都附带能补上它的那条命令,并按"补上它能解锁多少"排序。不需要 agent、不需要云、
不需要账号,线上不发一个包。
先分路:数据还在设备里,还是已经在 UNS 里?
iaiops onboard status 从 config.yaml 推出这个站点走哪条路、在第几步、下一条命令是什么;
推不出来就问 —— 两个选项都给,一个都不替你选。(0.28.0 起随包发布。)
| 从哪开始 | 之后 | |
|---|---|---|
| A · 设备直读(还没有 UNS) | iaiops scan run 勘察 → iaiops onboard draft 出端点草稿 | 点表 → 声明语义 → 采集 → 分析 |
| B · 订阅 UNS(数据已在消息代理上) | 配 mqtt 端点(必须写 stale_after_s)→ iaiops mqtt uns-live-audit 体检命名空间 | 选点(手写 tags:)→ 声明语义 → 采集 → 分析 |
两条路在「声明语义」之后合流,后面是同一个脑、同一套治理。B 路线不扫描 —— 扫描永远认不出 MQTT。
体检结论存在本地,把 UNS 站点分成 B1(命名空间干净) 与 B2(治理本身就是工作)。
onboard 不联网,所以它只认存下来的那份结论;没有就说「未定」,不猜。判 B1 要求那份体检:
按你给的命名标准(--root / --min-segments)、没被消息上限截断、听满至少一个发布间隔
(stale_after_s)、而且就是这个端点现在的代理与话题过滤。差一条就不判 B1,并说明差哪条。
只有 sprawling 才判 B2;minor 是几条启发式发现,列为待复核 —— 一个符合规范的 Sparkplug
命名空间就能触发它。
为什么 stale_after_s 必填:MQTT 是推送的,采集器读的是最后值缓存。发布者掉线后缓存照样
返回旧值,停了的线会读出 100% 可用率。只有现场知道一个点多久发一次,所以这个值不给默认。
没写就拒绝采集 —— readiness 也会把这个端点标成不可采集并写明原因。
然后是顺序不能颠倒的那三件事 —— 先看现场有什么,再取一份有界的样本,最后才谈说明:
| 碰设备吗 | ||
|---|---|---|
| 勘察 | iaiops scan plan → iaiops scan run | 预览零发包;run 会逐类列出它发过的每一个包 |
| 取数 | iaiops collect run line1 --duration 7d | 会 —— 而且会报告它看见了什么以及漏掉了什么 |
| 声明 | iaiops tags export → 人填 role → iaiops tags apply --by <你> | 不会 —— role 列是故意留空的 |
| 说明 | iaiops oee measure --since … --until … · iaiops investigate open · iaiops diag rca | 不会 —— 全部基于已采集的历史 |
想看完整流程对着真实设备跑一遍(约两分钟,含一次真实的中途断连),执行
./demo/oee-line/run_demo.sh —— 不需要硬件、不需要配置,也不会在临时目录外写任何东西。
demo/oee-line/ 说明了每一步是干什么的,以及那些数字能和不能说明什么。
为什么"读优先"
OT 正是最该给智能体上紧箍咒的地方。读路径才是产品本体;少数写路径属 OT 高危,默认关闭, 并受 MOC 纪律门控 —— dry-run、一次性审批令牌、undo 捕获、hash 链审计。
证明这套分析不需要模型
分析层够不着语言模型 —— 这是一条守卫,不是一句形容词:tests/test_brain_is_llm_free.py
扫描 8 个包(brain discovery runtime readiness collect knowledge retain
connectors)里任何能通向模型的 import,扫出来是空的才算通过。模型只出现在两个地方,
且都不承重:rca_narrate 把一个已经算完、已经带引用的结论换个说法,以及 agent 前端决定
调用哪个工具。两个都拿掉,数字还是那些数字。
但那条守卫是静态的 —— 它证明的是「不可能调用」。对做 CSV/验证的人来说,他要签的是跑过 的那一句,所以它现在真的会跑:
iaiops verify determinism --out determinism-record.json
一份钉死在仓里的数据集依次过可用率、产量计数、六大损失、ISA-18.2 告警负荷、控制图、
保守基线、RCA 副驾;每个结果规范化编码后取 SHA-256。整套在本进程跑两遍,再在两个
PYTHONHASHSEED 不同的全新解释器里各跑一遍 —— 最后这一臂才抓得到集合/字典迭代顺序渗进结果,
单跑一次永远抓不到。全程 socket 抛异常,所以一个伸手去找设备或主机名的计算会在这里失败,
而不是在恰好联网的机器上安静地成功。跑完再问一句:这一趟拉进来了什么模型库?
本来就加载着的(MCP server 进程为了那个可选的叙述工具持有 iaiops.core.llm)只记录、不定罪 ——
只有这一趟自己 import 的才判它不合格。
记录分两半:result(每次都相同,签的是这一半)与 context(这次在什么时间、什么机器上跑的)。
两次好的运行不会得到逐字节相同的记录文件,而一定有人会去 diff 它们 —— 所以两半是分开命名的,
不是混在一起。
这才是这句话能用的形态:不是「我们的模型很准」(在 GMP 语境下不构成任何证据),
而是一条能写进 IQ/OQ 的测试用例 —— 移除模型、断网、重跑标准数据集、比对哈希 —— 执行、签字。
MCP 侧同一个检查叫 verify_determinism;iaiops verify suite 只列出它覆盖了什么,不执行。
到底验证到什么程度
一句话:对真实协议库、容器、in-process 服务器验过;尚未对真实产线设备验过。 我们给证据分级,而不是笼统说"测过"—— 真容器 round-trip 和合成 fixture 不是同一种证据。
| 级别 | 含义 | 状态 |
|---|---|---|
| 真库 / 容器 / in-process 服务器 | OPC-UA(含证书 Sign/SignAndEncrypt 矩阵 + A&C)、Modbus-RTU 走 socat PTY + pymodbus 真串口、BACnet/IP 经 bacpypes3 双 IP 子网、IoTDB / TDengine 真容器写→读、HART 编解码对 hart-protocol、PLCnext 经 asyncua route 验证 | ✅ |
| Mock 验证(协议逻辑跑通,但无真设备) | 欧姆龙 FINS、IO-Link、BAS(Metasys / Niagara)、Ignition Gateway、EtherNet/IP PCCC、MTConnect 长轮询、Sparkplug B、S7 / MC / SECS-GEM | ⚠️ |
| 真实设备 | 物理 RS-485、EtherCAT 从站、真 HART 网关、在线 HVAC / BAS / Ignition、真 PLC | 每个协议都是零 |
逐协议证据(包括每个测试"没覆盖什么")见
docs/VERIFICATION-RECORD.md,一协议一行,注明支撑该结论的测试。
每一条 待核实 都是卡在硬件上,不是忘了 —— 每一条都点名了能了结它的那台设备。
🧪 测试与共创 / Beta testing & co-creation
我们在找现场测试伙伴。 软件里能验证的我们都验证了(真实 in-process 服务器、真实协议库、Docker 容器 loopback)——剩下的 待核实 清单只有真设备能回答:物理 Modbus-RTU(RS-485)、EtherCAT 从站、HART 网关、在线 BACnet 楼宇设备、在线 Metasys/Niagara BAS 控制器、在线 Ignition 网关、国产 PLC(汇川/信捷)、真机 PLCnext、真实变电站 RTU/IED、欧姆龙 FINS 真机、IO-Link 主站。如果你是 OT 工程师、系统集成商或工厂团队,手上有任何这类设备:装上 iaiops,对你的设备跑一遍 iaiops doctor,把结果告诉我们。经你验证的设备会署名写进支持矩阵;现场反馈的问题我们优先分诊;功能可以通过 GitHub Issues/Discussions 直接共创。
We're looking for field-testing partners. Everything software-verifiable has been verified; what's left on the honest 待核实 list only real equipment can answer. Run iaiops doctor against your gear and tell us what happened — verified-equipment reports get credited in the support matrix, field-reported issues get fast triage, and features are co-designed in the open.
👉 参与入口:开一个 issue,标题里带上协议名和设备型号;或者直接邮件 zhouwei008@gmail.com。 两条都是真人在看,而且会以当前版本为准回复。
边缘部署与生态定位(edge-native / Margo)
iaiops 以边缘应用(edge application)的形态跑在加固、集中管理的边缘主机上——不抢主机、也不抢编排层。它天然对齐 Margo 工业边缘互操作标准的角色划分:主机/设备 = 不可变边缘 OS,合规编排器 按期望状态下发工作负载,而 iaiops = OT 域应用(只读 tap + 跨协议 RCA,以受治理的 MCP 工具暴露),并可对接本机 LLM 脑做完全离线(气隙)诊断,数据不出厂。
诚实状态: iaiops 是天然的 Margo 边缘应用,但目前尚未 Margo-compliant——容器镜像 + application description + 公开的 conformance 结果均为 roadmap
⏳(见 docs/MARGO-ALIGNMENT.md 与docs/ROADMAP.md)。在那份测试结果出来前,任何材料都不声称 Margo-compliant。
容器 + application-description 骨架见 deploy/margo/(加固 Dockerfile · compose · 标 待核实 的 app 描述符);复用该镜像的按主机分发覆盖层存放于 deploy/(每个候选边缘主机一个目录)。
安装
协议客户端库都是可选 extras —— 只装现场真正在跑的那 1–2 种(每个协议库都懒加载;基础包不装任何 extra 也能安装和导入,调用未安装的协议会返回一个教学式错误指向正确的 extra):
pip install "iaiops[opcua,modbus]" # 只装你需要的协议
# 或单协议: pip install "iaiops[s7]" · 全装: pip install "iaiops[all]"
# 或按行业 edition 捆绑: pip install "iaiops[fab]"
iaiops init # 交互式:加端点、加密存口令
iaiops doctor # 配置 + 每协议连通性探测(可指向仿真器)
iaiops protocols # 能力地图
协议 extras: opcua · modbus · s7 · mc · fins(纯标准库,不 pin 任何依赖)· eip · mtconnect · sparkplug · secsgem · ethercat · profinet · bacnet · hart · iolink · bas(BAS 监控器层 REST,复用 mtconnect HTTP pin)· ignition(Ignition Gateway 只读层,复用 mtconnect HTTP pin)· 另有 tdengine · iotdb · influxdb(时序库下沉)· nats(流出口)· ollama(本机 LLM 叙述)· export(Parquet 导出)· all(全部可 pip 装的 connector)。
Edition 捆绑(与同名 IAIOPS_MCP profile 对应——按行业只装该垂直跑的协议):
fab(secsgem+opcua+s7+modbus)· factory(离散制造全套:opcua+modbus+s7+mc+fins+eip+mtconnect+sparkplug+ethercat+profinet+iolink+ignition)· process(opcua+modbus+hart)· building(bacnet+modbus+opcua+iolink+bas)· water(水处理:modbus+opcua+hart)· warehouse(仓储/物料搬运:eip+profinet+modbus+opcua+sparkplug)· clinical(医疗设施:bacnet+modbus+opcua)· pharma(制药:bacnet+modbus+hart+opcua)· renewables(光伏/风电:modbus+opcua+sparkplug)· plcnext(opcua+modbus)。能源捆绑在 iaiops-energy 包内。
信创/离线: 纯 Python 核心 + 可选 extras 支持离线/气隙安装(本地 wheelhouse +
pip install --no-index)。国产时序库下沉(TDengine/IoTDB)、合规对照见docs/CHINA.md。
主口令
机密(每端点口令、MQTT 凭据)绝不明文落盘——存在 ~/.iaiops/secrets.enc(Fernet + scrypt)。导出 IAIOPS_MASTER_PASSWORD 让 MCP server/CLI 非交互解锁:
export IAIOPS_MASTER_PASSWORD='…'
配置示例 ~/.iaiops/config.yaml(每协议一块)
endpoints:
- name: line1
protocol: opcua
endpoint_url: opc.tcp://plc.lan:4840
tags:
- { ref: "ns=2;i=5", label: temp, warn_high: 70, alarm_high: 90 }
- name: plc2
protocol: modbus
host: 10.0.0.5
port: 502
unit_id: 1
- name: meter1
protocol: modbus # Modbus-RTU(串口):设 transport 或 serial_port
transport: rtu
serial_port: /dev/ttyUSB0
baudrate: 9600
- name: xmtr1
protocol: hart # HART-IP 过程仪表(只读)
host: 10.0.0.20 # HART-IP 服务器/网关,默认端口 5094
- name: omron1
protocol: fins # 欧姆龙 FINS(默认 UDP;transport: tcp 走 FINS/TCP)
host: 10.0.0.11
port: 9600
- name: iolm1
protocol: iolink # IO-Link 主站 JSON 集成(只读)
host: 10.0.0.21
flavor: iotcore # ifm IoT-Core(默认)| rest(Balluff/Turck 风格)
- name: uns
protocol: mqtt
host: broker.lan
use_tls: true # → 8883
topic: spBv1.0/#
本文件不认识的键会被拒绝,而不是忽略 —— endpoint、tag、historian:、retention:
四处都是。被丢掉的键和从没写过的键无法区分:写成 rolle: good_count,在现场看来产量
计数器已经声明过了,而 iaiops readiness 会报 OEE 映射未满足,指的地方离这个拼写错误
十万八千里。报错会点出这个键、可接受的键集,以及最接近的那一个。
对着仿真器测(每协议)
- OPC-UA ——
asyncuademo server(测试套件就跑了一个真实 in-process 的)。 - Modbus —— ModbusPal 或
pymodbusserver 仿真(RTU 可用socatPTY 对搭软件串口)。 - 欧姆龙 FINS —— in-repo mock FINS UDP/TCP 响应器(
tests/test_fins.py)或备用 CP/CJ PLC。 - IO-Link —— in-process mock 主站(
tests/test_iolink.py,双 JSON 方言)或台架上的 ifm/Balluff/Turck 主站。 - TDengine / IoTDB —— 官方 docker 镜像(真实容器写读)。
- EtherCAT —— 无仿真器(硬实时、raw-Ethernet),仅 Linux+root+真总线(如 Beckhoff EK1100 + EL 端子)。
使用
从「不知道网上有什么」到一个实测的 OEE
scan 回答外面有什么。下面这几条回答能拿它做什么、数字是多少。
每一条都是真命令,没有一条是路线图。
iaiops readiness # 零联网
这套装置今天能跑哪些场景;跑不了的,逐条说出缺的那个具体输入, 并按「补上它能解锁多少」排序。它不碰任何设备,所以可以对着一个你还没拿到探测授权 的站点跑 —— 而那正是最需要这个答案的站点。它只报告缺口,永不替你填 (§9.4/D16:猜出来的产量计数器会给出一个看起来很像样的 OEE,那比报错危险)。
iaiops collect plan line1 --duration 7d --interval-ms 1000 # 零联网
iaiops collect run line1 --duration 7d --interval-ms 1000
iaiops collect run line1 --duration 7d --resume # 合过盖子之后
iaiops store status # 本地库里有什么
iaiops store prune --sealed-before 2026-08-01 --apply # 没有封存水位就拒绝
有界评估采集 —— 上限 14 天,而且操作员必须说出终点。故意没有「一直跑」模式: OT 网络上的常驻进程要走变更审批,笔记本跑一周不用(D21)。每次运行都记录它 没看见的那些窗口,所以盲区永远不会被悄悄读成停机。
要从中得到 OEE,得声明三个位号 —— 哪个值代表在跑、哪个寄存器计数、 以及(质量因子需要)哪个计好品:
endpoints:
- name: line1
ideal_cycle_time_s: 0.1
tags:
- {ref: "0", role: run_state, running_when: [2]} # 2 = 运行
- {ref: "10", role: total_count}
- {ref: "11", role: good_count}
running_when 是声明的,不是推断的。在大多数 PLC 暴露的
0=停机 1=空闲 2=运行 3=故障 状态字上,「非零即运行」会把四种状态里的三种算成生产。
iaiops oee measure line1 --reported 97 # 对照厂里自己在用的数字
iaiops oee measure line1 --since 2026-03-02T06:00:00Z --until 2026-03-09T06:00:00Z
iaiops oee measure line1 --report oee.html --lang zh --site "一号厂区"
用 --since / --until 限定测量窗口,两个一起给。 不给的话,测量的周期是本地库里
该端点的全部历史 —— 只跑过一次评估时没问题,一旦跑了两次就是错的:三月那次和八月
那次之间的几个月空档会变成一段巨大的盲区,两次都测不出来。
窗口是足额计费的。窗口里从未被采样的部分 —— 第一个样本之前、最后一个样本之后 —— 和中间的空洞一样计入盲区。所以把问题缩到刚好有数据的那几分钟,并不能把覆盖率做高: 问一个你只看到两小时的班次,得到的是「覆盖率 25%,拒绝报数」,而不是「我们看到的部分 100%」。
可用率只在采集器看得见的时间上计算,盲区被排除而不是算成停机; 另有性能、质量和六大损失。每个因子只在它的输入被声明时才报告 —— 一个说明白缺了什么的部分 OEE,胜过一个里面塞了猜测的完整 OEE。
--report 写出一个自包含 HTML 文件 —— 不从任何地方加载字体、脚本、样式或图片,
打开时零网络请求,所以离网笔记本能开,当附件转发不会坏。它的第一节是
「这次测量看见了什么」(覆盖率、盲区、实际节拍),排在数字之前;
而且带着销售材料通常会省掉的那一行:每个数字要求了什么、还差什么。
iaiops case open line1 --min-stop-s 300 # 每次长停机开一个案子
iaiops case list # 每个都带着「之后有人做了什么」
iaiops case causes # 确认时可用的固定词表
iaiops case confirm <id> --cause material_starvation --by wei
iaiops case agreement # 同意率 >90% 是警告,不是分数
iaiops diag learn-weights --site default # 学出本站的原因权重画像
iaiops diag rca --input bundle.json --from-case <id> # 人的答案进入判决
标签是已经在做的工作的副产品:审计轨迹本来就记下了「谁在停机四分钟后动了什么」, 案子直接把它显示出来。确认是从固定词表里选一个,永远不是自由文本; 「不是事故」也是一个标签。而一个答案算不算独立,是推导出来的 (看它是不是我们自己排过的),答话的人无法自称。
调查本身 —— 八步,以及每一步需要什么
readiness 回答这个站点能跑哪些场景。这一条回答再往下一层的问题:
如果明天出事了,我们实际能查到第几步?
iaiops investigate plan # 什么都不联
八步证据闭环 —— 定义事件、收集证据、归一与校验、压缩排序、关联时间线、 验证假设、对照已知机理、结论与闭环。对每一步走不通的,它说清那是你还没提供的 (并给出该跑哪条命令),还是这个产品根本没法表达的。这两者把人送去完全不同的地方。
iaiops investigate open line1 --start <iso> --end <iso> --asset "一号线"
iaiops investigate show <id> # 它被留在什么状态
iaiops investigate list
同样的八步,跑在一个真实的过去窗口上,并持久化下来,可以回读和继续推进。 不联任何设备 —— 窗口已经过去了,它的证据就是当时采到的那些。
三条命令都能出可转发的那一份 —— 一个自包含 HTML 文件,离网笔记本能开:
iaiops investigate plan --report readiness.html --lang zh
iaiops investigate open line1 --start <iso> --end <iso> --report incident.html
和 oee measure --report 反着来,而且是故意的:那条会拒绝为一次被拒的测量写文件,
因为 OEE 报告的内容是一个数字,文件存在本身就是「测过了」的断言。这一份的内容是
走到哪、每一步还差什么 —— 所以卡住的那种情况才是最值得转发的,
对一个还没上仪表的站点,这就是全部交付物。它唯一不做的,是让一次卡住的调查看起来像做完了:
头条永远是那个走位(2 / 8),不是结论。
其中两步需要人先说出一件事:
iaiops relations declare press oven --by wei # 谁喂谁
iaiops relations downstream press # 最近的在前
根因分析的第二根轴。只有时间的话,一次上游停机会产出一串同样自信的下游假原因 —— 在产线上,下游的同时发生不管什么原因都是必然的。正因为这个必然,它只能是声明, 不能是推断(D25)。没有它时间线照样跑,只是退化成单个设备 —— 并且它会说出来。
iaiops knowledge mount pump-library.yaml --by wei # ISO 14224 三层分离
iaiops knowledge check sensor_fault --protocol modbus
三个答案,而且前两个的区别就是全部要点:一无所知(库里没听说过这个原因 —— 这和「它没问题」完全是两回事)、知道、知道且可排除(这个原因的每一条机理 在这台设备上都不适用)。第三个是排序器做不到的强动作。它永不确认 —— 把一个原因升到「已确认」只能来自排序之外:一次测量、一次复现,或一个人(D29)。
确认点表的含义
这个产品唯一拒绝推断的东西。在此之前,提供它的唯一办法是手改配置文件里的 role: ——
正是一百行就撑不住的那个办法。
iaiops tags export sheet.csv # 每个被监控的位号一行;role 列是空的
# 人填 role + running_when
iaiops tags apply sheet.csv --by wei # 打印出要贴进 config.yaml 的那几行
role 列导出时是空的,哪怕紧挨着一个叫 GoodPartsCounter 的位号。
名字不是声明;有的是工厂的 GoodPartsCounter 数的是别的东西,而选错产量计数器
会得出一个看着合理的 OEE —— 比报错更糟(D16)。
apply 产出补丁而不是替你写。config.yaml 仍是唯一的真相源:oee measure 是直接
从配置里的位号对象读 role 的,所以另建一个存储会让 readiness 说「已满足」而
oee measure 仍然跑不了。run_state 没有 running_when 会被拒绝,理由和 MonitorTag
拒绝它一样 —— 「非零即运行」会把空闲和故障算成生产。
也可以在页面上逐行勾,而不是开表格软件:
iaiops tags page confirm.html --lang zh
HLD §13.9 的 App 前端,交付成一个文件而不是一个服务。在工控盒子里起 localhost 服务,
要回答绑哪个地址、谁认证;而这里每一处声明都强制 --by,一个没有身份的页面
回答不了「是谁勾的」 —— 而那正是这一步存在的意义。所以页面只负责收集,作者在 apply 时给。
页面不重新实现任何一条拒绝。run_state 要 running_when、ref 必须被监控、
一个角色不能被两个位号认领 —— 用 JavaScript 抄一遍就是让它们和真正把关配置的那些漂移开,
而「页面说没问题、apply 拒绝」比没有页面更糟。它带脚本(它是个表单),但不发任何网络请求:
拔了网线照样用。
这里故意没有 MCP 工具。 让 agent 去填 role 列,正是 D16 存在就是为了禁止的那个猜测。
CLI(读)
iaiops opcua read "ns=2;i=5" -e line1
iaiops opcua discover -e line1 # tag 自动发现 → 语义资产模型
iaiops modbus holding 0 -e plc2 --count 4 --decode float32
# 字节序自动探测目前只有 MCP 工具 `modbus_detect_byte_order`,没有 CLI 命令
iaiops hart pv -e xmtr1 # HART 主变量(过程仪表)
iaiops fins words 100 --area DM -e omron1 --count 8 # 欧姆龙 FINS 内存区读
iaiops iolink scan -e iolm1 # IO-Link 主站 + 连接设备扫描
iaiops mtconnect oee -e vmc1
iaiops mqtt nodes -e uns --timeout-s 15
iaiops opcua history "ns=2;i=5" -e line1 --start 2026-06-28T08:00:00Z # HDA 历史
iaiops opcua monitor "ns=2;i=5" -e line1 --duration-s 20 --deadband 0.5 # CoV 变化捕获
iaiops diag dataflow -e line1 --ref "ns=2;i=5" --freshness-s 30 # 断点定位
iaiops diag dataquality-fleet --input feeds.json # 数据质量舰队视图
CLI(写 —— 默认 dry-run,--apply 二次确认)
iaiops s7 write-db 1 INT 0 42 -e press1 # dry-run 预览
iaiops s7 write-db 1 INT 0 42 -e press1 --apply # 二次确认提示
写=HIGH 风险层:dry-run 默认 + 双重确认 + MOC 门控 + undo 捕获改前状态。
MCP server
IAIOPS_MCP=opcua,modbus iaiops-mcp # 按协议/profile 选择性暴露(菜单式, stdio)
IAIOPS_MCP=menu iaiops-mcp # 打印菜单(各 selection 工具数)后退出
iaiops-mcp-opcua # 等价的命名入口(每协议一个)
iaiops-mcp-fab # 按 edition profile(fab/factory/building/…)
iaiops-mcp-brain # 只暴露跨协议脑(零协议)
IAIOPS_MCP=all iaiops-mcp # 显式全量(>100 工具会警告洪泛)
0.10.0 起无默认值:裸 iaiops-mcp(不设 IAIOPS_MCP)打印菜单到 stderr 并 exit 2,
不再静默暴露 100+ 工具。多进程站点(1 脑 + N 协议):跑一个 iaiops-mcp-brain,协议
server 各自加 IAIOPS_MCP_NO_BRAIN=1 去掉脑避免重名(protocols_supported 仍保留)。
MCP 客户端按产线给每个 server 配一个 IAIOPS_MCP 菜单 = 现场只暴露该站点的 1–2 个协议 + 默认随附的"脑"工具。
程序变更基线 —— 认可的那版逻辑动过没有
控制程序是一份受控文件,而现场发现「有人改过且没记录」的常规方式是有人记得。 把你认可的那一版记下来,之后问某一次导出动没动:
iaiops program snapshot ~/exports/Line3.scl --name Line3 --label "approved v3.2 / MOC-118"
iaiops program drift ~/exports/Line3_today.scl --name Line3
快照存的是文件 SHA-256 加上每个 block 的结构指纹(名字/类型/语言、声明的变量、调用、分支条件、 定时器),刻意不含行号、注释和 block 顺序 —— 否则在文件顶上加一行注释就会把整份程序报成变更, 这种工具一周内就会被关掉。落到磁盘上的是 block 名 + 哈希 + 计数,不落任何声明、源码行或注释, 所以这个库不是你程序的第二份拷贝。
三个判词,每个词都咬得很紧:
| 判词 | 含义 |
|---|---|
identical | SHA-256 相同。只有这一种情况配得上这个词。 |
logic_changed | 抽取到的结构变了 —— 逐 block 报,并指出 variables / calls / branches / timers_counters 里哪一类动了。 |
changed_outside_extracted_structure | 字节变了,而每个 block 指纹都相同。 |
第三个才是诚实的那个。它多半是注释或排版 —— 但这些 parser 是结构抽取,不是文法解析, 所以一个发生在它建模不到的构造里的真实改动,从这里看起来一模一样。把它叫「仅文档变更」 是在按最舒服的方式读一份支持不了这个结论的证据,所以它不叫那个: 行数与注释数并排报出来供人判断,判词仍然是「去看」。一份 drift 报告是去读 diff 的理由,绝不是放行。
iaiops program history 列出在跟踪的程序;iaiops program compare <name> <before> <after>
比两个已存快照。删历史是 iaiops program forget,只在 CLI —— 删变更控制证据不该离 agent
只有一次调用。不做任何自动清理。 身份用名字不用路径:工程师站每开一次导出目录就换一个,
程序没换;不给 --name 时用文件名主干,并在输出里说明用的是哪一种。全程不碰设备 ——
读的是人导出来的文件。
典型场景
1. AI 停机根因 copilot(旗舰)
把你能给的证据(报警事件、tag 采样、diagnose_dataflow 结论、设备状态序列)围绕事故窗口关联,返回带证据引用、仅建议的结论。读优先:它只提议一个人审批、MOC 门控、可回滚的动作,不执行任何东西。设计上抗幻觉——只引用输入里真实存在的信号,按与故障起点的时间邻近度加权(因在果前),证据不足时降级为 insufficient_evidence 并给出 recommended_next_data,绝不瞎猜。
# 让它自己采证据:给端点 + 窗口 + 要看的 ref,它自己拉
iaiops diag rca-live -e line1 --start 2026-06-28T10:00:00Z \
--asset line1 --ref "ns=2;i=5" --ref "ns=2;i=6"
2. OPC-UA tag 自动发现 + 语义建模
走地址空间,收集每个 Variable,带上数据类型/值/工程单位,启发式语义分类(温度/压力/流量/设定值/报警/状态…),按 browse path 分组成资产,给每个 tag 提一个干净的规范别名,并出一份命名质量报告(别名冲突/晦涩名)。只读/仅建议——绝不在服务器上改名(那是 OT 高危)。默认跳过 ns=0 基建。
iaiops opcua discover -e line1
3. 数据质量看门狗
给每个 tag 在"数据可不可信"维度打 0–100 分:陈旧、死心跳、坏质量、flatline(卡值)、采样缺口、统计异常——按端点和舰队汇总,排出最差 offender。可配每 tag/每 feed 的陈旧阈值;心跳/flatline 是一等公民。data_quality_fleet_rollup 给跨端点的舰队视图。
4. Modbus 字节序自动探测 + 厂商模板
把一块原始寄存器按所有候选字节序(AB/BA、ABCD/DCBA/BADC/CDAB)解一遍,按提示值/合理区间打分选出正确字节序——纯逻辑、无需设备。配套一组厂商寄存器模板(Eastron SDM630、Schneider PM5xxx 等)把寄存器块解成命名工程量。
5. HART-IP 过程仪表(只读)
经 HART-IP 服务器/网关读现场仪表的通用变量:设备身份、主变量、动态变量 + 回路电流。不暴露写/设备专用命令(对在线仪表是 OT 高危)。命令编解码层对 hart-protocol 已验证;HART-IP 线传输 待核实。
6. 行业版(楼宇 / 水处理 / 仓储 / 医疗 / 光伏风电 / PLCnext / 能源)
楼宇(IAIOPS_MCP=building):BACnet/IP 设备发现 / 对象列表 / 读属性 / 读点位(HVAC/厂务)+ 有界 COV 订阅 + TrendLog 读取;bacnet_write_property 为 MOC 门控高危写。水处理(IAIOPS_MCP=water):modbus+opcua+hart + 水行业 tag 语义(溶解氧/ORP/余氯/氨氮/TSS/跨膜压差/加药/曝气)+ 水行业 Modbus 模板。能源(变电/电力)在独立包 iaiops-energy:IEC-104 / DNP3 / IEC-61850 MMS 只读监测。
0.11/0.12 新增行业版(每版都带自己的只读、引用优先、仅建议的检查工具,只在选中该 edition 时加载):
- 仓储/物料搬运(
IAIOPS_MCP=warehouse,eip+profinet+modbus+opcua+sparkplug):输送/分拣驱动 + VFD/电表 + WMS/WCS 网关 + AMR 遥测;版工具line_bottleneck(约束理论产能瓶颈)+sortation_health;复用 PdM /downtime_triage/ OEE。 - 医疗设施(
IAIOPS_MCP=clinical,bacnet+modbus+opcua):把医院设施作为区别于普通楼宇的患者安全垂直;版工具isolation_room_check(负压/正压隔离病房压差)、medical_gas_check(医用气体报警屏)、or_environment_check(手术室温湿度/压力包络)。 - 制药(
IAIOPS_MCP=pharma,bacnet+modbus+hart+opcua):不新增任何协议 —— 这正是重点: 制药没有专用现场协议(洁净室跑 BACnet、制水跑 Modbus/HART、灌装冻干跑 S7、DCS 跑 OPC-UA,全在基座里), 缺的是语义。版工具cleanroom_pressure_cascade(Annex 1 压差级联,逐门判;相邻关系由人声明, 不从房间清单里猜)、cleanroom_particle_check、pharma_water_check(USP <645> stage-1 程序: 未温度补偿读数、测得温度向下取档、超限报「转 Stage 2」而不是 FAIL)。 不内嵌任何药典限值 —— 限值属于贵厂在其药典版本下已确认的质量标准,本仓无人能核的转录数字 不该去决定一批环境算不算合格,而且抄松了读起来正好像「符合标准」。没声明的项报no_limit/not_graded并点名,绝不当作通过。已知缺口(写在该 edition 的 skill 里):没有 PI 连接器、 S7 无真机验证、尚无 GxP(Annex 11 / Part 11)对照、LIMS/QMS 有意不做(走 REST/DB 不走现场协议)。 - 光伏/风电(
IAIOPS_MCP=renewables,modbus+opcua+sparkplug):PV 逆变器(SUN2000/Growatt 模板)+ 风机控制器 + 场站 SCADA + Sparkplug 遥测;版工具pv_performance(组串性能对比)。 - PLCnext 打包版(
IAIOPS_MCP=plcnext,opcua+modbus):菲尼克斯 PLCnext 虚拟化 PLC,经其内置 OPC-UA server(opc.tcp4840)+ Modbus-TCP 过程数据 server,不新增 connector;route-verified,真机待核实。
7. 保守基线学习(0.10 新增)
baseline_learn/check/status(CLI iaiops baseline …)——变更日志式基线,明确不是黑盒异常检测:鲁棒 p1/p99 + 中位数/MAD 带;样本太薄(<100 条或 <24h)拒绝学习并明说缺什么;操作员变更记录后从变更点重新学习;默认静默——只有超带 >3×MAD 且连续 ≥3 个样本才报,每次违规都引用基线窗口和越界样本。
8. 历史库读回 + RCA 事故前证据(0.10 新增)
historian_query / historian_coverage(CLI iaiops historian query|coverage)把写进 sqlite/TDengine/IoTDB 的历史查回来;配置 historian: 块后,RCA copilot 自动拉取事故前 2 小时窗口作为一类新证据(引用注明来源/窗口/样本数)。不配则输出逐字节不变(有测试证明)。
9. 老 PLC 程序讲解(0.10 新增)
plc_program_outline/xref/section(CLI iaiops program …)对导出的程序文件(西门子 SCL/ST、AWL/STL、罗克韦尔 Studio 5000 .L5X)做结构化提取——块/变量/调用图/定时器/交叉引用,每个元素带 source_file + 行号(L5X 带梯级号),讲解 agent 必须引用真实位置。绝不上传/连接在线 PLC;XXE 加固。
9b. 停机分诊 + 老 PLC 可维护性 + Agent 技能(0.11/0.12 新增)
- 停机分诊 copilot(
downtime_triage):把报警级联 + RCA 结论 + PdM 前兆编排成一次分诊,并核对首出报警是否与诊断出的根因一致;仅建议、引用优先(基于早期的alarm_cascade首出重建与pdm_forecast到阈时间预警)。 - 老 PLC 可维护性(
plc_program_visibility):对导出的 ST/AWL/L5X 程序做风险/可维护性读评(体量、块数、交叉引用密度、无注释段),绝不上传在线 PLC;与plc_program_outline/xref/section讲解器配套。 - 每版工具机制(
mcp_server/profiles.py的EDITION_MODULES):某个 edition 可携带自己的@mcp.tool组,仅在选中该 edition 时加载——裸协议键与常驻脑都不加载,故各版专用工具不污染其他面、不膨胀基座。各版签名工具:仓储line_bottleneck/sortation_health;医疗isolation_room_check/medical_gas_check/or_environment_check;楼宇economizer_check/zone_comfort;过程control_loop_health/heat_exchanger_fouling;半导体spc_check/defect_pareto;工厂changeover_analysis;水处理disinfection_ct/water_quality_compliance;光伏风电pv_performance。 - Agent 技能:仓库随附一个路由技能(
skills/iaiops)+ 十个按行业技能(iaiops-fab/iaiops-factory/iaiops-process/iaiops-building/iaiops-water/iaiops-warehouse/iaiops-clinical/iaiops-pharma/iaiops-renewables/iaiops-plcnext),把 agent 路由到正确的 MCP server 并说明工具面。
10. ISA-18.2 报警洪泛分析 + 合规报告(0.9 新增)
alarm_flood_analysis(洪泛片段/抖动报警/常驻报警/合理化 worksheet,CLI iaiops diag alarm-flood|alarm-worksheet);iaiops compliance report(等保 2.0 二/三级状态 + IEC 62443 FR1–6 对照 + 诚实差距清单,md/html)与 iaiops compliance evidence(审计证据 zip,哈希链校验)。辅助整改,非认证。
11. 数据导出 + Prometheus/Grafana 桥(0.9 新增)
iaiops export csv|sqlite|parquet 从本地 SQLite 存储按时间/端点/tag 过滤导出(Parquet 需 iaiops[export]);iaiops metrics serve --port 9184 暴露 Prometheus /metrics(默认只绑 127.0.0.1),Grafana 配方见 docs/GRAFANA.md。
12. 信创 / 国产时序库下沉
historian_push 把任意 connector 归一化后的数据写入本地 SQLite 或国产时序库 TDengine / IoTDB(不自建库、不绑 InfluxDB)。compliance_mapping 对照《工控系统网络安全防护指南》给诚实的逐项状态;compliance_frameworks / compliance_dengbao_levels 给等保 2.0 + IEC 62443 对照与二/三级增量。
安全与治理
- 读优先:196 个受治理工具 = 183 只读 + 10 个 MOC 设备写 +
historian_push(也是写,但写的是历史库不是设备,[WRITE][risk=low])+ 2 个已弃用别名(每版工具只在选中对应 edition 时加载,故裸协议/单 edition 面比该全线总数小);读侧新增两层厂商 REST 只读面——BAS 控制器层(Metasys/Niagara,building 版)与 Ignition Gateway MES/SCADA 层(factory 版);10 个写/命令工具(s7_write_db、mc_write_words、fins_write_words、mqtt_publish、eip_write_tag、ethercat_write_sdo、ethercat_set_state、profinet_dcp_set、bacnet_write_property、bas_command)全部[WRITE][risk=HIGH][MOC](bas_command默认关闭 + 生命安全对象 denylist)。 - 破坏性操作:dry-run 默认 + 双重确认 + MOC 门控 + 需记录审批人(一次性
iaiops approve令牌;未配置risk_tiers时 high/critical 默认dual层);10 个写工具全部声明 undo(0.20.3 起无豁免),成功的写捕获改前值/状态并登记逆操作描述符。逆操作在真没有逆的情况下如实返回「无」——瞬时(retain=False)的mqtt_publish发出去就收不回;ethercat_set_state的+ERR/NONE/BOOT不是可重新请求的干净 AL 状态。一个过度承诺的 undo 比没有 undo 更糟,因为总会有人把它重放到活的设备上。 - 治理 harness:每个工具都过策略预检(策略引擎 fail-closed)+ 预算/失控熔断 + 风险分级 + 审计落库
~/.iaiops/audit.db(SHA-256 哈希链防篡改 +iaiops audit verify;高危写在审计不可用时拒绝执行);任何注册工具缺治理标记,MCP server 拒绝启动。审计状态如实反映结果(0.20.3):工具不抛异常而是返回规范{error, hint}信封,过去会被记成status='ok'——失败的写和成功的写在轨迹里无法区分,熔断器也被告知「成功」;现已识别该信封记error。失控窗口计入被拒绝的重试(0.20.3):上限不计拒绝(它没干活),但一个不理解拒绝、无限重试的调用方是最常见的卡死循环,过去完全拦不住(实测 500 次被拒高危写、上限 10、零拦停)。 - 机密:Fernet 加密库,绝不明文;配置目录权限告警。
- 品牌隔离:厂商中立,不跨品牌桥接。
- 质量门(发版前全绿):pytest + ruff + bandit(0 Medium+);全 MCP 工具带治理标记。
发布渠道
- PyPI:
pip install iaiops(能源版pip install iaiops-energy) - GitHub:https://github.com/industrial-aiops/industrial-aiops
- MCP Registry:
io.github.industrial-aiops/iaiops - ClawHub:
iaiops - 文档:
docs/CHINA.md(信创)·docs/ROADMAP.md(路线图)·CHANGELOG.md(总体/技术架构 HLD 为内部设计文档,不随本仓发布)
许可
MIT。提交/包/版权统一署名 wei <zhouwei008@gmail.com>。
评论与讨论
还没有评论,分享你的体验吧。