ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;display: table;padding: 0.3em 1.2em;color: rgb(255, 255, 255);background: rgb(15, 76, 129);border-radius: 8px 24px;box-shadow: rgba(0, 0, 0, 0.06) 0px 2px 6px;">前言ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 16px;letter-spacing: 0.1em;color: rgb(63, 63, 63);">dify是一款开源的大语言模型应用开发平台,旨在降低AI应用的开发门槛,帮助开发者和企业快速构建、部署及管理生成式AI应用。ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 16px;letter-spacing: 0.1em;color: rgb(63, 63, 63);">Dify自1.0.0引入全新插件化架构,模型(Models)与工具(Tools)迁移为插件(Plugins),引入 Agent 策略(Agent Strategies)、扩展(Extensions)类型插件和插件集(Bundles)。通过全新的插件机制,能够增强 AI 应用的感知和执行能力,拓宽AI在软件操作领域的应用能力。ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 16px;letter-spacing: 0.1em;color: rgb(63, 63, 63);">本文将介绍如下内容:ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 16px;color: rgb(63, 63, 63);" class="list-paddingleft-1">ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 16px;text-indent: -1em;display: block;margin: 0.5em 8px;color: rgb(63, 63, 63);">ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 16px;text-indent: -1em;display: block;margin: 0.5em 8px;color: rgb(63, 63, 63);">ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 16px;text-indent: -1em;display: block;margin: 0.5em 8px;color: rgb(63, 63, 63);">• 基于Dify搭建智能体通过插件操作MySQL实现理财助手智能体ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 16px;letter-spacing: 0.1em;color: rgb(63, 63, 63);">文末可获取完整插件代码下载地址ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;display: table;padding: 0.3em 1.2em;color: rgb(255, 255, 255);background: rgb(15, 76, 129);border-radius: 8px 24px;box-shadow: rgba(0, 0, 0, 0.06) 0px 2px 6px;">搭建基于Docker的MySQL数据库环境1) 启动Docker容器- • 建立docker_compose.yaml,内容如下
services: mysql: image:mysql:5.7 container_name:mysql5.7 ports: -"3306:3306" environment: -MYSQL_ROOT_PASSWORD=root -MYSQL_ALLOW_EMPTY_PASSWORD=yes -TZ=Asia/Shanghai volumes: -./volumes:/var/lib/mysql command:--character-set-server=utf8mb4
- • 执行
docker compose up -d启动数据库
2) 创建数据库和表- • 下载MySQL客户端软件,例如dbeaver (https://dbeaver.io/download)
createdatabase testdb;
use testdb;
CREATE TABLE`finance` ( `id`bigint(20)NOT NULLAUTO_INCREMENT, `user_id`varchar(36)NOT NULLDEFAULT''COMMENT'用户ID', `date` datetimeNOT NULLCOMMENT'金额发生日期', `amount`decimal(10,2)NOT NULLDEFAULT'0.00'COMMENT'收入支出金额(收入记为正数,支出记为负数)', `category`varchar(32)NOT NULLDEFAULT''COMMENT'收支类别', `remark`varchar(100)NOT NULLDEFAULT''COMMENT'收支具体类目', PRIMARY KEY(`id`), KEY `idx_user_date` (`user_id`,`date`) ) ENGINE=InnoDBDEFAULTCHARSET=utf8mb4 COMMENT='日常收支';
开发Dify工具插件实现MySQL数据库操作以windows开发环境为例: 1) 下载插件开发脚手架工具从https://github.com/langgenius/dify-plugin-daemon/releases下载适用于windows的dify-plugin-windows-amd64.exe。把程序所在目录加到系统PATH路径下,方便执行命令。运行命令查看版本信息,有输出版本信息则说明安装成功
 2) 创建项目执行命令dify-plugin-windows-amd64.exe plugin init创建项目,输入插件名(mysql),作者和描述
按Enter确认后,选择python做为开发语言
按Enter确认后,选择插件类型,这里我们选tool
 按Enter确认后,选择插件权限。mysql插件不需要勾选任何权限,一直按down键移到最后一行,然后按回车即可完成项目创建,系统将自动生成插件项目代码,目录为mysql。 生成的目录结构如下:
 3) 创建python虚拟环境进入生成的目录mysql,修改生成的requirements.txt,添加用到的python包: mysql-connector-python。
 创建python虚拟环境并安装依赖包 python -m venv .venv # 激活环境 .\.venv\Scripts\activate # 安装依赖包 pip install -r requirements.txt
