Community연구 & 데이터 분석github.com

SystemTce/dify-skills

Dify 플러그인 개발 완벽 가이드: 도구, 모델, 데이터 소스, 확장의 네 가지 플러그인 유형을 다룹니다.

dify-skills란 무엇인가요?

이 스킬은 Dify 플러그인 시스템 개발을 위한 포괄적인 가이드입니다. Beehive(벌집) 아키텍처를 기반으로 하는 Dify 플러그인 시스템은 도구(Tool), 모델(Model), 데이터 소스(Datasource), 확장(Extension)의 네 가지 플러그인 유형과 로컬(Local), 디버그(Debug), 서버리스(Serverless)의 세 가지 런타임 모드를 지원합니다. 개발자는 이 스킬을 통해 플러그인 프로젝트 초기화, 구현, 로컬 디버깅, 패키징 및 배포까지의 전체 개발 사이클을 이해할 수 있습니다. 또한 OAuth 2.0 통합, API-플러그인 마이그레이션, 단위 및 통합 테스트, 성능 최적화, 보안 모범 사례 등을 상세히 다루어 초보자부터 숙련된 개발자까지 Dify 생태계를 효과적으로 확장할 수 있도록 지원합니다. CLI 도구, Python SDK, 다양한 설정 파일 예제를 제공하여 실무에 즉시 적용 가능한 가이드를 제공합니다.

지원 대상✓Claude Code✓Codex CLI~Cursor✓Gemini CLI
npx skills add https://github.com/SystemTce/dify-skills/tree/main/02-plugin

Installed? Explore more 연구 & 데이터 분석 skills: affaan-m/uspto-database, affaan-m/scholar-evaluation, affaan-m/literature-review · View all 6 →

즐겨 사용하는 AI에게 물어보기

이 에이전트 스킬이 미리 로드된 새 채팅을 엽니다.

문서

Dify 플러그인 개발 SKILL

개요

Dify 플러그인 시스템은 혁신적인 Beehive(벌집) 아키텍처를 채택하여 세 가지 런타임 모드와 네 가지 플러그인 유형을 지원하며, 개발자에게 강력한 확장 기능을 제공합니다. 본 SKILL은 입문부터 숙련까지의 완벽한 플러그인 개발 가이드를 제공합니다.

적용 시나리오

다음과 같은 상황에서 이 SKILL을 사용하세요:

  • Dify 플러그인 개발: 도구, 모델, 데이터 소스, 확장 네 가지 유형
  • 타사 서비스 통합: API 래핑, OAuth 인증
  • 사용자 정의 도구 구현: AI 기능 확장
  • Dify 플랫폼 기능 확장: 트리거, 에이전트 전략
  • 기존 API를 플러그인으로 마이그레이션: API-플러그인 변환
  • 플러그인 성능 디버깅 및 최적화: 성능 튜닝 및 문제 해결

핵심 가치

  • Beehive 아키텍처: 분산 스케줄링, 마스터-슬레이브 선출, 자가 치유
  • 다중 런타임 지원: 로컬(Local), 디버그(Debug), 서버리스(Serverless) 세 가지 모드
  • 완벽한 도구 체인: dify CLI, Python SDK, 디버그 런타임
  • 풍부한 생태계: 70+ 모델 플러그인, 20+ 도구 플러그인, 18+ 데이터 소스 플러그인
  • 프로덕션 수준 품질: OAuth 2.0, 권한 제어, 모니터링 및 추적

빠른 시작

1. 환경 준비

# Python 3.12+ 설치
python --version  # >= 3.12 확인

# uv 패키지 관리자 설치 (권장)
curl -LsSf https://astral.sh/uv/install.sh | sh

# dify CLI 설치
pip install dify-cli

# 설치 확인
dify --version

2. 첫 번째 플러그인 생성

# 플러그인 프로젝트 초기화
dify plugin init

# 플러그인 유형 선택
? Select plugin type: Tool
? Plugin name: my_first_tool
? Author: your_name
? Description: My first Dify tool plugin

# 프로젝트 디렉토리로 이동
cd my_first_tool

# 의존성 설치
uv pip install -r requirements.txt

3. 플러그인 로직 구현

tools/my_tool.py 편집:

from typing import Any, Generator
from dify_plugin.entities.tool import ToolInvokeMessage
from dify_plugin import Tool


class MyTool(Tool):
    def _invoke(
        self, tool_parameters: dict[str, Any]
    ) -> Generator[ToolInvokeMessage, None, None]:
        """
        도구 호출 진입점
        """
        # 매개변수 가져오기
        text = tool_parameters.get("text", "")

        # 처리 로직
        result = f"처리 결과: {text.upper()}"

        # 결과 반환
        yield self.create_text_message(result)

