External data tools are used to fetch additional data from external sources after the end user submits data, and then assemble this data into prompts as additional context information for the LLM. Dify provides a default tool for external API calls, check for details.
For developers deploying Dify locally, to meet more customized needs or to avoid developing an additional API Server, you can directly insert custom external data tool logic in the form of a plugin based on the Dify service. After extending custom tools, your custom tool options will be added to the dropdown list of tool types, and team members can use these custom tools to fetch external data.
Quick Start
Here is an example of extending an external data tool for Weather Search, with the following steps:
Initialize the directory
Add frontend form specifications
Add implementation class
Preview the frontend interface
Debug the extension
1. Initialize the Directory
To add a custom type Weather Search, you need to create the relevant directory and files under api/core/external_data_tool.
weather_search.py code template, where you can implement the specific business logic.
Note: The class variable name must be the custom type name, consistent with the directory and file name, and must be unique.
from typing import Optionalfrom core.external_data_tool.base import ExternalDataToolclass WeatherSearch(ExternalDataTool): """ The name of custom type must be unique, keep the same with directory and file name. """ name: str = "weather_search" @classmethod def validate_config(cls, tenant_id: str, config: dict) -> None: """ schema.json validation. It will be called when user save the config. Example: .. code-block:: python config = { "temperature_unit": "centigrade" } :param tenant_id: the id of workspace :param config: the variables of form config :return: """ if not config.get('temperature_unit'): raise ValueError('temperature unit is required') def query(self, inputs: dict, query: Optional[str] = None) -> str: """ Query the external data tool. :param inputs: user inputs :param query: the query of chat app :return: the tool query result """ city = inputs.get('city') temperature_unit = self.config.get('temperature_unit') if temperature_unit == 'fahrenheit': return f'Weather in {city} is 32°F' else: return f'Weather in {city} is 0°C'
4. Debug the Extension
Now, you can select the custom Weather Search external data tool extension type in the Dify application orchestration interface for debugging.
Implementation Class Template
from typing import Optionalfrom core.external_data_tool.base import ExternalDataToolclass WeatherSearch(ExternalDataTool): """ The name of custom type must be unique, keep the same with directory and file name. """ name: str = "weather_search" @classmethod def validate_config(cls, tenant_id: str, config: dict) -> None: """ schema.json validation. It will be called when user save the config. :param tenant_id: the id of workspace :param config: the variables of form config :return: """ # implement your own logic here def query(self, inputs: dict, query: Optional[str] = None) -> str: """ Query the external data tool. :param inputs: user inputs :param query: the query of chat app :return: the tool query result """ # implement your own logic here return "your own data."
Detailed Introduction to Implementation Class Development
def validate_config
schema.json form validation method, called when the user clicks "Publish" to save the configuration.
config form parameters
{{variable}} custom form variables
def query
User-defined data query implementation, the returned result will be replaced into the specified variable.
inputs: Variables passed by the end user
query: Current conversation input content from the end user, a fixed parameter for conversational applications.