Dify工具集扩展从零开始步骤详解:打造专属AI Agent工作站的完整流程

2026-06-18阅读 0热度 0
ai 人工智能
Dify 自带了相当丰富的内置工具,这让创建 Agent 时能玩出很多花样。但看着这些现成的工具,难免会想:能不能把自己独特的工具也接进去呢? 今天就来演示一下,如何构建一个属于自己的工具,并将其无缝添加到 Dify 的内置工具集里。
## 运行 Dify 关于 Dify 的部署(无论是源码还是容器方式),这里就不再重复了。网上的相关教程非常详尽,我们直接进入正题。 ## 扩展工具 ### 厂商(供应商)和工具 要理解如何扩展,首先得弄清楚 Dify 内置工具里的两个基本概念:`厂商` 和 `工具`。 简单来说,要扩展工具,得先注册一个“厂商”——你可以把它理解为一个生产商或供应商,一个厂商下面可以挂载多个工具,选择的时候工具会按照厂商来分组。
### 扩展方式 扩展 Dify 工具和厂商,核心需要搞定两部分内容: * 使用 `yaml` 文件来描述工具的参数和功能。 * 使用 `python` 文件来编写厂商的注册函数和工具的具体实现逻辑。 比如,假设我们定义了两个工具,最终的目录结构大概是这样: ``` ├── _assets │ └── icon.svg ├── shuyi.py ├── shuyi.yaml └── tools ├── shuyi_excel.py ├── shuyi_excel.yaml ├── shuyi_test.py └── shuyi_test.yaml ``` ## 定义厂商 ### 厂商定义 yaml 这个 yaml 文件用来承载工具供应商的元信息,比如名称、图标、作者等,前端展示就靠它了。 我们需要在 `core/tools/provider/builtin` 目录下新建一个文件夹。比如命名为 `shuyi`,然后在该文件夹下创建 `shuyi.yaml`。 文件内容主要描述工具以及它的展示图标: ```yaml identity: author: Shuyi name: shuyi label: en_US: Shuyi zh_Hans: 数翼 pt_BR: Shuyi description: en_US: Shuyi tools zh_Hans: 数翼自定义工具集 pt_BR: Shuyi tools icon: icon.svg tags: - search - productivity ``` #### 授权定义 如果你的工具需要访问外部服务(比如调用谷歌搜索、DALL-E 绘图),那通常就需要“授权”,也就是让用户填写 API Key 等密钥,以保证调用的安全性。 如果配置了授权,工具详情页面就会出现一个“授权”按钮,点击后就能看到需要填写的授权参数表单。
我们自定义的工具打算增加两个授权参数: * **服务器地址**:我们自己部署的后端服务地址。 * **API Key**:用来验证调用是否合法的密钥。 在 `shuyi.yaml` 中增加如下内容: ```yaml credentials_for_provider: shuyi_api_key: type: secret-input required: true default: "123456" label: en_US: Shuyi API key zh_Hans: Shuyi API key pt_BR: Shuyi API key placeholder: en_US: Please input your Shuyi API key zh_Hans: 请输入你的 Shuyi API key pt_BR: Please input your Shuyi API key help: en_US: Get your Shuyi API key from Shuyi zh_Hans: 从 Shuyi 获取您的 Shuyi API key pt_BR: Get your Shuyi API key from Shuyi shuyi_api_url: type: text-input required: true default: label: en_US: Shuyi API url zh_Hans: Shuyi API 地址 pt_BR: Shuyi API url placeholder: en_US: Please input your Shuyi API url zh_Hans: 请输入你的 Shuyi API 服务地址 pt_BR: Please input your Shuyi API url help: en_US: Get your Shuyi API url from Shuyi zh_Hans: 从 Shuyi 获取您的 Shuyi API url pt_BR: Get your Shuyi API url from Shuyi ``` ![授权参数展示图](这里假设有一张显示授权参数配置的图片) ![授权表单展示图](这里假设有一张显示授权表单的图片) ### 是否必须授权和调用外部服务 这里需要明确一点:自定义工具**并非必须**要授权或者调用外部服务。 如果工具功能非常简单,比如做做 JSON 格式化,你完全可以在工具代码里实现所有逻辑。这种做法虽然简单直接,但也有几个明显的弊端: * **代码耦合高**:逻辑全部塞进工具代码,导致代码臃肿且难以测试。 * **依赖冲突**:工具的 Python 依赖可能与 Dify 本身产生冲突,升级维护是个麻烦事。 * **扩展性受限**:所有计算都堆在 Dify 进程里,不利于后续的分布式扩容。
所以,如果工具要实现比较复杂的功能,更推荐的做法是把它单独写成一个独立的服务,然后让 Dify 来调用。这样架构更清晰,也更专业。 ## 工具实现 工具的实现也同样分为两个部分:定义文件(Yaml)和功能实现类(Python)。 在 `shuyi/tools` 目录下,我们创建一个 `shuyi_test.yaml` 来描述这个工具。内容主要就是工具的描述信息以及它的输入参数。 ```yaml identity: name: shuyi_test author: Shuyi label: en_US: ShuyiTest zh_Hans: 数翼工具测试 pt_BR: ShuyiTest description: human: en_US: A tool for testing Dify message type and input parameters.Input should be a search query. zh_Hans: 用于测试Dify消息类型和输入参数的工具。 pt_BR: A tool for testing Dify message type and input parameters.Input should be a search query. llm: A tool for testing Dify message type and input parameters.Input should be a search query. parameters: - name: query type: string required: true label: en_US: Query string zh_Hans: 查询语句 pt_BR: Query string human_description: en_US: used for searching zh_Hans: 用于搜索内容 pt_BR: used for searching llm_description: key words for searching form: llm ``` Dify 目前支持四种参数类型: * string * number * boolean * select 这里有个值得留意的字段:`form`。它表示这个参数的表单类型,目前支持 `llm` 和 `form` 两种。`llm` 表示由 Agent 自行推理出这个字段的值,而 `form` 则代表需要在前端由用户手动填写。 工具的实现类 `shuyi_test.py`,最简单的方式就是直接返回一个固定的消息,比如: ```python from typing import Any, Union from core.tools.entities.tool_entities import ToolInvokeMessage from core.tools.tool.builtin_tool import BuiltinTool class ShuyiTestTool(BuiltinTool): def _invoke(self, user_id: str, tool_parameters: dict[str, Any], ) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]: return self.create_link_message('hello') ``` 当然,现实场景中不会这么简单。通常我们需要获取插件认证时填写的参数,然后去调用外部服务: ```python api_url = self.runtime.credentials['shuyi_api_url'], params = { "api_key": self.runtime.credentials['shuyi_api_key'], "type": tool_parameters['type'], "query": tool_parameters['query'], } ``` 调用外部服务: ```python response = requests.get(url=api_url, params=params) ``` 解析返回结果是比较复杂的部分,可以单独用一个函数来处理: ```python def _parse_response(self, response: dict) -> dict: result = {} # logics return result ``` 最终返回处理后的数据: ```python response.raise_for_status() valuable_res = self._parse_response(response.json()) return self.create_json_message(valuable_res) ``` 这里提供一个模板,大家可以直接基于它来创建自己的工具: ```python from typing import Any, Union import requests from core.tools.entities.tool_entities import ToolInvokeMessage from core.tools.tool.builtin_tool import BuiltinTool class ShuyiTestTool(BuiltinTool): def _parse_response(self, response: dict) -> dict: result = {} # logics return result def _invoke(self, user_id: str, tool_parameters: dict[str, Any], ) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]: api_url = self.runtime.credentials['shuyi_api_url'], params = { "api_key": self.runtime.credentials['shuyi_api_key'], "type": tool_parameters['type'], "query": tool_parameters['query'], } response = requests.get(url=api_url, params=params) response.raise_for_status() valuable_res = self._parse_response(response.json()) return self.create_json_message(valuable_res) ``` ## 消息类型 Dify 提供了几种不同的消息返回类型,从本质上讲,它们都是 **文本(Markdown)** 的封装,只是提供了不同的生成方法: * **图片**:`create_image_message(self, image: str, sa ve_as: str = '')` * **链接**:`create_link_message(self, link: str, sa ve_as: str = '')` * **文本**:`create_text_message(self, text: str, sa ve_as: str = '')` * **Blob**:`create_blob_message(self, blob: bytes, meta: dict = None, sa ve_as: str = '')` * **JSON**:`create_json_message(self, object: dict)` 当然,它也支持返回多条消息,用数组表示即可。 ### 文本 文本类型本质上就是 `Markdown`。举个例子,创建一个包含图片、列表、标题的 Markdown 消息: ```python return self.create_text_message( """### User message %s ### 生成式 AI 应用创新引擎 开源的 LLM 应用开发平台,轻松构建和运营生成式 AI 原生应用。 - 生成式 AI - 应用开发框架 #### RAG Pipeline """ % params['query']) ``` 效果如下:
### 图片消息 图片消息需要传入一个图片地址: ```python image_path = 'https://buffer.com/cdn-cgi/image/w=1000,fit=contain,q=90,f=auto/library/content/images/size/w1200/2023/10/free-images.jpg' return self.create_image_message(image_path) ``` 效果如下:
### Blob 消息 官方文档说 Blob 消息可以返回原始文件数据,比如图片、音频、视频、PPT、Word、Excel 等。但实际测试下来,效果有些差强人意。 ```python with open(file_path, 'rb') as mp4: byte_arr = mp4.read() return self.create_blob_message( blob=byte_arr, meta={ # 'mime_type': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'mime_type': 'video/mp4', 'file_name': 'xxx.mp4',}, sa ve_as=self.VARIABLE_KEY.IMAGE.value ) ``` 测试发现并没有直接显示出文件内容或提供一个下载链接。
经过尝试,如果确实想要返回一个文件供用户下载,目前比较实用的方式还是用 Markdown 来实现一个下载超链接: ```markdown [something.xlsx](https://yourhost/xxx.xlsx) ``` ## 链接消息 链接类型的消息只需要传入一个地址: ```python return self.create_link_message(link) ``` 返回的内容格式就是:`Link: ` 紧跟你的链接。
## 多条消息 Dify 也支持同时返回多条不同类型的消息,用数组组合即可: ```python messages = [ self.create_text_message("""### User message ...""" % params['query']), self.create_json_message({'result': 'success', 'text': 'This is a message'}), self.create_image_message(image_path), self.create_link_message(link), ... ] ``` 效果就是这些消息的依次拼接展示。
## 使用工具 当我们的工具代码写好之后,重启一下 Dify 服务,就可以使用刚刚创建的工具了。在添加节点的时候,找到并选中自己的工具,它就能像 Dify 自带的默认工具一样,被配置和使用。
## 总结 相比于在 UI 界面上创建基于 OpenAPI 的自定义工具,通过代码来扩展供应商和工具集,显然能更方便地完成工具的积累与传播,在应用层面也为我们提供了更大的想象空间。 通过这种方式扩展工具,我们可以基于 Dify **打造真正属于自己的、独特的 AI 工作站**,而不仅仅是一个通用的 AI Agent 工作站。同时,过去积累的各种工具能力也能得到很好的复用。
免责声明

本网站新闻资讯均来自公开渠道,力求准确但不保证绝对无误,内容观点仅代表作者本人,与本站无关。若涉及侵权,请联系我们处理。本站保留对声明的修改权,最终解释权归本站所有。

相关阅读

更多
欢迎回来 登录或注册后,可保存提示词和历史记录
登录后可同步收藏、历史记录和常用模板
注册即表示同意服务条款与隐私政策