在企业微信中,通过使用智能机器人,完成数据库的查询,也就是通过企业微信智能机器人,使用自然语言查询数据库,实现 AI 驱动的数据检索。
由于种种原因,最终实现这个功能的最终架构如下:
员工提问(企业微信)
↓
企业微信智能机器人(API长连接模式)
↓
LangBot(消息中转桥梁,WebSocket连接)
↓
Dify 工作流(编排 AI 逻辑)
↓
db_query 插件(Dify 内置数据库查询工具)
↓
SSH 隧道(autossh,端口转发)
↓
内部数据库服务器(MySQL)1 企业微信智能机器人创建(API长连接模式)
- 登录企业微信管理后台 (
work.weixin.qq.com)。 - 进入「管理工具」→「智能机器人」,点击“创建机器人”。
- 选择“手动创建”,然后选择“API模式创建”。
- 在连接方式中,选择 “长连接”(不要填写任何回调 URL)。
创建完成后,记录以下三个关键信息:
- 企业 ID (
CorpID):在「我的企业」页面底部获取。 - 机器人 ID (
BotId):在机器人详情页获取。 - 机器人 Secret (
Secret):在机器人详情页生成并保存。
- 企业 ID (
2 LangBot 部署与配置
LangBot 作为企业微信和 Dify 之间的“桥梁”,支持 WebSocket 长连接,无需公网域名。
2.1 部署 LangBot(Docker)
# 在 服务器上执行
docker run -d \
--name langbot \
-p 5300:5300 \
-v /path/to/langbot/data:/app/data \
--restart unless-stopped \
ghcr.io/langbot-app/langbot:latest访问 LangBot登录地址 进入 WebUI,默认账号密码见官方文档。
2.2 配置企业微信机器人
- 登录 LangBot WebUI。
- 进入「机器人」→「创建机器人」。
- 平台选择 “企业微信智能机器人”。
填入:
- 企业 ID
- 机器人 ID
- 机器人 Secret
- 关闭「启用 Webhook」选项(即使用长连接)。
- 保存并启动机器人,状态应显示“已连接(WebSocket)”。
2.3 创建流水线并绑定 Dify
- 进入 LangBot「流水线」→「创建流水线」,命名如“数据库查询助手”。
- 在「AI 能力」中,将运行器设为 “Dify”。
填写:
- Base URL:
https://api.dify.ai/v1(或自部署地址) - API Key:从 Dify 工作流应用的「访问API」页面获取
- 应用类型:选择 “工作流”
- Base URL:
- 回到「机器人」编辑页面,将流水线绑定到该机器人。
3 Dify 工作流创建
- 登录 Dify,进入「工作室」→「创建空白应用」。
- 应用类型选择 “工作流”。
设计工作流,至少包含:
- 开始节点:接收用户输入(如
query变量)。 - db_query 节点(稍后配置)。
- 结束节点:输出查询结果。
- 开始节点:接收用户输入(如
- 发布工作流,并在「访问API」页面生成 API 密钥(用于 LangBot 配置)。
4 SSH 隧道建立
由于数据库服务器只能通过 SSH 公钥认证访问,且 Dify 运行在 Docker 容器中,我们在 Dify 服务器上建立一个 SSH 隧道,将数据库的 3306 端口映射到本地的 3307 端口,并让隧道监听所有接口(0.0.0.0),以便 Docker 容器可以访问。
4.1 测试 SSH 连通性
# 在 Dify 服务器上测试
ssh -i /env/server_key root@数据库服务器IP
# 应能直接登录(免密)4.2 建立隧道(使用 autossh)
# 安装 autossh
sudo apt-get install autossh # Ubuntu/Debian
# 后台运行隧道(监听所有接口)
autossh -f -M 0 -L 0.0.0.0:3307:127.0.0.1:3306 -i /env/server_key root@数据库服务器IP -N参数说明:
-f:后台运行-M 0:禁用内置监控端口(与-N配合)-L 0.0.0.0:3307:127.0.0.1:3306:将本机所有接口的3307映射到数据库服务器的3306-N:不执行远程命令,仅端口转发
4.3 配置为 systemd 服务(开机自启)
创建服务文件 /etc/systemd/system/db-tunnel.service:
[Unit]
Description=SSH Database Tunnel
After=network.target
[Service]
User=root
ExecStart=/usr/bin/autossh -M 0 -L 0.0.0.0:3307:127.0.0.1:3306 -i /env/server_key root@数据库服务器IP -N
Restart=on-failure
RestartSec=10
[Install]
WantedBy=multi-user.target启动并启用:
sudo systemctl daemon-reload
sudo systemctl enable db-tunnel
sudo systemctl start db-tunnel
sudo systemctl status db-tunnel4.4 验证隧道
# 查看端口监听
ss -tlnp | grep 3307
# 应显示 0.0.0.0:3307 处于 LISTEN 状态
# 宿主机测试
mysql -h 127.0.0.1 -P 3307 -u dify -p5 Dify 中 db_query 插件配置
在 Dify 工作流中添加 db_query 节点(从插件市场安装),填写如下:
| 参数 | 值 |
|---|---|
| 数据库类型 | MySQL |
| 数据库地址 | 172.16.1.252(宿主机内网 IP) |
| 端口 | 3307 |
| 用户名 | XXX |
| 密码 | (数据库用户密码) |
| 库名 | XXXX |
| SQL查询语句 | 使用变量或固定语句(后续可结合 LLM 动态生成) |
| 输出格式 | JSON |
关键点:数据库地址必须填写宿主机的内网 IP,因为 Dify 容器内无法直接使用宿主机的 127.0.0.1。经过测试,172.16.1.252 是宿主机 eth0 的 IP。
6 数据库用户权限配置(MySQL)
6.1 创建用户并授予只读权限
最终我们使用 dify@localhost 用户(已从 % 收紧为 localhost),并使用 mysql_native_password 认证插件(兼容 pymysql)。
登录数据库服务器 MySQL(root 用户),执行:
-- 删除已存在的用户(可选)
DROP USER IF EXISTS 'XXX'@'localhost';
DROP USER IF EXISTS 'XXX'@'%';
DROP USER IF EXISTS 'XXX'@'127.0.0.1';
-- 创建用户(使用 mysql_native_password)
CREATE USER 'XXX(用户名)'@'localhost' IDENTIFIED WITH mysql_native_password BY '密码';
-- 授予 数据库XXX 的只读权限
GRANT SELECT ON `XXX(数据库名)`.* TO 'XXX(用户名)'@'localhost';
-- 刷新权限
FLUSH PRIVILEGES;
-- 验证
SELECT host, user FROM mysql.user WHERE user='XXX(用户名)';
SHOW GRANTS FOR 'XXX(用户名)'@'localhost';6.2 权限收紧过程
- 最初因
%权限解决连接问题(因为匹配更宽松)。 - 确认连接稳定后,逐步收紧为
localhost,并测试成功。
最终权限状态:
| 用户 | 允许主机 | 权限 | 数据库 |
|---|---|---|---|
XXX(用户名) | localhost | SELECT | XXX(数据库名) |
7 Dify 容器网络验证
由于 Dify 运行在 Docker 中,需确保容器能访问宿主机的 3307 端口。
# 进入 Dify API 容器
docker exec -it docker-api-1 /bin/bash
# 测试 MySQL 连接
mysql -h 172.16.1.252 -P 3307 -u XXX(用户名) -p
# 输入密码,应能正常连接如果连接失败,检查:
- 隧道是否监听
0.0.0.0(ss -tlnp | grep 3307)。 - 宿主机的防火墙是否放行
3307(一般本地端口默认开放)。
8 常见问题排查记录
8.1 bad permissions (SSH 私钥权限)
错误:Load key "/env/server_key": bad permissions
解决:
chmod 600 /env/server_key8.2 Connection refused(容器访问宿主机端口)
原因:隧道只监听 127.0.0.1,Docker 容器无法访问。
解决:改为监听 0.0.0.0(-L 0.0.0.0:3307:...)。
8.3 Access denied for user 'dify'@'localhost'
原因:用户权限不足或认证插件不兼容。
解决步骤:
- 使用
mysql_native_password认证插件。 - 授予
SELECT权限。 - 调整
Host为localhost(或%测试)。 - 刷新权限。
8.4 语法错误 IDENTIFIED BY in GRANT(MySQL 8.0)
原因:MySQL 8.0 不再支持 GRANT ... IDENTIFIED BY。
解决:分步执行 CREATE USER 和 GRANT。
8.5 权限虽然授予但仍拒绝
原因:可能匹配到错误的 Host 记录。
解决:使用 DROP USER 清理所有同名用户,只保留一个正确的 Host。
9 最终配置清单
| 组件 | 配置项 | 值 |
|---|---|---|
| 企业微信机器人 | 连接方式 | 长连接(WebSocket) |
| BotId / Secret | (实际值) | |
| LangBot | 运行器 | Dify(工作流类型) |
| Dify Base URL | https://api.dify.ai/v1(或自部署dify地址) | |
| Dify API Key | (工作流 API 密钥) | |
| SSH 隧道 | 监听地址 | 0.0.0.0:3307 |
| 目标 | 数据库服务器IP:3306 | |
| 私钥路径 | /env/server_key(自定义路径) | |
| 启动方式 | systemd 服务 db-tunnel | |
| Dify db_query | 数据库地址 | 宿主机内网IP地址 |
| 端口 | 3307 | |
| 用户名 | XXX(用户名) | |
| 密码 | (强密码) | |
| 库名 | XXX(数据库名) | |
| 输出格式 | JSON | |
| MySQL 用户 | 用户名 | XXX(用户名) |
| 允许主机 | localhost | |
| 认证插件 | mysql_native_password | |
| 全局权限 | USAGE | |
| 数据库权限 | SELECT ON XXX(数据库名).* |
10 后续建议
- 定期修改数据库密码,并同步更新 db_query 插件配置。
- 监控隧道健康:建议使用
systemd状态检查或监控脚本。 - 扩展工作流:结合 LLM 节点,实现自然语言到 SQL 的自动转换,提升用户体验。
- 日志审计:启用 Dify 操作日志,记录所有查询行为,便于安全审计。
- 权限最小化:根据实际需求,可进一步限制只能查询特定表或字段。
附录:关键命令速查
# SSH 隧道启动(前台测试)
autossh -M 0 -L 0.0.0.0:3307:127.0.0.1:3306 -i /env/server_key root@数据库IP -N
# 查看隧道状态
ss -tlnp | grep 3307
ps aux | grep autossh
# 进入 Dify 容器测试
docker exec -it docker-api-1 /bin/bash
mysql -h 172.16.1.252 -P 3307 -u dify -p
# MySQL 权限操作(示例)
CREATE USER 'XXX(用户名)'@'localhost' IDENTIFIED WITH mysql_native_password BY '密码';
GRANT SELECT ON `XXX(数据库名)`.* TO 'XXX(用户名)'@'localhost';
FLUSH PRIVILEGES;
SHOW GRANTS FOR 'XXX(用户名)'@'localhost';
暂无评论
还没有评论,来说点什么吧