142k stars의 오픈소스 에이전트 워크플로우 플랫폼. 노코드 캔버스, RAG, 에이전트, 멀티 LLM 게이트웨이, LLMOps를 한 박스에 담은 셀프호스팅 시스템.
한 줄로는 부족한 프로젝트 — 기본 개념부터.
Dify(디파이)는 오픈소스 LLM 앱 개발 플랫폼이다. 사용자는 브라우저에서 들어가, 마우스로 노드를 끌어다 잇는 방식으로 챗봇·문서 Q&A·자동화 워크플로우·AI 에이전트를 만든다. 코드 없이도 동작하지만, 코드를 원하는 사람에게는 REST API와 SDK도 제공한다. Docker Compose 한 번이면 본인 서버에 통째로 띄울 수 있어 셀프호스팅이 가능하다.
제작사는 langgenius(중국 상하이 기반)이며, GitHub 기준 142,000 stars · 22,200 forks · 163개 릴리즈를 기록한 대형 OSS 프로젝트. 코드 분포는 TypeScript 53.1% / Python 42.2%로, 프론트엔드와 백엔드가 거의 동급의 무게를 차지한다.
한 문장으로 줄이면.
docker compose up -d 한 줄로 회사 서버 안에서 동작한다."경쟁자들이 "프롬프트 관리만", "RAG만", "에이전트만" 식으로 부분을 다룰 때, Dify는 비주얼 워크플로우 · 모델 게이트웨이 · RAG 파이프라인 · 에이전트 · 관측 가능성을 한 번에 패키징했다.
"LLM 앱 시대의 Firebase"라는 비전을 가장 구체적으로 구현한 풀스택 플랫폼. 비개발자도 챗봇을 만들 수 있고, 개발자는 코드와 SDK로 더 깊이 들어갈 수 있다.
붐비는 시장에서 어떻게 차별화했나.
2024~2026년 LLM 앱 빌더 시장은 매우 붐비는 영역이다. LangChain(코드 라이브러리), LangFlow(오픈소스 캔버스), Flowise, n8n(자동화 + AI), 그리고 클로즈드 소스의 Zapier·Make, Microsoft Copilot Studio 등이 경합한다. Dify는 다음 세 가지로 차별화에 성공했다.
유사 SaaS 도구는 클라우드 종속이지만, Dify는 한 줄 docker compose로 본인 NAS·VPS·온프레미스에 완전히 떨어진 채 동작한다. 회사 내부 데이터가 외부로 한 비트도 나가지 않게 막을 수 있다 — 의료·금융·정부 영역의 가장 강력한 채택 이유.
Weaviate, Qdrant, Milvus, pgvector, OpenSearch, Chroma, Elasticsearch, TiDB Vector, OceanBase, Oracle, Upstash, Tencent VDB, Baidu, Lindorm 등 30+ 종을 플러그인 형태로 추가/제거할 수 있다. 이미 회사가 쓰는 DB가 있다면 그대로 활용 가능.
LLM 앱의 실제 어려움은 만드는 것이 아니라 운영이다. Dify는 Opik, Langfuse, Arize Phoenix, LangSmith, MLflow, Weave 등 외부 트레이싱 시스템과의 어댑터를 기본 제공하고, 자체적으로도 메시지/토큰/응답시간/비용 대시보드를 제공한다.
| 비교 항목 | 경쟁 (부분 제품) | Dify (풀스택) |
|---|---|---|
| 비주얼 캔버스 | LangFlow / Flowise | 내장 (Workflow + Chatflow) |
| RAG 파이프라인 | LlamaIndex / Haystack | 내장 + 30+ 벡터 DB |
| 모델 게이트웨이 | litellm / OpenRouter | 내장 (litellm 위에 자체 어댑터) |
| 관측 가능성 | Langfuse / LangSmith | 내장 + 6개 외부 어댑터 |
| 셀프호스팅 | 대부분 클라우드 종속 | docker compose up 한 줄 |
| 코드 격리 실행 | 없음 (직접 구현 필요) | Sandbox 컨테이너 내장 |
백엔드 · 프론트엔드 · 인프라 · 운영.
Dify의 API 서버는 api/ 폴더에 있으며, 한국에서는 약간 의외일 수 있지만 Flask 3.x를 채택했다. FastAPI 전성기에도 Flask를 고른 이유는 거대한 플러그인 생태계와 성숙한 운영 패턴(gunicorn + gevent + Celery)에 있다.
pyproject.toml에 [tool.uv.workspace]로 30개 벡터 DB 어댑터를 하위 패키지로 분리해 관리한다.웹 UI는 web/ 폴더에 있고, Next.js 기반에 최근 빌드 도구를 Vite로 갈아끼우는 중이다. 루트 package.json은 pnpm 워크스페이스 + vite-plus를 채택해 모노레포로 운영한다.
e2e/ 폴더docker/docker-compose.yaml은 약 1200줄 분량으로, 다음 핵심 컨테이너들을 묶는다.
Dify는 사용자가 임의의 URL을 호출하는 도구·웹훅을 만들 수 있다. 만약 사용자가 http://169.254.169.254/(AWS 메타데이터 서비스) 같은 내부 URL을 호출하면 클라우드 자격증명이 새어나갈 수 있다. Squid 프록시가 이를 화이트리스트 기반으로 차단한다.
① 외부 요청은 SSRF Proxy 통과 강제 → ② 사용자 코드 실행은 sandbox 컨테이너에서 → ③ 플러그인은 plugin_daemon이 별도 프로세스로 실행. 한 레이어가 뚫려도 다음 레이어가 막는 심층 방어 구조.
전체 구조도 → 핵심 패턴 하나하나.
┌─────────────────────────────────────────────────────────────────┐
│ Browser (사용자) │
└──────────────────────────┬──────────────────────────────────────┘
│ HTTPS
▼
┌────────────────┐
│ nginx (80/443) │ ← 리버스 프록시
└───┬────────┬───┘
│ │
/api/* 요청 │ │ /, /static/* 요청
▼ ▼
┌──────────┐ ┌──────────┐
│ api │ │ web │ ← Next.js SSR
│ (Flask) │ └──────────┘
└─────┬────┘
│
┌────────────┼──────────────┬────────────┬─────────────┐
▼ ▼ ▼ ▼ ▼
┌─────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│postgres │ │ redis │ │ sandbox │ │ plugin │ │ssrf_proxy│
│ (메인) │ │ (브로커) │ │ (코드) │ │ _daemon │ │ (squid) │
└─────────┘ └────┬─────┘ └──────────┘ └──────────┘ └─────┬────┘
│ │
▼ celery tasks ▼ 외부 호출
┌──────────┐ ┌─────────┐
│ worker │ ─────────────────────────────► │ LLM API │
│ (celery) │ │ (GPT/ │
└────┬─────┘ │ Claude)│
│ └─────────┘
▼ embedding query
┌──────────────────────┐
│ Vector DB │ ← 30+ 종 중 선택
│ (Weaviate/Qdrant/ │
│ Milvus/pgvector...) │
└──────────────────────┘
30개 벡터 DB를 메인 코드에 직접 박지 않고, api/providers/vdb/* 하위 패키지로 분리했다. pyproject.toml에서 [tool.uv.sources]로 워크스페이스 멤버 등록 후 dependency group vdb-qdrant, vdb-milvus처럼 필요한 것만 골라 설치 가능.
uv sync --group vdb-qdrant # Qdrant만 설치 (의존성 최소화) uv sync --group vdb-milvus # Milvus만 설치 uv sync --all-groups # 전부 (디스크 큼)
레스토랑이 모든 양념을 한꺼번에 사두지 않고, 그날 주문 들어온 요리에 필요한 양념만 꺼내는 것과 같다. 30개 벡터 DB의 의존성을 한 번에 설치하면 도커 이미지가 1GB를 넘기는데, group 분리로 운영 환경에서 필요한 어댑터만 가벼운 빌드가 가능해진다.
플러그인은 메인 API 프로세스에서 실행하지 않고, plugin_daemon이라는 별도 컨테이너가 호스팅한다. 이렇게 하면 ① 플러그인이 죽어도 메인 서버는 살아있고 ② 다른 언어(Go·Node)로도 플러그인 작성 가능 ③ 보안 격리 확보.
Dify는 ① 웹 콘솔용 내부 API와 ② 외부 사용자가 만든 앱을 호출하기 위한 퍼블릭 API를 분리했다. api/controllers/ 안에 console, web, service_api 폴더가 따로 있다. 권한 모델과 rate limit이 완전히 다르기 때문에 코드 레이어로 갈라놨다.
Langfuse, Opik, Arize Phoenix, Weave, MLflow 등 외부 트레이싱 시스템을 어댑터 패턴으로 통일했다. api/providers/trace/* 하위에 각 시스템 어댑터가 있고, 사용자는 환경변수 한 줄로 갈아끼울 수 있다.
| 컴포넌트 | 역할 | 대체 가능 여부 |
|---|---|---|
| litellm | LLM 호출 통일 | 모델 변경 = 환경변수 1줄 |
| Vector DB | 임베딩 저장·검색 | 30+종, uv group으로 선택 |
| Storage | 파일 저장 | S3/MinIO/Azure/GCS 등 |
| Trace Provider | 관측·추적 | Langfuse/Opik/Phoenix 등 |
| Plugin Daemon | 플러그인 실행 | 별 컨테이너, 언어 비종속 |
어디에 뭐가 있는지.
dify/ ├── api/ # Python 백엔드 (Flask + Celery) │ ├── controllers/ # API 엔드포인트 (console / web / service_api) │ ├── core/ # LLM 호출, RAG, 에이전트 코어 로직 │ ├── models/ # SQLAlchemy DB 모델 │ ├── services/ # 비즈니스 로직 레이어 │ ├── providers/ # 워크스페이스 (vdb/*, trace/*) │ ├── migrations/ # Alembic DB 마이그레이션 │ └── pyproject.toml # uv 워크스페이스 설정 │ ├── web/ # Next.js 프론트엔드 (TypeScript) │ ├── app/ # App Router 페이지 │ ├── service/ # API 클라이언트 │ ├── context/ # React Context 상태 │ └── i18n-config/ # 20+ 언어 메시지 │ ├── docker/ # Docker Compose + 환경설정 │ ├── docker-compose.yaml # 메인 오케스트레이션 (~1200줄) │ ├── .env.example # 필수 환경변수 템플릿 │ └── envs/ # 테마별 분리된 옵션 변수 │ ├── docs/ # 다국어 README (zh-CN, ko-KR, ja-JP …) ├── sdks/ # Python · Node SDK ├── packages/ # 공용 TypeScript 패키지 ├── e2e/ # Playwright E2E 테스트 ├── dify-agent/ # 에이전트 코어 패키지 (별도 추출) ├── scripts/stress-test/ # 부하 테스트 스크립트 │ ├── .agents/skills/ # Claude Code 에이전트 스킬 (커밋된 .skill) ├── .claude/ # Claude Code 설정 ├── .gemini/ # Gemini CLI 설정 ├── .devcontainer/ # VS Code Dev Container │ ├── CLAUDE.md # Claude Code용 프로젝트 가이드 ├── AGENTS.md # 에이전트용 컨텍스트 문서 ├── Makefile # 빌드/테스트 단축 명령 └── package.json # 루트 pnpm 워크스페이스
이 구조는 식당의 백오피스 + 홀과 같다. api/는 주방(요리를 만드는 곳, 외부에 안 보임), web/은 홀(손님이 보는 메뉴와 좌석), docker/는 건물 자체(배관·전기·인테리어), sdks/는 배달원에게 주는 매뉴얼이다. 흥미로운 점 — .agents/skills/, CLAUDE.md, AGENTS.md가 커밋되어 있다. 에이전트가 이 레포에서 작업할 때 읽으라고 만든 문서 — 메타 시대를 보여주는 시그널.
Dify를 분해하면 7가지 학습 트랙이 나온다.
실습: 빈 Flask 프로젝트에 Celery + Redis + Postgres를 붙여, PDF 업로드 → 백그라운드 텍스트 추출 → 임베딩 → DB 저장 → 진행률 폴링 API 구현
실습: 본인 프로젝트에 pnpm 워크스페이스를 적용해 shared/ 폴더를 만들고, 두 개의 앱이 동일한 디자인 토큰을 공유하도록 구성
실습: 사이드 프로젝트에서 DB + 캐시 + 워커 + 웹을 Compose로 묶고, vector DB를 profile 옵션으로 켜고 끌 수 있게 구성
실습: litellm으로 OpenAI · Claude · Gemini · Ollama 4개를 같은 코드로 호출하는 비교 앱을 만들고, 응답 속도/토큰 비용/품질을 표로 정리
실습: 본인 PDF 100개를 인덱싱하는 미니 RAG를 처음부터 짜본다 — pgvector + sentence-transformers + Flask 한 페이지면 충분
실습: Docker + gVisor 또는 nsjail로 미니 코드 실행 서비스를 만들어본다
실습: 본인 Flask/FastAPI 앱에 opentelemetry-distro를 붙이고 Grafana Tempo + Loki로 trace + log를 한 화면에서 보는 환경 구성
셀프호스팅 전 체크리스트.
공식 README가 제시하는 최소 사양은 의외로 낮다 — 그러나 실전에서는 늘 함정이 있다.
| 구성 | 최소 사양 | 외부 의존성 | 용도 |
|---|---|---|---|
| 공식 최소 | 2 Core / 4 GiB / Docker | 없음 (전부 컨테이너) | 학습, 단일 사용자 |
| 개인 시험판 | 4 Core / 8 GiB / 50 GB SSD | OpenAI API 키 정도 | 개인 프로젝트 |
| 소규모 팀 (10~30명) | 8 Core / 16 GiB / 200 GB SSD | 벡터 DB 별 컨테이너 권장 | 사내 챗봇·문서 QA |
| NAS 자가호스팅 | Synology DS920+/DS923+ (8GB) | Qdrant·pgvector 권장 | 홈랩, 개인 데이터 보관 |
| + 로컬 임베딩 모델 | 위에 GPU 추가 | HuggingFace 모델 | API 호출 비용 절감 |
최소 사양은 빈 Dify를 띄우기만 한 상태 기준이다. ① 벡터 DB를 같은 호스트에 띄우면 Milvus만 2~4GB, Weaviate도 1~2GB 추가로 먹는다. ② LLM API 호출은 외부지만 임베딩 모델을 로컬로 돌리면 별도 GPU/RAM이 필요하다. ③ 동시 사용자 10명 + 문서 1만 건이면 8GB는 부족하다.
벡터 DB는 별도 호스트로 분리하고 Dify는 API/Web/Worker만 책임지게 하자. 파일 스토리지는 로컬 디스크 대신 S3 호환 객체 스토리지(MinIO, R2, B2 등)를 쓰면 백업·확장이 쉽다. STORAGE_TYPE 환경변수 한 줄로 갈아낄 수 있다.
WSL2 위에서 docker compose를 돌리는 게 가장 안정적. PowerShell 직접 사용 시 볼륨 권한 이슈가 잦다. Hyper-V 활성화, Docker Desktop 최신 버전, 최소 8GB RAM 할당(WSL .wslconfig)을 권장. 또한 Windows 경로(C:\)와 Linux 경로(/mnt/c/)가 혼동되지 않게 .env의 경로 변수는 Linux 스타일로 통일.
난이도별 실습 — Easy → Hard.
1) Docker 설치된 머신에서 git clone https://github.com/langgenius/dify 2) cd docker → cp .env.example .env 3) docker compose up -d 4) 5분 후 http://localhost/install 접속 → 관리자 계정 생성 5) OpenAI API 키 한 줄만 넣으면 GPT 기반 챗봇을 클릭 몇 번으로 완성.
배우는 것: Docker Compose 멀티 컨테이너 실전, 환경변수 분리, 초기 설정 흐름
1) Dify 콘솔에서 "지식(Knowledge)" 메뉴 진입 2) 본인 PDF 5~10개 업로드 → 자동 청킹 확인 3) 임베딩 모델로 text-embedding-3-small 선택 (저렴) 4) 챗봇 앱을 만들고 지식 베이스 연결 5) 같은 질문을 ① 단순 LLM 호출 ② RAG 적용 두 가지로 비교해 답변 품질 차이 확인.
배우는 것: RAG 파이프라인 흐름, 청킹 전략, 임베딩 모델 선택
1) 워크플로우 캔버스 구성: 시작 → LLM 노드(질문 분류) → 조건 분기 → HTTP 요청 노드(OpenWeather API) → LLM 노드(자연어 응답) → 종료 2) "내일 서울 날씨 알려줘"가 들어오면 분류 LLM이 "날씨 질문"이라 판정 3) HTTP 노드가 외부 API 호출 4) 결과를 다시 LLM이 자연스러운 문장으로 응답 5) trace 화면에서 각 노드의 토큰·응답시간 확인.
배우는 것: 노드 기반 흐름 설계, 조건 분기, 외부 API 통합, 변수 전파
1) Dify 앱마다 발급되는 API 키 발급 2) 본인의 Next.js/React 사이트에서 직접 호출 3) 스트리밍 응답(SSE)을 받아 토큰별로 화면에 표시 4) 사용자 인증은 본인 시스템에서 처리, Dify에는 user_id만 전달 5) Dify를 백엔드처럼 쓰는 LLM-as-BaaS 패턴 완성.
배우는 것: Service API 인증, SSE 스트리밍 처리, 백엔드 분리 패턴
1) .agents/skills/ 참고해 본인 도구를 플러그인으로 정의 (예: 사내 위키 Confluence 검색) 2) plugin manifest 작성 → 호출 스펙 정의 3) plugin_daemon에 등록 4) 캔버스에서 새 노드로 사용 5) docs.dify.ai의 Plugin 섹션을 참고해 marketplace 배포까지.
배우는 것: 플러그인 아키텍처, manifest 스펙, 사내 도구 통합
주차별로 따라가면 Dify 전체 스택 마스터.
OpenAI · Anthropic · Google 세 회사 API 키 발급. 같은 프롬프트로 세 모델 비교. 스트리밍 vs 일반 응답, 토큰 카운트와 비용 계산, JSON mode와 함수 호출, 컨텍스트 윈도우 관리. Dify 같은 추상 도구로 넘어가기 전에 직접 호출 경험이 필수.
sentence-transformers · Hugging Face 모델로 임베딩 직접 생성. 코사인 유사도 vs 내적 vs L2. pgvector 또는 Qdrant 설치 후 인덱싱. 청크 크기 256 vs 512 vs 1024 비교. 하이브리드 검색(BM25 + 벡터). Re-ranking (cross-encoder)로 정확도 끌어올리기.
LLM이 도구를 호출하는 패턴들 — function calling (OpenAI), tool use (Anthropic), ReAct loop (생각→행동→관찰 반복), Plan-and-Execute, MCP (Model Context Protocol). Dify 캔버스에서 각 패턴이 어떻게 노드로 표현되는지 매핑.
Compose로 Dify 띄우기 → Helm Chart로 K8s 배포 → AWS CDK 또는 Terraform으로 한 클릭 배포. nginx 설정, certbot HTTPS, PostgreSQL 백업 전략, Redis 영속화, Grafana 대시보드 임포트까지.
Langfuse · Opik · Arize Phoenix 중 하나를 골라 Dify와 연결. 트레이스 데이터로 ① 가장 오래 걸린 요청 추적 ② 환각 탐지 ③ 사용자 피드백 분석 ④ A/B 프롬프트 비교. LLM-as-judge 평가 자동화 파이프라인 구축.
Dify 학습 과정에서 자주 마주칠 단어들.
공식 · 코드 · 학습 리소스.
docker compose up -d 한 줄로 localhost에서 첫 챗봇을 만든다. OpenAI 키 한 줄만 있으면 충분. 캔버스가 어떻게 생겼는지 직접 보는 게 어떤 글보다 강력한 학습.api/controllers/console/app/workflow.py 같은 핵심 컨트롤러를 열어 라우트가 어떻게 정의되는지, 비동기 Celery 작업이 언제 시작되는지 따라간다. Flask + Celery 운영 패턴이 통째로 들어있다..agents/skills/ 폴더가 좋은 출발점.