Советы по разработке плагинов Dify с помощью Cursor

堆友AI

Вы - старший разработчик, который может помочь мне в разработке Dify Plugin Tool, который является инструментом AI Agent Tool, который может быть использован в AI Agent Development Tool, Dify. Вы собираетесь следовать инструкции ниже, чтобы помочь мне создать Plugin Tool под названием { }. Автором этого инструмента является { }. Автором этого инструмента является { }. Этот инструмент должен обладать функциональностью { }. Убедитесь, что вы редактируете существующую папку проекта: { } и структуру файлов. Наиболее важными являются отступы в yaml-файле и Самое главное, чтобы отступы и форматирование yaml-файла строго соответствовали примерам yaml-файла. После того как инструмент плагина готов, настройте venv и установите все требования под плагином После того как инструмент плагина будет готов, настройте venv и установите все требования в директорию плагина. Вы должны изменить только те файлы, которые указаны в инструкции. Не меняйте ничего другого, например, файл env.example .
Прежде чем применять что-либо, я хочу, чтобы вы {прочитали документацию по API-доступу инструмента}/{поняли, в чем заключается функциональность инструмента, что входит в его состав, какой функционал он имеет и что мы получаем на выходе}.
Ниже приводится схема инструмента Dify Plugin Tool, и вы должны следовать следующей инструкции, чтобы помочь мне собрать инструмент.
your_plugin/ ├──── _assets/ # Каталог для визуальных активов, используемых в листингах marketplace │ └──── icon.svg # Иконка плагина, отображаемая в Dify marketplace UI │ ├──── provider/ # Настройка и проверка аутентификации │ ├──── your_plugin.py # Класс, наследующий от ToolProvider; проверяет учетные данные │ ├──── your_plugin.py # Класс, наследующий от ToolProvider. Проверяет учетные данные │ └──── your_plugin.yaml # Настраивает поля пользовательского интерфейса аутентификации, метки и текст справки │ ├──── tools/ # Файлы реализации инструмента │ ├──── your_plugin.py your_plugin.py # Класс, наследующий от Tool; реализует функциональность API │ └──── your_plugin.yaml # Определяет параметры инструмента, описания │ ├──── .diftyignore # Перечисляет файлы, которые нужно исключить при публикации на marketplace │ ├──── .env.example # Шаблон для окружения переменных, необходимых для тестирования │ # Содержит заполнитель REMOTE_INSTALL_KEY │ ├──── .gitignore # Стандартный файл игнорирования Git для контроля версий │ ├──── [ GUIDE.md]() # Подробные инструкции по использованию, показываемые пользователям в marketplace │ ├──── [main.py]() # Точка входа для локального тестирования через python -m main test │ # Вообще не должен модифицироваться │ ├──── manifest.yaml # Основные метаданные для листинга marketplace: │ # - Номер версии │ # - Совместимость информация │ # - Возможности плагина │ # - Категоризация маркетплейса │ ├──── [PRIVACY.md]() # Политика конфиденциальности, отображаемая в маркетплейсе │ ├──── [README .md]() # Общая документация и обзор для разработчиков │ └──── requirements.txt # Зависимости пакета Python, необходимые плагину
1. Как редактировать manifest.yaml
Вам предстоит создать файл manifest.yaml для плагина Dify. Этот файл является центральным конфигурационным файлом, который описывает весь ваш плагин для Dify Marketplace. Этот файл является центральным конфигурационным файлом, который описывает весь ваш плагин для Dify Marketplace. Я проведу вас через создание этого файла, объясняя, какие части влияют на внешний вид вашего плагина в Marketplace.
Назначение файла
Файл manifest.yaml служит основным конфигурационным файлом для вашего плагина, определяя его.
Основная информация о плагине, отображаемая на Торговой площадке
Требования к версиям и ресурсам
Разрешения, необходимые вашему плагину
Ссылки на поставщиков инструментов
Пример реализации (Dropbox)
Вот как выглядит файл manifest.yaml для инструмента Dropbox.
версия: 0.0.1
тип: плагин
Автор: langgenius
название: dropbox
этикетка.
en_US: Dropbox
ja_JP: Dropbox
zh_Hans: Dropbox
pt_BR: Dropbox
zh_Hant: Dropbox
описание.
en_US: Взаимодействие с файлами и папками Dropbox. Позволяет перечислять, искать, загружать, скачивать и управлять файлами.
ja_JP: Dropbox のファイルとフォルダ を操作します。 Список файлов, поиск, приложение, загрузка и управление.
zh_Hans: Взаимодействует с файлами и папками Dropbox. Позволяет перечислять, искать, загружать, скачивать и управлять файлами.
pt_BR: Взаимодействие с архивами и пастами Dropbox. Позволяет перечислять, просматривать, загружать, скачивать и создавать архивы.
zh_Hant: Взаимодействие с файлами и папками Dropbox. Список, поиск, загрузка, скачивание и управление файлами.
значок: icon.svg
ресурс.
память: 268435456
разрешение.
инструмент.
включено: true
модель.
включено: true
llm: true
text_embedding: false
рерайтинг: ложь
tts: false
speech2text: false
модерация: ложь
хранение.
включено: true
Размер: 1048576
плагины.
инструменты.
- provider/dropbox.yaml
мета.
версия: 0.0.1
арка.
- amd64
- арм64
бегун.
язык: python
версия: "3.12"
точка входа: главная
created_at: 2025-04-03T17:41:08.159756+08:00
конфиденциальность: PRIVACY.md
Ключевые компоненты, влияющие на отображение информации на рынке
Основная информация (отображается в листинге плагинов).
version: номер версии вашего плагина
Автор: Название вашей организации, отображаемое в Marketplace
name: Внутреннее имя вашего плагина
label: отображение имени на разных языках
created_at: Время создания в формате RFC3339 (должно быть в прошлом).
icon: путь к значку вашего плагина
описание: Полное описание на разных языках
Теги: Категории для вашего плагина. Вы можете установить только один тег за раз. (Сейчас в тегах есть только поиск', 'изображения', 'видео', 'погода', 'финансы', 'дизайн', ' путешествия", "социальный", "новости", "медицина", "продуктивность", "образование", "бизнес", "развлечения", "утилиты" или "другое")
Требования к ресурсам (указаны в разделе требований).
resource.memory: Максимальное использование памяти в байтах (например, 1048576 = 1 МБ).
resource.permission: Необходимые разрешения для вашего плагина
Ссылки на плагин.
plugins.tools: Путь к YAML-файлу(ам) вашего провайдера.
Влияние на рынок
Если посмотреть на предоставленный вами снимок экрана Marketplace, то можно увидеть, как отображаются эти поля.
Название плагина, иконка и описание появляются в верхней части
Имя автора и номер версии отображаются под описанием
Теги появляются в разделе "TAGS".
Требования к памяти указаны в разделе "РЕКВИЕМЕНТЫ".
Важные замечания
Большинство полей можно оставить в том виде, в котором они были изначально заданы в шаблоне, в частности.
тип: Сохранить как "плагин"
раздел мета: сохранить значения по умолчанию
resource.permission: изменяйте только в том случае, если вашему плагину нужны особые разрешения.
Поля, которые необходимо настроить.
version: номер версии вашего плагина
Автор: Название вашей организации
name: уникальный идентификатор для вашего плагина
label: отображаемое имя на разных языках
описание: четкое описание того, что делает ваш плагин
теги: релевантные категории для вашего плагина
plugins.tools: Путь к YAML-файлу(ам) вашего провайдера.
Чтобы создать свой собственный файл manifest.yaml, начните с шаблона и настройте поля, которые влияют на то, как ваш плагин отображается в Marketplace. Главное - предоставить четкую и лаконичную информацию, которая поможет пользователям понять, что делает ваш плагин. Однако, несмотря на все вышесказанное, вы всегда должны оставлять файл файл манифеста в исходном виде, так как все настраивается при инициализации.
2. Как отредактировать файл provider/your_plugin.yaml
Перед вами стоит задача создать YAML-файл конфигурации провайдера для плагина Dify. В этом файле определяются учетные данные, необходимые для вашего сервиса, и то, как Я проведу вас через создание этого файла шаг за шагом, используя Google Search в качестве примера.
Назначение файла
В YAML-файле провайдера (your_plugin.yaml) определяются.
Какие учетные данные необходимо предоставить пользователям, чтобы воспользоваться вашим сервисом
Как эти учетные данные собираются и отображаются в пользовательском интерфейсе
Какие инструменты включены в ваш плагин
Файл Python, который проверяет эти учетные данные
Необходимые компоненты
Раздел identity: Основные метаданные для вашего плагина (требуется, но не влияет на внешний вид Marketplace)
Раздел credentials_for_provider: определяет, какие учетные данные аутентификации должны предоставить пользователи
Раздел инструментов: перечисляет, какие файлы конфигурации инструментов включены
дополнительная секция: указывает файл Python, используемый для проверки учетных данных
Пример реализации
Вот как выглядит YAML-файл провайдера для инструмента Dropbox.
личность.
Автор: lcandy
название: dropbox
этикетка.
en_US: Dropbox
zh_Hans: Dropbox
pt_BR: Dropbox
ja_JP: Dropbox
zh_Hant: Dropbox
описание.
en_US: Взаимодействие с файлами и папками Dropbox
zh_Hans: Взаимодействие с файлами и папками Dropbox
pt_BR: Interaja com arquivos e pastas do Dropbox
ja_jp: Dropbox のファイルとフォルダ を操作します
zh_Hant: Взаимодействие с файлами и папками Dropbox
значок: icon.svg
credentials_for_provider.
access_token.
тип: секретный вход
обязательно: true
этикетка.
en_US: Access Токен
zh_Hans: токен доступа
pt_BR: Token de Acesso
ja_jp: акустический кочегар
zh_Hant: Доступ к скипетру
место.
en_US: Пожалуйста, введите свой токен доступа к Dropbox
zh_Hans: Пожалуйста, введите свой токен доступа к Dropbox!
pt_BR: Пожалуйста, вставьте свой токен доступа в Dropbox
ja_jp: Dropbox アクセストークンを入力してください
zh_Hant: Пожалуйста, введите свой ключ доступа к Dropbox.
помогать.
en_US: Получите токен доступа в Dropbox App Console
zh_Hans: Получение токена доступа из консоли приложения Dropbox
pt_BR: Получите свой токен доступа в консоли приложений Dropbox
ja_JP: Dropbox アプリコンソールからアクセストークンを取得してください
zh_Hant: Пожалуйста, получите свой ключ доступа из консоли приложения Dropbox.
url.
инструменты.
- tools/list_files.yaml
- tools/search_files.yaml
- tools/upload_file.yaml
- tools/download_file.yaml
- tools/create_folder.yaml
- tools/delete_file.yaml
дополнительно.
python.
источник: provider/dropbox.py
Ключевые моменты, о которых следует помнить
Секция идентификации: хотя она не влияет на работу Marketplace, она все же необходима в структуре файла. Включает в себя основную информацию, такую как имя, автор и описание. Теги должны наследоваться от файла manifest.yaml.
Секция полномочий.
Каждое удостоверение должно иметь уникальный идентификатор (как токен доступа к dropbox).
варианты типа.
секретный вход: для конфиденциальной информации, которая будет зашифрована
text-input: Для обычной текстовой информации
select: для выбора из выпадающего списка
булево: для тумблеров
tool-selector: для объектов конфигурации инструментов
Включить обязательно: true/false, чтобы указать, является ли учетная запись обязательной.
Предоставляйте удобные для пользователя метки, вставки и справочный текст на разных языках
Поле url содержит ссылку на документацию по получению учетных данных
Раздел "Инструменты".
Список YAML-файлов для каждого инструмента в вашем плагине
Пути должны быть относительными к корню плагина
Дополнительная секция.
Указывает файл Python, который проверяет учетные данные.
Этот файл должен совпадать с файлом, созданным в вашем файле "provider/your_plugin.py".
Создание файла YAML
Чтобы адаптировать это для своего сервиса.
Измените раздел идентификации, добавив в него основную информацию о плагине
Определите, какие учетные данные требуются вашей службе, в разделе credentials_for_provider.
Перечислите YAML-файлы ваших инструментов в разделе инструментов
Укажите файл проверки Python в дополнительном разделе
Помните, что этот YAML-файл работает в связке с файлом проверки Python, который будет использовать эти учетные данные для аутентификации в вашем сервисе.
3. Как отредактировать файл provider/your_plugin.py
Перед вами стоит задача создать файл аутентификации провайдера для плагина Dify. Этот файл будет подтверждать учетные данные, необходимые для доступа к сторонним ресурсам. Я проведу вас через создание этого файла на примере интеграции Google Search API.
Назначение файла
Python-файл провайдера (provider_name.py) служит модулем тестирования аутентификации для вашего плагина Dify. Его основная задача - проверить действительны ли учетные данные, предоставленные пользователями, путем выполнения простого вызова API к сервису.
Необходимые компоненты
Ваш класс провайдера должен наследоваться от dify_plugin.
Вы должны реализовать метод _validate_credentials
Вы должны использовать ToolProviderCredentialValidationError для обработки ошибок
Как это работает
Процесс аутентификации проходит следующим образом.
Пользователь вводит свои учетные данные в пользовательском интерфейсе Dify
Dify передает эти учетные данные в ваш метод _validate_credentials
Ваш код пытается выполнить простой вызов API, используя предоставленные учетные данные
В случае успеха аутентификация считается действительной; если нет, вы выдаете ошибку
Пример реализации
Вот как можно реализовать файл провайдера для инструмента Dropbox
from typing import Any

из dify_plugin import ToolProvider
из dify_plugin.errors.tool.import ToolProviderCredentialValidationError
импорт dropbox
from dropbox.exceptions import AuthError

from dropbox_utils import DropboxUtils

класс DropboxProvider(ToolProvider).
def _validate_credentials(self, credentials: dict[str, Any]) -> None.
попробуйте.
# Проверьте, предоставлен ли access_token в учетных данных
если "access_token" нет в учетных данных или нет credentials.get("access_token"):.
raise ToolProviderCredentialValidationError("Требуется токен доступа Dropbox.")

# Попробуйте пройти аутентификацию в Dropbox с помощью маркера доступа
попробуйте.
# Используйте функцию полезности, чтобы получить клиента
DropboxUtils.get_client(credentials.get("access_token"))
except AuthError as e.
raise ToolProviderCredentialValidationError(f "Неверный токен доступа Dropbox: {str(e)}")
except Exception as e.
raise ToolProviderCredentialValidationError(f "Не удалось подключиться к Dropbox: {str(e)}")

except Exception as e.
raise ToolProviderCredentialValidationError(str(e))
Ключевые моменты, о которых следует помнить
Всегда используйте класс инструментов: провайдер не выполняет вызовы API напрямую. Вместо этого он использует класс инструментов через метод from_credentials.
Используйте минимальный тестовый запрос: проведите простой тест на проверку - достаточно, чтобы убедиться, что учетные данные работают.
Правильная обработка ошибок: всегда оборачивайте проверку в блок try/except и преобразуйте любые исключения в стандартные ToolProviderCredentialValidationError.
Общий словарь учетных данных: параметр credentials содержит все параметры аутентификации, определенные в файле provider_name.yaml.
Работа с генераторами: обратите внимание на синтаксис for _ in ... синтаксис, используемый для работы с генератором, возвращаемым методом invoke.
4. Как редактировать файл tools/your_plugin.yaml
Перед вами стоит задача создать YAML-файл конфигурации инструмента для плагина Dify. Этот файл определяет, как ваш инструмент отображается в интерфейсе Dify, какие параметры он принимает и как эти параметры представляются пользователям и агенту ИИ. какие параметры он принимает, и как эти параметры будут представлены пользователям и агенту ИИ. Я проведу вас через создание этого файла на примере Google Search в качестве примера.
Yaml-схема файла tools/your_plugin.yaml.
импортировать base64
import contextlib
импортировать uuid
from collections.abc import Mapping
from enum import Enum, StrEnum
из typing import Any, Optional, Union

из pydantic import (
BaseModel.
Поле.
field_serializer.
field_validator.
model_validator,
)

из dify_plugin.core.utils.yaml_loader import load_yaml_file
из dify_plugin.entities import I18nObject
из dify_plugin.entities.model.message.import PromptMessageTool

класс LogMetadata(str, Enum).
STARTED_AT = "started_at"
FINISHED_AT = "finished_at"
ELAPSED_TIME = "elapsed_time"
TOTAL_PRICE = "total_price"
TOTAL_TOKENS = "total_tokens"
поставщик = "поставщик"
CURRENCY = "валюта"

класс CommonParameterType(Enum).
SECRET_INPUT = "secret-input"
TEXT_INPUT = "text-input"
SELECT = "select"
STRING = "строка"
NUMBER = "число"
FILE = "файл"
FILES = "файлы"
BOOLEAN = "булево"
APP_SELECTOR = "app-selector"
MODEL_SELECTOR = "model-selector"
# TOOL_SELECTOR = "tool-selector"
TOOLS_SELECTOR = "array[tools]"

класс AppSelectorScope(Enum).
ALL = "все"
CHAT = "чат"
РАБОЧИЙ ФЛОТ = "рабочий процесс"
COMPLETION = "завершение"

класс ModelConfigScope(Enum).
LLM = "llm"
TEXT_EMBEDDING = "text-embedding"
RERANK = "rerank"
TTS = "tts"
SPEECH2TEXT = "speech2text"
МОДЕРАЦИЯ = "умеренность"
VISION = "видение"

класс ToolSelectorScope(Enum).
ALL = "все"
PLUGIN = "plugin"
API = "api"
WORKFLOW = "рабочий процесс"

класс ToolRuntime(BaseModel).
credentials: dict[str, Any]user_id: Optional[str]session_id: Optional[str]

класс ToolInvokeMessage(BaseModel).
класс TextMessage(BaseModel).
текст: str

def to_dict(self).
return {"text": self.text}

класс JsonMessage(BaseModel).
json_object: dict

def to_dict(self).
return {"json_object": self.json_object}

класс BlobMessage(BaseModel).
блоб: байты

class BlobChunkMessage(BaseModel).
id: str = Field(... , description="Идентификатор блоба")
sequence: int = Field(... , description="Последовательность чанка")
total_length: int = Field(... , description="Общая длина шара")
blob: bytes = Field(... , description="Данные чанка в блобе")
end: bool = Field(... , description="Является ли чанк последним чанком")

класс VariableMessage(BaseModel).
имя_переменной: str = Поле(
...,
description="Имя переменной, поддерживает только переменные корневого уровня".
)
variable_value: Any = Field(... , description="Значение переменной")
stream: bool = Field(default=False, description="Является ли переменная потоковой")

@model_validator(mode="before")
@classmethod
def validate_variable_value_and_stream(cls, values).
# пропускать проверку, если значения не являются dict
if not isinstance(values, dict):: if not isinstance(values, dict):: if not isinstance(values, dict).
возвращаемые значения

если values.get("stream") и не isinstance(values.get("variable_value"), str).
raise ValueError("Когда 'stream' равно True, 'variable_value' должно быть строкой.")
возвращаемые значения

класс LogMessage(BaseModel).
класс LogStatus(Enum).
START = "старт"
ERROR = "ошибка"
SUCCESS = "успех"

id: str = Field(default_factory=lambda: str(uuid.uuid4()), description="Идентификатор журнала")
label: str = Field(... , description="Метка журнала")
parent_id: Optional[str] = Field(default=None, description="Оставьте пустым для корневого журнала")
error: Optional[str] = Field(default=None, description="Сообщение об ошибке")
статус: LogStatus = Поле(... , description="Статус журнала")
data: Mapping[str, Any] = Field(... , description="Подробные данные журнала")
metadata: Optional[Mapping[LogMetadata, Any]] = Field(default=None, description="Метаданные журнала")

класс MessageType(Enum).
TEXT = "текст"
FILE = "файл"
BLOB = "blob"
JSON = "json"
LINK = "ссылка"
IMAGE = "изображение"
IMAGE_LINK = "image_link"
VARIABLE = "переменная"
BLOB_CHUNK = "blob_chunk"
LOG = "log"

тип: MessageType
# TODO: pydantic будет проверять и конструировать сообщения по одному, пока не встретит правильный тип
# нам необходимо оптимизировать процесс строительства
сообщение: TextMessage | JsonMessage | VariableMessage | BlobMessage | BlobChunkMessage | LogMessage | None
meta: Optional[dict] = None

@field_validator("message", mode="before")
@classmethod
def decode_blob_message(cls, v).
если isinstance(v, dict) и "blob" в v.
с contextlib.suppress(Exception).
v["blob"] = base64.b64decode(v["blob"])
вернуть v

@field_serializer("message")
def serialize_message(self, v).
if isinstance(v, self.BlobMessage)::
return { "blob": base64.b64encode(v.blob).decode("utf-8")}
elif isinstance(v, self.BlobChunkMessage)::
вернуться {
"id": v.id,
"sequence": v.sequence,
"total_length": v.total_length,
"blob": base64.b64encode(v.blob).decode("utf-8"),
"end": v.end,
}
вернуть v

класс ToolIdentity(BaseModel).
author: str = Field(... , description="Автор инструмента")
name: str = Field(... , description="Название инструмента")
label: I18nObject = Field(... , description="Метка инструмента")

class ToolParameterOption(BaseModel).
value: str = Field(... , description="Значение опции")
label: I18nObject = Field(... , description="Метка опции")

@field_validator("value", mode="before")
@classmethod
def transform_id_to_str(cls, value) -> str.
if not isinstance(value, str): if not isinstance(value, str).
return str(value)
еще.
возвращаемое значение

класс ParameterAutoGenerate(BaseModel).
класс Type(StrEnum).
PROMPT_INSTRUCTION = "prompt_instruction"

тип: тип

класс ParameterTemplate(BaseModel).
enabled: bool = Field(... , description="Включен ли параметр в jinja")

класс ToolParameter(BaseModel).
class ToolParameterType(str, Enum).
STRING = CommonParameterType.STRING.value
NUMBER = CommonParameterType.NUMBER.value
BOOLEAN = CommonParameterType.BOOLEAN.value
SELECT = CommonParameterType.SELECT.value
SECRET_INPUT = CommonParameterType.SECRET_INPUT.value
FILE = CommonParameterType.FILE.value
FILES = CommonParameterType.FILES.value
MODEL_SELECTOR = CommonParameterType.MODEL_SELECTOR.value
APP_SELECTOR = CommonParameterType.APP_SELECTOR.value
# TOOL_SELECTOR = CommonParameterType.TOOL_SELECTOR.value

класс ToolParameterForm(Enum).
SCHEMA = "schema" # должен быть установлен при добавлении инструмента
FORM = "form" # должен быть установлен перед вызовом инструмента.
LLM = "llm" # будет установлен LLM

name: str = Field(... , description="Имя параметра")
label: I18nObject = Field(... , description="Метка, представляемая пользователю")
human_description: I18nObject = Field(... , description="Описание, представляемое пользователю")
тип: ToolParameterType = Field(... , description="Тип параметра")
auto_generate: Optional[ParameterAutoGenerate] = Field(
default=None, description="Автогенерация параметра"
)
template: Optional[ParameterTemplate] = Field(default=None, description="Шаблон параметра")
область видимости: str | None = None
form: ToolParameterForm = Field(... , description="Форма параметра, schema/form/llm")
llm_description: Optional[str] = None
required: Optional[bool] = False
по умолчанию: Optional[Union[int, float, str]] = None
min: Optional[Union[float, int]] = None
max: Optional[Union[float, int]] = None
точность: Опционально[int] = Нет
options: Optional[list[ToolParameterOption]] = None

класс ToolDescription(BaseModel).
человек: I18nObject = Field(... , description="Описание, представленное пользователю")
llm: str = Field(... , description="Описание, представленное в LLM")

класс ToolConfigurationExtra(BaseModel).
класс Python(BaseModel).
источник: str

python: Python

класс ToolConfiguration(BaseModel).
идентификатор: ToolIdentity
параметры: list[ToolParameter] = Field(default=[], description="Параметры инструмента")
описание: ToolDescription
extra: ToolConfigurationExtra
has_runtime_parameters: bool = Field(default=False, description="Имеет ли инструмент параметры времени выполнения")
output_schema: Optional[Mapping[str, Any]] = None

класс ToolLabelEnum(Enum).
SEARCH = "поиск"
IMAGE = "изображение"
ВИДЕО = "видео"
WEATHER = "погода"
FINANCE = "финансы"
DESIGN = "дизайн"
TRAVEL = "путешествие"
SOCIAL = "социальный"
NEWS = "новости"
MEDICAL = "медицинский"
PRODUCTIVITY = "производительность"
EDUCATION = "образование"
BUSINESS = "бизнес"
ENTERTAINMENT = "развлечения"
UTILITIES = "коммунальные услуги"
OTHER = "другой"

класс ToolCredentialsOption(BaseModel).
value: str = Field(... , description="Значение опции")
label: I18nObject = Field(... , description="Метка опции")

класс ProviderConfig(BaseModel).
класс Config(Enum).
SECRET_INPUT = CommonParameterType.SECRET_INPUT.value
TEXT_INPUT = CommonParameterType.TEXT_INPUT.value
SELECT = CommonParameterType.SELECT.value
BOOLEAN = CommonParameterType.BOOLEAN.value
MODEL_SELECTOR = CommonParameterType.MODEL_SELECTOR.value
APP_SELECTOR = CommonParameterType.APP_SELECTOR.value
# TOOL_SELECTOR = CommonParameterType.TOOL_SELECTOR.value
TOOLS_SELECTOR = CommonParameterType.TOOLS_SELECTOR.value

@classmethod
def value_of(cls, value: str) -> "ProviderConfig.
"""
Получение значения заданного режима.

:param value: значение режима
:return: mode
"""
для режима в cls.
если mode.value == value.
режим возврата
raise ValueError(f "недопустимое значение режима {значение}")

name: str = Field(... , description="Имя учетной записи")
type: Config = Field(... , description="Тип учетных данных")
область видимости: str | None = None
required: bool = False
по умолчанию: Optional[Union[int, float, str]] = None
options: Optional[list[ToolCredentialsOption]] = None
метка: I18nObject
help: Optional[I18nObject] = None
url: Optional[str] = None
placeholder: Optional[I18nObject] = None

класс ToolProviderIdentity(BaseModel).
author: str = Field(... , description="Автор инструмента")
name: str = Field(... , description="Название инструмента")
description: I18nObject = Field(... , description="Описание инструмента")
icon: str = Field(... , description="Иконка инструмента")
label: I18nObject = Field(... , description="Метка инструмента")
метки: list[ToolLabelEnum] = Field(
default=[],
description="Теги инструмента".
)

класс ToolProviderConfigurationExtra(BaseModel).
класс Python(BaseModel).
источник: str

python: Python

класс ToolProviderConfiguration(BaseModel).
identity: ToolProviderIdentity
credentials_schema: list[ProviderConfig] = Field(
default_factory=list,
alias="credentials_for_provider",
description="Схема учетных данных поставщика инструмента".
)
инструменты: list[ToolConfiguration] = Field(default=[], description="Инструменты поставщика инструментов")
extra: ToolProviderConfigurationExtra

@model_validator(mode="before")
@classmethod
def validate_credentials_schema(cls, data: dict) -> dict.
original_credentials_for_provider: dict[str, dict] = data.get("credentials_for_provider", {})

credentials_for_provider: list[dict[str, Any]] = []for name, credentials in original_credentials_for_provider.items():
credential["name"] = name
credentials_for_provider.append(credential)

data["credentials_for_provider"] = credentials_for_provider
возвращаемые данные

@field_validator("tools", mode="before")
@classmethod
def validate_tools(cls, value) -> list[ToolConfiguration].
if not isinstance(value, list):: if not isinstance(value, list): if not isinstance(value, list).
raise ValueError("инструменты должны быть списком")

инструменты: список[ToolConfiguration] = []

для инструмента по стоимости:
# читать из yaml
if not isinstance(tool, str): if not isinstance(tool, str).
raise ValueError("путь к инструменту должен быть строкой")
попробуйте.
file = load_yaml_file(tool)
tools.append(
ToolConfiguration(
identity=ToolIdentity(**file["identity"]),
parameters=[ToolParameter(**param) for param in file.get("parameter", []) or []],
description=ToolDescription(**file["description"]),
extra=ToolConfigurationExtra(**file.get("extra", {})),
output_schema=file.get("output_schema", None),
)
)
except Exception as e.
raise ValueError(f "Ошибка загрузки конфигурации инструмента: {str(e)}") from e

возвратные инструменты

класс ToolProviderType(Enum).
"""
Класс Enum для поставщика инструментов
"""

BUILT_IN = "builtin"
WORKFLOW = "рабочий процесс"
API = "api"
APP = "app"
DATASET_RETRIEVAL = "dataset-retrieval"

@classmethod
def value_of(cls, value: str) -> "ToolProviderType".
"""
Получение значения заданного режима.

:param value: значение режима
:return: mode
"""
для режима в cls.
если mode.value == value.
режим возврата
raise ValueError(f "недопустимое значение режима {значение}")

класс ToolSelector(BaseModel).
класс Parameter(BaseModel).
name: str = Field(... , description="Имя параметра")
тип: ToolParameter.ToolParameterType = Field(... , description="Тип параметра")
required: bool = Field(... , description="Является ли параметр обязательным")
description: str = Field(... , description="Описание параметра")
по умолчанию: Optional[Union[int, float, str]] = None
options: Optional[list[ToolParameterOption]] = None

provider_id: str = Field(... , description="Идентификатор провайдера")
название_инструмента: str = Поле(... , description="Название инструмента")
tool_description: str = Field(... , description="Описание инструмента")
tool_configuration: Mapping[str, Any] = Field(... , description="Конфигурация, тип формы")
tool_parameters: Mapping[str, Parameter] = Field(... , description="Параметры, тип llm")

def to_prompt_message(self) -> PromptMessageTool.
"""
Преобразование селектора инструментов в инструмент подсказок, основанный на openai вызов функции схема.
"""
tool = PromptMessageTool(
name=self.tool_name,
description=self.tool_description,
параметры={
"тип": "объект",
"свойства": {},
"required": [],
},
)

for name, parameter in self.tool_parameters.items()::
tool.parameters[name] = {
"тип": параметр.тип.значение,
"описание": parameter.description,
}

если parameter.required.
tool.parameters["required"].append(name)

if parameter.options.
tool.parameters[name]["enum"] = [option.value for option in parameter.options]

возвратный инструмент
Назначение файла
В YAML-файле инструмента (your_plugin.yaml) определяются.
Основная информация о вашем инструменте
Описания для людей и агента ИИ
Параметры, которые принимает ваш инструмент
Как представлены и собраны эти параметры
Пример реализации
Вот как выглядят YAML-файлы инструментов для Dropbox.
ceate_folder.yaml.
личность.
имя: create_folder
Автор: lcandy
этикетка.
en_US: Создать папку
zh_Hans: Создание папок
pt_BR: Criar Pasta
ja_jp: Сложенный
zh_Hant: Создать папку
описание.
человек.
en_US: Создание новой папки в Dropbox
zh_Hans: Создание новой папки в Dropbox
pt_BR: Criar uma nova pasta no Dropbox
ja_jp: Dropbox выпускает новую версию Frida!
zh_Hant: Создание новой папки в Dropbox
llm: Создает новую папку по указанному пути в Dropbox. Возвращает информацию о созданной папке, включая путь и ID.
параметры.
- имя: folder_path
тип: строка
обязательно: true
этикетка.
en_US: Folder Path
zh_Hans: путь к папке
pt_BR: Каминьо да Паста
ja_jp:ォルダパス
zh_Hant: путь к папке
описание человека.
en_US: путь, по которому будет создана папка в Dropbox
zh_Hans: путь создания папки в Dropbox
pt_BR: O caminho onde a pasta será criada no Dropbox
ja_jp: Dropbox でフォルダを作成するパス
zh_Hant: путь к папке, которую вы хотите создать в Dropbox.
llm_description: Путь, по которому будет создана папка в Dropbox. Должен быть указан полный путь, например '/Documents/Projects' или '/Photos/ Vacation2023". Пути чувствительны к регистру и должны начинаться с прямой косой черты.
форма: llm
дополнительно.
python.
источник: tools/create_folder.py
delete_file.yaml.
личность.
имя: delete_file
Автор: lcandy
этикетка.
en_US: Удалить файл/папку
zh_Hans: Удаление файлов/папок
pt_BR: Excluir Arquivo/Pasta
ja_jp: ファイル/フォルダ削除
zh_Hant: Удалить файл/папку
описание.
человек.
en_US: Удалить файл или папку из Dropbox
zh_Hans: Удаление файлов или папок из Dropbox
pt_BR: Исключить из Dropbox архив или пасту
ja_jp: Dropbox からファイルやフォルダを削除します
zh_Hant: Удаление файла или папки из Dropbox
llm: Постоянное удаление файла или папки из Dropbox по указанному пути. Возвращает подтверждающую информацию об удаленном элементе.
параметры.
- имя: file_path
тип: строка
обязательно: true
этикетка.
en_US: Путь к файлу/папке
zh_Hans: путь к файлу/папке
pt_BR: Каминьо ду Аркиво/Паста
ja_jp:ファイル/フォルダパス
zh_Hant: путь к файлу/папке
описание человека.
en_US: Путь к файлу или папке, которую нужно удалить из Dropbox.
zh_Hans: путь к файлу или папке, которые нужно удалить из Dropbox.
pt_BR: O caminho do arquivo ou pasta para excluir do Dropbox
ja_jp: Dropbox から削除するファイルやフォルダのパス
zh_Hant: путь к файлу или папке, которую вы хотите удалить из Dropbox.
llm_description: Путь к файлу или папке, которые нужно удалить из Dropbox. Должен быть указан полный путь, например '/Documents/report.txt' или '/Photos /Vacation2023'. Пути чувствительны к регистру и должны начинаться с прямой косой черты. ПРЕДУПРЕЖДЕНИЕ - Это безвозвратное удаление.
форма: llm
дополнительно.
python.
источник: tools/delete_file.py
download_file.py.
личность.
имя: download_file
Автор: lcandy
этикетка.
en_US: Download File
zh_Hans: Скачать файл
pt_BR: Baixar Arquivo
ja_jp: ファイルダウンロード
zh_Hant: Загрузить файл
описание.
человек.
en_US: Загрузить файл из Dropbox
zh_Hans: Загрузка файлов из Dropbox
pt_BR: Baixar um arquivo do Dropbox
ja_jp: Dropbox からファイルをダウンロードします
zh_Hant: Загрузка файлов из Dropbox
llm: Загружает файл из Dropbox по указанному пути. Возвращает метаданные файла и, по желанию, его содержимое (в формате base64 для бинарных файлов или текст для текстовых файлов).
параметры.
- имя: file_path
тип: строка
обязательно: true
этикетка.
en_US: File Path
zh_Hans: путь к файлу
pt_BR: Caminho do Arquivo
ja_jp: ファイルパス
zh_Hant: Пути к файлам
описание человека.
en_US: Путь к файлу, который нужно загрузить из Dropbox.
zh_Hans: путь к файлу, который нужно загрузить из Dropbox
pt_BR: O caminho do arquivo para baixar do Dropbox
ja_JP: Dropbox からダウンロードするファイルのパス
zh_Hant: путь к файлу, который вы хотите загрузить из Dropbox.
llm_description: Путь к файлу, который нужно загрузить из Dropbox. Должен содержать полный путь с именем и расширением файла, например '/Documents/report. txt'. Пути чувствительны к регистру и должны начинаться с прямой косой черты.
форма: llm
- имя: include_content
тип: булево
обязательный: false
по умолчанию: false
этикетка.
en_US: Include Content
zh_Hans: Содержание
pt_BR: Incluir Conteúdo
ja_JP: Содержание
zh_Hant: Содержит содержимое
описание человека.
en_US: Включать ли содержимое файла в ответ.
zh_Hans: включать или не включать содержимое файла в ответ
pt_BR: Se deve incluir o conteúdo do arquivo na resposta
ja_jp: Содержание фильма в Rathponies включено в фильм.
zh_Hant: включать или не включать содержимое файла в ответ
llm_description: Установите значение true, чтобы включить содержимое файла в ответ. Для небольших текстовых файлов содержимое будет представлено в виде текста. Для бинарных файлов содержимое будет представлено в виде строки, закодированной в base64. Содержимое будет предоставлено в виде base64-кодированной строки. По умолчанию false.
форма: llm
дополнительно.
python.
источник: tools/download_file.py

dropbox.yaml.
личность.
название: dropbox
Автор: lcandy
этикетка.
en_US: Dropbox
zh_Hans: Dropbox
pt_BR: Dropbox
ja_JP: Dropbox
zh_Hant: Dropbox
описание.
человек.
en_US: Взаимодействие с Dropbox
zh_Hans: Взаимодействие с Dropbox
pt_BR: Interagir com o Dropbox
ja_JP: Dropbox и возможность подключения
zh_Hant: Взаимодействие с Dropbox
llm: Предоставляет доступ к сервисам Dropbox, позволяя взаимодействовать с файлами и папками в аккаунте Dropbox.
параметры.
- название: запрос
тип: строка
обязательно: true
этикетка.
en_US: Строка запроса
zh_Hans: Высказывание запроса
pt_BR: Termo de consulta
ja_jp: Текстовые колонки K'eri
zh_Hant: Заявление на запрос
описание человека.
en_US: введите запрос операции Dropbox
zh_Hans: Введите запрос операции Dropbox
pt_BR: Оцифруйте свою консультацию по работе с Dropbox
ja_JP: Dropbox Operation クエリを入力してください
zh_Hant: Пожалуйста, введите операцию Dropbox, которую вы хотите выполнить.
llm_description: запрос, описывающий операцию Dropbox, которую вы хотите выполнить.
форма: llm
дополнительно.
python.
источник: tools/dropbox.py
Ключевые компоненты
Раздел "Идентификация".
name: Внутреннее имя вашего инструмента (должно соответствовать именованию файлов).
Автор: кто создал инструмент
label: отображение имени на разных языках
Описание Раздел.
человек: Описание, показанное пользователям на разных языках
llm: описание, предоставляемое агенту ИИ для понимания того, что делает ваш инструмент и как его использовать
Раздел параметров.
Список параметров, которые принимает ваш инструмент, каждый из которых содержит.
name: Идентификатор параметра (используется в коде Python).
type: Тип данных (строка, число, булево и т.д.)
required: Является ли этот параметр обязательным
этикетка: удобное название на разных языках
human_description: пояснения для человеческих пользователей на разных языках
llm_description: Пояснение, чтобы агент ИИ понял этот параметр.
Форма: Как собирается параметр
llm: агент искусственного интеллекта извлекает информацию из запросов пользователей
Рабочий процесс: Пользователь должен указать переменную в пользовательском интерфейсе
Необязательно: по умолчанию: значение по умолчанию для этого параметра
Дополнительная секция.
python.source: Путь к файлу реализации Python вашего инструмента.
Важные замечания
Разделение файлов.
Важно!!!! : Если ваш инструмент имеет различную функциональность, например, чтение и запись электронной почты, чтение или обновление базы данных, вам следует разделить yaml-файл на несколько. Принцип заключается в том, что каждый yaml-файл и файл кода предназначены исключительно для каждого типа выполнения инструмента. Сам файл должен извлекать только те параметры, которые извлекает инструмент Например, для чтения и обновления базы данных необходимо использовать два yaml-файла: read_database.yaml и update_ database.yaml. database.yaml по отдельности.
Описания LLM.
Описание llm для инструмента и параметров имеет решающее значение - оно сообщает агенту ИИ, как использовать ваш инструмент.
Четко определите, какие параметры необходимы и какую информацию будет выдавать ваш инструмент
Это поможет агенту ИИ решить, когда использовать ваш инструмент и как извлекать параметры из пользовательских запросов.
Конфигурация параметров.
Для каждого параметра укажите, является ли он обязательным
Выберите подходящий тип данных
Установите форму на llm, если хотите, чтобы ИИ извлекал ее из запросов пользователя.
Установите форму на рабочий процесс, если вы хотите, чтобы пользователи предоставляли ее напрямую
Локализация.
Обеспечение перевода этикеток и описаний на несколько языков по мере необходимости
Как минимум, включите английский язык (en_US)
Чтобы создать собственный YAML-файл инструмента, адаптируйте эту структуру для своего конкретного инструмента, четко определив, какие параметры ему нужны и как они должны быть представлены для человека и агента ИИ.
5. Как отредактировать файл tools/your_plugin.py
Вам поручено создать файл реализации инструмента для плагина Dify. Этот файл содержит фактическую логику для вашего инструмента, который делает запросы к API и обрабатывает результаты. Этот файл содержит фактическую логику для вашего инструмента, который делает API-запросы и обрабатывает результаты. Я проведу вас через создание этого файла, используя Google Search в качестве примера.
Назначение файла
Инструментальный Python-файл (your_plugin.py) отвечает за.
Выполнение API-запросов к вашему сервису
Обработка ответов
Возвращение результатов в формате, пригодном для использования в Dify
Необходимые компоненты
Ваш класс инструмента должен наследоваться от dify_plugin.
Вы должны реализовать метод _invoke, который возвращает генератор
Вы должны включить в него эти необходимые импортные товары.
from collections.abc import Generator
from typing import Any
из dify_plugin import Tool
из dify_plugin.entities.tool.import ToolInvokeMessage
Пример реализации
Вот как выглядит реализация инструмента для Dropbox.
ceate_folder.yaml.
from collections.abc import Generator
from typing import Any

из dify_plugin import Tool
из dify_plugin.entities.tool.import ToolInvokeMessage
from dropbox.exceptions import ApiError, AuthError

from dropbox_utils import DropboxUtils

класс CreateFolderTool(Tool).
def _invoke(self, tool_parameters: dict[str, Any]) -> Generator[ToolInvokeMessage, None, None].
"""
Создайте папку в Dropbox
"""
# Получить параметры
folder_path = tool_parameters.get("folder_path", "")

# Проверка параметров
if not folder_path: if not folder_path: if not folder_path: if not folder_path.
yield self.create_text_message("Требуется путь к папке в Dropbox.")
возврат

# Убедитесь, что путь к папке начинается с /
if not folder_path.startswith("/"):.
folder_path = "/" + folder_path

попробуйте.
# Получение маркера доступа из учетных данных
access_token = self.runtime.credentials.get("access_token")
if not access_token.
yield self.create_text_message("Требуется токен доступа к Dropbox.")
возврат

# Получите клиент Dropbox
попробуйте.
dbx = DropboxUtils.get_client(access_token)
except AuthError as e.
yield self.create_text_message(f "Authentication failed: {str(e)}")
возврат
except Exception as e.
yield self.create_text_message(f "Не удалось подключиться к Dropbox: {str(e)}")
возврат

# Создайте папку
попробуйте.
result = DropboxUtils.create_folder(dbx, folder_path)

# Создать ответ
summary = f "Папка '{result['name']}' успешно создана по адресу '{result['path']}'".
yield self.create_text_message(summary)
yield self.create_json_message(result)

except ApiError as e.
if "path/conflict" in str(e).
yield self.create_text_message(f "Папка уже существует по адресу '{folder_path}'")
еще.
yield self.create_text_message(f "Ошибка при создании папки: {str(e)}")
возврат

except Exception as e.
yield self.create_text_message(f "Ошибка: {str(e)}")
возврат
delete_file.py
from collections.abc import Generator
from typing import Any

из dify_plugin import Tool
из dify_plugin.entities.tool.import ToolInvokeMessage
from dropbox.exceptions import ApiError, AuthError

from dropbox_utils import DropboxUtils

класс DeleteFileTool(Tool).
def _invoke(self, tool_parameters: dict[str, Any]) -> Generator[ToolInvokeMessage, None, None].
"""
Удалить файл или папку из Dropbox
"""
# Получить параметры
file_path = tool_parameters.get("file_path", "")

# Проверка параметров
если не file_path: если не file_path: если не file_path.
yield self.create_text_message("Требуется путь к файлу или папке в Dropbox.")
возврат

# Убедитесь, что путь начинается с /
if not file_path.startswith("/"):.
file_path = "/" + file_path

попробуйте.
# Получение маркера доступа из учетных данных
access_token = self.runtime.credentials.get("access_token")
if not access_token.
yield self.create_text_message("Требуется токен доступа к Dropbox.")
возврат

# Получите клиент Dropbox
попробуйте.
dbx = DropboxUtils.get_client(access_token)
except AuthError as e.
yield self.create_text_message(f "Authentication failed: {str(e)}")
возврат
except Exception as e.
yield self.create_text_message(f "Не удалось подключиться к Dropbox: {str(e)}")
возврат

# Удалить файл или папку
попробуйте.
result = DropboxUtils.delete_file(dbx, file_path)

# Создать ответ
summary = f"'{result['name']}' удален успешно"
yield self.create_text_message(summary)
yield self.create_json_message(result)

except ApiError as e.
if "path/not_found" in str(e)::
yield self.create_text_message(f "Файл или папка не найдены по адресу '{file_path}'")
еще.
yield self.create_text_message(f "Ошибка при удалении файла/папки: {str(e)}")
возврат

except Exception as e.
yield self.create_text_message(f "Ошибка: {str(e)}")
возврат
download_file.yaml.
from collections.abc import Generator
импортировать base64
from typing import Any

из dify_plugin import Tool
из dify_plugin.entities.tool.import ToolInvokeMessage
from dropbox.exceptions import ApiError, AuthError

from dropbox_utils import DropboxUtils

класс DownloadFileTool(Tool).
def _invoke(self, tool_parameters: dict[str, Any]) -> Generator[ToolInvokeMessage, None, None].
"""
Загрузить файл из Dropbox
"""
# Получить параметры
file_path = tool_parameters.get("file_path", "")
include_content = tool_parameters.get("include_content", False)

# Проверка параметров
если не file_path: если не file_path: если не file_path.
yield self.create_text_message("Требуется путь к файлу в Dropbox.")
возврат

# Убедитесь, что путь к файлу начинается с /
if not file_path.startswith("/"):.
file_path = "/" + file_path

попробуйте.
# Получение маркера доступа из учетных данных
access_token = self.runtime.credentials.get("access_token")
if not access_token.
yield self.create_text_message("Требуется токен доступа к Dropbox.")
возврат

# Получите клиент Dropbox
попробуйте.
dbx = DropboxUtils.get_client(access_token)
except AuthError as e.
yield self.create_text_message(f "Authentication failed: {str(e)}")
возврат
except Exception as e.
yield self.create_text_message(f "Не удалось подключиться к Dropbox: {str(e)}")
возврат

# Скачать файл
попробуйте.
result = DropboxUtils.download_file(dbx, file_path)

# Создать ответ
ответ = {
"имя": result["name"],
"путь": result["путь"],
"id": result["id"],
"Размер": result["size"],
"modified": result["modified"]}

# Включите содержимое по запросу
if include_content.
# Кодирование двоичного содержимого в формат base64
response["content_base64"] = base64.b64encode(result["content"]).decode('utf-8')

# Попробуйте декодировать как текст, если он достаточно мал.
if result["size"] < 1024 * 1024: # Менее 1 МБ
попробуйте.
text_content = result["content"].decode('utf-8')
response["content_text"] = text_content
кроме UnicodeDecodeError.
# Не текстовый файл, просто включите base64
пройти

summary = f "Файл '{result['name']}' успешно загружен"
yield self.create_text_message(summary)
yield self.create_json_message(response)

except ApiError as e.
yield self.create_text_message(f "Ошибка при загрузке файла: {str(e)}")
возврат

except Exception as e.
yield self.create_text_message(f "Ошибка: {str(e)}")
возврат
Ключевые моменты, о которых следует помнить
Разделение файлов.
Важно: Если ваш инструмент имеет различную функциональность, например, чтение и запись электронной почты, чтение или обновление базы данных, вам следует разделить yaml-файл на несколько частей. Принцип заключается в том, что каждый yaml-файл и файл кода предназначены исключительно для выполнения каждого типа инструментов. Сам файл должен извлекать только те параметры, которые будут использоваться в функционале инструмента. Например, для чтения и обновления базы данных необходимо использовать два yaml-файла: read_database.py и update_ database.py. database.py по отдельности.
Необходимые импорты: всегда включайте необходимые импорты в начало файла.
Наследование классов: класс вашего инструмента должен наследоваться от dify_plugin.
Извлечение параметров.
Словарь tool_parameters содержит все параметры, определенные в YAML-файле вашего инструмента.
Обращайтесь к этим параметрам напрямую, используя ключи словаря, например, tool_parameters["query"] Эти параметры автоматически извлекаются из пользовательских запросов Эти параметры автоматически извлекаются из пользовательских запросов агентом искусственного интеллекта
Убедитесь, что вы обработали все необходимые параметры и обеспечили соответствующую обработку ошибок, если они отсутствуют
Пример.
query = tool_parameters["query"] # Извлечение параметра запросаlimit = tool_parameters.get("limit", 10) # Извлечение со значением по умолчанию# Необязательная проверка Если не query: raise ValueError("Параметр запроса не может быть пустым")
Доступ к учетным данным.
Получите доступ к своим учетным данным аутентификации с помощью self.runtime.credentials
Ключи соответствуют ключам, определенным в YAML-файле вашего провайдера
Пример: self.runtime.credentials["serpapi_api_key"] Обработка ответа: Создайте вспомогательный метод для извлечения только нужной информации из ответов API.
Выдача результатов: Чтобы вернуть данные, необходимо использовать yield с одним из методов создания сообщения.
При реализации собственного инструмента убедитесь, что вы правильно извлекли все необходимые параметры из словаря tool_parameters, и при необходимости проверьте их. Доступные параметры определяются в YAML-файле вашего инструмента и будут автоматически извлекаться из пользовательских запросов агентом ИИ.
6. Как создать файлы PRIVACY.md и README.md
Вам поручено создать политику конфиденциальности и файлы readme для вашего плагина Dify. Эти файлы написаны в формате Markdown и служат важным Эти файлы написаны в формате Markdown и служат важным целям для пользователей и разработчиков вашего плагина.
PRIVACY.md
Файл PRIVACY.md конспекты Практика конфиденциальности вашего плагина, включая то, какие данные он собирает и как эти данные используются. Это важная информация для пользователей, обеспокоенных конфиденциальностью своих данных. Это важная информация для пользователей, обеспокоенных конфиденциальностью своих данных.
Что включить
Основываясь на размещенном вами тексте ("!!!!! Пожалуйста, заполните политику конфиденциальности плагина."), вы должны включить.
Какие данные собирает ваш плагин
Как хранятся и обрабатываются эти данные
Какие сторонние сервисы используются (если таковые имеются)
Права пользователей в отношении их данных
Как долго хранятся данные
Контактная информация по вопросам конфиденциальности
Пример структуры
# Политика конфиденциальности

## Сбор данных
[Опишите, какие пользовательские данные собирает ваш плагин и зачем].

## Обработка данных
[Объясните, как обрабатываются собранные данные]

## Услуги третьих лиц
[Перечислите все сторонние сервисы, используемые вашим плагином, и укажите ссылку на их политику конфиденциальности]

## Сохранение данных
[Объясните, как долго хранятся данные пользователя].

Права пользователя ##
[Опишите, какие права имеют пользователи в отношении своих данных].

Контактная информация ##
[Предоставьте контактную информацию для запросов, связанных с конфиденциальностью]

Последнее обновление: [Дата]README.md
Файл README.md содержит важную информацию о вашем плагине, в том числе о том, что он делает, как его установить и как его использовать. Это первый документ, к которому обращается большинство пользователей и разработчиков.
Что включить
Исходя из примера, которым вы поделились (Jira plugin readme), вы должны включить.
Название плагина в качестве основного заголовка
Информация об авторе
Информация о версии
Тип плагина
Подробное описание того, что делает плагин
Инструкции по установке
Примеры использования
Параметры конфигурации
Информация об устранении неполадок
Пример структуры
# Название вашего плагина

**Автор:** [Ваше имя или организация]**Версия:** [Номер текущей версии]**Тип:** [Тип плагина]

## Описание
[Укажите подробное описание того, что делает ваш плагин]

Характеристики ##
- [Характеристика 1]- [Характеристика 2]- [Характеристика 3]

Установка ##
[Предоставляем пошаговые инструкции по установке]

Конфигурация ##
[Объясните, как настроить ваш плагин].

Примеры использования ##
[Приведите примеры использования вашего плагина].

Устранение неполадок ##
[Перечислите общие проблемы и их решения].

## Вклад
[Объясните, как другие могут внести свой вклад в ваш плагин].

Лицензия ##
[Укажите лицензию, под которой выпущен ваш плагин]Использование изображений
Как вы уже сказали, если вы хотите включить изображения в любой документ.
Сохраните изображения в папке _assets.
Ссылайтесь на них в уценке, используя относительные пути.
! [Описание изображения](_assets/image_name.png)
Оба этих файла должны быть написаны в формате Markdown (расширение .md) и помещены в корневую директорию проекта плагина. Обязательно обновляйте их по мере развития плагина. Обязательно обновляйте их по мере развития вашего плагина.
Требования.txt
Вы всегда должны использовать последние версии зависимостей, используя ~= в вашем txt-файле, а dify_plugin~=0.0.1b72 является обязательным.

© заявление об авторских правах

Похожие посты

Нет комментариев

Вы должны войти в систему, чтобы участвовать в комментариях!
Войти сейчас
нет
Нет комментариев...