物流 TMS 数据库接入企微查件机器人实战
今年 7 月,一个做物流的朋友问我:能不能在企微群里发个单号就查到物流轨迹?
他们有一套跑了好几年的 TMS 系统,PostgreSQL 数据库,200+ 张表。没有 API 文档,没有开发团队,只有一个只读账号。
客服每天要查件。已有查询系统,但有单独的链接,操作路径长。目标就是在企微群里直接查。
数据库调研
连上 PostgreSQL TMS 库。200+ 张表,第一步是找到业务对应的核心表。
经过和对方确认业务流程,定位到三张核心表:
business_express— 运单主表,一个单号一条记录customerservice_track— 物流轨迹表,每次扫描/更新追加一行business_shipperconsignee— 收发件人表,记录发件人/收件人信息
核心关联逻辑:business_express 的一条记录,对应 customerservice_track 的多条轨迹、business_shipperconsignee 的一条收发件信息。
SQL 验证
找到核心表后,写了验证 SQL。目标:输入单号 → 返回运单信息 + 最新轨迹。
SELECT
e.business_customerinvoicecode,
COALESCE(st.order_statusname, e.business_status),
e.consignee_country,
s.consignee_name,
t.track_date,
t.track_location,
t.track_content
FROM business_express e
JOIN business_shipperconsignee s ON e.business_id = s.business_id
JOIN customerservice_track t ON e.business_id = t.business_id
LEFT JOIN basic_orderstatus st ON e.business_status = st.order_status
WHERE LOWER(e.business_customerinvoicecode) = LOWER($1)
ORDER BY t.track_date DESC
LIMIT 20
验证通过。只读查询,无写操作,无锁。
技术方案
确定了数据源后,搭建企微查件机器人。
调研阶段用 Python 验证可行性。但目标服务器是 Windows Server 2012,Go 单文件部署比维护 Python 环境省心,最终方案用了 Go:
企微群 @机器人 → Go Web 服务 → PostgreSQL TMS(只读)
- Go(chi 路由 + pgx 驱动):编译成单
.exe文件 - NSSM 注册 Windows 服务:开机自启、异常重启
- DeepSeek API:非查件类消息走 AI 闲聊兜底
- 只读账号:
GRANT SELECT,不做写操作
踩坑记录
无 API 文档时的对接思路
朋友公司没有 API 文档。反正没有,直接给了数据库只读账号——连上数据库看懂表结构就能干活。
表结构理解成本
200+ 张表,真正的核心只有 3 张。难点不是 SQL,是找到对的那几张表。这一点需要和业务方反复确认流程,光看字段名猜是不够的。
Go 还是 Python?
调研时先用 Python 3.8 写了验证脚本和原型。目标服务器是 Windows Server 2012,上面已经装了 Python 3.8,跑 Python 方案技术上没问题。
但还是选了 Go。原因:
| 对比项 | Python | Go 1.20 单文件 |
|---|---|---|
| 运行时 | 已有 Python 3.8 | 不需要,编译即完成 |
| 进程管理 | winsw/NSSM 包装 python 命令 | 直接注册 .exe |
| 依赖 | pip install + 维护虚拟环境 | go build 一个文件 |
| 异常恢复 | 进程退出需额外处理 | NSSM 自动拉起 |
| 版本限制 | Python 3.8 在 Server 2012 上能跑 | Go 1.20 是最后一个支持 Server 2012 的版本(Go 1.21 起要求 Windows 10+) |
Server 2012 已经是十几年前的操作系统,Python 和 Go 都受版本限制。Go 1.20 够用,单文件部署比维护 Python 环境省心太多。部署环境决定了技术选型,不是技术流行度。
企微客服消息:按 send_time 取最新
和内部群聊机器人不同,企微客服(KF)消息回调不直接发消息内容——它先发一个 kf_msg_or_event 事件通知,再通过 SyncKFMsg API 把真正的消息拉回来。
sync_msg 返回一个消息列表,包含该客服账号下所有未读消息。这个列表可能包含:
- 用户发的多条消息(只应该处理最新那条)
- 之前已经处理过的消息(重复推送)
- 非文本消息(图片、系统消息等)
所以不能简单地循环处理每条消息,逻辑是遍历列表,按 send_time 取最新一条:
var newest *wework.KFMsgItem
for i := range items {
if items[i].MsgType != "text" || items[i].Origin != 3 {
continue
}
if newest == nil || items[i].SendTime > newest.SendTime {
newest = &items[i]
}
}
过滤条件:MsgType == "text"(只处理文本消息)、Origin == 3(只处理客户发的消息,排除客服自己的回复)。找到最新消息后还需用 MsgID 去重,防止重复处理。
现状
能正常工作。
总结
- 老系统数据接入的核心门槛不是技术,是理解业务表结构
- 不需要对方提供 API 文档,有只读数据库账号就能接
- 部署方案要跟着环境走:Windows Server 2012 → Go 1.20 单文件 + NSSM 服务
- 从接到数据库到 SQL 验证通过,一个下午
这个方案适用于有老数据库、无 API 文档、想在 IM 里查数据的场景。