一、项目背景:工业大模型落地的安全痛点

最近在做一个汽车零部件产线的智能化改造项目,客户要求在本地部署大模型作为产线运维助手,核心需求是运维人员用自然语言就能查询PLC点位状态、调用上位机的OEE分析、报警统计等能力,全程数据不出厂。

最开始的方案是把上位机的能力封装成HTTP接口,直接给大模型做工具调用。跑了两周测试就发现了几个绕不开的问题:

  • 安全边界模糊:大模型直接对接业务接口,一旦出现指令越权或者参数异常,很容易触碰到PLC写入类的高危操作,生产设备的风险不可控。
  • 适配成本很高:每新增一个工具就要写一套prompt规则、参数校验、错误处理,大模型版本迭代还要重新适配,维护量越滚越大。
  • 能力碎片化:PLC读写、上位机分析、报表生成分散在不同服务里,大模型侧要维护多套接口配置,排查问题非常麻烦。

调研了一圈工具调用的标准化方案,最终选择用MCP(Model Context Protocol)协议做能力接入层,用C#实现MCP服务端,把PLC和上位机的所有能力统一封装、统一鉴权,大模型只和MCP服务交互,完全不接触底层设备。上线两个多月,稳定性和安全性都达到了生产要求。

二、为什么选MCP协议?工业场景下的方案对比

很多人会问,工业场景有OPC UA,为什么还要用MCP?其实两者定位完全不同:OPC UA是设备间的数据交互标准,而MCP是大模型与外部能力的交互标准。我们对比了四种常见的对接方案:

方案大模型适配成本安全管控粒度能力扩展性运维复杂度
自定义HTTP API高,每个接口写prompt适配低,只能做接口级鉴权一般,新增接口改两端代码高,接口散、文档难维护
OPC UA直连大模型极高,需自定义节点解析逻辑低,仅节点级权限差,仅能做数据读写中
MQTT中转转发中,需定义Topic与参数规范低,Topic粒度管控一般中
MCP协议极低,工具自描述自动识别高,工具+参数双维度校验强,新增能力无需改大模型端低,统一入口统一治理

MCP最核心的价值是工具自描述:服务端注册工具的时候会带上完整的参数Schema,大模型客户端可以自动识别工具用途和参数要求,不需要额外写prompt适配。对于工业场景来说,更重要的是可以把所有设备操作的安全校验全部收敛到MCP服务层,大模型永远碰不到真实的设备连接,安全边界非常清晰。

三、整体架构设计:分层隔离的安全调用方案

整个方案采用四层隔离架构,从设备到大模型之间层层设防,所有跨层调用必须经过安全校验。
在这里插入图片描述

架构分层的核心逻辑:

  1. 设备层:PLC、传感器、上位机业务服务,只对MCP服务端开放内网端口,禁止其他服务直连。
  2. MCP服务层:C#实现的核心层,负责工具注册、请求转发、安全校验、日志审计,是整个方案的安全闸门。
  3. 大模型层:本地部署的开源大模型,作为MCP客户端,仅能调用MCP服务开放的工具,无法感知底层设备存在。
  4. 安全管控层:贯穿MCP服务全程,包含工具白名单、参数校验、角色权限、操作频率限制、异常熔断五个维度的防护。

四、C#实现MCP服务端:核心能力封装

4.1 基础环境与依赖选型

我们选用了.NET 6作为运行时,兼容工控机主流的Windows Server环境,核心依赖两个库:

  • ModelContextProtocol.NET:开源的MCP协议C#实现,支持标准的JSON-RPC交互,自带工具注册与调用框架。
  • S7.Net:西门子PLC通信库,稳定支持S7-1200/1500系列的读写操作。

服务端采用控制台应用托管,部署在内网工控机上,通过标准输入输出流与大模型客户端通信,全程无HTTP端口暴露,进一步降低攻击面。

4.2 PLC读写能力的MCP封装

PLC操作是最高危的能力,我们做了两层封装:底层是统一的PLC连接池,解决并发安全问题;上层是MCP工具,严格做权限与参数校验。

核心代码片段如下:

/// <summary>
/// 读取PLC指定DB块的字节数据
/// 仅允许读取白名单内的地址范围
/// </summary>
[McpTool("plc_read_db_block", "读取西门子PLC指定DB块的点位数据,返回十六进制结果")]
public async Task<string> ReadDbBlock(
    [McpParameter("dbNumber", "DB块编号", Required = true)] int dbNumber,
    [McpParameter("startByte", "起始字节偏移量", Required = true)] int startByte,
    [McpParameter("length", "读取字节长度", Required = true)] int length)
{
    // 第一层校验:地址白名单校验
    if (!_plcSecurity.IsReadAllowed(dbNumber, startByte, length))
    {
        return "操作拒绝:该地址不在授权读取范围内,请确认参数";
    }

    // 第二层校验:调用频率限制
    if (!_rateLimiter.TryAcquire("plc_read"))
    {
        return "操作频繁:请稍后再试";
    }

    try
    {
        // 从连接池获取PLC连接
        using var connection = await _plcConnectionPool.RentAsync();
        var result = await connection.Plc.ReadBytesAsync(
            DataType.DataBlock, dbNumber, startByte, length);
        
        _auditLogger.Log("plc_read", dbNumber, startByte, length, "成功");
        return BitConverter.ToString(result);
    }
    catch (Exception ex)
    {
        _auditLogger.Log("plc_read", dbNumber, startByte, length, $"失败:{ex.Message}");
        return $"读取失败:{ex.Message}";
    }
}

