这个标题听起来有点大,但最近我真的在车间级的测试环境里把整套流程跑通了:DolphinDB 存着产线上每台设备的高频传感器数据,MCP Server 把 DolphinDB 的查询能力暴露给大模型 Agent,业务人员不用再天天找工程师导数据做报表,开口说人话就能查设备状态、复盘告警。这个过程让我对“工业 AI 落地”这件事的认识清晰了很多——不是算法不够强,而是模型根本够不到生产数据。这篇文章就把我从选型、搭 MCP Server、到让 Agent 真正处理设备数据的完整过程写出来,适合正在做工业大数据平台、或者想把大模型接进现有数据栈的工程师参考。
1. 工业AI为什么进不了生产系统?我看到的问题都出在“最后一公里”
1.1 项目里的典型困境:模型在机房,数据在产线
过去几年,我们团队接过的工业 AI 项目不算少,有做设备健康度预测的,有做产品质量归因的,还有做能耗优化的。可只要往生产系统里推,几乎都会卡在同一个地方:AI 模型拿不到“新鲜、干净、带上下文”的数据。
听上去很奇怪,因为产线上根本不缺数据。PLC、SCADA、数采网关每天疯狂往外吐数据,振动、温度、电流、压力,秒级甚至毫秒级都有,一天一个车间几十个 GB 也很正常。但数据落在哪呢?绝大部分落在各个厂商自带的实时库、历史库、关系库里,格式不统一,表结构不透明,要取数得先找设备厂商要文档,找信息中心开权限,再写一堆 ETL 才能把数据搬到算法组那边。
等数据折腾到模型手里,已经是三天前的事了。你拿三天前的数据去做预测性维护,跟看着后视镜开车没什么区别。工业场景的决策窗口往往是以小时、甚至分钟计算的,数据链路一长,AI 的价值就大打折扣。
1.2 数据接入不缺工具,缺的是“标准通路”
有人可能会问,现在不是有 Kafka、Flink、各种 API 网关吗?把这些串起来不就行了。理论上可以,实际做起来却非常痛苦。
问题在于,每一套系统都有自己的接入方式。OPC UA 是一套协议,Modbus 是一套,厂商私有 API 又是一套。你想让 AI Agent 去查“3号空压机过去一周的振动趋势”,它得知道去哪台机器、哪个库、哪个表、哪个字段对应哪个物理量,还要知道时间字段用什么格式、单位是什么。这些东西全部是隐性的知识,散落在工程师脑子里。
在这种情况下,即便你把一个训练好的模型放到生产环境旁边,它也是个瞎子。因为它没有一个统一、标准的方式去访问现场的实时数据和历史数据。我们要解决的核心问题,不是“再做一个更聪明的模型”,而是“让模型能够在一个安全的边界内,自由地查询生产数据”。
1.3 为什么我在选型时赌了 MCP
后来 MCP(Model Context Protocol)进入我的视野,我第一反应是:这不就是给 AI 用的“USB-C 接口”吗?
以前的 AI 应用接入数据,基本是“一对一”定制开发。你要让 AI 能查数据库,就得写一套工具调用封装;要让 AI 能操作工单系统,又得写一套。每接一个新系统,开发量几乎线性增长。而 MCP 做的事情是:定义了一套统一的协议,让 AI 应用(Host/Client)和外部数据源(Server)之间,通过标准的工具调用、资源读取、提示词模板来交互。
说人话就是:我只要把 DolphinDB 封装成一个 MCP Server,任何支持 MCP 的客户端——Claude Desktop、Cursor、自研的 Agent 框架——都能直接发现它、调用它。以后不止一个 AI 应用能用,整个团队的所有 Agent 都能共用这一层数据能力。
我这个判断,在自己动手搭完一个 DolphinDB MCP Server 之后更确定了。这确实是目前把工业 AI 真正推进生产系统里,最值得走的一条路。
2. 为什么是 DolphinDB + MCP:一个时序库、一个协议的组合逻辑
2.1 DolphinDB 不是普通数据库,它是为时序和分析而生的
很多做业务系统的人可能不熟悉 DolphinDB,我先花一点篇幅讲清楚它的位置。工业数据有个特点:数据量大、带有明确的时间戳、按设备维度不断追加。传统关系型数据库(MySQL、PostgreSQL)在几十亿行这种量级下做聚合分析,响应速度会非常感人;而像 Redis 这种内存库,又不适合做海量历史数据的复杂计算。
DolphinDB 是分布式时序数据库,它的核心优势有几个:一是列式存储,能高效处理海量时序数据;二是内置了强大的计算引擎,SQL 语法里可以直接写很多时序分析函数,比如移动平均、异常检测、窗口计算;三是支持分区存储,可以按时间、按设备分区,查询时能快速裁剪数据。
在做工业 AI 时,DolphinDB 往往承担“数据底座”的角色。产线数据经过采集和清洗后,写入到 DolphinDB 的分区表里,后续无论是做实时监控、历史回溯,还是给模型提供训练样本,都从它这里出数。我们项目里有不少查询是“过去 30 天、60 台设备、每 5 分钟一个指标”这种量级的,换成别的库早就慢得没法用了,DolphinDB 还能保持在秒级返回。
2.2 选型前我列的“数据底座与 AI 接入”能力清单
为了不让选型拍脑袋,我专门列了一个清单,用四个维度来评估这套组合能不能扛住生产系统:
| 维度 | 要求 | DolphinDB + MCP 的对应能力 |
|---|---|---|
| 时序写入能力 | 支持高频写入、海量数据落地 | DolphinDB 分区表 + 流数据框架,写入吞吐很稳 |
| 查询计算能力 | 能在数据库内直接做聚合和时序分析 | 内置大量时序函数,SQL 里直接算移动平均、分位数 |
| AI 可访问性 | 大模型能理解数据、能执行查询 | MCP Server 把表结构、字段含义、查询能力暴露给模型 |
| 权限与安全 | 生产环境不允许绕过权限 | MCP Server 后端使用只读账户,SQL 白名单 + 超时控制 |
我实际测下来,最有感觉的就是“AI 可访问性”这一栏。以前想做一个自然语言查数功能,要从零写 NL2SQL、做语义解析、做字段映射,工程量非常大。而 MCP 天然给大模型提供了工具描述和参数 schema,模型能读懂“这个工具是查询振动数据的,参数是设备编号和时间范围”,于是语义理解这件事就被协议层解决了一大半。
2.3 为什么不自己写一版 REST API 给 Agent 用
这是我在评审时被问得最多的问题:“你直接写个 Flask 接口,把 SQL 结果封装成 JSON 返回不就完了?非要搞个 MCP 干嘛?”
说实话,如果只服务一个模型、只暴露一个查询能力,自己写 REST API 确实更直接。但放到生产系统里看,差别就出来了。
REST API 的问题在于:接口的语义是“死的”。你写一个/api/vibration/query,传入device_id和time_range,返回 JSON。模型能调用,但模型并不知道这个接口返回的字段代表什么含义,也不知道还有哪些可用的分析和查询接口。你需要把每个接口的用途、参数、返回结构全部塞进 system prompt 里,而且塞得再多,模型面对一个新的查询需求时也无法组合这些接口。
MCP 则不同。它的 Tool 描述是有结构的,模型可以通过 server 返回的工具列表,自己去理解“有哪些能力可用”、“每个能力需要什么参数”。Agent 可以根据用户的一句话,自主决定先查表结构、再跑聚合、最后取详细记录,把多个工具串起来用。这种动态组合能力,是静态 REST API 很难给的。
2.4 MCP 的三方角色和一次完整调用
MCP 的架构不复杂,总共就三个角色:
- Host:用户面对的 AI 应用,比如 Claude Desktop、Cursor,或者我们内部开发的 Agent 平台,负责接收用户意图。
- Client:Host 内部的连接组件,负责和 Server 建立会话、收发消息。这个概念有点像 JDBC 里的 Driver。
- Server:暴露数据和能力的服务。我们这里就是 DolphinDB MCP Server——它接收标准 MCP 请求,翻译成 DolphinDB 查询,把结果返回给模型。
一次调用的流程大概是这样的:用户在 Host 里输入一句需求,模型判断需要调用某个工具,Client 就把“工具名 + 参数”通过 JSON-RPC 发到 Server;Server 执行 DolphinDB 脚本获取结果,再把结构化结果返回给模型。整个过程走的是标准协议,不是某家公司私有的一套东西。
3. DolphinDB MCP Server 搭建全过程:从目录结构到可运行代码
3.1 整体架构:四层进程各司其职
我建议你把这两套进程的关系在脑子里先立起来:
业务入口(Host/Agent) ↓ MCP 协议(stdio 或 HTTP) DolphinDB MCP Server(Python 进程) ↓ dolphindb Python SDK DolphinDB 分布式集群(数据存储与计算节点) ↓ 产线数采入库(Kafka/API/写入网关)MCP Server 本质上是一个常驻的 Python 进程。它一方面通过 MCP 协议和上层的 AI 客户端通信,另一方面通过 DolphinDB Python SDK 连接 DolphinDB 集群,执行查询、取回 DataFrame、转成 JSON,再送回给上层。中间不经过业务系统的数据库,AI 只能通过我们暴露的工具来接触数据,这本身就是一个很好的安全边界。
3.2 环境准备和依赖安装
先说环境。DolphinDB 我用的是集群版,版本在 2.00.x 以上,装好之后会有一个用于查询的只读账号。MCP Server 这边我用 Python 3.10,单独建一个虚拟环境,避免和公司其他 Python 服务互相污染。
需要安装的核心依赖不多,就三个:
pip install dolphindb pip install mcp pip install fastmcpdolphindb是官方 Python SDK,负责和数据库通信;mcp是官方协议库;fastmcp是一个让 MCP Server 开发变得非常省事的封装库,用装饰器就能把普通函数暴露成工具,省掉一堆样板代码。
3.3 用 FastMCP 写出第一个 Server
我不喜欢把代码写得绕来绕去,FastMCP 的好处就是直观。下面是一版能跑通“查询表结构 + 执行只读 SQL”的最小实现,放在dolphindb_mcp_server.py里:
import os import json import re import dolphindb as ddb from mcp.server.fastmcp import FastMCP mcp = FastMCP("dolphindb-mcp") DDB_HOST = os.getenv("DDB_HOST", "127.0.0.1") DDB_PORT = int(os.getenv("DDB_PORT", "8848")) DDB_USER = os.getenv("DDB_USER", "ai_reader") DDB_PWD = os.getenv("DDB_PWD", "") MAX_ROWS = 2000 QUERY_TIMEOUT_SEC = 15 _IDENTIFIER_RE = re.compile(r"^[A-Za-z_][A-Za-z0-9_]*$") _SAFE_ONLY_SQL_PREFIX = ("select", "show", "desc") def _get_session(): session = ddb.session() session.connect(DDB_HOST, DDB_PORT, DDB_USER, DDB_PWD) session.run("setMaxQueryMem=16GB") return session def _validate_identifier(name: str, label: str = "identifier") -> str: if not _IDENTIFIER_RE.match(name): raise ValueError(f"invalid {label}: {name}") return name @mcp.tool() def list_tables(database_path: str = "dfs://iot_assets") -> str: """列出指定分布式数据库下的所有数据表,返回表名列表。""" _validate_identifier(database_path.replace("dfs://", ""), "database") conn = _get_session() try: tables = conn.run( f"exec tableName from pnodeDatabases(['{database_path}'])" ) return json.dumps(tables.to_dict("records"), ensure_ascii=False, default=str) finally: conn.close() @mcp.tool() def get_table_schema(database_path: str = "dfs://iot_assets", table_name: str = "sensor_5m") -> str: """获取某张表的字段名、类型,帮助模型理解表结构。""" _validate_identifier(table_name, "table_name") conn = _get_session() try: schema = conn.run(f"schema(loadTable('{database_path}', '{table_name}')).colDefs") return json.dumps(schema.to_dict("records"), ensure_ascii=False, default=str) finally: conn.close() @mcp.tool() def query_sql(sql: str) -> str: """执行只读 SQL,返回结果集 JSON。只允许 SELECT/ SHOW / DESC 开头。""" stripped = sql.strip().lower() if not stripped.startswith(_SAFE_ONLY_SQL_PREFIX): raise ValueError("only read-only queries are allowed") if stripped.startswith("select") and "limit" not in stripped: raise ValueError("select query must include a limit") conn = _get_session() try: df = conn.run(sql) if len(df) > MAX_ROWS: df = df.head(MAX_ROWS) return json.dumps({"rows": len(df), "data": df.to_dict("records")}, ensure_ascii=False, default=str) finally: conn.close() if __name__ == "__main__": mcp.run()这段代码有几点值得说明:列表中的list_tables里的查询脚本,我用了pnodeDatabases之类的服务端函数来获取表信息,实际版本可能会略有差异。你在自己的环境里,可以直接用 Python SDK 的s.loadTable(...)再读 schema,效果一样,不必死抠我这里的脚本写法。
关键是后面两个设计:get_table_schema给模型“理解数据”的能力,query_sql给模型“操作数据”的能力。就这么两组工具,已经能让模型在大部分查数场景里跑起来了。
3.4 核心工具的取舍:能力边界比功能数量更重要
刚开始做这个 Server 时,我的第一版工具特别多,什么query_device_list、query_sensor_avg、query_anomaly_count,把业务功能一个个往上堆。结果在实际测试中发现,工具越多,模型越容易选错,而且每个工具的描述、参数、返回格式都要维护,成本极高。
后来我把思维从“按业务功能切工具”转成“按数据能力切工具”。业务上再复杂的分析,本质都可以归约成几个基础动作:看有哪些表、看表结构、执行只读查询、执行预置分析函数。所以我最终在一线环境里保留的工具面非常窄,但每个工具都很通用。模型通过组合这些通用工具,反而能处理更多之前没预料到的查询。
这条经验我想放在前面重点说:MCP Server 不是功能堆得越多越好。给大模型暴露的工具,要像给实习生开放的权限一样——够用,但不能越界。
3.5 客户端配置与连通性自测
Server 写好后,先在命令行直接跑一遍,确认没有 import 错误:
python dolphindb_mcp_server.py看到 MCP server 启动成功的日志后,把它配到客户端里。比如 Claude Desktop,需要在配置文件里加一段:
{ "mcpServers": { "dolphindb": { "command": "python", "args": ["/path/to/dolphindb_mcp_server.py"], "env": { "DDB_HOST": "10.20.1.5", "DDB_PORT": "8848", "DDB_USER": "ai_reader", "DDB_PWD": "your-password" } } } }配置完之后,重启客户端,在工具列表里应该能看到dolphindb下的几个工具。如果看不到,优先检查环境变量是否注入成功、脚本路径是否是绝对路径,以及客户端是不是加载到了旧的配置缓存。这里踩坑的人特别多,后面我会单独写一节。
4. 跑通一个真实生产任务:让 Agent 自己查设备、算超限、写结论
4.1 场景设定:空压机的振动告警分析
光把 MCP Server 跑起来不算本事,关键要看 Agent 能不能独立解决一个真实的生产问题。我拿车间里最常见的场景来演示:空压机振动异常分析。
空压机是产线动力的核心设备,一旦非计划停机,上下游全停。振动值是判断轴承、转子健康状态的重要指标。我们每天都会看振动数据,但人工看报表效率太低——得先从库里导出数据,再用 Excel 透视表算超限时长,最后人工写分析结论。整个过程熟练工程师也得花半小时以上。
在 DolphinDB 里,我们有一张 5 分钟聚合的传感器表,主要字段如下:
| 字段名 | 类型 | 说明 |
|---|---|---|
| device_code | SYMBOL | 设备编号,如 A-03 |
| ts | TIMESTAMP | 采样时间 |
| vibration | DOUBLE | 振动速度有效值(mm/s) |
| temperature | DOUBLE | 轴承温度(℃) |
| current | DOUBLE | 电流(A) |
建表脚本大概是这样的:
login("admin", "123456") db = database("dfs://iot_assets", VALUE, 2025.01M..2025.12M, engine="TSDB") schema = table( id=`device_code` as symbol, `ts` as timestamp, `vibration`as double, `temperature` as double, `current` as double ) db.createPartitionedTable(schema, "sensor_5m", "ts")这张表按月份分区,加上设备编号列的索引,查询特定设备在某个时间范围的数据时,DolphinDB 能只扫描必要分区,速度很快。
4.2 给模型的一句“人话”需求
我们在接入了 DolphinDB MCP Server 的客户端里,直接输入下面这句话:
请查一下今天 00:00 到 16:00,A-03 空压机的振动数据。标准是振动速度有效值不能超过 6.3mm/s,帮我统计超限次数、单次最长持续时间,以及超限期间对应的温度和电流均值,最后生成一段简要的分析结论。
如果是以前,这句话意味着:查数据、写 SQL、设计统计逻辑、手动算均值、写报告,五个环节全部要人工处理。现在,Agent 会自己拆解需求、规划步骤,并调用我们的 MCP 工具。
4.3 Agent 实际运行的调用链条
我在日志里看过它完整的工具调用过程,流程非常清晰:
第一步,Agent 调用get_table_schema,确认sensor_5m表有哪些字段、字段类型。它需要知道振动字段叫什么、时间字段叫什么叫才能写 SQL。
第二步,Agent 调用query_sql,筛选出今天指定设备的数据。如果发现返回数据量不够,它会自动调整 SQL,进一步缩小时间范围。
第三步,Agent 自己判断“6.3mm/s 是阈值”,写一个 SQL 把超过阈值的记录打上标记,再用窗口函数把连续超限的时段合并成一个个事件,统计每个事件的持续时长。
第四步,Agent 再跑一条 SQL,计算超限期间的平均温度和平均电流。
第五步,Agent 把前面的统计结果汇总成自然语言结论,直接告诉用户。
实际得到的结果类似:A-03 在 02:12 至 03:48 之间出现 2 次超限,最长持续 41 分钟;超限期间平均温度 78.6℃,明显高于正常工况的 65℃ 左右。因此提示可能轴承润滑不良或磨损加重,建议检查润滑系统并安排一次振动频谱测试。
老实说,第一次看到这个完整流程跑通的时候我是有点惊讶的。因为整个过程中,没有人告诉它 6.3 这个阈值对应哪个字段,没有人帮它写那条复杂的超限合并 SQL,它完全是靠着表结构信息和通用数据能力自己推理出来的。
4.4 和传统方式比,提升的核心不是“快”而是“日常可用”
有人说,这种结果我们写个固定报表也能出,而且比大模型稳定。我不否认,固定报表在标准指标上确实稳定;但工业现场的问题是:需求永远在变。今天想看振动,明天想看电流波动,后天又想把两个设备放在一起对比,每次需求变化都要找开发改报表,周期以周计。
MCP + Agent 的价值在于,它把“数据分析”这种原本需要专业技能的工作,降维成了“日常对话”。对于车间设备工程师来说,他不需要会 SQL,也不需要知道数据在哪个表里,只要会描述“我想看什么”,Agent 就能自己去 DolphinDB 里折腾。这恰恰是我理解的“工业 AI 进入生产系统”——不是做一两个炫酷的算法 Demo,而是让 AI 成为日常工作中随手可用的数据助手。
5. MCP 要进生产环境,必须先守住这四条底线
5.1 只读账户和最小权限是底线中的底线
工业数据是生产核心资产,权限控制不能有任何侥幸心理。MCP Server 背后连接数据库的账号,我强烈建议单独建一个只读用户,绝不使用管理员账号,更不要把直连生产库的高权限账号密码放到 MCP Server 的环境变量里。
DolphinDB 里可以给账号授权最小权限。我这里的ai_reader账号只拥有select权限,连建表、删表、写入的权限都没有。这样就算某个环节被攻击,甚至大模型把 SQL 写错了,最坏的结果也只是查询失败,不会造成数据破坏。生产系统的安全设计,不是防住所有人,而是把每一次操作的爆炸半径都压到最小。
5.2 SQL 注入和大模型“幻觉 SQL”都要防
很多人担心大模型生成的 SQL 会注入,我觉得这个担心不太准确——真正要防的不是模型故意使坏,而是它“一本正经地生成一段错误 SQL”。比如模型以为字段叫vibrate,实际表里叫vibration,SQL 就会报错;更麻烦的是模型可能拼接出一些语义不对的查询,返回结果看似正常但实际含义完全错误。
我的防护做法是三层:第一层,后端只读账号,从权限上保证任何 SQL 都改不了数据。第二层,MCP 工具层校验,query_sql只放行select、show、desc开头的 SQL,而且强制必须有limit,防止模型真跑一个全表扫描。第三层,在工具描述里把表结构、字段单位、常用取值约束写得非常清楚,从源头降低模型生成错误 SQL 的概率。
当然,强制limit这招也有副作用,比如模型想算一个全量数据的聚合,结果被截断后聚合值就是错的。所以我只在探索性的query_sql里强制 limit,另外提供一个专用的聚合查询工具,里面由我预写好 SQL 模板,模型只能传设备、时间等参数,不能自行拼接整段 SQL。生产环境里一定要做这类“参数化工具”和“自由 SQL 工具”的隔离。
5.3 超时、限流和结果集上限
AI Agent 有时候会在同一个问题上反复尝试,如果每个查询都放出去,DolphinDB 再能扛也扛不住。生产环境中,我给三个维度都加了限制。
第一个是查询超时。MCP Server 里对 DolphinDB 连接设置了 15 秒的执行超时,超过就取消,避免个别慢查询把数据库连接池拖垮。第二个是结果集上限,不管 SQL 返回多少行,最终回给 Agent 的只保留 2000 行,数据量再大时就提示模型走聚合查询或者缩小时间范围。第三个是并发限制,我给 MCP Server 加了个信号量,同一时刻最多允许 4 个查询并发,超过的请求直接拒绝并提示稍后重试。
这些限制单独看都会牺牲一点体验,但合在一起才能保证生产系统不被打挂。MCP 给 AI 打开了数据大门,但门里必须装上减速带。
5.4 把慢查询问题解决在源头:分区和预聚合
有一次,Agent 回答一个跨三个月、查全部设备的统计问题时,卡了将近半分钟。查了执行计划才发现,它写出来的 SQL 没有带任何时间范围条件,等于把三个月几十亿行数据全部扫了一遍。虽然最后返回了结果,但这种查询如果在白天高峰期多来几个,DolphinDB 也受不了。
解决思路不是去限制 Agent 不许查全量数据,而是从数据架构上让慢查询“慢不下来”。我们做的第一件事是确认所有表都按时间分区,这样只要 SQL 里带时间条件,DolphinDB 就能直接裁剪掉不相关的分区。第二件事是把最常用的指标做了预聚合,比如 5 分钟明细之上再维护一张 1 小时的均值表,绝大多数宏观分析直接查预聚合表就行。第三件事是在 MCP 工具的说明里明确告诉模型:查全量趋势请用agg_1h表,查具体超限事件才用sensor_5m明细表。模型看到工具描述后,绝大多数情况下会主动选择合适的数据源。
6. 实战中踩过的坑与排查速查表
6.1 MCP 工具在客户端里总是注册不上
这个问题我跟同事排查过整整一下午。现象是:MCP Server 在命令行里单独跑没问题,但配置到客户端后,工具列表里就是看不到dolphindb相关工具。
后来定位到三个原因:第一,客户端启动 MCP Server 时用的是自己继承的环境变量,我在终端里 export 的变量它拿不到,尤其是 PATH 里找不到 Python 命令。解决办法是配置文件里command直接写 Python 的绝对路径。第二,脚本里依赖了本地某个包,但该包没装到客户端使用的 Python 环境里。解决办法是尽量用虚拟环境,并让command指向虚拟环境里的python。第三,MCP Server 启动时如果有任何报错,客户端默认会静默失败,想排查就得看客户端日志,把日志打开后往往能发现真正的报错堆栈。
这里建议大家,凡是遇到工具注册不上的问题,第一反应不是改代码,而是先去客户端日志目录把 MCP Server 的 stderr 捞出来看。80% 的问题都藏在日志里。
6.2 大模型生成的 SQL 不符合 DolphinDB 语法
这个坑几乎无法避免。大模型训练语料里,最熟悉的是 MySQL 和 PostgreSQL 的 SQL 方言,而 DolphinDB 的 SQL 在窗口函数、表函数、时序函数上都有自己的写法,直接让模型自由写 SQL,经常会生成“合成错误”。
我的对策有三个:第一,在系统提示里明确告诉模型“当前数据库是 DolphinDB,语法与 MySQL 不同”,并附上两三个正确的例子。第二,尽量少开放自由 SQL 工具,多预设一些高频场景的参数化工具,让模型输入的是参数而不是整段 SQL。第三,如果确实要写复杂 SQL,建议先用一个explain类工具来验证语法,把验证通过后的 SQL 再真正执行。
6.3 Agent 在同一个问题上反复调用,造成重复查询
AI Agent 有一个常见毛病:如果第一次的查询结果没有完全满足用户问题,它会基于同样的思路反复执行类似的查询,像是在“猜答案”。我见过一个简单问题触发十几次工具调用的,数据库都被打出一堆慢查询日志。
针对这个问题,我在 MCP Server 里做了一层简单的缓存:对于相同的工具名、相同参数的调用,在 30 秒内直接返回上次结果。这个策略非常有效,因为 Agent 在同一轮对话里的多次尝试,往往是基于同一批数据。加入缓存后,重复查询基本消失了,用户体验也变得更流畅。更高级一点的做法是把缓存下沉到 DolphinDB 的数据访问层,但对我目前这个量级来说,MCP Server 这层缓存已经够用。
6.4 一些排查经验速查
| 现象 | 可能原因 | 排查顺序 |
|---|---|---|
| 工具列表不出现 | 环境变量/PATH 问题、依赖缺失、启动报错 | 1. 看客户端日志 2. 检查绝对路径 3. 命令行手动启动验证 |
| SQL 执行一直超时 | 缺少时间范围条件、扫了全量分区 | 1. 看 SQL 条件 2. 检查执行计划 3. 改用预聚合表 |
| 返回数据含义不对 | 工具描述不清,模型选错字段或表 | 1. 检查工具描述 2. 核对字段单位 3. 补充示例 |
| Agent 反复查同一问题 | 上下文不连续、无缓存 | 1. 增加 MCP Server 缓存 2. 观察工具调用链 3. 提炼 prompt 约束 |
7. 一点个人体会和后续扩展
把 DolphinDB MCP 这套东西真正跑通之后,我最大的体会是:工业 AI 进入生产系统的难点,从来不在模型精度,而在“让 AI 与真实生产数据建立标准、安全、低摩擦的连接”。MCP 恰好在这个位置上补了一个大窟窿。它不要求你推翻现有的数据架构,也不要求你学会一套全新的 AI 框架,只需要你写一个薄薄的适配层,就能让你已有的数据底座变得“AI 可用”。
如果后续要继续扩展,我个人觉得有两个方向特别值得做。第一个方向是把设备告警事件回流到 DolphinDB,让 Agent 不仅能查数据,还能在发现异常时自动写入一条待确认事件,这样就形成了“AI 发现问题—人工复核—事件归档”的闭环。第二个方向是在 MCP Server 上引入工业知识库的检索功能,比如把设备维修手册、历史故障案例都塞进向量库,让 Agent 在查完数据后还能结合维修经验给出排查建议。这两个方向做完,工业 AI 就不再是一个“查数机器人”,而是真正懂设备、懂工况的产线助手了。