Dify
简体中文
简体中文
  • 入门
    • 欢迎使用 Dify
      • 特性与技术规格
      • 模型供应商列表
    • 云服务
    • 社区版
      • Docker Compose 部署
      • 本地源码启动
      • 宝塔面板部署
      • 单独启动前端 Docker 容器
      • 环境变量说明
      • 常见问题
    • Dify Premium
    • Dify 教育版
  • 手册
    • 接入大模型
      • 增加新供应商
      • 预定义模型接入
      • 自定义模型接入
      • 接口方法
      • 配置规则
      • 负载均衡
    • 构建应用
      • 创建应用
      • 聊天助手
        • 多模型调试
      • Agent
      • 应用工具箱
        • 敏感内容审查
    • 工作流
      • 关键概念
      • 变量
      • 节点说明
        • 开始
        • LLM
        • 知识检索
        • 问题分类
        • 条件分支
        • 代码执行
        • 模板转换
        • 文档提取器
        • 列表操作
        • 变量聚合
        • 变量赋值
        • 迭代
        • 参数提取
        • HTTP 请求
        • Agent
        • 工具
        • 结束
        • 直接回复
        • 循环
      • 快捷键
      • 编排节点
      • 文件上传
      • 异常处理
        • 预定义异常处理逻辑
        • 错误类型
      • 附加功能
      • 预览与调试
        • 预览与运行
        • 单步调试
        • 对话/运行日志
        • 检查清单
        • 运行历史
      • 应用发布
      • 结构化输出
      • 变更公告:图片上传被替换为文件上传
    • 知识库
      • 创建知识库
        • 1. 导入文本数据
          • 1.1 从 Notion 导入数据
          • 1.2 从网页导入数据
        • 2. 指定分段模式
        • 3. 设定索引方法与检索设置
      • 管理知识库
        • 维护知识库内文档
        • 通过 API 维护知识库
      • 元数据
      • 在应用内集成知识库
      • 召回测试/引用归属
      • 知识库请求频率限制
      • 连接外部知识库
      • 外部知识库 API
    • 工具
      • 快速接入工具
      • 高级接入工具
      • 工具配置
        • Google
        • Bing
        • SearchApi
        • StableDiffusion
        • Dall-e
        • Perplexity Search
        • AlphaVantage 股票分析
        • Youtube
        • SearXNG
        • Serper
        • SiliconFlow (支持 Flux 绘图)
        • ComfyUI
    • 发布
      • 发布为公开 Web 站点
        • Web 应用的设置
        • 文本生成型应用
        • 对话型应用
      • 嵌入网站
      • 基于 APIs 开发
      • 基于前端组件再开发
    • 标注
      • 日志与标注
      • 标注回复
    • 监测
      • 集成外部 Ops 工具
        • 集成 LangSmith
        • 集成 Langfuse
        • 集成 Opik
      • 数据分析
    • 扩展
      • API 扩展
        • 使用 Cloudflare Workers 部署 API Tools
        • 敏感内容审查
      • 代码扩展
        • 外部数据工具
        • 敏感内容审查
    • 协同
      • 发现
      • 邀请与管理成员
    • 管理
      • 应用管理
      • 团队成员管理
      • 个人账号管理
      • 订阅管理
      • 版本管理
  • 动手实验室
    • 初级
      • 如何搭建 AI 图片生成应用
      • AI Agent 实战:搭建个人在线旅游助手
    • 中级
      • 使用文件上传搭建文章理解助手
      • 使用知识库搭建智能客服机器人
      • ChatFlow 实战:搭建 Twitter 账号分析助手
  • 社区
    • 寻求支持
    • 成为贡献者
    • 为 Dify 文档做出贡献
  • 插件
    • 功能简介
    • 快速开始
      • 安装与使用插件
      • 插件开发
        • 初始化开发工具
        • Tool 插件
        • Model 插件
          • 创建模型供应商
          • 接入预定义模型
          • 接入自定义模型
        • Agent 策略插件
        • Extension 插件
        • Bundle 插件包
      • 插件调试
    • 插件管理
    • 接口定义
      • Manifest
      • Endpoint
      • Tool
      • Agent
      • Model
        • 模型设计规则
        • 模型接口
      • 通用规范定义
      • 持久化存储
      • 反向调用 Dify 服务
        • App
        • Model
        • Tool
        • Node
    • 最佳实践
      • 开发 Slack Bot 插件
      • Dify MCP 插件指南:一键连接 Zapier 并自动发送邮件
    • 发布插件
      • 自动发布插件
      • 发布至 Dify Marketplace
        • 插件开发者准则
        • 插件隐私政策准则
      • 发布至个人 GitHub 仓库
      • 本地发布与分享
      • 第三方签名验证
    • 常见问题
  • 研发
    • 后端
      • DifySandbox
        • 贡献指南
    • 模型接入
      • 接入 Hugging Face 上的开源模型
      • 接入 Replicate 上的开源模型
      • 接入 Xinference 部署的本地模型
      • 接入 OpenLLM 部署的本地模型
      • 接入 LocalAI 部署的本地模型
      • 接入 Ollama 部署的本地模型
      • 接入 LiteLLM 代理的模型
      • 接入 GPUStack 进行本地模型部署
      • 接入 AWS Bedrock 上的模型(DeepSeek)
    • 迁移
      • 将社区版迁移至 v1.0.0
  • 阅读更多
    • 应用案例
      • DeepSeek 与 Dify 集成指南:打造具备多轮思考的 AI 应用
      • 本地私有化部署 DeepSeek + Dify,构建你的专属私人 AI 助手
      • 如何训练出专属于“你”的问答机器人?
      • 教你十几分钟不用代码创建 Midjourney 提示词机器人
      • 构建一个 Notion AI 助手
      • 如何在几分钟内创建一个带有业务数据的官网 AI 智能客服
      • 使用全套开源工具构建 LLM 应用实战:在 Dify 调用 Baichuan 开源模型能力
      • 手把手教你把 Dify 接入微信生态
      • 使用 Dify 和 Twilio 构建 WhatsApp 机器人
      • 将 Dify 应用与钉钉机器人集成
      • 使用 Dify 和 Azure Bot Framework 构建 Microsoft Teams 机器人
      • 如何让 LLM 应用提供循序渐进的聊天体验?
      • 如何将 Dify Chatbot 集成至 Wix 网站?
      • 如何连接 AWS Bedrock 知识库?
      • 构建 Dify 应用定时任务助手
      • 如何在 Dify 内体验大模型“竞技场”?以 DeepSeek R1 VS o1 为例
      • 在 Dify 云端构建 AI Thesis Slack Bot
      • 将 Dify 快速接入 QQ、微信、飞书、钉钉、Telegram、Discord 等平台
    • 扩展阅读
      • 什么是 LLMOps?
      • 什么是数组变量?
      • 检索增强生成(RAG)
        • 混合检索
        • 重排序
        • 召回模式
      • 提示词编排
      • 如何使用 JSON Schema 让 LLM 输出遵循结构化格式的内容?
    • 常见问题
      • 本地部署
      • LLM 配置与使用
      • 插件
  • 政策
    • 开源许可证
    • 用户协议
      • 服务条款
      • 隐私政策
      • 获取合规报告
