在 AI 应用开发平台中,工具(Tool)系统是连接大语言模型与外部世界的桥梁,它使 AI 能够执行各种实际任务,如搜索信息、生成图片、处理数据等。本文将深入解析 Dify 工具系统的核心架构设计,帮助理解其工作原理并进行扩展开发。
👆👆👆欢迎关注,一起进步👆👆👆
文件组织结构
core/tools/
├── provider/builtin/ # 内置工具供应商
│ └── {provider\_name}/ # 如 google
│ ├── \_assets/ # 图标等资源
│ ├── {provider\_name}.yaml # 供应商配置
│ ├── {provider\_name}.py # 供应商代码
│ └── tools/ # 工具集合
│ ├── {tool\_name}.yaml # 工具配置
│ └── {tool\_name}.py # 工具实现
└── docs/ # 文档
1、工具系统概述
Dify 工具系统是一个模块化、可扩展的框架,用于在 Agent 助手和工作流中实现各种功能。该系统的设计理念是实现前后端解耦,使开发者能够在不修改前端逻辑的情况下定义和展示自己的工具,从而实现 Dify 能力的水平扩展。(推荐阅读,了解 Dify 如何快速集成新模型👉从零开始学 Dify-详细介绍 Dify 模型运行时的核心架构)
目前,Dify 工具系统支持两种类型的工具:
- 内置工具(Built-in Tools) :在产品内部实现,硬编码用于 Agent 和工作流。
- API 工具(Api-Based Tools) :利用第三方 API 实现,无需编码即可集成,只需在前端提供 OpenAPI、Swagger 或 OpenAI-plugin 格式的接口定义。
2、核心架构设计
2.1 整体架构
Dify 工具系统采用了分层架构设计,主要包括管理层、提供者层和工具层三个层次。
2.2 核心组件
2.2.1 工具管理器(ToolManager)
ToolManager 是工具系统的核心管理类,负责管理所有工具提供者和工具实例。它提供了获取工具提供者、工具实例和工具运行时的方法,是工具系统的入口点。
主要功能:
- 加载和管理内置工具提供者
- 获取特定工具提供者和工具实例
- 为 Agent 和工作流创建工具运行时
2.2.2 工具提供者控制器(ToolProviderController)
ToolProviderController 是工具提供者的抽象基类,定义了工具提供者的接口。每个工具提供者都需要实现这个接口,以提供工具列表、获取特定工具、验证凭据等功能。
主要子类:
BuiltinToolProviderController:内置工具提供者控制器ApiToolProviderController:API 工具提供者控制器
2.2.3 工具(Tool)
Tool 是工具的抽象基类,定义了工具的接口。每个工具都需要实现这个接口,以提供工具的调用、参数验证等功能。
主要子类:
BuiltinTool:内置工具ApiTool:API 工具
2.3 数据结构
3、工具接入方式
3.1 快速接入
快速接入适用于简单工具的开发,通过配置驱动的方式快速实现工具功能。以 Google 搜索工具为例,快速接入需要完成以下步骤:
3.1.1 准备工具供应商 YAML
identity:
author:Dify
name
:google
label:
en\_US:Google
zh\_Hans:Google
description:
en\_US:Google
zh\_Hans:Google
icon:icon.svg
tags:
-search
3.1.2 准备供应商凭据
credentials
\_for\_provider:
serpapi\_api\_key:
type:secret-input
required:true
label:
en\_US:SerpApiAPIkey
zh\_Hans:SerpApiAPIkey
placeholder:
en\_US:PleaseinputyourSerpApiAPIkey
zh\_Hans:请输入你的SerpApiAPIkey
help:
en\_US:GetyourSerpApiAPIkey
from
SerpApi
zh\_Hans:从SerpApi获取您的SerpApiAPIkey
url:https://serpapi.com/manage-api-key
3.1.3 准备工具 YAML
identity:
name
:google\_search
author:Dify
label:
en\_US:GoogleSearch
zh\_Hans:谷歌搜索
description:
human:
en\_US:AtoolforperformingaGoogleSERPsearchandextractingsnippetsandwebpages.
zh\_Hans:一个用于执行GoogleSERP搜索并提取片段和网页的工具。
llm:AtoolforperformingaGoogleSERPsearchandextractingsnippetsandwebpages.
parameters:
-name:query
type:
string
required:true
label:
en\_US:Query
string
zh\_Hans:查询语句
human\_description:
en\_US:usedforsearching
zh\_Hans:用于搜索网页内容
llm\_description:keywordsforsearching
form:llm
-name:result\_type
type:select
required:true
options:
-value:text
label:
en\_US:text
zh\_Hans:文本
-value:link
label:
en\_US:link
zh\_Hans:链接
default:link
label:
en\_US:Resulttype
zh\_Hans:结果类型
human\_description:
en\_US:usedforselectingtheresulttype,textorlink
zh\_Hans:用于选择结果类型,使用文本还是链接进行展示
form:form
3.1.4 准备工具代码
from
core.tools.tool.builtin\_tool import BuiltinTool
from
core.tools.entities.tool\_entities import ToolInvokeMessage
from typing import Any, Dict, List, Union
class GoogleSearchTool(BuiltinTool):
def \_invoke(self,
user\_id: str,
tool\_parameters: Dict[str, Any],
) -> Union[ToolInvokeMessage, List[ToolInvokeMessage]]:
"""
invoke tools
"""
query = tool\_parameters['query']
result\_type = tool\_parameters['result\_type']
api\_key = self.runtime.
credential
s['serpapi\_api\_key']
result = SerpAPI(api\_key).run(query, result\_type=result\_type)
if result\_type == 'text':
return self.create\_text\_message(text=result)
return self.create\_link\_message(link=result)
3.1.5 准备供应商代码
from
core.tools.provider.builtin\_tool\_provider import BuiltinToolProviderController
from
core.tools.errors import ToolProvider
Credential
Validation
Error
from
core.tools.provider.builtin.google.tools.google\_search import GoogleSearchTool
from
typing import Any, Dict
class GoogleProvider(BuiltinToolProviderController):
def \_validate\_
credentials
(self,
credentials
: Dict[str, Any]) -> None:
try:
GoogleSearchTool().fork\_tool\_runtime(
meta={
"
credential
s":
credentials
,
}
).invoke(
user\_id='',
tool\_parameters={
"query": "test",
"result\_type": "link"
},
)
except
Exception as e:
raise ToolProvider
Credential
Validation
Error
(str(e))
3.2 高级接入
高级接入适用于复杂工具的开发,支持多种消息类型、变量池和工具链的构建。
3.2.1 多种消息类型
Dify 工具系统支持多种消息类型,包括文本、图片、链接、文件 BLOB 和 JSON。
示例代码:
# 返回文本消息
self.create\_text\_message(text="Hello, world!")
# 返回图片消息
self.create\_image\_message(image="https://example.com/image.png")
# 返回链接消息
self.create\_link\_message(link="https://example.com")
# 返回文件 BLOB 消息
self.create\_blob\_message(blob=binary\_data, meta={"mime\_type": "image/png"})
# 返回 JSON 消息
self.create\_json\_message(object={"key": "value"})
3.2.2 变量池机制
变量池是工具系统中的一个重要组件,用于在工具之间共享数据。它允许一个工具生成的数据被另一个工具使用,从而构建复杂的工具链。
示例代码(DallE3 生成图片并保存到变量池):
# 将图片保存到变量池
self.create\_blob\_message(
blob=b64decode(image.b64\_json),
meta={"mime\_type": "image/png"},
save\_as=self.VARIABLE\_KEY.IMAGE.value
)
示例代码(Vectorizer.AI 从变量池获取图片):
# 从变量池获取图片
image\_binary = self.get\_variable\_file(self.VARIABLE\_KEY.IMAGE)
if not image\_binary:
return self.create\_text\_message("Image not found")
# 处理图片
response
= post(
"https://vectorizer.ai/api/v1/vectorize",
files={"image": image\_binary},
data={"mode": "test"},
auth=(api\_key\_name, api\_key\_value),
timeout=30
)
3.2.3 动态参数生成
工具可以根据当前变量池中的数据动态生成参数列表,使 LLM 能够根据实际情况选择合适的参数。
def get\_runtime\_parameters(self) -> List[ToolParameter]:
"""
override the runtime parameters
"""
return [
ToolParameter.get\_simple\_instance(
name="image\_id",
llm\_description="the image id that you want to vectorize",
type=ToolParameter.ToolParameterType.SELECT,
required=True,
options=[i.name for i in self.list\_default\_image\_variables()]
)
]
3.2.4 工具可用性控制
工具可以根据当前变量池中的数据决定自己是否可用,避免在不适合的情况下被调用。
def is\_tool\_
available
(self) -> bool:
# 只有当变量池中有图片时,工具才可用
return len(self.list\_default\_image\_variables()) > 0
4、工具系统工作流程
4.1 工具调用过程
- 用户发送请求到 Agent 或工作流
- Agent 或工作流通过 ToolManager 获取工具运行时
- ToolManager 获取工具提供者和工具实例
- ToolManager 创建工具运行时,包括加载凭据和变量池
- Agent 或工作流调用工具
- 工具执行逻辑,可能会保存结果到变量池
- 工具返回结果给 Agent 或工作流
- Agent 或工作流返回响应给用户
4.2 变量池使用过程
- 工具 A 执行逻辑,生成结果
- 工具 A 将结果保存到变量池
- 工具 B 从变量池获取工具 A 的结果
- 工具 B 使用工具 A 的结果执行自己的逻辑
5、总结
Dify 的工具架构设计充分考虑了灵活性和可扩展性,通过配置驱动开发、变量池机制、动态参数生成和工具可用性控制等技术,使开发者能够快速构建从简单到复杂的各类工具。特别是变量池机制,为构建复杂工具链提供了强大支持,使得多个工具可以协同工作,完成更复杂的任务。
参考资料
https://github.com/langgenius/dify (v0.6.3)
推荐阅读
- 从零开始学 Dify
- 从零开始学 Dify-系统架构
- 从零开始学 Dify- API 后端架构原来是这样设计的
- 从零开始学 Dify- 帐户与租户管理系统设计揭秘
- 从零开始学 Dify- 模型提供者系统设计实现模型统一调用接口
- 从零开始学 Dify- RAG 知识库系统设计详解
- 从零开始学 Dify- 对话系统的关键功能
- 从零开始学 Dify- 工作流(Workflow)系统架构
- 从零开始学 Dify-扫描、加载和管理模型提供者的详细过程
- 从零开始学 Dify-详细介绍 Dify 模型运行时的核心架构
👆👆👆欢迎关注,一起进步👆👆👆
欢迎留言讨论哈
🧐点赞、分享、推荐 ,一键三连,养成习惯👍