写入类工具的管控更严格,除了地址白名单,还增加了数值范围校验、操作二次确认、管理员角色鉴权,并且所有写入操作强制留痕,可追溯到具体的调用来源与时间。

4.3 上位机业务能力的工具化封装

上位机的数据分析、报表生成、报警查询这类业务能力,封装逻辑相对简单,核心是把原有上位机的服务接口适配成MCP工具,统一输入输出格式。

比如产线OEE查询工具,只需要传入产线编号和时间范围,就能返回结构化的分析结果,大模型拿到结果后可以直接用自然语言整理给用户。这一层不需要接触设备,风险较低,主要做参数合法性校验和异常处理。

4.4 安全管控模块的核心实现

安全是整个方案的底线,我们在MCP服务层做了五道防护:

  1. 工具白名单机制:每个客户端连接绑定固定角色,角色对应可调用的工具列表,不在白名单的工具直接拒绝执行。
  2. 参数强校验:所有参数做类型、范围、格式校验,禁止传入异常参数绕过业务逻辑。
  3. 操作频率限制:针对高危工具设置调用频率阈值,防止大模型循环调用导致设备压力过大。
  4. 全链路审计日志:每一次工具调用的参数、结果、耗时、来源全部写入本地日志,保留90天,支持溯源排查。
  5. 异常熔断机制:连续出现调用失败、参数异常、越权尝试时,自动熔断对应客户端连接,人工排查后恢复。

五、本地大模型对接:MCP客户端的配置

我们产线环境用的是Ollama部署的本地大模型,配合MCP客户端插件,只需要在配置文件里声明MCP服务的启动路径,大模型就能自动识别所有注册的工具,无需额外开发。

如果是C#技术栈的大模型应用,也可以用Semantic Kernel对接MCP服务,整个技术栈统一,维护成本更低。核心逻辑是把MCP服务注册为SK的工具集合,后续大模型调用和普通插件完全一致。

实际测试下来,本地7B参数的模型就能很好地理解工具用途,简单的查询、统计类需求准确率接近100%,复杂的多步分析任务也能按顺序调用工具完成。

六、落地踩坑与优化经验

整个落地过程踩了不少工业场景特有的坑,这里分享几个最典型的,大家做类似方案可以避开。

1. PLC连接的线程安全问题

最开始用了单例PLC连接,大模型并发调用两个工具的时候,频繁出现通信错误和数据乱码。后来确认S7.Net的Plc对象不支持多线程并发访问,底层Socket不是线程安全的。

最终解决方案是实现了一个简易连接池,维护3-5个长连接,调用时借出、用完归还,既保证了并发安全,又避免了频繁开关连接导致的PLC连接数过载。产线实际并发不高,3个连接完全够用,响应延迟也控制在100ms以内。

2. 复杂参数的Schema识别问题

一开始把PLC读取结果封装成了复杂的自定义类,结果大模型经常解析错误返回格式。后来发现MCP的参数Schema越简单,大模型识别准确率越高。

优化方案是所有输入输出尽量用基础类型,复杂结构统一序列化为JSON字符串返回,大模型侧再做解析,准确率提升了很多。另外枚举类型尽量用字符串代替,避免大模型传错枚举值。

3. 大模型诱导越权问题

测试阶段发现,通过诱导性prompt可以让大模型尝试调用不在预期内的工具,或者传入边界参数尝试绕过校验。

我们的应对方式是双重校验:工具层做权限拦截,参数层做规则校验,同时在系统prompt里明确禁止越权操作。前后测试了近百种诱导话术,没有出现过成功越权的情况。工业场景一定要做前置校验,不能完全相信大模型的输出。

4. 长耗时任务的超时问题

上位机的月度报表生成、历史数据分析这类工具,执行时间可能超过30秒,大模型端容易超时断开。

解决方案是改成异步调用模式:大模型触发任务后,MCP服务端立即返回任务ID,大模型可以通过查询工具轮询任务状态和结果。既避免了超时,也不会阻塞大模型的其他交互。

七、总结与落地建议

MCP协议并不是工业大模型落地的银弹,但它很好地解决了大模型工具调用的标准化和安全管控问题。对于有本地大模型+工业设备对接需求的场景,这套方案的性价比非常高。

最后给几点落地建议:

  1. 优先从只读能力开放,跑通全流程、验证安全机制后,再逐步放开写入类的高危操作。
  2. 安全管控一定要做在MCP服务层,不要依赖大模型的自律,所有输入都当作不可信处理。
  3. 工业环境优先用流传输方式对接MCP,尽量少开HTTP端口,缩小网络攻击面。
  4. 所有设备操作必须留审计日志,生产环境出问题可以快速溯源。
Logo

更多推荐