4. 로컬 디버깅

# Debug Runtime 시작
dify plugin run

# Dify 인터페이스에서 플러그인 테스트
# http://localhost:5001 접속

5. 패키징 및 배포

# 플러그인 패키징
dify plugin package

# my_first_tool.difypkg 파일 생성됨
# Dify Marketplace 또는 프라이빗 배포에 업로드

핵심 개념

Beehive 아키텍처

Dify 플러그인 시스템은 Beehive(벌집) 아키텍처를 채택하며, 핵심 특징은 다음과 같습니다:

  1. 분산 스케줄링: 각 데몬 프로세스 노드가 로컬 플러그인을 독립적으로 관리
  2. 마스터-슬레이브 선출: Redis 분산 잠금을 통한 자동 마스터 노드 선출
  3. 상태 동기화: 모든 노드 상태를 Redis에 저장하여 교차 노드 액세스 지원
  4. 자가 치유: 노드 다운 시 자동으로 플러그인 재할당

자세한 아키텍처 설명은 types/architecture.md를 참조하세요.

세 가지 런타임 모드

런타임 모드적용 시나리오통신 방식장점단점
Local Runtime로컬 개발, 소규모 배포STDIN/STDOUT낮은 지연 시간, 리소스 격리높은 메모리 사용량, 확장성 제한
Debug Runtime원격 디버깅, 개발 환경TCP 전이중개발 친화적, 유연한 배포네트워크 의존성, 상태 관리 복잡
Serverless Runtime대규모 프로덕션 환경HTTP/SSE자동 확장, 비용 최적화콜드 스타트 지연, 디버깅 복잡

자세한 비교는 development/runtime-modes.md를 참조하세요.

네 가지 플러그인 유형

1. Tool (도구 플러그인)

AI 기능을 확장하는 도구입니다. 예: 번역, 검색, 데이터 처리 등.

# 예시: Google Translate
type: plugin
plugins:
  tools:
    - provider/google_translate.yaml

사용 시나리오:

  • API 래핑 (REST API → Tool)
  • 데이터 처리 (형식 변환, 계산)
  • 외부 서비스 통합 (검색, 번역)

2. Model (모델 플러그인)

LLM 제공자(Anthropic, OpenAI, Gemini 등)에 연결합니다.

# 예시: Anthropic Claude
type: plugin
plugins:
  models:
    - provider/anthropic.yaml

사용 시나리오:

  • 새로운 LLM 제공자 연결
  • 사용자 정의 모델 구성
  • 멀티모달 모델 지원

3. Datasource (데이터 소스 플러그인)

S3, Google Drive, Notion 등 저장 시스템에 연결합니다.

# 예시: AWS S3
type: plugin
plugins:
  datasources:
    - provider/aws_s3.yaml

사용 시나리오:

  • 클라우드 스토리지 통합
  • 문서 플랫폼 연결
  • 데이터베이스 액세스

4. Extension (확장 플러그인)

Slack, 기업용 WeChat 등 타사 플랫폼 통합과 같은 플랫폼 기능 확장.

# 예시: Slack
type: plugin
plugins:
  extensions:
    - provider/slack.yaml

사용 시나리오:

  • 타사 플랫폼 통합
  • 트리거 구현
  • 사용자 정의 에이전트 전략

자세한 유형 설명은 types/를 참조하세요.


프로젝트 구조

표준 Dify 플러그인 프로젝트 구조:

my_plugin/
├── manifest.yaml           # 플러그인 매니페스트 (필수)
├── main.py                 # 진입 파일 (필수)
├── requirements.txt        # Python 의존성
├── pyproject.toml         # 프로젝트 설정
├── README.md              # 플러그인 설명
├── PRIVACY.md             # 개인정보 처리방침 (OAuth 필요 시)
├── .env.example           # 환경 변수 예시
│
├── _assets/               # 리소스 파일
│   └── icon.svg          # 플러그인 아이콘
│
├── provider/              # 제공자 설정
│   ├── provider_name.yaml # 제공자 설정 파일
│   └── provider_name.py   # 제공자 구현
│
└── tools/                 # 도구 구현 (Tool 플러그인)
    ├── tool_name.yaml    # 도구 설정 파일
    └── tool_name.py      # 도구 구현

핵심 파일 설명

manifest.yaml

플러그인의 기본 정보와 설정을 정의하는 매니페스트 파일:

author: your_name
name: my_plugin
version: 0.0.1
type: plugin

