工业时序数据的 Agent 化:TDEngine + LangChain4j 集成实战

31 阅读4分钟

Agent 不能只看告警,还要看数据——设备过去一小时的温度、振动、压力趋势。时序数据库就是 Agent 的「历史记忆」。


为什么 Agent 需要时序数据?

现在的 DeviceAgent 能查告警、能搜维修知识,但缺了最关键的一块:设备运行数据

「CNC-001 振动异常」——异常是相对于什么?正常范围是多少?振动值是一瞬间的尖峰还是持续上升趋势?这些问题,告警信息和知识库都回答不了。只有历史时序数据能回答。

时序数据库(TSDB)就是做这件事的——高效存储和查询带时间戳的设备遥测数据。


为什么选 TDEngine?

工业设备的数据特征和互联网完全不同:

特征互联网数据工业设备数据
采集频率毫秒级秒~分钟级
数据量每个用户独立每台设备持续产生
查询模式点查为主聚合 + 窗口查询为主
存储周期天~周月~年

TDEngine 是专为时序场景设计的,天然支持超级表(Super Table)——一个表模板适配所有同类设备。

-- 一个超级表定义,自动管理所有设备的数据
CREATE STABLE devices (
    ts TIMESTAMP,
    temp FLOAT,
    vibration FLOAT,
    pressure FLOAT,
    rpm FLOAT,
    current FLOAT
) TAGS (device_id BINARY(64), device_type BINARY(32), factory BINARY(64));

新增一台设备只需一行 CREATE TABLE 引用超级表,不需要重复建表。


架构

architecture.png

DeviceSimulator → MQTT → MqttToTdengineBridge → TDEngine
                         (批量写入,5秒刷新)
                                                 ↓
用户 → Agent → DeviceDataTool → TdengineDataService → REST API → TDEngine
                             (聚合查询:avg/max/latest)

两条数据流:

  1. 写入流(实时):设备模拟器 → MQTT → Bridge → TDEngine
  2. 查询流(按需):Agent → Tool → REST API → TDEngine

实现

1. TDEngine Websocket 服务

TDEngine 提供了 Websocket 能力,不需要 JDBC 驱动:

// 初始化超级表
CREATE STABLE IF NOT EXISTS industrial.devices ...

// 插入数据
INSERT INTO industrial.d_CNC_001 USING industrial.devices
      TAGS ('CNC-001','CNC','factory-A') VALUES (now,72.5,4.8,0.9,1500,28.5)

2. MQTT → TDEngine 桥接

@Component
public class MqttToTdengineBridge {
    // 订阅 MQTT topic: industrial/devices/+/data
    // 解析 JSON payload → 缓存到内存队列
    // 每 5 秒批量写入 TDEngine
}

3. Agent Tool 改写

原来的 DeviceDataTool 用随机数模拟数据,现在改为真实 TDEngine 查询:

@Tool("查询指定设备的历史遥测数据,包括温度、振动、压力、转速、电流等关键指标。" +
      "输入设备ID,返回最近1小时的关键指标统计和最新数据点。")
public String queryDeviceHistory(String deviceId) {
    Map<String, Object> stats = tdengine.queryStats(deviceId, 60);   // 60分钟聚合
    Map<String, Object> latest = tdengine.queryLatest(deviceId);      // 最新数据点
    return formatJson(deviceId, stats, latest);
}

LLM 拿到的不再是随机数,而是真实的设备运行数据。


关键设计决策

批量写入 vs 逐条写入

5 秒批量刷新一次,单次最多写 100 条。这在数据可靠性和写入延迟之间取了平衡——设备数据的采集间隔通常是秒级,5 秒的写入延迟完全可接受。

Websocket vs JDBC 驱动

TDEngine 的 Java 驱动(taosc)需要安装本地动态库。对于 Docker 化的部署来说,Websocket 更简单——不需要额外的依赖,跨网络调用也无额外配置。

DeviceDataTool 的查询设计

一个 Tool 方法返回最新的一个数据点 + 过去一小时的聚合统计,而不是返回原始全量数据。这样做有两个理由:

  1. 控制 token 消耗:100 条原始数据点 ≈ 2000+ token;一条聚合统计 ≈ 200 token
  2. LLM 更擅长读聚合数据:avg/max 比 100 行数字表更容易被理解

测试

# 启动 TDEngine
docker compose up -d tdengine

# 初始化 Schema
curl -X POST http://localhost:8080/api/agent/tdengine/init

# 模拟设备数据(通过 MQTT)
# DeviceSimulator 自动发布 → Bridge 自动吸入

# Agent 对话验证
curl -X POST http://localhost:8080/api/agent/chat \
  -H "Content-Type: application/json" \
  -d '{"message":"CNC-001 最近一小时的振动趋势怎么样?"}'

下一步

TDEngine 集成后,Agent 具备了完整的感知能力——实时告警 + 历史数据 + 知识库检索。接下来是MVP 集成:把这些能力编排成一个完整的「从告警到工单」的诊断链路。


代码仓库:github.com/LaoLiang-ag…


本文由 LaoLiang 原创,首发于掘金/知乎/微信公众号。转载请联系作者。