从零到一:用 AI 重构 IoT 监控系统,我踩过的坑和真实收获
一、写在前面:为什么写这篇文章?
最近在做一个 IoT 设备监控系统,本来是一个传统的 Spring Boot 项目,负责采集 EMQX 数据、调用 JetLinks API、统计设备状态。
但做着做着,我发现一个问题:代码越写越多,规则越写越死。
-
设备ID格式不统一?写正则匹配
-
健康分怎么算?定权重公式
-
数据异常怎么判断?设阈值
-
用户问"在线设备多少?"?写 switch 分支
每一个需求都要改代码、加规则、重新部署。
于是我开始思考:能不能让 AI 来做这些事?
结果发现,这条路比我想象的复杂得多,但也值得多得多。
这篇文章,我想和大家分享一个真实 IoT 系统如何被 AI 重构的过程,以及传统开发 vs AI 开发的本质区别。
二、最初的想法:调用 API 就完事了?
刚开始,我的想法很简单:
"AI 不就是调个接口吗?我传问题,它返回答案。"
于是写了个简单的 OllamaClientUtil,把用户问题直接发给 qwen2.5:1.5b 模型。
结果呢?
用户问:"在线设备多少?"
模型回答:"在线设备是指能够通过网络连接到服务器的设备,通常包括...(以下省略500字)"
它根本不知道去哪里查数据!
我意识到:AI 需要数据,数据在数据库里,数据库需要代码去查。
AI 能帮我的不是"替我做",而是"帮我决定做什么"。
三、传统开发 vs AI 开发:一个真实案例的对比
以设备状态查询为例,我们来看看两种开发方式的差别。
传统开发模式
1. 意图识别:写正则匹配
java
// 用户输入:"设备001在线吗?"
if (question.matches(".*设备\\d+.*在线.*")) {
String deviceId = extractDeviceId(question);
return queryDeviceStatus(deviceId);
}
每增加一种表达方式,就要加一条正则。
2. 数据查询:写 SQL
java
String sql = "SELECT online_status FROM device_status WHERE device_id = ?"; String status = jdbcTemplate.queryForObject(sql, String.class, deviceId);
3. 回答生成:拼接字符串
java
return "设备" + deviceId + "状态:" + status;
4. 添加新问题:"设备001健康分多少?"
java
// 1. 加正则
if (question.matches(".*设备\\d+.*健康分.*")) { ... }
// 2. 加 SQL
String sql = "SELECT health_score FROM device_health WHERE device_id = ?";
// 3. 改代码 → 编译 → 部署
问题:每加一个功能,都要改代码、发版。用户换种说法,系统就不认识了。
AI 开发模式
1. 定义工具(一次)
java
register(new AgentTool(
"query_device_status",
"查询设备状态。参数: deviceId",
Map.of("deviceId", "设备ID"),
args -> {
String deviceId = (String) args.get("deviceId");
return queryDeviceStatusFromDB(deviceId);
}
));
2. AI 决策
java
// AI 返回
{"tool": "query_device_status", "args": {"deviceId": "001"}}
// 执行工具
String result = tool.getExecutor().apply(args);
3. 用户换种说法,AI 自动识别
| 用户说 | AI 决策 |
|---|---|
| "设备001在线吗?" | query_device_status |
| "001设备状态?" | query_device_status |
| "设备001咋样了?" | query_device_status |
| "001号设备怎么样?" | query_device_status |
不用改代码!
4. 添加新功能:注册新工具
java
register(new AgentTool(
"analyze_device_health",
"分析设备健康分。参数: deviceId",
Map.of("deviceId", "设备ID"),
args -> analyzeHealth(args.get("deviceId"))
));
AI 自动学会什么时候该用这个工具。
直观对比表
| 维度 | 传统开发 | AI 开发 |
|---|---|---|
| 理解用户表达 | 写正则,一条一条加 | AI 自动理解,不用加 |
| 添加新功能 | 改代码 → 编译 → 部署 | 注册新工具,热生效 |
| 用户换种说法 | 不认识,要加规则 | 自动识别 |
| 业务规则变化 | 改代码逻辑 | 改 Prompt 或加知识 |
| 代码量 | 随功能线性增长 | 工具数增长,主逻辑不变 |
| 维护成本 | 越来越高 | 稳定 |
四、第一次尝试:让 AI 识别意图
我的第一个改进:让 AI 识别用户意图,然后代码执行对应的查询。
java
// 意图识别结果
{"intent": "统计设备数量", "deviceId": "全部", "timeRange": "今天"}
// 代码路由
switch (intent) {
case "统计设备数量": return countDevices();
case "查询设备状态": return queryDeviceStatus(deviceId);
}
效果立竿见影:
-
"在线设备多少?" → AI 识别意图 → 代码统计 → 返回结果
-
"设备001状态?" → AI 识别意图 → 代码查数据库 → 返回结果
但问题来了:意图种类是有限的。用户说"设备001咋样了?",AI 还能识别吗?"设备001最近有没有问题?"呢?
加更多的意图 → 改代码 → 加 switch 分支 → 重新部署。
我又回到了老路上:改代码。
五、第二次尝试:让 AI 自己选工具
这次我换了个思路:不让 AI 选意图,而是让它选工具。
java
// 工具定义
- count_online_devices: 统计在线设备
- query_device_status: 查询设备状态
- analyze_log: 分析日志
- learn_knowledge: 学习新知识
- search_knowledge: 搜索知识库
// AI 决策
{"tool": "count_online_devices", "args": {}}
这样,添加新功能不需要改 switch,只需要注册新工具。
java
register(new AgentTool(
"sync_devices_from_jetlinks",
"从 JetLinks 同步设备列表",
args -> syncDevices()
));
AI 成了"大脑",代码成了"手脚"。
六、真正的挑战:让 AI 理解你的业务
工具化之后,AI 确实能调用工具了。但还有一个核心问题:AI 不懂你的业务。
用户说:"emqx@iot-emqx 不是设备"
AI 会怎么处理?它不知道这是在告诉它一个规则,还是真的在问设备状态。
于是我们加入了知识学习功能:
java
// 用户告诉 AI 知识
"emqx@iot-emqx 不是设备"
// AI 存入知识库
INSERT INTO ai_knowledge VALUES ('emqx@iot-emqx 不是设备')
// 后续用户问 "emqx@iot-emqx 是什么?"
// AI 从知识库检索,回答:"emqx@iot-emqx 不是设备"
这样,AI 能听懂业务了。
七、最意外的坑:动态网页抓取
为了让 AI 能学习文档,我们加了"学习网页"功能。
结果语雀的网页抓不到内容!折腾了很久,最后发现:语雀是动态渲染的,Jsoup 抓不到。
试了 HtmlUnit,试了 Selenium,都太重。
最后发现:语雀的正文其实在 HTML 里是静态的,只是我们没找到正确的选择器。
java
// 正确提取语雀正文
String text = doc.select(".lake-content").text();
教训:不要一上来就用重型工具,先看看是不是自己没找对地方。
八、最终架构:AI Agent 模式
经过几个月的迭代,系统最终变成了这样:
text
用户问题
↓
AgentExecutor(AI 决策)
↓
选择工具(AI 自己决定)
↓
执行工具(调用业务代码)
↓
润色回答(AI 美化)
↓
返回用户
核心能力:
| 能力 | 实现方式 |
|---|---|
| 设备状态查询 | AI 调用 query_device_status |
| 设备统计 | AI 调用 count_online_devices |
| 知识学习 | AI 调用 learn_knowledge |
| 日志分析 | AI 调用 analyze_log |
| 网页学习 | AI 调用 learn_from_url |
九、核心收获:AI 开发的几个认知
1. AI 不是魔法,是决策引擎
AI 不替你写代码,不替你查数据库,它帮你决定查什么、怎么查、怎么回答。
2. 小模型能干活,但别指望它完美
我用的是 qwen2.5:1.5b(1.5B 参数),在 CPU 上跑。它不能像 ChatGPT 那样理解所有复杂表达,但简单意图识别、工具选择、知识检索完全够用。
关键是:给它明确的工具列表和清晰的示例。
3. 知识库是 AI 的灵魂
通用模型不懂你的业务。你得教它。
-
教它:设备ID格式
-
教它:日志路径
-
教它:什么是异常
AI 学得越多,越懂你。
4. 工具化比意图识别更灵活
意图识别 → 改代码加 switch → 麻烦
工具化 → 注册新工具 → 不改主逻辑
java
register(new AgentTool(
"新功能",
"功能描述",
args -> 执行代码
));
5. 动态网页是个坑
如果只是学文档,Jsoup 够用了。别一上来就上 Selenium。
十、传统开发 vs AI 开发:本质区别
| 传统开发 | AI 开发 |
|---|---|
| 你告诉计算机怎么做 | 你告诉 AI 做什么 |
| 规则写死在代码里 | 规则在 Prompt 里,可随时改 |
| 添加功能要改代码 | 添加功能注册工具 |
| 用户表达必须精确匹配 | AI 理解语义,容错性强 |
| 维护成本越来越高 | 维护成本稳定 |
十一、什么时候用 AI 开发?
| 场景 | 推荐方式 |
|---|---|
| 功能固定、用户少 | 传统开发 |
| 功能多变、用户表达多样 | AI 开发 |
| 需要快速响应业务变化 | AI 开发 |
| 需要用户教系统新知识 | AI 开发 |
十二、写在最后
这个项目让我深刻体会到:AI 不是来替代你的,是来放大你的能力的。
你仍然需要写代码:
-
连接数据库
-
调用 API
-
处理业务逻辑
但 AI 帮你做了最头疼的事:理解用户意图、决定执行什么、让系统更灵活。
如果你也在做类似的系统,希望这篇文章能给你一些启发。关键要明白为什么用ai,传统的开发项目是做功能点,比如查看设备情况,就是查询数据库,显示信息。一个功能点一组代码。ai可以在一定程度上像普通人一样交流。数据也多样。以前设备状态一定是格式化收集在数据库表,需要就是点击查询按钮去sql查询,写对应的sql语句。现在也要写。但是更加通用。另外就是数据源,可以是文件本,可以是查询数据库表。一段文字让ai识别自己提取信息。
你的系统也可以有自己的 AI 大脑。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)