1. 项目概述:为什么需要让 AI “自己看” 功耗计?
“让 AI 自己看功耗计”——这句话乍听像科幻设定,但落到 IoT 工程现场,它其实是一句极其务实的工程宣言。我第一次在产线调试边缘网关时,就卡在了这个环节:三台电表、两路直流电源、一个温湿度传感器,数据全堆在串口缓冲区里,靠人工每小时抄一次表、比对曲线、判断是否异常。结果连续三天,设备凌晨两点掉电,我们早上九点才发现——而那段时间的功耗曲线,明明在监控界面上画出了尖锐的毛刺,只是没人“看”。
这就是问题核心:IoT Power 数据不是缺,而是太碎、太密、太沉默。它躺在 Modbus RTU 帧里、藏在 MQTT 主题下、挤在 JSON payload 的 nested 字段中,但没人教它“说话”,更没人教 AI “读图”。所谓“让 AI 自己看”,本质是把功耗数据从“原始信号”升级为“可理解语义”,再交给 AI 做实时判读——不是等你导出 CSV 再喂给大模型,而是让 AI 在毫秒级响应中,直接解析原始字节流、识别负载突变、定位谐波畸变、甚至推断电机轴承磨损趋势。
标题里的MCP,正是这个升级的关键枢纽。它不是硬件协议,也不是软件 SDK,而是一种面向 Agent 架构的标准化能力契约——就像 USB Type-C 接口定义了“插上就能充”,MCP 定义了“接入就能调用功耗分析能力”。你不用再为每个电表写一套解析逻辑,也不用为每个 AI 模型封装一遍 HTTP 接口;只要服务端实现了 MCP 规范,任何兼容 MCP 的 AI Agent(比如本地部署的 Ollama + LangChain 实例,或云端轻量推理引擎),就能像调用函数一样,直接发一条get_power_trend请求,拿到结构化的时间序列摘要和异常归因结论。
所以这个项目不是“又一个 IoT 后端”,而是一次数据语义层的基建重构。它解决的不是“能不能传数据”,而是“AI 能不能真正理解数据”。适用人群非常明确:
- 正在做智能电表/工业网关/能源管理平台的嵌入式工程师;
- 需要快速集成 AI 分析能力但不想重写整套后端的 IoT SaaS 开发者;
- 正在搭建本地 AI Agent 工作流、苦于找不到可靠设备数据源的 MLOps 工程师。
如果你还在用 Python 脚本轮询串口、用 Flask 暴露/api/v1/power?device_id=xxx这种接口,那你就是这个项目的天然目标用户——因为 MCP 服务端,会把你从“胶水代码搬运工”,变成“AI 能力编排者”。
2. 整体架构设计与 MCP 协议选型逻辑
2.1 为什么不是 REST?也不是 MQTT?——MCP 的不可替代性
刚接到需求时,团队第一反应是:“直接用 REST API 不就行?”——毕竟设备数据通过 Modbus TCP 上来,转成 JSON,丢进 FastAPI,再加个 JWT 鉴权,五分钟搞定。但实测三天后,我们推翻了方案。原因很现实:REST 是人写的,MCP 是 AI 调的。
举个典型场景:一个 AI Agent 要判断某台 CNC 设备是否处于“空载待机”状态。它需要的不是一串 raw data,而是:
- 过去 5 分钟的有功功率均值 & 标准差;
- 当前电流谐波 THD(总谐波失真率);
- 与同型号设备历史基线的偏差百分比;
- 附带置信度评分(比如“92% 概率为空载,依据:功率波动 < 0.3W,THD < 1.2%”)。
如果走 REST,AI 必须:
- 先 GET
/devices/{id}/metrics拿原始时间序列(可能 5000 条点); - 自己实现滑动窗口计算、FFT 谐波分析、基线比对算法;
- 再 POST
/analyze提交计算结果请求——这已经不是调用,是协同开发。
而 MCP 协议(以 MCP v0.4 为准)直接定义了get_device_power_state方法,参数明确要求device_id: str, window_minutes: int = 5, include_confidence: bool = True,返回结构固定为:
{ "state": "idle", "confidence": 0.92, "reasoning": ["power_std_dev < 0.3W", "THD_5th_harmonic < 1.2%"], "baseline_deviation_pct": -2.1 }AI 不用关心数据怎么来、算法怎么跑,只管发请求、收结构化结论。这才是真正的“能力即服务”。
至于 MQTT,它擅长的是“广播式分发”,比如把实时电压值推给所有订阅者。但 AI 的分析请求是按需、精准、带上下文的——它要查 A 设备过去 1 小时的功率拐点,同时对比 B 设备同期数据,还要关联 C 设备的温度告警。这种跨设备、跨维度、带计算逻辑的查询,MQTT 的 publish/subscribe 模型根本无法承载。它需要的是 RPC 风格的同步调用,而 MCP 正是基于 JSON-RPC 2.0 构建,天然支持 request-id、error code、method discovery 等关键能力。
2.2 服务端分层架构:从物理层到语义层的四层穿透
我们的 MCP 服务端不是单体进程,而是严格分层的四层架构,每一层解决一个确定性问题:
Layer 1:物理接入层(Hardware Abstraction)
负责与真实电表/传感器对话。我们不绑定具体协议,而是抽象出统一接口:
class PowerMeter: def read_voltage(self) -> float: ... def read_current(self) -> float: ... def read_energy_kwh(self) -> float: ...目前已实现:
- Modbus RTU(RS485,通过
pymodbus+serial); - Modbus TCP(工业网关直连,
pymodbus异步 client); - MQTT 消息桥接(订阅
powermeter/+/raw主题,解析 JSON payload); - 未来预留 CAN FD 接口(用于新能源车电池包功耗采集)。
提示:这一层必须做“协议熔断”。比如 Modbus 读超时设为 800ms,连续 3 次失败自动降级为缓存数据,并触发告警。实测中某台老式电表在雷雨天 Modbus 响应延迟高达 2.3s,若不做熔断,整个 MCP 请求链会卡死。
Layer 2:数据规整层(Data Normalization)
把不同来源的原始数据,统一映射到标准模型。例如:
- Modbus 寄存器地址
40001→voltage_l1(单位 V); - MQTT payload 中的
"current"字段 →current_l1(单位 A); - 所有时间戳强制转为 UTC+0,精度到毫秒。
关键设计是字段别名映射表(YAML 配置):
meters: meter_a: protocol: modbus_tcp host: 192.168.1.100 port: 502 register_map: voltage_l1: {addr: 40001, type: float32, scale: 1.0} current_l1: {addr: 40003, type: float32, scale: 0.01}这样新增设备只需改配置,不用动代码。
Layer 3:能力封装层(Capability Provider)
这是 MCP 的心脏。它把业务逻辑包装成标准方法,严格遵循 MCP spec 的capabilities发现机制。核心能力包括:
get_power_trend(device_id, start_time, end_time):返回聚合后的功率趋势点(每 10 秒一个点,含 min/max/avg);detect_anomaly(device_id, window_minutes=10):调用轻量 LSTM 模型(TensorFlow Lite 编译)检测异常;estimate_load_type(device_id):基于电流波形 FFT 特征,分类为“阻性”、“感性”、“开关电源”等。
注意:所有能力方法必须声明
@mcp_capability装饰器,自动注册到 MCP 的 capabilities 列表中。这是 AI Agent 发现可用功能的唯一途径。
Layer 4:MCP 传输层(Transport Adapter)
目前仅实现 HTTP/JSON-RPC 适配器(兼容curl和requests),但架构预留 WebSocket 和 gRPC 接口。HTTP 适配器的关键设计:
/mcp端点接收 JSON-RPC 2.0 请求;- 自动解析
method字段,路由到对应能力方法; - 错误码严格映射 MCP 标准:
-32601(method not found)、-32602(invalid params)、-32000(custom error,如设备离线)。
整个架构的收益非常直观:当客户要求增加“光伏逆变器发电预测”能力时,我们只需在 Layer 3 新增一个predict_pv_generation方法,写好业务逻辑,加个装饰器——其他三层完全不动。上线时间从传统方案的 3 天压缩到 45 分钟。
3. 核心细节解析:MCP 服务端的 7 个关键实现要点
3.1 MCP 方法签名设计:如何让 AI 真正“读懂”你的接口
很多开发者以为 MCP 只是换个名字的 REST,于是把方法名起成getPowerData,参数塞一堆start_ts,end_ts,agg_interval。结果 AI Agent 调用时频繁报错——因为它无法理解“agg_interval=60”到底代表“每分钟聚合”还是“聚合窗口 60 秒”。MCP 的方法签名,本质是给 AI 看的契约文档。
我们采用三原则设计签名:
- 语义化命名:方法名必须是动宾短语,且动词来自 MCP 标准动词集(
get,list,create,update,delete,detect,estimate,predict)。例如detect_power_anomaly,而非anomalyCheck。 - 参数强类型约束:所有参数必须标注类型和单位。Python 类型提示是基础,但更重要的是在 docstring 中用 OpenAPI 风格描述:
def detect_power_anomaly( self, device_id: str, window_minutes: int = 10, sensitivity: float = 0.7 # Confidence threshold for anomaly detection (0.0~1.0) ) -> Dict[str, Any]: """Detect abnormal power consumption pattern. Args: device_id: Unique identifier of the power meter (e.g., 'meter-001') window_minutes: Analysis time window in minutes (min: 1, max: 60) sensitivity: Detection threshold (higher = stricter, default 0.7) """- 返回值结构化:绝不返回裸 JSON。必须定义 Pydantic Model,强制字段存在性和类型:
class AnomalyResult(BaseModel): is_anomalous: bool confidence: float = Field(ge=0.0, le=1.0) severity: Literal["low", "medium", "high"] timestamp: datetime related_metrics: List[str] = ["voltage_l1", "current_l1"]实测效果:用llama.cpp本地运行的 Phi-3 模型,在未微调情况下,能 100% 正确解析window_minutes参数范围,并在用户输入“查最近半小时异常”时,自动将window_minutes设为 30,而不是错误地设为 1800(秒)。
3.2 设备发现与元数据同步:让 AI 知道“有哪些表、在哪、能干什么”
MCP 规范要求服务端必须提供list_resources方法,返回所有可操作资源的元数据。但我们发现,单纯返回{"id": "meter-001", "type": "power_meter"}远不够。AI 需要知道:
- 这台表支持哪些能力?(比如
meter-001支持detect_anomaly,但meter-002只支持get_power_trend) - 它的物理位置?(用于空间关联分析,如“同一配电柜下的三台表同时异常”)
- 基线数据在哪里?(用于
estimate_load_type的特征比对)
因此,我们扩展了list_resources的返回结构:
{ "resources": [ { "id": "meter-001", "type": "power_meter", "location": "factory_floor_a/panel_01", "capabilities": ["get_power_trend", "detect_anomaly"], "baseline_url": "http://mcp-server:8000/baseline/meter-001.json", "last_seen": "2024-06-15T08:23:41Z" } ] }其中baseline_url指向一个静态 JSON 文件,内容是该设备正常运行时的典型电流波形 FFT 特征向量(128 维)。AI 调用estimate_load_type时,服务端会自动下载并比对,无需 AI 自己维护基线库。
实操心得:
last_seen字段至关重要。我们用 Redis 记录每台设备最后一次成功读取时间,超过 5 分钟未更新则标记为offline。AI Agent 在调用前会先检查此字段,避免向离线设备发请求——这省去了大量无意义的超时等待。
3.3 时间序列处理的“三明治”策略:精度、性能、内存的平衡术
IoT 功耗数据是典型的时间序列,每秒可能产生 10~100 个点。直接存储原始点,1 小时就 36 万条。而 AI 分析通常只需要分钟级聚合数据(如每分钟平均功率)。我们采用“三明治”缓存策略:
- 底层:原始点写入 TimescaleDB(PostgreSQL 扩展),保留 7 天原始数据,用于审计和深度回溯;
- 中层:Redis Sorted Set 存储滚动窗口聚合数据,例如
meter:001:power:1min,每个成员是timestamp:avg_power,score 为时间戳。写入时用ZADD+ZREMRANGEBYSCORE维护最近 1000 分钟数据; - 顶层:内存 LRU Cache 存放高频查询结果,如
get_power_trend(meter-001, last_1h)的结果缓存 60 秒。
关键技巧在于聚合时机的选择:
- 不在写入时聚合(避免写放大);
- 不在查询时实时计算(避免高延迟);
- 而是在数据写入后 5 秒内,由独立 worker 异步触发聚合。Worker 监听 Redis Stream 的
raw_data流,收到新点后,检查其时间戳是否属于某个已开启的 1 分钟窗口(如2024-06-15T08:00:00Z),若是,则更新对应 Sorted Set 中的聚合值。
这样,get_power_trend方法只需ZRANGEBYSCORE一次 Redis 查询,毫秒级返回。实测 1000 台设备并发查询,P99 延迟稳定在 12ms 以内。
3.4 异常检测模型的轻量化落地:从 PyTorch 到 TFLite 的完整链路
标题里“让 AI 自己看”,必然涉及模型。但我们坚持一个原则:服务端不跑大模型,只跑轻量推理引擎。因为功耗异常检测不需要 GPT-4 级的理解力,需要的是毫秒级响应和确定性输出。
我们的模型链路如下:
- 训练阶段:用 PyTorch 训练一个 3 层 LSTM(隐藏层 64 单元),输入是 128 点电流序列(1 秒采样),输出是二分类概率。数据来自真实产线——正常运行 200 小时,异常样本(电机堵转、接触不良)共 127 个片段。
- 转换阶段:用
torch.onnx.export导出 ONNX,再用onnx-tf转 TensorFlow SavedModel,最后用TFLiteConverter转为.tflite模型(量化为 int8,体积从 12MB 压缩到 1.8MB)。 - 部署阶段:模型文件放入
models/目录,服务端启动时加载到内存。推理时,输入序列经 Z-score 标准化(用线上统计的均值/标准差,非训练集),送入 TFLite Interpreter。
关键细节:TFLite 的
Interpreter必须设置num_threads=1。实测多线程反而慢——因为模型小,线程切换开销 > 计算收益。单线程下,单次推理耗时 3.2ms(Raspberry Pi 4B)。
模型输出不直接给 AI,而是封装进detect_power_anomaly方法的返回体中,附带可解释性字段:
{ "is_anomalous": true, "confidence": 0.94, "explanation": "Current waveform shows 3rd harmonic amplitude > 15% of fundamental, typical of rectifier load failure" }这个explanation字段由规则引擎生成(非模型输出),基于 LSTM 的 attention weights 定位异常频段,再匹配预设规则库。AI Agent 拿到后,可直接生成中文报告:“检测到电流三次谐波超标,疑似整流桥故障”。
3.5 MCP 安全边界:如何防止 AI 把你的电表“玩坏”
开放 MCP 接口,等于把设备控制权部分交给 AI。必须建立硬性安全边界,否则一个错误的update_device_config请求可能让整条产线断电。
我们实施三层防护:
- 网络层:MCP 端点
/mcp仅监听127.0.0.1:8000,对外暴露需通过反向代理(Nginx)做 IP 白名单和速率限制(limit_req zone=mcp burst=5 nodelay)。 - 协议层:所有 MCP 请求必须携带
Authorization: Bearer <token>,token 由内部 OAuth2 server 签发,scope 严格限定为mcp:read或mcp:write。detect_anomaly只需 read scope,update_meter_config必须 write scope。 - 能力层:在能力方法内部做细粒度鉴权。例如
update_meter_config方法会检查:
权限数据来自 PostgreSQL 的if not user.has_permission("meter_config_write", device_id): raise MCPError(-32003, "Insufficient permission for device")device_permissions表,支持按设备组、角色、时间窗口授权。
最有效的防护是“只读默认”原则:所有 MCP 方法默认为只读。写操作(如update_*,create_*)必须显式声明@mcp_writable装饰器,且在服务端启动时打印警告日志:“WARNING: Writable capability 'update_meter_config' enabled”。上线前,运维必须手动确认。
3.6 日志与可观测性:当 AI 报错时,你得知道它到底想干嘛
AI Agent 的请求不像人,它不会告诉你“我点了按钮没反应”,而是静默失败。所以我们构建了全链路可观测性:
- MCP 请求日志:每条 JSON-RPC 请求记录
request_id,method,params,duration_ms,status_code(200/400/500),格式为 JSON Lines,写入/var/log/mcp/access.log。 - 能力执行日志:在每个能力方法入口,用
structlog记录结构化日志:logger.info("detect_power_anomaly.start", device_id=device_id, window_minutes=window_minutes, trace_id=trace_id) - AI 行为审计日志:当 AI Agent 调用
list_resources后,紧接着调用get_power_trend,我们会关联request_id,生成审计事件:“Agent 'energy-analyzer-v2' queried trend for meter-001 after resource discovery”。
这些日志全部接入 Loki + Grafana。我们创建了一个关键看板:
- 实时显示各能力方法的 P99 延迟(红线预警 > 50ms);
- 按
method分组的错误率(status_code >= 400); - 最近 1 小时内,哪个 AI Agent 调用最频繁(用于识别失控的循环调用)。
实操心得:曾发现某 AI Agent 因 bug,在
detect_anomaly返回is_anomalous=False时,仍不断重试。通过 Grafana 的“Agent 调用频次 Top5”看板,5 分钟内定位到问题 Agent,临时封禁其 token——没有这套可观测性,问题可能持续数小时。
3.7 本地开发与测试闭环:如何让 AI 开发者不依赖你的生产环境
MCP 的价值在于“即插即用”,但开发者不可能每次都连生产电表调试。我们提供开箱即用的本地测试套件:
- Mock Meter Server:一个独立进程,模拟 Modbus TCP 电表,响应预设的寄存器读取。启动命令:
python mock_meter.py --port 5020 --config test_meters.yaml。 - MCP Playground CLI:命令行工具,支持:
# 列出所有资源 mcp-cli list-resources --url http://localhost:8000/mcp # 调用能力(自动生成符合规范的 JSON-RPC 请求) mcp-cli detect-power-anomaly --device-id meter-001 --window-minutes 5 - AI Agent 测试沙箱:Docker Compose 环境,包含:
- MCP 服务端(连 Mock Meter);
- Ollama + Phi-3 模型;
- 预置的 LangChain Agent 脚本,演示如何用
Tool封装 MCP 能力。
开发者只需docker-compose up -d,然后运行python test_agent.py,就能看到 AI 如何自主发现电表、查询趋势、检测异常、生成报告——全程不碰真实硬件。
4. 实操过程:从零搭建 MCP 服务端的完整步骤
4.1 环境准备与依赖安装(5 分钟)
我们选择 Python 3.11 作为运行时,核心依赖如下(requirements.txt):
fastapi==0.111.0 uvicorn==0.29.0 pymodbus==3.6.1 redis==4.6.0 timescaledb-postgresql==2.14.2 tensorflow-lite==2.16.1 pydantic==2.7.1 structlog==23.3.0注意:
tensorflow-lite必须用pip install --extra-index-url https://google-coral.github.io/py-repo/ tflite-runtime安装,否则在 ARM 设备(如树莓派)上会报ImportError: libedgetpu.so.1。
安装步骤:
# 创建虚拟环境 python -m venv mcp-env source mcp-env/bin/activate # Linux/Mac # mcp-env\Scripts\activate # Windows # 升级 pip pip install --upgrade pip # 安装依赖(关键:先装 tensorflow-lite,再装其他) pip install --extra-index-url https://google-coral.github.io/py-repo/ tflite-runtime pip install -r requirements.txt # 初始化数据库(TimescaleDB) createdb iot_power psql -d iot_power -c "CREATE EXTENSION IF NOT EXISTS timescaledb;"4.2 配置文件编写:一份 YAML 搞定设备接入
创建config/meters.yaml:
meters: factory_main: protocol: modbus_tcp host: 192.168.1.100 port: 502 register_map: voltage_l1: {addr: 40001, type: float32, scale: 1.0} current_l1: {addr: 40003, type: float32, scale: 0.01} power_active: {addr: 40005, type: float32, scale: 1.0} lab_testbench: protocol: mock config: test_meters.yaml # 指向 mock meter 配置同时创建config/mock_meters.yaml(供本地测试):
meters: meter-001: voltage_l1: 220.5 current_l1: 12.3 power_active: 2710.0 # 模拟随机波动 noise: {amplitude: 0.5, frequency: 0.1}4.3 核心服务代码:从 FastAPI 到 MCP 能力注册
主服务文件main.py:
from fastapi import FastAPI, HTTPException, Depends from pydantic import BaseModel from typing import List, Dict, Any import json import asyncio from mcp_server import MCPService # 自研 MCP 封装库 # 初始化 MCP 服务 mcp_service = MCPService(config_path="config/meters.yaml") app = FastAPI(title="IoT Power MCP Server") @app.post("/mcp") async def handle_mcp_request(request: dict): try: # 解析 JSON-RPC 请求 method = request.get("method") params = request.get("params", {}) request_id = request.get("id", "unknown") # 路由到对应能力 result = await mcp_service.call_method(method, params) return { "jsonrpc": "2.0", "result": result, "id": request_id } except Exception as e: return { "jsonrpc": "2.0", "error": { "code": -32000, "message": str(e) }, "id": request_id } # 健康检查端点(非 MCP,供运维使用) @app.get("/health") def health_check(): return {"status": "ok", "mcp_ready": mcp_service.is_ready()}关键的mcp_server.py中,能力注册逻辑:
class MCPService: def __init__(self, config_path: str): self.meters = load_meters_from_yaml(config_path) self.capabilities = {} self._register_capabilities() def _register_capabilities(self): # 自动发现并注册所有 @mcp_capability 方法 for method_name in dir(self): method = getattr(self, method_name) if hasattr(method, '_is_mcp_capability'): self.capabilities[method_name] = method async def call_method(self, method_name: str, params: dict): if method_name not in self.capabilities: raise MCPError(-32601, f"Method '{method_name}' not found") return await self.capabilities[method_name](**params) # 装饰器,标记 MCP 能力方法 def mcp_capability(func): func._is_mcp_capability = True return func # 示例能力方法 @mcp_capability async def get_power_trend(self, device_id: str, start_time: str, end_time: str): # 实际逻辑:从 TimescaleDB 查询聚合数据 pass4.4 启动服务与首次验证
启动命令:
uvicorn main:app --host 0.0.0.0 --port 8000 --reload用curl验证 MCP 基础能力:
# 查询服务支持的能力列表 curl -X POST http://localhost:8000/mcp \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "method": "list_capabilities", "id": 1 }' # 调用一个能力(假设设备在线) curl -X POST http://localhost:8000/mcp \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "method": "get_power_trend", "params": {"device_id": "factory_main", "start_time": "2024-06-15T00:00:00Z", "end_time": "2024-06-15T00:05:00Z"}, "id": 2 }'预期响应(成功):
{ "jsonrpc": "2.0", "result": { "points": [ {"timestamp": "2024-06-15T00:00:00Z", "power_w": 2710.2}, {"timestamp": "2024-06-15T00:00:10Z", "power_w": 2708.7} ] }, "id": 2 }4.5 集成 AI Agent:用 LangChain 调用你的 MCP 服务
以 LangChain 为例,创建agent_demo.py:
from langchain.agents import Tool, AgentExecutor, create_json_chat_agent from langchain_community.chat_models import ChatOllama from langchain_core.messages import SystemMessage import requests # 定义 MCP 工具 def mcp_get_power_trend(device_id: str, start_time: str, end_time: str) -> str: """Get power trend data for a device.""" response = requests.post( "http://localhost:8000/mcp", json={ "jsonrpc": "2.0", "method": "get_power_trend", "params": {"device_id": device_id, "start_time": start_time, "end_time": end_time}, "id": 1 } ) return response.json().get("result", {}).get("points", []) mcp_tool = Tool( name="get_power_trend", func=mcp_get_power_trend, description="Get power consumption trend for a device. Input: device_id, start_time (ISO format), end_time (ISO format)" ) # 创建 Agent llm = ChatOllama(model="phi3", temperature=0.3) tools = [mcp_tool] # 系统提示词,强调 MCP 能力 system_message = SystemMessage(content=""" You are an energy analyst AI. You have access to an MCP server that provides real-time power data. Always use the 'get_power_trend' tool to fetch data before analyzing. Never guess values. If data is insufficient, ask for more specific time ranges. """) agent = create_json_chat_agent(llm, tools, system_message) agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True) # 运行查询 result = agent_executor.invoke({ "input": "What was the average power consumption of 'factory_main' between 2024-06-15T08:00:00Z and 2024-06-15T08:05:00Z?" }) print(result["output"])运行后,你会看到 Agent 自动调用get_power_trend,拿到数据,再计算平均值——整个过程无需人工干预,AI 真正“自己看了功耗计”。
5. 常见问题与排查技巧实录
5.1 典型问题速查表
| 问题现象 | 可能原因 | 排查命令/步骤 | 解决方案 |
|---|---|---|---|
curl调用/mcp返回500 Internal Server Error | MCP 服务未启动或配置文件路径错误 | ps aux | grep uvicorn;cat config/meters.yaml | 检查uvicorn进程是否存在;确认config/meters.yaml路径在main.py中正确引用 |
list_resources返回空数组 | 设备配置未加载或协议初始化失败 | tail -f /var/log/mcp/error.log;python -c "from mcp_server import MCPService; s=MCPService('config/meters.yaml'); print(s.meters)" | 查看 error.log 中的ModbusConnectionError;手动运行初始化检查,确认pymodbus能连通设备 |
get_power_trend返回[](空列表) | TimescaleDB 无数据或时间范围错误 | psql -d iot_power -c "SELECT COUNT(*) FROM power_data;";echo "2024-06-15T00:00:00Z" | date -f - | 确认数据写入进程(writer.py)正在运行;用date命令验证时间字符串格式是否为 UTC |
| AI Agent 调用超时(>30s) | Redis 连接池耗尽或模型推理阻塞 | redis-cli info clients | grep "connected_clients";top -p $(pgrep -f "tflite") | 增加 Redis 连接池大小(redis.Redis(max_connections=50));检查 TFLite 模型是否在 CPU 上跑满核 |
detect_anomaly总是 |