전문가 심화편 전체 목차
Dify 아키텍처 & 앱 유형 완전 이해
Dify는 단순한 챗봇 빌더가 아닙니다. LLM 오케스트레이션 + 비주얼 워크플로우 + RAG 엔진 + LLMOps + 배포 허브를 통합한 프로덕션 AI 플랫폼입니다. 2026년 3월 $30M 시리즈 Pre-A를 유치했고, Fortune 500 기업 포함 280개 이상의 기업이 프로덕션에서 사용합니다.
🏗️ Dify 플랫폼 3계층 구조
📱 4가지 앱 유형 — 언제 무엇을 써야 하는가
| 앱 유형 | 구조 | 최적 용도 | 특징 |
|---|---|---|---|
| Chatbot | 대화형 · 메모리 보존 | 고객 지원, 사내 Q&A, 상담 봇 | 대화 기록 유지. 사람과 자연스럽게 여러 턴 대화 |
| Text Generator | 단방향 생성 | 이메일 초안, 번역, 요약, SEO 콘텐츠 | 입력 → 출력. 대화 불필요한 일회성 텍스트 생성 |
| Agent | 자율 추론 + 도구 | 조사, 데이터 분석, 자율 코딩 | LLM이 상황 판단해 도구 자율 선택. ReAct/FC 전략 |
| Workflow | DAG 방식 결정론적 | 문서 처리, 다단계 파이프라인, 자동화 | 노드 간 명확한 흐름. 분기·병렬·반복 제어 가능 |
Workflow: 처리 단계가 정해져 있고 예측 가능한 결과가 필요할 때. 문서 → 요약 → 번역 → 저장 같은 파이프라인. Agent: LLM이 상황을 판단하고 도구를 자율 선택해야 할 때. “이 질문에 답하기 위해 웹을 검색하고 계산하고 판단한다”. 두 유형을 혼합한 Chatflow(대화형 Workflow + Agent Node)도 매우 강력합니다.
🔀 Dify vs n8n vs LangChain — 선택 기준
| 항목 | Dify | n8n | LangChain |
|---|---|---|---|
| 주요 용도 | AI 앱 빌더 · RAG · 에이전트 | 일반 워크플로우 자동화 | 코드 기반 LLM 앱 개발 |
| 코딩 필요 | 최소 (Code Node로 선택적) | 최소 (Function 노드) | 필수 (Python/TS) |
| RAG 기능 | 🟢 최고 수준 (내장) | 🟡 별도 구성 필요 | 🟡 직접 구현 |
| AI 에이전트 | 🟢 강력 (Agent Node) | 🟡 AI 노드 연동 | 🟢 강력 (코드) |
| LLMOps | 🟢 내장 | 🔴 없음 | 🔴 별도 도구 필요 |
| 통합 서비스 | 🟡 50+ 도구 | 🟢 500+ 서비스 | 🟢 수백 개 |
| 권장 조합 | Dify(AI 앱) + n8n(업무 자동화) 함께 쓰는 것이 최강 | ||
프로덕션 Docker 설치 & 환경 구성
🐳 Docker Compose 빠른 시작
# 1. 저장소 클론 git clone https://github.com/langgenius/dify.git cd dify/docker # 2. 환경변수 파일 복사 cp .env.example .env # 3. .env 핵심 설정 (반드시 변경!) nano .env # 4. 서비스 시작 docker compose up -d # 5. 상태 확인 docker compose ps docker compose logs -f api # 접속: http://서버IP # 초기 관리자 계정 설정 후 사용 시작
📋 .env 핵심 환경변수 완전 해설
# ── 보안 핵심 키 (반드시 변경!) ────────────────────── # SECRET_KEY: Flask 세션 서명용. openssl rand -base64 42 로 생성 SECRET_KEY=your_very_long_random_secret_key_here # 초기 관리자 이메일 & 비밀번호 (첫 실행 시만 적용) INIT_PASSWORD=your_admin_password # ── 외부 공개 URL ───────────────────────────────────── # 도메인 연결 시 반드시 실제 URL로 변경 CONSOLE_API_URL=https://dify.yourcompany.com CONSOLE_WEB_URL=https://dify.yourcompany.com SERVICE_API_URL=https://dify.yourcompany.com APP_WEB_URL=https://dify.yourcompany.com # ── 데이터베이스 (PostgreSQL) ───────────────────────── DB_USERNAME=postgres DB_PASSWORD=difyai123456 # 반드시 변경! DB_HOST=db DB_PORT=5432 DB_DATABASE=dify # ── 벡터 데이터베이스 선택 ──────────────────────────── # weaviate | qdrant | milvus | chroma | pgvector | opensearch VECTOR_STORE=qdrant # Qdrant 설정 (권장) QDRANT_URL=http://qdrant:6333 QDRANT_API_KEY=difyai123456 # 변경 권장 # ── Redis ───────────────────────────────────────────── REDIS_HOST=redis REDIS_PORT=6379 REDIS_PASSWORD=difyai123456 # 변경 권장 # ── 파일 저장소 ─────────────────────────────────────── # local | s3 | azure-blob | google-storage STORAGE_TYPE=local STORAGE_LOCAL_PATH=/app/api/storage # ── 모델 공급자 기본 설정 (선택) ────────────────────── # 워크스페이스별로 설정하는 것이 더 권장되지만 # 기본값으로 넣을 수 있음 # ANTHROPIC_API_KEY=sk-ant-xxx # OPENAI_API_KEY=sk-xxx # ── 플러그인 설정 (v1.x) ────────────────────────────── PLUGIN_DAEMON_URL=http://plugin_daemon:5003 PLUGIN_DAEMON_KEY=lYkiYYT6owG+71oLerGzA7GXCgOT++6dFUAg== # 변경! # ── 이메일 (비밀번호 재설정 등) ────────────────────── MAIL_TYPE=smtp SMTP_SERVER=smtp.gmail.com SMTP_PORT=587 [email protected] SMTP_PASSWORD=your_app_password [email protected]
📦 Dify Docker Compose 서비스 구조 해설
| 서비스명 | 역할 | 포트 | 데이터 저장 |
|---|---|---|---|
api | Dify 백엔드 API 서버 (Python/Flask) | 5001 | 스토리지 볼륨 |
web | Dify 프론트엔드 (Next.js) | 3000 | 없음 (정적) |
worker | Celery 비동기 태스크 (임베딩 등) | 없음 | Redis 큐 |
db | PostgreSQL 데이터베이스 | 5432 | db 볼륨 |
redis | 캐시 & 태스크 큐 | 6379 | redis 볼륨 |
qdrant (또는 다른 VDB) | 벡터 데이터베이스 (RAG) | 6333 | qdrant 볼륨 |
nginx | 내부 역방향 프록시 | 80/443 | 없음 |
plugin_daemon | 플러그인 실행 데몬 (v1.x) | 5003 | 플러그인 볼륨 |
sandbox | Python/JS 코드 노드 격리 실행 | 8194 | 없음 |
🌐 Nginx 역방향 프록시 설정 (외부 도메인 공개)
server {
listen 80;
server_name dify.yourcompany.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
server_name dify.yourcompany.com;
ssl_certificate /etc/letsencrypt/live/dify.yourcompany.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/dify.yourcompany.com/privkey.pem;
# 파일 업로드 크기 (대용량 문서 처리)
client_max_body_size 100M;
location / {
proxy_pass http://localhost:80; # Dify 내부 Nginx
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto https;
# SSE(Server-Sent Events) 스트리밍 — 필수!
proxy_buffering off;
proxy_cache off;
proxy_read_timeout 3600s; # 긴 워크플로우 처리 시간
}
}워크플로우 노드 완전 정복 — 모든 노드 유형 해설
Dify 워크플로우는 노드(Node)를 캔버스에 연결하는 DAG(방향 비순환 그래프) 구조입니다. 각 노드는 특정 역할을 수행하고 결과를 다음 노드에 전달합니다. 노드를 이해하는 것이 고급 워크플로우 설계의 핵심입니다.
🧠 핵심 노드 완전 해설
| 노드 | 역할 | 주요 설정 | 활용 패턴 |
|---|---|---|---|
| Start | 워크플로우 진입점. 입력 변수 정의 | input 변수 스키마 정의 | 모든 워크플로우의 시작 |
| End | 워크플로우 종료. 출력 변수 정의 | output 변수 선택 | 최종 결과 반환 |
| LLM | LLM 호출. 프롬프트 + 모델 선택 | 시스템 프롬프트 · 사용자 프롬프트 · 모델 · 파라미터 | 텍스트 생성, 분석, 분류 |
| Knowledge Retrieval | Knowledge Base에서 관련 청크 검색 | KB 선택 · Top K · Threshold · 검색 모드 | RAG 파이프라인 핵심 |
| If/Else | 조건 분기. 변수 값에 따라 경로 분기 | 조건식 (contains, =, >, < 등) | 분류 후 라우팅, 오류 처리 |
| Code | Python 또는 JavaScript 실행 (샌드박스) | 코드 입력 · 입출력 변수 | 데이터 변환, 계산, 파싱 |
| HTTP Request | 외부 API 호출 (GET/POST/PUT/DELETE) | URL · 헤더 · 바디 · 인증 | 외부 서비스 연동, 데이터 조회 |
| Template Transform | Jinja2 템플릿으로 텍스트 조합 | Jinja2 템플릿 문자열 | 여러 변수를 하나의 프롬프트로 조합 |
| Variable Aggregator | 여러 분기의 결과를 하나로 통합 | 통합할 변수 선택 | 병렬 처리 후 결과 합치기 |
| Iteration | 배열 데이터를 반복 처리 | 입력 배열 · 내부 노드 구성 | 여러 문서 처리, 배치 작업 |
| Agent | LLM이 자율적으로 도구를 선택·실행 | 에이전트 전략 · 도구 목록 · 최대 반복 | 자율 조사, 복잡한 멀티스텝 |
| Tool | 특정 도구를 명시적으로 호출 | 도구 선택 · 파라미터 매핑 | 웹 검색, 이미지 생성, API 호출 |
| Parameter Extractor | LLM을 이용해 텍스트에서 구조화 데이터 추출 | 추출할 필드 스키마 정의 | 사용자 입력 파싱, NLU |
| Document Extractor | 업로드된 파일에서 텍스트 추출 | 파일 변수 선택 | PDF/DOCX 처리 파이프라인 |
| List Filter | 배열 데이터 필터링, 정렬, 슬라이싱 | 필터 조건 · 정렬 기준 | 검색 결과 정제 |
🔢 변수 시스템 완전 이해
Dify 워크플로우에서 노드 간 데이터는 변수(Variable)로 전달됩니다. 변수 참조는 이중 중괄호로 작성합니다.
# 기본 변수 참조 문법
{{노드ID.변수명}}
# 예시 — 이전 노드의 출력 참조
{{start.user_input}} # Start 노드의 user_input 변수
{{llm_1.text}} # LLM 노드 1의 텍스트 출력
{{knowledge_1.result}} # Knowledge Retrieval의 결과
{{http_1.body}} # HTTP 요청의 응답 본문
{{code_1.output.summary}} # Code 노드의 출력 내 summary 필드
# 시스템 변수 (내장)
{{sys.query}} # 사용자 질문 (Chatbot/Chatflow)
{{sys.user_id}} # 현재 사용자 ID
{{sys.app_id}} # 앱 ID
{{sys.conversation_id}} # 대화 ID (Chatbot)
# Jinja2 템플릿에서 변수 사용
# Template Transform 노드에서:
사용자 {{sys.user_id}}님의 질문: {{start.query}}
관련 문서:
{% for item in knowledge_1.result %}
- {{item.content}} (점수: {{item.score}})
{% endfor %}
위 문서를 참고해 답변하세요.🔀 고급 워크플로우 패턴
🐍 Code 노드 심화 — Python & JavaScript
# ── 예시 1: JSON 파싱 & 구조화 ──────────────────────
def main(raw_text: str) -> dict:
"""
LLM이 생성한 JSON 텍스트를 안전하게 파싱합니다.
입력: raw_text (이전 LLM 노드의 text 출력)
"""
import json
import re
# JSON 블록 추출 (마크다운 코드블록 내 JSON 처리)
json_match = re.search(r'```json\s*([\s\S]*?)\s*```', raw_text)
if json_match:
raw_text = json_match.group(1)
try:
parsed = json.loads(raw_text.strip())
return {
"success": True,
"data": parsed,
"error": ""
}
except json.JSONDecodeError as e:
return {
"success": False,
"data": {},
"error": str(e)
}
# ── 예시 2: Knowledge 검색 결과 재정렬 & 포맷팅 ────
def main(knowledge_results: list, query: str) -> dict:
"""
Knowledge Retrieval 결과를 점수순 정렬 후 포맷팅합니다.
"""
# 점수 기준 정렬 (높은 것 우선)
sorted_results = sorted(
knowledge_results,
key=lambda x: x.get('score', 0),
reverse=True
)
# 마크다운 형식으로 포맷팅
formatted = "## 관련 문서\n\n"
for i, item in enumerate(sorted_results[:5], 1): # 상위 5개만
score = item.get('score', 0)
content = item.get('content', '').strip()
source = item.get('metadata', {}).get('source', '알 수 없음')
formatted += f"**[{i}] {source}** (관련도: {score:.2%})\n{content}\n\n"
return {
"formatted_context": formatted,
"count": len(sorted_results)
}
# ── 예시 3: 배열 생성 (Iteration 노드 공급용) ────────
def main(file_urls: str) -> dict:
"""
줄바꿈으로 구분된 URL 목록을 배열로 변환합니다.
Iteration 노드에 공급하는 배열 생성.
"""
urls = [url.strip() for url in file_urls.split('\n') if url.strip()]
return {
"url_list": urls,
"total": len(urls)
}RAG 파이프라인 심화 — Knowledge Base 완전 최적화
Dify의 RAG 엔진은 문서 인덱싱부터 검색·리랭킹까지 완전히 내장되어 있습니다. LangChain이나 LlamaIndex 없이도 프로덕션 수준의 RAG를 구현할 수 있습니다.
📊 인덱싱 전략 3가지 완전 비교
| 인덱싱 방식 | 특징 | 토큰 비용 | 검색 품질 | 권장 상황 |
|---|---|---|---|---|
| 고품질 모드 | LLM이 각 청크를 분석해 Q&A 쌍 생성. 의미 기반 임베딩 | 높음 $$ | 🟢 최고 | 중요 문서, 정확도 최우선 |
| 경제 모드 | 임베딩 모델만 사용. LLM 호출 없음 | 낮음 $ | 🟡 중간 | 대량 문서, 비용 절감 |
| 부모-자식 청킹 | 큰 청크(부모)와 작은 청크(자식)를 동시 저장. 정밀 검색 + 맥락 보존 | 중간 $$ | 🟢 높음 | 긴 법률/기술 문서 |
✂️ 청킹 전략 심화 설정
# ── 기술 문서 / API 매뉴얼 ─────────────────────────── 청크 크기: 300~500 토큰 (짧고 정확한 기술 내용) 청크 오버랩: 50 토큰 (최소한의 중복) 구분자: \n\n (단락 기준) 권장 임베딩: text-embedding-3-small (빠름) # ── 법률 / 계약 문서 ────────────────────────────────── 청크 크기: 1000~1500 토큰 (조항 단위로 충분한 맥락) 청크 오버랩: 150 토큰 구분자: 제N조, 제N항, \n\n 권장 임베딩: BAAI/bge-m3 (한국어 법률 문서) # ── 사내 FAQ / Q&A 문서 ─────────────────────────────── 청크 크기: 200~400 토큰 (질문-답변 쌍이 하나의 청크) 청크 오버랩: 30 토큰 구분자: Q:, 질문:, ## 권장 임베딩: BAAI/bge-m3 # ── 제품 카탈로그 / 스펙 문서 ──────────────────────── 청크 크기: 400~800 토큰 청크 오버랩: 80 토큰 전처리: 표를 마크다운으로 변환 후 인덱싱 권장 # ── 공통 권장 설정 ──────────────────────────────────── • 하이브리드 검색 ON (BM25 + 벡터 결합) • 리랭킹 모델: BAAI/bge-reranker-v2-m3 • Top K: 5~8 (많을수록 맥락↑ 비용↑) • Score Threshold: 0.3~0.5 • Summary Index: ON (긴 문서에서 관련 청크 발견 향상)
🔍 하이브리드 검색 & 리랭킹 완전 설정
| 검색 방식 | 원리 | 강점 | 약점 |
|---|---|---|---|
| Vector Only | 임베딩 유사도 | 의미 이해. “빠른 차”→”스포츠카” 검색 | 정확한 키워드 매칭 약함 |
| Full-text (BM25) | TF-IDF 키워드 | 정확한 용어 매칭. 코드·고유명사 | 의미 이해 없음 |
| Hybrid (권장) | Vector + BM25 결합 | 의미 + 키워드 모두. 최고 재현율 | 약간 느림 |
| Reranking (추가) | 크로스 인코더로 재정렬 | 최종 정밀도 20~40% 향상 | 처리 시간 증가 |
🏷️ Metadata 필터 — 접근 제어 & 정밀 검색
Dify v1.1.0부터 Metadata를 청크에 붙여 검색 시 필터링이 가능합니다. 부서별 문서 접근 제어, 날짜 기반 필터, 문서 유형 분류 등에 활용합니다.
// 문서 업로드 시 Metadata 추가 (API로 설정 가능)
{
"document": "연봉 협상 가이드.pdf",
"metadata": {
"department": "HR", // 부서 필터
"access_level": "manager", // 접근 레벨
"doc_type": "policy", // 문서 유형
"valid_until": "2027-01-01", // 유효 기간
"language": "ko" // 언어
}
}
// Knowledge Retrieval 노드에서 Metadata 필터 적용
// 사용자가 "HR팀 소속, manager 역할"인 경우만 이 문서 검색
{
"filters": [
{
"key": "department",
"operator": "in",
"value": ["HR", "ALL"]
},
{
"key": "access_level",
"operator": "=",
"value": "{{start.user_role}}" // 사용자 역할 변수 활용
}
]
}
// 워크플로우에서 동적 필터 적용 예:
// Start 노드에서 user_department 변수 받기
// Knowledge Retrieval 노드에서 department = {{start.user_department}}
// 부서 전용 문서만 검색 → 데이터 격리 구현📋 Summary Index — 긴 문서 검색 정확도 향상
Summary Index는 각 청크에 AI가 생성한 요약을 함께 저장합니다. 검색 시 요약과 원문 모두 매칭해 긴 문서에서 관련 청크를 놓치는 문제를 해결합니다. 2025년 Summer 업데이트에서 추가된 기능입니다.
# Knowledge → 문서 업로드 또는 편집 → Indexing Settings # Summary Index 활성화 시: # 1. 각 청크 내용을 LLM이 1~2문장으로 요약 (인덱싱 시 실행) # 2. 검색 시: 요약 텍스트 + 원본 텍스트 동시 매칭 # 3. 관련 청크가 반환될 때: 요약 + 원본 함께 전달 # 효과: # - 긴 문서(100페이지 PDF)에서 관련 내용 발견율 30~50% 향상 # - 요약이 헤더나 제목 역할을 하여 청크 컨텍스트 보강 # 비용: 인덱싱 시 LLM 호출 추가 발생 (토큰 비용 증가)
Agent Node & 에이전트 전략 완전 구현
Agent Node는 “워크플로우 안의 두뇌”입니다. 고정된 흐름 대신 LLM이 상황을 판단해 도구를 자율 선택하고 실행합니다. 에이전트 전략(Agent Strategy)은 그 판단 방식을 정의하는 플러그인 모듈입니다.
🧠 에이전트 전략 비교
| 전략 | 원리 | 강점 | 권장 모델 |
|---|---|---|---|
| Function Calling | LLM이 사전 정의된 함수 형식으로 도구 호출 | 구조적. 예측 가능. 빠름 | GPT-4o, Claude, Gemini |
| ReAct | Thought → Action → Observation 반복 루프 | 복잡한 다단계 추론. 설명 가능 | GPT-4o, Claude Sonnet |
| CoT (Chain-of-Thought) | 단계별 사고 과정 명시. 도구 호출 전 계획 | 정확도↑ 투명성↑ | o1, Claude Thinking |
| Custom Strategy | YAML+Python으로 직접 전략 정의 | 완전 커스터마이징. ToT, GoT 구현 | 모델 무관 |
# 커스텀 에이전트 전략 플러그인 구조
# function_calling.yaml
parameters:
- name: model
type: model-selector
scope: tool-call&llm
label: "추론 모델"
- name: tools
type: array[tools]
label: "사용 가능한 도구"
- name: max_iterations
type: number
default: 5
label: "최대 반복 횟수"
description: "에이전트가 도구를 최대 몇 번 호출할 수 있는지"
- name: reasoning_mode
type: select
options:
- value: "standard"
label: "표준"
- value: "step_by_step"
label: "단계별 (높은 정확도)"
default: "standard"
extra:
python:
source: function_calling.py # 실제 실행 로직# Agent Node 설정 예시 (Dify UI에서 설정하는 내용)
# 에이전트 전략: Function Calling
# 사용 가능한 도구:
# - web_search (Brave Search API)
# - calculator
# - knowledge_search (사내 KB)
# - code_interpreter
# 지시문 (Instruction):
"""
당신은 시장 조사 전문가입니다.
사용자가 요청한 주제에 대해 다음 단계로 조사하세요:
1. 웹 검색으로 최신 동향 파악
2. 사내 Knowledge Base에서 관련 선행 조사 확인
3. 수치 데이터가 있으면 계산기로 분석
4. 한국어로 체계적인 조사 보고서 작성
조사 결과에는 반드시:
- 핵심 통계 (출처 포함)
- 주요 플레이어 분석
- 리스크 & 기회 요인
를 포함하세요.
"""
# 쿼리 (Query):
# {{start.research_topic}} 시장에 대한 조사를 수행해줘
# 최대 반복: 10회
# 출력: 완성된 조사 보고서 텍스트🤝 멀티에이전트 워크플로우 — 역할 분담 설계
# 패턴 1: 순차 파이프라인 (Orchestrator → Worker → Reviewer)
Start → [조사 에이전트] → [작성 에이전트] → [검토 에이전트] → End
웹검색, KB조회 초안 작성 품질 검토, 개선
# 패턴 2: 병렬 전문가 (동시 실행)
Start → ┬→ [마케팅 에이전트] → ┐
├→ [기술 에이전트] → Variable Aggregator → [통합 에이전트] → End
└→ [재무 에이전트] → ┘
각자 전문 분야 결과 통합 최종 합성
# 패턴 3: 동적 라우팅 (의도 파악 후 전문가 선택)
Start → [Parameter Extractor: 의도 분류]
→ If: 기술 질문 → [기술 에이전트 (GPT-4o)]
→ If: 법률 질문 → [법률 에이전트 + 법률 KB]
→ If: 일반 질문 → [일반 에이전트 (Groq - 빠름)]
→ Variable Aggregator → End
# Dify에서 에이전트 간 데이터 전달:
# - 이전 Agent Node의 output을 다음 노드의 {{agent_1.output}}으로 참조
# - Template Transform으로 컨텍스트 조합 후 다음 에이전트에 전달MCP 양방향 연동 — Dify를 MCP 허브로
Dify v1.6.0부터 MCP(Model Context Protocol)가 양방향으로 내장됩니다. Dify → MCP 서버 호출(MCP 클라이언트)과 Dify 워크플로우 → MCP 서버로 노출(MCP 서버) 모두 가능합니다.
📥 MCP 클라이언트 — 외부 MCP 서버를 도구로 사용
# Dify UI → Tools → MCP → Add Server # 1. Linear (프로젝트 관리) URL: https://mcp.linear.app/sse 인증: API Key (Linear Settings → API → Create Key) → 이슈 생성·수정·조회, 프로젝트 관리 22개 도구 추가 # 2. Notion URL: https://mcp.notion.com/sse 인증: OAuth (Notion 연결) → 페이지 읽기·쓰기, 데이터베이스 쿼리 # 3. GitHub URL: https://api.githubcopilot.com/mcp/ 인증: Bearer Token (GitHub PAT) → 이슈, PR, 코드 검색, 저장소 관리 # 4. Zapier MCP (8,000개 앱 연결!) URL: https://mcp.zapier.com/api/mcp/mcp 인증: Zapier API Key → 단일 연결로 8,000개 서비스 도구 사용 # 5. Composio MCP (250개+ 앱) URL: https://mcp.composio.dev/api/mcp 인증: Composio API Key → Salesforce, HubSpot, Jira 등 기업 도구 # 6. 홈랩 Ollama (로컬 모델을 도구로) URL: http://192.168.1.253:11434/mcp (MCP 지원 버전) 인증: 없음 → 로컬 LLM을 특정 태스크 전용 도구로 활용
📤 Dify → MCP 서버 노출 — 워크플로우를 API로 공개
Dify 플러그인 마켓플레이스의 mcp-server 플러그인을 사용하면 만든 워크플로우를 MCP 서버로 노출할 수 있습니다. Claude Desktop, Cursor, Open WebUI 등 어떤 MCP 클라이언트에서도 Dify 워크플로우를 도구로 사용합니다.
# ── 방법 1: 네이티브 mcp-server 플러그인 (권장) ──────
# 1. Dify Marketplace에서 'mcp-server' 플러그인 설치
# (hjlarry 작성 / Marketplace에서 1-click 설치)
# 2. 노출할 앱 설정
# Plugins → mcp-server → Configure:
{
"apps": [
{
"app_id": "your-app-id",
"app_name": "사내 문서 검색",
"description": "사내 Knowledge Base를 검색하는 도구",
"input_schema": {
"query": "검색할 질문"
}
}
],
"auth_token": "your_bearer_token" // 선택적 인증
}
# 3. MCP 엔드포인트 확인
# http://dify.yourcompany.com/api/mcp (Streamable HTTP)
# ── Claude Desktop에서 사용 ─────────────────────────
# ~/Library/Application Support/Claude/claude_desktop_config.json
{
"mcpServers": {
"dify-company": {
"url": "https://dify.yourcompany.com/api/mcp",
"headers": {
"Authorization": "Bearer your_bearer_token"
}
}
}
}
# ── Cursor에서 사용 ──────────────────────────────────
# .cursor/mcp.json
{
"mcpServers": {
"dify-tools": {
"url": "https://dify.yourcompany.com/api/mcp"
}
}
}
# 결과: Claude나 Cursor에서 바로 Dify 워크플로우를 도구로 호출!
# "사내 문서에서 보안 정책 찾아줘" → Dify RAG 워크플로우 실행 → 결과 반환플러그인 에코시스템 & 커스텀 Tool 개발
Dify v1.0.0부터 플러그인 아키텍처가 도입됐습니다. 모든 도구·모델 공급자가 플러그인으로 관리되며, Marketplace에서 설치하거나 직접 개발할 수 있습니다.
🛒 Dify Marketplace — 주요 플러그인 카탈로그
| 카테고리 | 플러그인 | 기능 |
|---|---|---|
| 웹 검색 | Brave Search, Google, Tavily | 실시간 웹 검색 결과 |
| 생산성 | Notion, Google Docs, Confluence | 문서 읽기·쓰기 |
| 개발 | GitHub, GitLab, Jira, Linear | 이슈·PR·코드 관리 |
| 커뮤니케이션 | Slack, MS Teams, Discord | 메시지 전송·읽기 |
| 이미지 | DALL-E, Stable Diffusion, Comfy | 이미지 생성 |
| 데이터 | MySQL, PostgreSQL, MongoDB | DB 조회·업데이트 |
| AI 에이전트 | mcp-server, Claude Max Proxy | MCP 연동·모델 확장 |
| 분석 | Wolfram Alpha, Python Sandbox | 수학 계산·코드 실행 |
🦙 Ollama 로컬 모델 완전 연동
# ── 방법 1: Dify 내장 Ollama 지원 ──────────────────── # Settings → Model Provider → Ollama URL: http://host.docker.internal:11434 # Docker 내부에서 호스트 접근 # 또는 홈랩 서버: URL: http://192.168.1.253:11434 # 모델 목록이 자동으로 불러와집니다 # qwen2.5:14b, llama3.3:70b, gemma3:12b 등 선택 사용 # ── 용도별 모델 전략 ────────────────────────────────── # 비용 최적화를 위한 모델 라우팅: 고품질 추론 (복잡한 분석): Claude claude-sonnet-4-5 또는 GPT-4o 빠른 분류/추출: Groq/llama-4-scout-17b (초고속) 대용량 문서 처리: Gemini 2.0 Flash (1M 컨텍스트) 로컬 프라이버시 요청: Ollama/qwen2.5:14b (API 비용 0) 임베딩: BAAI/bge-m3 via Ollama (무료) 리랭킹: BAAI/bge-reranker-v2-m3 via Ollama # ── Ollama 임베딩 모델 설정 ─────────────────────────── # Settings → Model Provider → Ollama → Embedding Models # nomic-embed-text: 경량 (768차원) # BAAI/bge-m3: 한국어 강력 (1024차원) ← 권장
🔧 커스텀 Tool 플러그인 개발
# tools/crm_search.yaml
identity:
name: crm_search
author: your-company
label: 사내 CRM 고객 검색
description:
human: 사내 CRM에서 고객 정보를 검색합니다
llm: Search customer information from internal CRM system
parameters:
- name: customer_name
type: string
required: true
label: 고객명
human_description: 검색할 고객의 이름 또는 회사명
llm_description: Customer name or company name to search
- name: search_type
type: select
required: false
default: "all"
options:
- value: "name"
label: 이름 검색
- value: "phone"
label: 전화번호 검색
- value: "all"
label: 전체 검색
---
# tools/crm_search.py
import requests
from dify_plugin import Tool
from dify_plugin.entities.tool import ToolInvokeMessage
class CRMSearchTool(Tool):
def _invoke(self, parameters: dict) -> ToolInvokeMessage:
customer_name = parameters.get("customer_name", "")
search_type = parameters.get("search_type", "all")
# 사내 CRM API 호출
api_url = self.runtime.credentials.get("crm_api_url")
api_key = self.runtime.credentials.get("crm_api_key")
response = requests.get(
f"{api_url}/api/customers/search",
params={"q": customer_name, "type": search_type},
headers={"Authorization": f"Bearer {api_key}"},
timeout=10
)
if not response.ok:
return self.create_text_message(f"CRM 검색 오류: {response.status_code}")
customers = response.json().get("customers", [])
if not customers:
return self.create_text_message(f"'{customer_name}'에 해당하는 고객을 찾을 수 없습니다.")
# 결과 포맷팅
result = f"🔍 **CRM 검색 결과: {len(customers)}건**\n\n"
for c in customers[:5]:
result += f"**{c['name']}** ({c['company']})\n"
result += f" 📞 {c['phone']} | 📧 {c['email']}\n"
result += f" 마지막 연락: {c['last_contact']}\n\n"
return self.create_text_message(result)API 배포 & 외부 시스템 통합 — n8n · Webhook
🚀 Dify 앱을 API로 배포하기
import requests
DIFY_BASE_URL = “https://dify.yourcompany.com/v1”
API_KEY = “app-xxxxxxxxxxxxxxxxxxxx” # 앱 → API Access → API Key
# ── Chatbot (대화형) ────────────────────────────────
response = requests.post(
f”{DIFY_BASE_URL}/chat-messages”,
headers={“Authorization”: f”Bearer {API_KEY}”},
json={
“query”: “안녕하세요! 반품 정책이 어떻게 되나요?”,
“conversation_id”: “”, # 새 대화: “” / 이어서: “conv-xxx”
“user”: “user-001”, # 사용자 식별자
“response_mode”: “streaming”, # streaming | blocking
“inputs”: { # 앱 정의 입력 변수
“user_type”: “premium”
}
},
stream=True
)
# 스트리밍 응답 처리
for line in response.iter_lines():
if line:
decoded = line.decode(‘utf-8’)
if decoded.startswith(“data: “):
import json
data = json.loads(decoded[6:])
if data.get(“event”) == “message”:
print(data.get(“answer”, “”), end=””, flush=True)
# ── Workflow 실행 ────────────────────────────────────
response = requests.post(
f”{DIFY_BASE_URL}/workflows/run”,
headers={“Authorization”: f”Bearer {API_KEY}”},
json={
“inputs”: {
“document_url”: “https://example.com/report.pdf”,
“output_language”: “ko”,
“summary_length”: “short”
},
“response_mode”: “blocking”, # 완료까지 대기
“user”: “user-001”
}
)
result = response.json()
print(result[“data”][“outputs”][“summary”]) # 워크플로우 출력
# ── File Upload → 워크플로우 실행 ───────────────────
# 1단계: 파일 업로드
with open(“report.pdf”, “rb”) as f:
upload = requests.post(
f”{DIFY_BASE_URL}/files/upload”,
headers={“Authorization”: f”Bearer {API_KEY}”},
files={“file”: (“report.pdf”, f, “application/pdf”)},
data={“user”: “user-001”}
)
file_id = upload.json()[“id”]
# 2단계: 파일 ID로 워크플로우 실행
response = requests.post(
f”{DIFY_BASE_URL}/workflows/run”,
headers={“Authorization”: f”Bearer {API_KEY}”},
json={
“inputs”: {
“document”: {
“transfer_method”: “local_file”,
“upload_file_id”: file_id,
“type”: “document”
}
},
“response_mode”: “blocking”,
“user”: “user-001”
}
)⚡ n8n ↔ Dify 완전 양방향 연동
# ══ 시나리오 1: n8n → Dify (n8n이 Dify 워크플로우 실행) ══
# n8n HTTP Request 노드 설정:
# URL: https://dify.yourcompany.com/v1/workflows/run
# Method: POST
# Headers: Authorization: Bearer app-xxxxx
# Body (JSON):
{
"inputs": {
"email_content": "{{ $json.email.body }}",
"sender": "{{ $json.email.from }}"
},
"response_mode": "blocking",
"user": "n8n-worker"
}
# 응답에서 {{ $json.data.outputs.summary }} 로 결과 사용
# ══ 시나리오 2: Dify → n8n (Dify 워크플로우에서 n8n 웹훅 호출) ══
# Dify Workflow의 HTTP Request 노드:
# URL: http://n8n:5678/webhook/dify-complete
# Method: POST
# Body:
{
"result": "{{llm_1.text}}",
"workflow_id": "{{sys.workflow_run_id}}"
}
# ══ 시나리오 3: 양방향 파이프라인 ═══════════════════
# 1. Gmail에 새 이메일 도착 (n8n Gmail Trigger)
# 2. n8n → Dify: 이메일 분류 워크플로우 실행
# → 결과: {"type": "complaint", "priority": "high", "summary": "..."}
# 3. n8n: 분류 결과에 따라 라우팅
# → complaint + high: Slack #긴급 채널 알림
# → general: Dify 자동 답변 워크플로우 실행
# → spam: Gmail 스팸 처리
# 4. Dify 자동 답변: 사내 KB 검색 → 맞춤 답변 초안 생성
# 5. n8n: 답변 초안을 Google Docs에 저장 + 담당자에게 검토 요청🌐 Embed 위젯 — 웹사이트에 챗봇 삽입
<!-- Dify 앱 → Embed → 코드 복사 -->
<script>
window.difyChatbotConfig = {
token: 'your-app-token',
baseUrl: 'https://dify.yourcompany.com',
systemVariables: {
user_id: getCurrentUserId(), // 로그인 사용자 ID
user_name: getCurrentUserName() // 사용자 이름
}
}
</script>
<script
src="https://dify.yourcompany.com/embed.min.js"
id="your-app-token"
defer>
</script>
<!-- 커스터마이징 옵션 -->
<style>
#dify-chatbot-bubble-button {
background-color: #1a56db !important; /* 버튼 색상 */
}
</style>LLMOps — 관측 가능성 · 평가 · 최적화
📊 내장 LLMOps 대시보드
| 기능 | 위치 | 활용 방법 |
|---|---|---|
| Logs & Monitor | 앱 → Logs | 모든 대화·워크플로우 실행 기록. 사용자 쿼리·응답·토큰·지연시간 확인 |
| Conversation Variables | Logs → 대화 클릭 | 각 노드의 입출력, 사용 토큰, 실행 시간 상세 추적 |
| Annotations | 앱 → Annotations | AI 응답에 올바른 답변을 직접 주석으로 달기 → Few-shot 예시로 활용 |
| Overview | 앱 → Overview | 일별 메시지 수, 활성 사용자, 평균 세션 길이, 오류율 통계 |
| Token Usage | Settings → Billing | 모델별·앱별 토큰 소비량 및 비용 추정 |
🔬 Langfuse 통합 — 고급 관측 가능성
# Langfuse 자체 호스팅 또는 클라우드 # Settings → Monitoring → Langfuse 연결 # Langfuse 클라우드 (cloud.langfuse.com) LANGFUSE_PUBLIC_KEY=pk-lf-xxxxx LANGFUSE_SECRET_KEY=sk-lf-xxxxx LANGFUSE_HOST=https://cloud.langfuse.com # Langfuse 자체 호스팅 (Docker) LANGFUSE_HOST=http://langfuse:3000 # 연동 후 Langfuse 대시보드에서: # - 모든 LLM 호출의 완전한 트레이스 # - 프롬프트 버전 관리 # - 모델 비용 분석 # - 품질 평가 데이터셋 구축 # - A/B 테스트 결과 비교
📝 Annotations — AI 응답 품질 개선
# Annotations 동작 방식: # 1. AI가 잘못된 답변을 한 경우 Logs에서 해당 대화 열기 # 2. 올바른 답변을 직접 입력 (주석 추가) # 3. 이후 동일/유사한 질문이 오면: # a) 유사도 기반으로 Annotation 매칭 # b) AI 대신 Annotation 답변을 직접 반환 (빠르고 정확) # c) 또는 Annotation을 Few-shot 예시로 프롬프트에 주입 # 설정: # 앱 → Annotations → Score Threshold: 0.8 (유사도 80% 이상 매칭) # 앱 → Annotations → Embedding Model: BAAI/bge-m3 (한국어) # Annotation 활용 전략: # - 반복적으로 틀리는 질문 유형부터 주석 달기 # - 회사 고유 용어·정책은 반드시 주석으로 정확한 답변 등록 # - 100~200개 Annotation으로 응답 품질 크게 향상 가능
실전 완전 구현 레시피 12선
🏢 레시피 1 — 사내 멀티 소스 RAG 검색 시스템
# 워크플로우: 사내 멀티 소스 RAG
Start (query: 사용자 질문, user_dept: 부서)
│
├─→ [Parameter Extractor] — 의도·카테고리 분류
│ 출력: category (HR/기술/재무/일반)
│
├─→ If category = HR
│ └─→ [Knowledge Retrieval: HR Policy KB]
│ Metadata Filter: department = "HR"
│
├─→ If category = 기술
│ └─→ [Knowledge Retrieval: Technical Docs KB]
│
├─→ If category = 재무
│ └─→ [Knowledge Retrieval: Finance KB]
│ Metadata Filter: access_level = manager (부서장만)
│
└─→ Default: 전체 KB 검색
│
[Variable Aggregator] — 검색 결과 통합
│
[Template Transform] — 컨텍스트 조합
│ 시스템: 아래 문서를 참고하여 {{query}}에 답변하세요
│ 컨텍스트: {{aggregator.result}}
│
[LLM Node: Claude Sonnet] — 최종 답변 생성
│ temperature: 0.1 (일관성)
│
End — answer 반환📄 레시피 2 — 대용량 PDF 자동 분석 파이프라인
Start
input: document (file), analysis_type (요약/위험분석/경쟁사분석)
│
[Document Extractor] — PDF 텍스트 추출
│
[Code Node: 텍스트 청크 분할]
# 매우 긴 문서를 4000토큰 단위로 분할
def main(full_text: str) -> dict:
chunks = []
words = full_text.split()
for i in range(0, len(words), 3000):
chunks.append(' '.join(words[i:i+3000]))
return {"chunks": chunks}
│
[Iteration 노드] — 청크별 병렬 처리
│ └─→ [LLM: 청크 요약] — 각 청크의 핵심 포인트 3개
│
[Variable Aggregator] — 모든 청크 요약 통합
│
[LLM: Gemini 2.0 Flash] — 전체 문서 종합 분석
│ (긴 컨텍스트 모델 활용. 1M 토큰 지원)
│ 프롬프트: analysis_type에 따른 분기 지시
│
[LLM: 리포트 포맷팅] — 마크다운 리포트 생성
│
End — report 반환🤖 레시피 3 — 자율 경쟁사 모니터링 에이전트
Start (Chatbot 형태)
│
[Agent Node — 경쟁사 조사 전문가]
에이전트 전략: ReAct (다단계 추론)
최대 반복: 15회
사용 도구:
– web_search (Brave API)
– http_request (회사 내부 API)
– knowledge_search (기존 경쟁사 리포트 KB)
– calculator (수치 계산)
지시문:
“””
당신은 경쟁사 분석 전문가입니다.
사용자가 지정한 경쟁사에 대해:
1. 최근 30일 뉴스·공식 발표 검색
2. 주요 제품 변화·가격 정책 조사
3. 기존 KB의 이전 분석과 비교
4. 변화가 우리 회사에 미치는 영향 분석
각 단계마다 출처를 명시하고
수치 비교 시 계산기 도구 활용.
“””
│
[HTTP Request: Slack 전송]
분석 완료 시 #경쟁사-모니터링 채널에 자동 전송
│
End📞 레시피 4 — AI 고객 지원 봇 (에스컬레이션 포함)
Start (Chatflow — 대화형)
사용자 입력 → sys.query
│
[Parameter Extractor] — 의도 분류
출력:
- intent: 배송조회 | 환불 | 기술문제 | 불만 | 기타
- sentiment: positive | neutral | negative | angry
- urgency: low | medium | high
│
[If/Else: sentiment = angry 또는 urgency = high]
│
├─→ True: [HTTP Request → CRM 에스컬레이션]
│ 담당자 배정 + Slack 긴급 알림
│ [LLM: 공감 메시지] → 사람이 곧 연락할 것임을 안내
│
└─→ False: [If intent = 배송조회]
└─→ [HTTP Request: 물류 API 조회]
주문번호로 배송 상태 조회
[LLM: 배송 현황 안내]
[If intent = 환불]
└─→ [Knowledge: 환불 정책 KB]
[LLM: 정책 기반 안내]
[Default]
└─→ [Knowledge: 전체 FAQ KB]
[LLM: 답변 생성]
│
[If/Else: 해결 여부 확인]
LLM이 "해결됐습니다" 판단 시 → Annotation 저장
미해결 시 → 다음 라운드 대화 계속
End (Chatflow는 대화 지속)📊 레시피 5 — 자동 BI 리포트 생성기
Start
input: report_type (주간/월간), date_range, department
│
[HTTP Request: 데이터 웨어하우스 API]
GET /api/metrics?type={{report_type}}&dept={{department}}
→ JSON 데이터: 매출, 사용자, 전환율, 비용 등
│
[Code Node: 데이터 전처리 & 통계 계산]
# Python으로 증감률, 이상치, 트렌드 계산
def main(raw_data: dict) -> dict:
import statistics
metrics = raw_data[‘metrics’]
analysis = {
‘revenue_growth’: …,
‘top_products’: …,
‘anomalies’: […],
‘trend_direction’: …
}
return {“analysis”: analysis}
│
[병렬 처리]
├─→ [LLM: 트렌드 분석] (GPT-4o — 정확한 분석)
├─→ [LLM: 위험 요소] (Claude — 세밀한 리스크)
└─→ [LLM: 추천 액션] (Gemini — 전략적 제안)
│
[Variable Aggregator] — 분석 통합
│
[LLM: 최종 리포트 작성] (GPT-4o)
프롬프트: 마크다운 형식, 임원용 요약, 팀별 액션 아이템
│
[HTTP Request: Notion에 페이지 생성]
[HTTP Request: 이메일 발송 (n8n 웹훅 트리거)]
End — report_url 반환- 4가지 앱 유형 — Chatbot·Text Generator·Agent·Workflow를 상황에 맞게 선택
- 15종 워크플로우 노드 — LLM·Knowledge·If/Else·Code·HTTP·Iterator·Agent 완전 활용
- RAG 최적화 — 인덱싱 전략·청킹·하이브리드 검색·리랭킹·Metadata 필터
- MCP 양방향 — 외부 MCP 서버를 도구로·Dify 워크플로우를 MCP 서버로 노출
- 플러그인 생태계 — Marketplace 50+ 플러그인·커스텀 Tool 개발·Ollama 로컬 연동
- n8n 통합 — 양방향 API 연동으로 AI(Dify) + 자동화(n8n) 최강 조합
- LLMOps — Logs·Annotations·Langfuse로 프로덕션 품질 지속 개선
🎉 Dify 전문가 심화편 완독 완료! 비주얼 워크플로우로 시작해 프로덕션 수준의 AI 앱을 빠르게 구축하고, MCP로 AI 생태계와 연결하며, LLMOps로 지속적으로 개선합니다. Dify + n8n + Ollama 조합으로 완전한 자체 AI 인프라를 완성하세요.
