Dify + PostgreSQL 数据库实现智能客服完整指南
结合工作流配置与实战经验,以下是可直接落地的详细配置步骤。
工作流架构解析
架构流程图
可视化工作流节点
详细配置步骤
Step 1:配置数据库工具(Database 工具)
1.1 添加数据库工具
左侧菜单 → 工具 → 创建自定义工具
选择类型:Database(数据库)
填写基础配置:
工具名称:PostgreSQL 查询工具
描述:用于查询学生信息和统计数据
数据库类型:PostgreSQL
1.2 配置 DB URI(数据库连接字符串)
格式:
postgresql://用户名:密码@主机:端口/数据库名
示例:
postgresql://postgres:123456@localhost:5432/postgres
参数分解:
用户名:postgres(默认管理员账号)
密码:123456(数据库登录密码)
主机:localhost(本地)/ 服务器公网 IP(远程)
端口:5432(PostgreSQL 默认端口)
数据库名:postgres(目标数据库名称)
Step 2:配置核心节点(重点)
节点 1:用户输入(开始节点)
节点类型: start
变量配置:
- 变量名: query
类型: string
必填: 是
描述: 用户自然语言查询(如"找出年纪最小的学生")
节点 2:LLM 意图识别 + SQL 生成(deepseek-reasoner) 系统提示词(核心):
# 角色定义
你是PostgreSQL数据库专家,负责将自然语言转换为准确的SQL查询。
# 数据库Schema(关键!)
## students 表
| 字段 | 类型 | 示例值 | 约束 |
|------|------|--------|------|
| name | VARCHAR | '张三','李四' | 学生姓名 |
| age | INTEGER | 12-25 | 年龄范围 |
| grade | VARCHAR | '初中','高中','大学' | ⚠️只能这三个值 |
| class | VARCHAR | '一班','计算机系' | 班级/系别 |
## age_statistics 表
| 字段 | 类型 | 示例值 | 约束 |
|------|------|--------|------|
| age_group | VARCHAR | '初中组','高中组','大学组' | ⚠️必须中文 |
| min_age | INTEGER | 12, 16, 19 | 最小年龄 |
| max_age | INTEGER | 15, 18, 25 | 最大年龄 |
# 查询规则(强制约束)
1. ⚠️ 禁止使用英文值(如'Teen'),必须用中文(如'初中组')
2. "最小年龄" = ORDER BY age ASC
3. "最大年龄" = ORDER BY age DESC
4. 能单表查询就不要多表关联
5. 统计人数用 COUNT(*) + GROUP BY
# 示例库
用户:找出年纪最小的学生
SQL:SELECT name, age FROM students ORDER BY age ASC LIMIT 1;
用户:统计各年级人数
SQL:SELECT grade, COUNT(*) FROM students GROUP BY grade;
# 输出要求
直接输出sql语句到 reasoning_content,无需额外解释
模型:deepseek-reasoner
温度:0.1(保证生成 SQL 的准确性)
节点 3:TEXT TO SQL 节点
授权已创建的「PostgreSQL 查询工具」
关联上游 LLM 节点的输出(reasoning_content)作为 SQL 语句来源
节点 4:SQL EXECUTE 节点
数据库工具:选择 Step 1 创建的 PostgreSQL 工具
SQL 语句:{{TEXT TO SQL 节点输出}}
返回格式:JSON
超时时间:10s
节点 5:代码执行(可选,格式化结果)
import json
# 获取 SQL 执行结果
sql_result = {{SQL EXECUTE 节点输出}}
# 格式化结果(空值处理)
if not sql_result:
formatted_result = "[]"
else:
formatted_result = json.dumps(sql_result, ensure_ascii=False, indent=2)
# 输出格式化后的数据
print(formatted_result)
运行环境:Python3 输出类型:String 节点 6:LLM 2 结果润色(deepseek-chat) 系统提示词:
你是一个数据库查询结果分析助手。
## 输入信息
- 用户原始问题:{{#sys.query#}}
- 数据库查询结果:{{#context#}}
## 重要:先判断查询是否正确
如果用户问"最小/最大/特定条件"但结果返回了全部数据:
→ 回复:"查询可能不完整,建议确认 SQL 语句是否正确"
如果查询结果为空:
→ 回复:"未找到相关数据"
如果查询结果正常:
→ 用简洁中文回复,突出关键信息
## 回复示例
用户:帮我找最小的学生
结果:[{"name":"小明","age":6}]
回复:"最小年纪的学生是 **小明**,今年 **6 岁**。"
用户:最小年纪的学生名字叫啥
结果:[{"name":"小明","age":6}]
回复:"最小年纪的学生叫 **小明**。"
用户:查询所有学生
结果:[...103 条...]
回复:"共找到 **103 名学生**。"
模型:deepseek-chat 温度:0.7(保证回复的自然性) 输入变量: sys.query:{{用户输入节点.query}} context:{{代码执行节点输出}} 节点 7:直接回复节点 回复内容:{{LLM 2 节点输出}} 🚨 常见问题与解决方案
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 表不存在 | 数据库名 / Schema 错误 | 确认 DB URI 中数据库名正确,表名加 public. 前缀(如 public.students) |
| SQL 语法错误 | LLM 生成错误 | 优化系统提示词,增加更多示例;降低 LLM 温度至 0.1 |
| 连接超时 | 网络 / 防火墙限制 | 检查数据库允许远程连接,开放 5432 端口;确认服务器安全组规则 |
| 权限不足 | 用户无访问权限 | 授予 SELECT 权限:GRANT SELECT ON ALL TABLES IN SCHEMA public TO 用户名 |
| 中文乱码 | 数据库编码问题 | 确认数据库 UTF-8 编码:执行 SHOW server_encoding 验证 |
配置检查清单
数据库工具已创建并测试连接成功
DB URI 配置正确(数据库名、账号、密码无误)
TEXT TO SQL 节点已授权 Database 工具
LLM 节点系统提示词包含完整 Schema 和查询规则
SQL EXECUTE 节点配置正确(工具关联、超时时间)
LLM 2 回复节点提示词完善(包含异常处理逻辑)
所有节点连接正确(无断连 / 错连)
测试用例验证通过(如 "找出年纪最小的学生")
立即操作步骤
先配置 Database 工具(Step 1),测试数据库连接
再配置 TEXT TO SQL 节点(核心,重点核对 Schema)
测试简单查询(如 "找出年纪最小的学生")
根据测试结果优化 LLM 提示词(重点调整 SQL 生成规则)
测试异常场景(如空结果、错误查询),验证回复逻辑
核心优化建议
SQL 安全性:使用只读账号连接数据库,避免数据篡改
性能优化:开启 SQL 缓存,避免重复执行相同查询
提示词迭代:根据实际错误案例,持续补充 SQL 生成示例
容错处理:在工作流中添加「条件分支」,处理 SQL 执行失败场景
总结
核心流程围绕「自然语言→SQL→数据库查询→自然语言回复」展开,TEXT TO SQL 节点是关键;
LLM 提示词需明确数据库 Schema 和查询规则,才能生成准确的 SQL;
部署前务必完成「配置检查清单」,重点验证数据库连接和权限;
常见问题(如表不存在、权限不足)可通过调整连接字符串 / 数据库权限快速解决。