description:
  en_US: Plugin description
  zh_Hans: 플러그인 설명

label:
  en_US: My Plugin
  zh_Hans: 내 플러그인

icon: icon.svg

meta:
  version: 0.0.1
  arch:
    - amd64
    - arm64
  runner:
    language: python
    version: '3.12'
    entrypoint: main

plugins:
  tools:
    - provider/my_provider.yaml

resource:
  memory: 1048576  # 1MB = 1048576 bytes
  permission:
    tool:
      enabled: true
    model:
      enabled: true
      llm: true

tags:
  - utilities

자세한 설정 설명은 development/manifest.md를 참조하세요.

main.py

플러그인 진입 파일:

from dify_plugin import Plugin, DifyPluginEnv

# 플러그인 인스턴스 생성
plugin = Plugin(DifyPluginEnv(MAX_REQUEST_TIMEOUT=120))

if __name__ == '__main__':
    # 플러그인 시작
    plugin.run()

개발 가이드

Tool 플러그인 개발

1. Provider 생성

provider/my_provider.yaml 편집:

identity:
  author: your_name
  name: my_provider
  label:
    en_US: My Provider
    zh_Hans: 내 제공자
  description:
    en_US: Provider description
    zh_Hans: 제공자 설명
  icon: icon.svg
  tags:
    - utilities

extra:
  python:
    source: provider/my_provider.py

tools:
  - tools/my_tool.yaml

provider/my_provider.py 편집:

from typing import Any
from dify_plugin.errors.tool import ToolProviderCredentialValidationError
from dify_plugin import ToolProvider
from tools.my_tool import MyTool


class MyProvider(ToolProvider):
    def _validate_credentials(self, credentials: dict[str, Any]) -> None:
        """
        자격 증명 검증 (필요한 경우)
        """
        try:
            # API Key 또는 기타 자격 증명 검증
            api_key = credentials.get("api_key")
            if not api_key:
                raise ToolProviderCredentialValidationError("API Key is required")

            # 자격 증명 유효성 테스트
            MyTool().invoke(
                tool_parameters={"text": "test"}
            )
        except Exception as e:
            raise ToolProviderCredentialValidationError(str(e))

2. Tool 생성

tools/my_tool.yaml 편집:

identity:
  author: your_name
  name: my_tool
  label:
    en_US: My Tool
    zh_Hans: 내 도구

description:
  human:
    en_US: Tool description for humans
    zh_Hans: 인간용 도구 설명
  llm: LLM용 도구 설명

extra:
  python:
    source: tools/my_tool.py

parameters:
  - name: text
    type: string
    required: true
    label:
      en_US: Input Text
      zh_Hans: 입력 텍스트
    human_description:
      en_US: The text to process
      zh_Hans: 처리할 텍스트
    llm_description: 처리할 입력 텍스트
    form: llm

tools/my_tool.py 편집:

from typing import Any, Generator
from dify_plugin.entities.tool import ToolInvokeMessage
from dify_plugin import Tool


class MyTool(Tool):
    def _invoke(
        self, tool_parameters: dict[str, Any]
    ) -> Generator[ToolInvokeMessage, None, None]:
        """
        도구 호출 진입점

        Args:
            tool_parameters: 도구 매개변수 딕셔너리

        Yields:
            ToolInvokeMessage: 도구 호출 메시지
        """
        # 1. 매개변수 가져오기
        text = tool_parameters.get("text", "")

        if not text:
            yield self.create_text_message("Error: text parameter is required")
            return

        try:
            # 2. 처리 로직
            result = self._process_text(text)

            # 3. 결과 반환
            yield self.create_text_message(result)

        except Exception as e:
            yield self.create_text_message(f"Error: {str(e)}")

    def _process_text(self, text: str) -> str:
        """
        텍스트 처리의 구체적인 로직
        """
        return text.upper()

자세한 개발 가이드는 development/tool.md를 참조하세요.


OAuth 2.0 통합

OAuth 흐름 개요

Dify는 완전한 OAuth 2.0 인증 흐름을 지원합니다:

  1. 인증 URL 가져오기: 사용자가 인증 버튼 클릭
  2. 사용자 인증: 타사 서비스 인증 페이지로 리디렉션
  3. 인증 코드 가져오기: 사용자 인증 후 인증 코드 반환
  4. 액세스 토큰 교환: 인증 코드를 사용하여 액세스 토큰 교환
  5. 토큰 갱신: 액세스 토큰 만료 시 갱신 토큰으로 새 토큰 획득

OAuth 스키마 구성

