本篇笔记将分享教程中利用Dify,以Datawhale出版的“蘑菇书”为例,构建一个能够处理售前咨询和售后问题的智能客服应用。
概览
工作流程示意
- 用户在聊天界面输入问题(例如:“这本书适合我吗?”或“我的订单状态是什么?”)。
- Dify工作流启动,参数提取器节点通过LLM分析问题,识别出是“售前”还是“售后”意图。
- 根据识别出的意图,工作流通过条件分支节点将请求路由到对应的处理路径。
- 不同的路径:
- 售前路径: 知识检索节点从知识库中查找相关产品信息,代码执行节点提供模拟订单数据。
- 售后路径: 直接进入售后LLM(当前无额外数据准备)。
- 相应的LLM节点结合其预设的“工作手册”(Prompt)以及准备好的信息(知识检索结果、模拟数据),生成针对性、专业化的回复。
- 最终的文本回复通过“直接回复”节点展示给用户。
教程给我们编写的初版应用的开场白被设定为:“你好,我是《蘑菇书》的销售客服,有什么相关问题都可以问问我哦~”
同时,教程还有启用了文本转语音(Text-to-Speech)功能,让AI的回复能够以中文语音形式播报,提升了用户体验的自然度和便捷性。
教程在售前、售后这两块把流程、思路写得特别详细、清晰
大家看了教程之后会发现,教程把数据之类的都是硬编码到流程里边,显然在实际落地的时候这种处理并不能满足业务需求
接下来讲一下后端数据库相关的一些思路
🤔后端数据库设计
数据库设计架构概述
为了支持Dify智能客服应用中对用户订单信息的查询和管理,设想采用一个基于MySQL的后端架构。
整个数据库设计遵循关系型数据库的基本范式,将不同类型的数据分离到独立的表中,并通过主键和外键建立关联,以减少数据冗余并优化查询性能。
下面是数据库里边核心的一些表,以及他们的作用
users
表: 存储系统用户的基本信息,如手机号、用户名等。products
表: 存储所售商品的详细信息,如商品名称、价格、ISBN等。在教程这个例子里边以及其他单个产品的客服应用,我们不太需要这个表,但如果是一个网站的客服(需要能够介绍这个组织的所有产品等),那么建议单独做一个产品表orders
表: 存储每笔订单的主体信息,如订单状态、支付渠道、收货人信息、总金额等。order_items
表: 存储每个订单中具体包含的商品明细,支持一个订单购买多种商品。
表结构的详细设计
接下来,我们将详细定义各个表的结构,包括其用途、字段、数据类型、约束以及如何映射数据。
users
表 (用户表)
存储系统注册用户的基本信息。在实际应用中,能够通过用户的手机号或其他标识符,找到其对应的唯一用户记录,并进而查询其所有订单。
-
字段
user_id
(INT, PRIMARY KEY, AUTO_INCREMENT): 用户的唯一标识符,自动增长。phone
(VARCHAR(20), UNIQUE, NOT NULL): 用户注册手机号,作为用户的关键识别信息,并设为唯一索引以确保数据不重复且查询高效。username
(VARCHAR(50), NULLABLE): 用户的昵称或真实姓名。registration_date
(DATETIME, DEFAULT CURRENT_TIMESTAMP): 用户注册的时间戳。
-
SQL语句
CREATE TABLE users (user_id INT AUTO_INCREMENT PRIMARY KEY,phone VARCHAR(20) UNIQUE NOT NULL COMMENT '用户手机号',username VARCHAR(50) NULL COMMENT '用户名/昵称',registration_date DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '注册时间' );
products
表(可选)
存储所有可销售商品的详细信息,例如“蘑菇书”。这使得商品信息能够独立于订单进行管理和更新。
这个表根据实际的业务需求来,比如在教程里边,我们这只是要建一个"蘑菇书"的客服,我们就没必要再新弄一个商品表
包括这个表的字段,其实没必要这么详细.我们可以这样做:商品表里边指明商品的类型,而不同类型的商品又有一个详细点的信息表.比如书籍就有数的出版社、作者等,而电脑就会有型号等数据
-
字段
product_id
(VARCHAR(50), PRIMARY KEY): 商品的唯一标识符,可以是ISBN或内部定义的SKU。product_name
(VARCHAR(255), NOT NULL): 商品的完整名称。current_price
(DECIMAL(10, 2), NOT NULL): 商品当前的销售价格。isbn
(VARCHAR(20), UNIQUE, NULLABLE): 国际标准书号,对于书籍类商品很重要,并设为唯一索引。author
(VARCHAR(255), NULLABLE): 商品的作者信息。publisher
(VARCHAR(255), NULLABLE): 商品的出版社信息。description
(TEXT, NULLABLE): 商品的详细描述,可以存储较长的文本内容。
-
SQL语句
CREATE TABLE products (product_id VARCHAR(50) PRIMARY KEY COMMENT '商品唯一标识符/SKU',product_name VARCHAR(255) NOT NULL COMMENT '商品名称',current_price DECIMAL(10, 2) NOT NULL COMMENT '商品当前价格',isbn VARCHAR(20) UNIQUE NULL COMMENT 'ISBN号',author VARCHAR(255) NULL COMMENT '作者',publisher VARCHAR(255) NULL COMMENT '出版社',description TEXT NULL COMMENT '商品描述' );
orders
表**
存储每笔订单的核心属性,如订单的整体状态、支付方式、收货信息等。可以通过外键与users
表关联。
-
字段:
order_id
(INT, PRIMARY KEY, AUTO_INCREMENT): 订单的唯一标识符,自动增长。user_id
(INT, NOT NULL): 外键,关联到users
表中的user_id
,表示该订单属于哪个用户。order_status
(ENUM('completed', 'pending_payment', 'cancelled'), NOT NULL): 订单的当前状态,使用枚举类型限制可选值。order_date
(DATETIME, NOT NULL): 订单创建的具体时间。payment_channel
(VARCHAR(50), NOT NULL): 支付渠道的名称,如“微信支付”、“支付宝”。payment_id
(VARCHAR(100), UNIQUE, NULLABLE): 第三方支付系统生成的交易流水号,支付成功后填充,设为唯一索引。shipping_address
(VARCHAR(255), NOT NULL): 完整的收货地址。recipient_name
(VARCHAR(50), NOT NULL): 收件人的姓名。courier_name
(VARCHAR(50), NULLABLE): 快递公司的名称,在发货后填充。tracking_number
(VARCHAR(100), UNIQUE, NULLABLE): 物流跟踪单号,在发货后生成,设为唯一索引。total_amount
(DECIMAL(10, 2), NOT NULL): 订单的总金额。
-
SQL语句
CREATE TABLE orders (order_id INT AUTO_INCREMENT PRIMARY KEY,user_id INT NOT NULL COMMENT '用户ID,关联users表',order_status ENUM('completed', 'pending_payment', 'cancelled') NOT NULL COMMENT '订单状态',order_date DATETIME NOT NULL COMMENT '订单创建时间',payment_channel VARCHAR(50) NOT NULL COMMENT '支付渠道',payment_id VARCHAR(100) UNIQUE NULL COMMENT '第三方支付单号',shipping_address VARCHAR(255) NOT NULL COMMENT '收货地址',recipient_name VARCHAR(50) NOT NULL COMMENT '收件人姓名',courier_name VARCHAR(50) NULL COMMENT '快递公司名称',tracking_number VARCHAR(100) UNIQUE NULL COMMENT '物流单号',total_amount DECIMAL(10, 2) NOT NULL COMMENT '订单总金额',FOREIGN KEY (user_id) REFERENCES users(user_id) );
order_items
表**
存储每个订单中具体购买的商品明细。由于一个订单可能包含多种商品,此表通过与orders
表和products
表的外键关联,实现了多对多的关系,并记录了购买时的商品单价。
-
字段
order_item_id
(INT, PRIMARY KEY, AUTO_INCREMENT): 订单项的唯一标识符。order_id
(INT, NOT NULL): 外键,关联到orders
表中的order_id
,表示该订单项属于哪个订单。product_id
(VARCHAR(50), NOT NULL): 外键,关联到products
表中的product_id
,表示该订单项对应的商品。quantity
(INT, NOT NULL): 该商品在订单中的购买数量。unit_price_at_purchase
(DECIMAL(10, 2), NOT NULL): 该商品在本次购买时的单价。
-
SQL语句
CREATE TABLE order_items (order_item_id INT AUTO_INCREMENT PRIMARY KEY,order_id INT NOT NULL COMMENT '订单ID,关联orders表',product_id VARCHAR(50) NOT NULL COMMENT '商品ID,关联products表',quantity INT NOT NULL COMMENT '购买数量',unit_price_at_purchase DECIMAL(10, 2) NOT NULL COMMENT '购买时单价',FOREIGN KEY (order_id) REFERENCES orders(order_id),FOREIGN KEY (product_id) REFERENCES products(product_id) );
示例数据映射到表结构
为了更好地理解上述表结构,我们将Dify应用中硬编码的两个订单示例数据,映射到我们设计的数据库表中。
示例订单 1 :
{"phone": "13812345678","order_status": "completed","date": "2025-07-10 14:30:25","payment_channel": "微信支付","address": "北京市朝阳区建国门外大街1号国贸大厦A座","recipient": "张明","courier": "顺丰速运","quantity": 2
}
映射数据:
users
表: (假定user_id
为1)user_id
: 1,phone
: '13812345678',username
: '张明',registration_date
: '2025-01-01 00:00:00' (示例日期)
products
表: (假定product_id
为'joyrl_book_001', 购买时单价为49.90)product_id
: 'joyrl_book_001',product_name
: 'Joy RL:强化学习实践教程',current_price
: 43.95 (示例),isbn
: '978-7-04-050673-6' (示例), ...
orders
表: (假定order_id
为1001)order_id
: 1001,user_id
: 1,order_status
: 'completed',order_date
: '2025-07-10 14:30:25',payment_channel
: '微信支付',payment_id
: 'WX202507101430251234' (示例),shipping_address
: '北京市朝阳区建国门外大街1号国贸大厦A座',recipient_name
: '张明',courier_name
: '顺丰速运',tracking_number
: 'SF1234567890' (示例),total_amount
: 99.80
order_items
表:order_item_id
: 2001,order_id
: 1001,product_id
: 'joyrl_book_001',quantity
: 2,unit_price_at_purchase
: 49.90
示例订单 2 :
{"phone": "13987654321","order_status": "pending_payment","date": "2025-07-15 10:15:30","payment_channel": "支付宝","address": "上海市浦东新区张江高科技园区科苑路88号","recipient": "李华","courier": "","quantity": 1
}
映射数据:
users
表: (假定user_id
为2)user_id
: 2,phone
: '13987654321',username
: '李华',registration_date
: '2025-01-01 00:00:00' (示例日期)
orders
表: (假定order_id
为1002)order_id
: 1002,user_id
: 2,order_status
: 'pending_payment',order_date
: '2025-07-15 10:15:30',payment_channel
: '支付宝',payment_id
: NULL,shipping_address
: '上海市浦东新区张江高科技园区科苑路88号',recipient_name
: '李华',courier_name
: NULL,tracking_number
: NULL,total_amount
: 43.95
order_items
表:order_item_id
: 2002,order_id
: 1002,product_id
: 'joyrl_book_001',quantity
: 1,unit_price_at_purchase
: 43.95
如何与Dify衔接?
我们可以在Dify的“代码执行”节点中编写Python代码,实现以下功能:
1. 接收Dify工作流传递的用户查询参数(如手机号、订单ID)。
2. 通过数据库连接库连接到MySQL数据库。
3. 根据接收到的参数执行相应的SQL查询。
4. 将查询结果集处理并格式化为Dify LLM能够理解的JSON或文本格式。
5. 将格式化后的数据作为“代码执行”节点的输出,传递给后续的LLM节点。
我也在网上找了一些相关的资料和项目,有兴趣的同学可以看一下。
第一个项目是github上面一个闲鱼的客服机器人,很有意思,可以看到README.md文件上面的对话非常自然。
第二个资料是Dify官方文档里边的
🚀 Xianyu AutoAgent - 智能闲鱼客服机器人系统
如何在几分钟内创建一个带有业务数据的官网 AI 智能客服