Powered by GitBook
On this page
  1. 手册
  2. 工具

高级接入工具

Previous快速接入工具Next工具配置

Last updated 3 months ago

“工具”已全面升级为“插件”生态,详细的开发说明请参考。以下内容已归档。

在开始高级接入之前,请确保你已经阅读过,并对Dify的工具接入流程有了基本的了解。

工具接口

我们在Tool类中定义了一系列快捷方法,用于帮助开发者快速构较为复杂的工具。

消息返回

Dify支持文本 链接 图片 文件BLOB 等多种消息类型,你可以通过以下几个接口返回不同类型的消息给 LLM 和用户。

注意,在下面的接口中的部分参数将在后面的章节中介绍。

图片URL

只需要传递图片的URL即可,Dify会自动下载图片并返回给用户。

    def create_image_message(self, image: str, save_as: str = '') -> ToolInvokeMessage:
        """
            create an image message

            :param image: the url of the image
            :return: the image message
        """

链接

如果你需要返回一个链接,可以使用以下接口。

    def create_link_message(self, link: str, save_as: str = '') -> ToolInvokeMessage:
        """
            create a link message

            :param link: the url of the link
            :return: the link message
        """

文本

如果你需要返回一个文本消息,可以使用以下接口。

    def create_text_message(self, text: str, save_as: str = '') -> ToolInvokeMessage:
        """
            create a text message

            :param text: the text of the message
            :return: the text message
        """