provider/my_provider.yaml에 OAuth 구성 추가:

oauth_schema:
  client_schema:
    - name: client_id
      type: secret-input
      required: true
      label:
        en_US: Client ID
        zh_Hans: 클라이언트 ID
      placeholder:
        en_US: Enter your OAuth Client ID
        zh_Hans: OAuth 클라이언트 ID를 입력하세요
      help:
        en_US: Get your client ID from the service provider
        zh_Hans: 서비스 제공자로부터 클라이언트 ID를 받으세요
      url: https://console.example.com/credentials

    - name: client_secret
      type: secret-input
      required: true
      label:
        en_US: Client Secret
        zh_Hans: 클라이언트 시크릿
      placeholder:
        en_US: Enter your OAuth Client Secret
        zh_Hans: OAuth 클라이언트 시크릿을 입력하세요

  credentials_schema:
    - name: access_token
      type: secret-input
      label:
        en_US: Access Token
        zh_Hans: 액세스 토큰

    - name: refresh_token
      type: secret-input
      label:
        en_US: Refresh Token
        zh_Hans: 리프레시 토큰

OAuth Provider 구현

from typing import Any
from dify_plugin import ToolProvider
from dify_plugin.errors.tool import ToolProviderCredentialValidationError
import requests


class MyOAuthProvider(ToolProvider):
    def _validate_credentials(self, credentials: dict[str, Any]) -> None:
        """
        OAuth 자격 증명 검증
        """
        access_token = credentials.get("access_token")
        if not access_token:
            raise ToolProviderCredentialValidationError(
                "Access token is required"
            )

        # 액세스 토큰 유효성 테스트
        try:
            response = requests.get(
                "https://api.example.com/user",
                headers={"Authorization": f"Bearer {access_token}"}
            )
            response.raise_for_status()
        except Exception as e:
            raise ToolProviderCredentialValidationError(
                f"Invalid access token: {str(e)}"
            )

OAuth 토큰 사용

Tool에서 OAuth 토큰 사용:

class MyOAuthTool(Tool):
    def _invoke(
        self, tool_parameters: dict[str, Any]
    ) -> Generator[ToolInvokeMessage, None, None]:
        # OAuth 자격 증명 가져오기
        credentials = self.runtime.credentials
        access_token = credentials.get("access_token")

        # API 호출
        response = requests.get(
            "https://api.example.com/data",
            headers={"Authorization": f"Bearer {access_token}"}
        )

        yield self.create_text_message(response.text)

전체 OAuth 통합 가이드는 development/oauth-integration.md를 참조하세요.


테스트 및 디버깅

단위 테스트

pytest를 사용하여 단위 테스트 작성:

# tests/test_my_tool.py
import pytest
from tools.my_tool import MyTool


def test_my_tool():
    tool = MyTool()
    result = list(tool.invoke(tool_parameters={"text": "hello"}))

    assert len(result) == 1
    assert "HELLO" in result[0].message

테스트 실행:

pytest tests/

통합 테스트

Dify 시스템과의 플러그인 통합 테스트:

# tests/test_integration.py
def test_plugin_integration():
    # 플러그인 설치 테스트
    # 도구 호출 테스트
    # OAuth 흐름 테스트
    pass

Debug Runtime 디버깅

Debug Runtime을 시작하여 원격 디버깅:

# Debug Runtime 시작
dify plugin run --debug

# Dify 인터페이스에서 테스트
# 실시간 로그 및 오류 정보 확인

일반적인 문제 해결

플러그인 시작 실패

  • Python 버전 확인 (3.12+ 필요)
  • 의존성 설치 확인 (requirements.txt)
  • manifest.yaml 설정 확인
  • 진입 파일 경로 확인 (main.py)

권한 검증 실패

  • credentials 설정 확인
  • OAuth 토큰 만료 확인
  • API Key 유효성 확인
  • 권한 선언 확인 (resource.permission)

런타임 오류

  • 타임아웃 조정 (MAX_REQUEST_TIMEOUT)
  • 메모리 사용 최적화 (resource.memory)
  • 네트워크 연결 확인
  • 역호출 권한 확인

자세한 문제 해결 가이드는 testing/troubleshooting.md를 참조하세요.


API에서 플러그인으로 마이그레이션

마이그레이션 전략

  1. API 래핑 모드: REST API를 Tool 플러그인으로 래핑
  2. SDK 통합 모드: 타사 Python SDK 사용
  3. OAuth 마이그레이션: OAuth 2.0 인증 흐름 구현
  4. 배치 작업 최적화: 스트리밍 응답을 사용하여 대용량 데이터 처리