4) 封装数据库功能在tools目录下增加db.py,通过类DbManagerSingleton封装数据库操作。DbManagerSingleton实现为单例模式,以便插件内不同的代码共用类的实例对象。 importjson importmysql.connector fromcontextlibimportcontextmanager fromthreadingimportLock
# 单例模式 classDbManagerSingleton: _instance =None _lock = Lock() # 线程锁,确保线程安全
def__new__(cls, *args, **kwargs): ifnotcls._instance: withcls._lock: ifnotcls._instance: cls._instance =super().__new__(cls) cls._instance.__init__(*args, **kwargs) returncls._instance
def__init__(self, host, port, user, password, database): self.connection_pool = mysql.connector.pooling.MySQLConnectionPool( pool_name="db_pool", pool_size=5, pool_reset_session=True, host=host, # 数据库服务器Host port=port, # 数据库服务器端口 user=user, # 数据库用户名 password=password, # 数据库密码 database=database, # 数据库名 )
@contextmanager defget_cursor(self): withself.connection_pool.get_connection()asconnection: cursor =None try: cursor = connection.cursor() yieldcursor connection.commit() exceptExceptionase: connection.rollback() raisee finally: ifcursor: cursor.close()
defexecute_sql(self, sql:str) ->str: withself.get_cursor()ascursor: cursor.execute(sql) ifcursor.descriptionisnotNone: rows = cursor.fetchall() result = { "columns": [desc[0]fordescincursor.description], "rows": rows, } returnjson.dumps(result, default=str) else: returnf"row affected:{cursor.rowcount}"
5) 实现授权配置修改provider/mysql.yaml。其中,credentials_for_provider的信息用于配置插件授权(配置数据库连接相关信息)。内容如下: identity: author:testuser name:mysql label: en_US:mysql zh_Hans:mysql description: en_US:mysqltools zh_Hans:mysqltools icon:icon.svg tools:# 插件包含的工具列表 -tools/get_table_definition.yaml -tools/execute_sql.yaml
extra: python: source:provider/mysql.py
credentials_for_provider: host:# 数据库HOST type:text-input# 输入类型为普通文本 required:true# 此凭证是必需的 label: # 在 Dify UI 中显示的标签 (支持多语言) en_US:MySQLServerHost zh_Hans:MySQLServer主机 port:# 数据库端口 type:text-input# 输入类型为普通文本 required:true# 此凭证是必需的 label:# 在 Dify UI 中显示的标签 (支持多语言) en_US:MySQLServerPort zh_Hans:MySQLServer端口 user:# 数据库用户名 type:text-input# 输入类型为普通文本 required:true# 此凭证是必需的 label:# 在 Dify UI 中显示的标签 (支持多语言) en_US:username zh_Hans:用户名 password:# 数据库密码 type:secret-input# 输入类型为密码框 required:true# 此凭证是必需的 label:# 在 Dify UI 中显示的标签 (支持多语言) en_US:password zh_Hans:密码 database:# 数据库名 type:text-input# 输入类型为普通文本 required:true# 此凭证是必需的 label:# 在 Dify UI 中显示的标签 (支持多语言) en_US:databasename zh_Hans:数据库名
修改provider/mysql.py,实现配置校验,通过建立连接执行show tables验证参数是否正确。代码如下: fromtypingimportAny
fromdify_pluginimportToolProvider fromdify_plugin.errors.toolimportToolProviderCredentialValidationError
classMysqlProvider(ToolProvider): def_validate_credentials(self, credentials:dict[str,Any]) ->None: try: """ IMPLEMENT YOUR VALIDATION HERE """ fromtools.dbimportDbManagerSingleton
dbManager = DbManagerSingleton( host=credentials["host"], port=credentials["port"], user=credentials["user"], password=credentials["password"], database=credentials["database"], ) dbManager.execute_sql("show tables") exceptExceptionase: raiseToolProviderCredentialValidationError(str(e))
6) 实现工具get_table_definition获取表结构定义provider/mysql.yaml的tools字段定义了插件包含的工具列表。 tools:# 插件包含的工具列表 -tools/get_table_definition.yaml -tools/execute_sql.yaml
每个工具需要一个yaml文件进行描述,包含工具的名称、描述、参数列表等。 将自动生成的tools目录下的mysql.yaml和mysql.py分别重命名为get_table_definition.yaml和get_table_definition.py get_table_definition.yaml修改为如下内容: identity: name:get_table_definition author:testuser label:# 在 Dify UI 中显示的工具名称 (多语言) en_US:getdatabasetabledefinition zh_Hans:获取数据库表定义 description: human:# 给人类用户看的工具描述 (多语言) en_US:getdatabasetabledefinition zh_Hans:获取数据库表定义 llm:getdatabasetabledefinition# 给 LLM 看的工具描述 (用于 Agent 模式) parameters:# 定义工具的输入参数列表 -name:table type:string required:true label:# 在 Dify UI 中显示的参数标签 (多语言) en_US:databasetablename zh_Hans:数据库表名 human_description:# 给人类用户看的参数描述 (多语言) en_US:databasetablename zh_Hans:数据库表名 llm_description:databasetablename# 给 LLM 看的参数描述 (指导 Agent 如何填充) form:llm# 参数表单类型 ('llm' 或 'form') extra: python: source:tools/get_table_definition.py
get_table_definition.py修改为如下内容: fromcollections.abcimportGenerator fromtypingimportAny fromdify_pluginimportTool fromdify_plugin.entities.toolimportToolInvokeMessage fromtools.dbimportDbManagerSingleton
classGetTableDefinitionTool(Tool): def__init__(self, runtime, session): super().__init__(runtime, session) self.dbManager = DbManagerSingleton( host=runtime.credentials["host"], port=runtime.credentials["port"], user=runtime.credentials["user"], password=runtime.credentials["password"], database=runtime.credentials["database"], )
def_invoke(self, tool_parameters:dict[str,Any]) -> Generator[ToolInvokeMessage]: table = tool_parameters["table"] sql =f"show create table{table}" yieldself.create_text_message(self.dbManager.execute_sql(sql))
7) 实现工具execute_sql执行SQL语句在tools目录新建execute_sql.yaml和execute_sql.py execute_sql.yaml修改为如下内容: identity: name:execute_sql author:testuser label:# 在 Dify UI 中显示的工具名称 (多语言) en_US:executesql zh_Hans:执行sql语句 description: human:# 给人类用户看的工具描述 (多语言) en_US:executesql zh_Hans:执行sql语句 llm:executesql# 给 LLM 看的工具描述 (用于 Agent 模式) parameters:# 定义工具的输入参数列表 -name:sql type:string required:true label: # 在 Dify UI 中显示的参数标签 (多语言) en_US:sql zh_Hans:sql语句 human_description:# 给人类用户看的参数描述 (多语言) en_US:thesqltoexecute zh_Hans:要执行的sql语句 llm_description:sql# 给 LLM 看的参数描述 (指导 Agent 如何填充) form:llm# 参数表单类型 ('llm' 或 'form') extra: python: source:tools/execute_sql.py
execute_sql.py修改为如下内容: fromcollections.abcimportGenerator fromtypingimportAny fromdify_pluginimportTool fromdify_plugin.entities.toolimportToolInvokeMessage fromtools.dbimportDbManagerSingleton
classExecuteSqlTool(Tool): def__init__(self, runtime, session): super().__init__(runtime, session) self.dbManager = DbManagerSingleton( host=runtime.credentials["host"], port=runtime.credentials["port"], user=runtime.credentials["user"], password=runtime.credentials["password"], database=runtime.credentials["database"], )
def_invoke(self, tool_parameters:dict[str,Any]) -> Generator[ToolInvokeMessage]: sql = tool_parameters["sql"] yieldself.create_text_message(self.dbManager.execute_sql(sql))
8) 修改manifest.yamlmanifest.yaml定义了插件最基础的信息,包括插件名称、作者、包含的工具、模型等信息。 本插件虽然没用到storage持久化存储的权限,但需要将storage里的size字段从0改为大于等于1024,否则启动插件时会报错。 storage: enabled: false size: 1024
9) 调试在Dify的插件管理页面,点击图中红框部分,弹出调试的URL和Key。
复制.env.example到.env,修改REMOTE_INSTALL_HOST和REMOTE_INSTALL_KEY。
执行命令python main.py启动插件,等待至显示"dify_plugin.plugin:Installed tool",工具安装成功。
此时,在Dify的插件管理页面可以看到mysql插件。选择mysql插件,在右侧点击“去授权”
填上相关参数并保存
新建测试Agent,添加mysql插件的两个工具,模型选择doubao-1.5-pro-32k,模型会根据用户提问自动调用数据库工具,并根据工具的响应生成回复。效果如下图: |