从车间主任一句"能不能让电脑直接告诉我上周A线为什么不良率飙升"的需求开始,我在一个老牌的WinForms桌面项目里接入了AI大模型,做了一套生产数据分析助手。这篇笔记记录了整个过程:为什么选WinForms而不是Web或Python、项目架构怎么拆、生产数据如何加工成Prompt、大模型调用的核心实现与异常处理、以及上线前必须考虑的性能和数据安全平衡。内容偏实操,适合正在做类似"传统桌面应用 + AI能力"的.NET开发者参考,也适合想了解AI落地时那些真实坑的人。
1. 为什么偏偏在WinForms里做AI数据分析
1.1 需求起点:车间里那句"能不能直接问我"
事情起源于一个挺朴素的场景。公司一条生产线的管理看板上,每天都滚动着产量、不良率、停机时长、设备OEE这些指标,但整个系统本质上是"人查报表"。老板问一句"这周B线停机为什么比上周多2小时",数据分析员要先打开数据库客户端、写SQL、导Excel、套图表,折腾半小时才能给个大概齐的答复。生产部的同事抱怨了很久,说"报表是死的,问题得靠人想"。
于是项目组就想加一个对话式分析入口。最初讨论过两条路:一是用纯规则和统计算法做"伪智能",把常见问题模板化成SQL查询;二是直接上大模型,让AI理解自然语言、生成结论。第一条路胜在可控,但碰到"为什么""对比一下""你觉得哪个环节最值得优化"这类开放问题就抓瞎。第二条路能力够强,但想在老WinForms项目里落地,顾虑也不少。
这个项目的核心定位很快明确:不是做取代报表系统的AI平台,而是在现有桌面客户端里嵌入一个"生产数据分析助手",让操作工和分析员可以用自然语言问数据,AI负责理解问题、查数、分析、生成带结论的答复。项目的技术关键词有两个:AI和WinForms。前者决定了能力上限,后者决定了实现姿势——这是一个跑在内网、部署在Windows工控机上的桌面应用,不是公网Web服务。
1.2 团队讨论时三个方案怎么取舍
第一个方案是搭一个Python后端做AI服务,WinForms客户端通过HTTP调用。这个方案的优点是Python生态好,做数据处理和模型调用都方便,团队里写Python的人也熟。缺点是内网环境多了一套Python服务要维护,部署在工控机上还多了一层进程守护和依赖管理,对IT运维不友好。
第二个方案是干脆把客户端改成WPF甚至Electron,顺便把UI重构一遍。这方案被否得最快,因为现有WinForms项目有大量成熟的第三方控件和业务代码,重构UI周期长、风险高,而且车间工控机配置普遍不高,Electron那套内存占用确实扛不住。
第三个方案就是现在落地的:客户端仍然是纯WinForms,.NET Framework 4.7.2,AI能力作为一个服务层封装在客户端进程内部,通过HTTP调用本地或远程的大模型推理服务。选这个方案的核心原因有三点:一是改动面最小,能在不重建UI的前提下把AI能力嵌进现有工程;二是数据不出内网,敏感的生产数据不需要经过公网;三是部署简单,客户端还是原来的安装包,多出来的只是一个模型服务的配置项。
有个容易忽略但很重要的点:WinForms虽然老,但在工控和企业内网场景里反而是一种优势。Form窗体、DataGridView、定时器这些控件的启动速度和内存占用都很可控,尤其是在Windows 7到Windows 10并存、部分机器还在用机械硬盘的环境里,WinForms的先天轻量能省掉很多麻烦。
1.3 一个反直觉的结论:AI服务到底放哪
最开始团队以为AI服务必须独立部署,但后来发现不完全是。模型推理服务确实要独立进程,但中间那一层"分析服务"可以有两个选择:一是嵌在WinForms客户端里,二是放在局域网中央服务器。
放到中央服务器的好处是多个客户端共享同一份模型、同一份日志,还能统一做数据脱敏和权限控制;坏处是车间网络如果出现波动,整个分析功能就瘫痪了,而且中央服务器的CPU和内存压力会比较大。放到客户端本地的好处是单机可用、隔离性和稳定性都强,但每台机器都要拉一份模型数据,模型更新时也是个麻烦。
我们最终选择的是"本地推理服务 + 中央配置下发"的混合模式。每台工控机装Ollama服务,模型用qwen2.5的7B量化版,占用大约5GB磁盘和4GB内存,车间机器基本都能扛住。客户端启动时从中央接口拉一份"模型服务配置",如果本机Ollama连不上,自动尝试连接备用地址。这样既保证了离线可用性,也避免了把所有鸡蛋放在一个篮子里。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 项目架构拆解:老框架如何装下新智能
2.1 三层结构:数据层、分析层、AI适配层
先说整体结构。这个项目的代码分了三层,不是传统意义上的三层架构,而是按"数据在哪里、逻辑在哪里、AI在哪里"来划分的。
数据层负责访问生产数据库。数据库是SQL Server,里面有产量表、不良记录表、设备停机表、工单表这几张核心表。数据层用Dapper做轻量ORM,避免引入EF那种重量级框架。每次AI分析需要数据时,数据层根据分析层下发的参数去查询,返回DataTable或List
分析层是核心,它干三件事:一是把用户问的自然语言问题做预处理和意图分类;二是根据问题意图决定调哪些数据、查哪些字段;三是把查询结果加工成"模型友好的上下文",拼进Prompt。这一层不关心模型具体是怎么调用的,只关心"给模型什么内容"。
AI适配层是最薄的一层,封装了所有与大模型推理服务的HTTP通信。包括请求超时、重试、流式接收、结果解析。之所以单独抽一层,是因为想保留切换模型后端的能力——本地用Ollama,也可以切到任意OpenAI兼容接口,只需要改配置,不动业务代码。
这样分层之后,最大的收益是「可测试性」。分析层的Prompt构造逻辑可以本地单测,AI适配层可以用Mock数据模拟模型返回,不需要每次调试都真的调一次模型,省了很多算力和时间。
2.2 AI适配层核心设计:一个几乎没人愿意多写的接口
AI适配层的核心接口很简单,简单到可能有人觉得没必要抽象:
csharp复制public interface IAnalysisService
{
Task<AnalysisResult> AnalyzeAsync(
AnalysisRequest request,
CancellationToken cancellationToken);
}
AnalysisRequest里包含用户问题、数据库查询结果、业务字典、历史对话上下文;AnalysisResult里包含模型返回的文本、解析出的结构化结论、耗时和Token消耗统计。
接口简单,但实现里有几个细节值得说。
第一个是请求响应超时。生产环境里,7B模型在纯CPU机器上生成一段分析可能要30秒到2分钟,所以超时时间必须单独设置,不能跟着HttpClient默认的100秒走。我们实测下来,把超时设为180秒