마이그레이션 단계

  1. 기존 API 분석

    • API 엔드포인트 및 매개변수
    • 인증 방식 (API Key / OAuth)
    • 응답 형식 및 오류 처리
  2. 플러그인 유형 선택

    • REST API → Tool 플러그인
    • LLM API → Model 플러그인
    • 스토리지 API → Datasource 플러그인
  3. 플러그인 프로젝트 생성

    dify plugin init
    
  4. API 호출 구현

    import requests
    
    class APIWrapperTool(Tool):
        def _invoke(self, tool_parameters: dict[str, Any]):
            response = requests.post(
                "https://api.example.com/endpoint",
                json=tool_parameters,
                headers={"Authorization": f"Bearer {api_key}"}
            )
            yield self.create_text_message(response.text)
    
  5. 인증 구성

    • API Key: provider.yaml에서 credentials 구성
    • OAuth: oauth_schema 구성
  6. 오류 처리 추가

    try:
        response = requests.post(...)
        response.raise_for_status()
    except requests.exceptions.RequestException as e:
        yield self.create_text_message(f"API Error: {str(e)}")
    
  7. 테스트 작성

    def test_api_wrapper():
        tool = APIWrapperTool()
        result = list(tool.invoke(tool_parameters={...}))
        assert result[0].message
    
  8. 패키징 및 배포

    dify plugin package
    

실제 사례

  • REST API → Tool: Google Translate (인증 없음)
  • OAuth API → Tool: Google Contacts (OAuth 2.0)
  • LLM API → Model: Anthropic Claude (API Key)
  • 스토리지 API → Datasource: AWS S3 (IAM 인증)

자세한 마이그레이션 가이드는 development/migration-guide.md를 참조하세요.


모범 사례

코드 구성

  1. 단일 책임: 각 Tool은 하나의 작업만 수행
  2. 오류 처리: 모든 예외를 포착하고 친숙한 오류 메시지 반환
  3. 매개변수 검증: _invoke 시작 시 모든 매개변수 검증
  4. 로깅: 구조화된 로깅을 사용하여 주요 작업 기록

성능 최적화

  1. 스트리밍 응답: 대용량 데이터의 경우 Generator를 사용한 스트리밍 반환
  2. 캐싱 전략: 자주 액세스하는 데이터 캐싱
  3. 비동기 처리: I/O 집약적 작업에 async/await 사용
  4. 리소스 제한: resource.memory를 적절히 구성

보안 고려 사항

  1. 입력 검증: 모든 사용자 입력 검증
  2. 민감 데이터: secret-input 유형을 사용하여 민감 정보 저장
  3. 권한 제어: 최소 권한 원칙, 필요한 권한만 선언
  4. 오류 정보: 오류 메시지에 민감 데이터 노출 금지

사용자 경험

  1. 명확한 설명: 상세한 description 및 help 제공
  2. 합리적인 기본값: 매개변수에 합리적인 기본값 제공
  3. 다국어 지원: 최소 en_US 및 zh_Hans 지원
  4. 친숙한 오류: 사용자가 이해할 수 있는 오류 메시지 반환

배포 및 운영

런타임 모드 선택

시나리오권장 모드이유
로컬 개발Local Runtime낮은 지연 시간, 쉬운 디버깅
원격 디버깅Debug Runtime유연함, 원격 지원
소규모 프로덕션Local Runtime간단함, 저비용
대규모 프로덕션Serverless Runtime자동 확장, 고가용성

Serverless 배포

AWS Lambda에 배포:

# 1. 플러그인 패키징
dify plugin package

# 2. Lambda 함수 생성
aws lambda create-function \
  --function-name my-plugin \
  --runtime python3.12 \
  --handler main.handler \
  --zip-file fileb://my_plugin.difypkg

# 3. 환경 변수 구성
aws lambda update-function-configuration \
  --function-name my-plugin \
  --environment Variables={...}

# 4. API Gateway 구성 (HTTP 엔드포인트)

로컬 Runtime 배포

# Local Runtime 시작
dify plugin run

# STDI 환경 통신
# 기본 포트: 5001

모니터링 및 알림

  • 로깅: 구조화된 JSON 로그 사용
  • 메트릭: 플러그인 성능 지표 수집
  • 알림: 오류 임계값 초과 시 알림 설정
  • 추적: 분산 추적으로 요청 추적

참고 자료

문서

관련 저장소

지원

문제가 발생하면 다음 채널을 통해 도움을 받을 수 있습니다:

Individual skills in this repo

This repo contains 5 individual skills — each has its own dedicated page.

관련 스킬