文件 BLOB

如果你需要返回文件的原始数据,如图片、音频、视频、PPT、Word、Excel 等,可以使用以下接口。

  • blob 文件的原始数据,bytes 类型

  • meta 文件的元数据,如果你知道该文件的类型,最好传递一个mime_type,否则Dify将使用octet/stream作为默认类型

    def create_blob_message(self, blob: bytes, meta: dict = None, save_as: str = '') -> ToolInvokeMessage:
        """
            create a blob message

            :param blob: the blob
            :return: the blob message
        """

快捷工具

在大模型应用中,我们有两种常见的需求:

  • 先将很长的文本进行提前总结,然后再将总结内容传递给 LLM,以防止原文本过长导致 LLM 无法处理

  • 工具获取到的内容是一个链接,需要爬取网页信息后再返回给 LLM

为了帮助开发者快速实现这两种需求,我们提供了以下两个快捷工具。

文本总结工具

该工具需要传入 user_id 和需要进行总结的文本,返回一个总结后的文本,Dify 会使用当前工作空间的默认模型对长文本进行总结。

    def summary(self, user_id: str, content: str) -> str:
        """
            summary the content

            :param user_id: the user id
            :param content: the content
            :return: the summary
        """

网页爬取工具

该工具需要传入需要爬取的网页链接和一个 user_agent(可为空),返回一个包含该网页信息的字符串,其中user_agent是可选参数,可以用来识别工具,如果不传递,Dify将使用默认的user_agent。

    def get_url(self, url: str, user_agent: str = None) -> str:
        """
            get url
        """ the crawled result

变量池

我们在Tool中引入了一个变量池,用于存储工具运行过程中产生的变量、文件等,这些变量可以在工具运行过程中被其他工具使用。

下面,我们以DallE3和Vectorizer.AI为例,介绍如何使用变量池。

  • DallE3是一个图片生成工具,它可以根据文本生成图片,在这里,我们将让DallE3生成一个咖啡厅的 Logo。

  • Vectorizer.AI是一个矢量图转换工具,它可以将图片转换为矢量图,使得图片可以无限放大而不失真,在这里,我们将DallE3生成的PNG图标转换为矢量图,从而可以真正被设计师使用。

DallE3

首先我们使用 DallE3,在创建完图片以后,我们将图片保存到变量池中,代码如下

from typing import Any, Dict, List, Union
from core.tools.entities.tool_entities import ToolInvokeMessage
from core.tools.tool.builtin_tool import BuiltinTool

from base64 import b64decode

from openai import OpenAI

class DallE3Tool(BuiltinTool):
    def _invoke(self, 
                user_id: str, 
               tool_Parameters: Dict[str, Any], 
        ) -> Union[ToolInvokeMessage, List[ToolInvokeMessage]]:
        """
            invoke tools
        """
        client = OpenAI(
            api_key=self.runtime.credentials['openai_api_key'],
        )

        # prompt
        prompt = tool_Parameters.get('prompt', '')
        if not prompt:
            return self.create_text_message('Please input prompt')

        # call openapi dalle3
        response = client.images.generate(
            prompt=prompt, model='dall-e-3',
            size='1024x1024', n=1, style='vivid', quality='standard',
            response_format='b64_json'
        )

        result = []
        for image in response.data:
            # 将所有图片通过 save_as 参数保存到变量池中,变量名为 self.VARIABLE_KEY.IMAGE.value,如果如果后续有新的图片生成,那么将会覆盖之前的图片
            result.append(self.create_blob_message(blob=b64decode(image.b64_json), 
                                                   meta={ 'mime_type': 'image/png' },
                                                    save_as=self.VARIABLE_KEY.IMAGE.value))

        return result

我们可以注意到这里我们使用了self.VARIABLE_KEY.IMAGE.value作为图片的变量名,为了便于开发者们的工具能够互相配合,我们定义了这个KEY,大家可以自由使用,也可以不使用这个KEY,传递一个自定义的KEY也是可以的。

Vectorizer.AI

接下来我们使用 Vectorizer.AI,将 DallE3 生成的PNG图标转换为矢量图,我们先来过一遍我们在这里定义的函数,代码如下

from core.tools.tool.builtin_tool import BuiltinTool
from core.tools.entities.tool_entities import ToolInvokeMessage, ToolParameter
from core.tools.errors import ToolProviderCredentialValidationError

from typing import Any, Dict, List, Union
from httpx import post
from base64 import b64decode

class VectorizerTool(BuiltinTool):
    def _invoke(self, user_id: str, tool_Parameters: Dict[str, Any]) \
        -> Union[ToolInvokeMessage, List[ToolInvokeMessage]]:
        """
        工具调用,图片变量名需要从这里传递进来,从而我们就可以从变量池中获取到图片
        """
        
    
    def get_runtime_parameters(self) -> List[ToolParameter]:
        """
        重写工具参数列表,我们可以根据当前变量池里的实际情况来动态生成参数列表,从而 LLM 可以根据参数列表来生成表单
        """
        
    
    def is_tool_available(self) -> bool:
        """
        当前工具是否可用,如果当前变量池中没有图片,那么我们就不需要展示这个工具,这里返回 False 即可
        """     

接下来我们来实现这三个函数

from core.tools.tool.builtin_tool import BuiltinTool
from core.tools.entities.tool_entities import ToolInvokeMessage, ToolParameter
from core.tools.errors import ToolProviderCredentialValidationError

from typing import Any, Dict, List, Union
from httpx import post
from base64 import b64decode

class VectorizerTool(BuiltinTool):
    def _invoke(self, user_id: str, tool_Parameters: Dict[str, Any]) \
        -> Union[ToolInvokeMessage, List[ToolInvokeMessage]]:
        """
            invoke tools
        """
        api_key_name = self.runtime.credentials.get('api_key_name', None)
        api_key_value = self.runtime.credentials.get('api_key_value', None)

        if not api_key_name or not api_key_value:
            raise ToolProviderCredentialValidationError('Please input api key name and value')

        # 获取 image_id,image_id 的定义可以在 get_runtime_parameters 中找到
        image_id = tool_Parameters.get('image_id', '')
        if not image_id:
            return self.create_text_message('Please input image id')

        # 从变量池中获取到之前 DallE 生成的图片
        image_binary = self.get_variable_file(self.VARIABLE_KEY.IMAGE)
        if not image_binary:
            return self.create_text_message('Image not found, please request user to generate image firstly.')

        # 生成矢量图
        response = post(
            'https://vectorizer.ai/api/v1/vectorize',
            files={ 'image': image_binary },
            data={ 'mode': 'test' },
            auth=(api_key_name, api_key_value), 
            timeout=30
        )

        if response.status_code != 200:
            raise Exception(response.text)
        
        return [
            self.create_text_message('the vectorized svg is saved as an image.'),
            self.create_blob_message(blob=response.content,
                                    meta={'mime_type': 'image/svg+xml'})
        ]
    
    def get_runtime_parameters(self) -> List[ToolParameter]:
        """
        override the runtime parameters
        """
        # 这里,我们重写了工具参数列表,定义了 image_id,并设置了它的选项列表为当前变量池中的所有图片,这里的配置与 yaml 中的配置是一致的
        return [
            ToolParameter.get_simple_instance(
                name='image_id',
                llm_description=f'the image id that you want to vectorize, \
                    and the image id should be specified in \
                        {[i.name for i in self.list_default_image_variables()]}',
                type=ToolParameter.ToolParameterType.SELECT,
                required=True,
                options=[i.name for i in self.list_default_image_variables()]
            )
        ]
    
    def is_tool_available(self) -> bool:
        # 只有当变量池中有图片时,LLM 才需要使用这个工具
        return len(self.list_default_image_variables()) > 0

可以注意到的是,我们这里其实并没有使用到image_id,我们已经假设了调用这个工具的时候一定有一张图片在默认的变量池中,所以直接使用了image_binary = self.get_variable_file(self.VARIABLE_KEY.IMAGE)来获取图片,在模型能力较弱的情况下,我们建议开发者们也这样做,可以有效提升容错率,避免模型传递错误的参数。

插件开发
快速接入