Dify와 Make를 이용한 문의 워크플로우 작성 체험
요약
본 기사는 사내 문의를 채팅(Slack)으로 시작하여, Dify 워크플로우를 통해 답변을 생성하고, 그 결과를 Google 스프레드시트에 자동 기록하는 통합 워크플로우 구축 과정을 다룹니다. 핵심은 Make가 Slack 이벤트를 받아 Dify API로 요청을 전달하는 '오케스트레이션' 역할을 수행하며, 실제 답변 생성 및 스프레드시트 쓰기(노드 연동)는 Dify 내부에서 처리된다는 점입니다. 이 구조는 노코드에 가까운 Make와 유연한 LLM/도구 연동이 가능한 Dify를 결합하여 사내 PoC나 소규모 운영 환경에 적합하며, 문의 분류 및 RAG(지식 베이스) 참조 과정을 상세히 보여줍니다.
핵심 포인트
- Slack 멘션 이벤트를 Make가 수신하고 이를 Dify API로 전달하는 오케스트레이션 구조를 구축했습니다.
- 답변 생성과 Google 스프레드시트 기록은 Make가 아닌, Dify 워크플로우 내부의 노드 연동 기능을 통해 완료됩니다.
- Dify는 LLM 앱 및 복잡한 워크플로우(노드 연결)를 GUI로 구성하고 외부 시스템에서 호출할 수 있는 플랫폼입니다.
- Make는 Slack 같은 외부 서비스 이벤트를 받아 Dify API 호출을 자동화하는 데 사용되었습니다.
- 워크플로우는 질문 분류기 노드를 통해 문의 유형을 파악하고, 적절한 지식 베이스(RAG)를 참조하여 답변의 정확도를 높이는 과정을 포함합니다.
목차
시작하며
본 기사는 문의 워크플로우(Workflow) 작성 체험을 기술한 것입니다.
사내 문의나 지식 탐색을 채팅을 통해 자연스럽게 시작할 수 있게 하고 싶다——라는 동기에서, Slack에서 멘션된 질문을 Make로 받고, Dify의 워크플로우(LLM)로 답변하며, Google 스프레드시트에 질문과 답변을 추가하는 구조를 구축했습니다.
본 구성에서는 스프레드시트 쓰기는 Make가 아니라, Dify 워크플로우 내(노드 연동)에서 수행합니다. Make의 역할은 Slack에서 받은 내용을 Dify API로 전달하는 것까지가 중심입니다.
본고에서는 완성된 워크플로우의 전체 모습과, 구현 및 운용 과정에서 실제로 겪었던 어려움과 대처 방법을 정리합니다. 노코드(No-code)에 가까운 연동(Make)과 프롬프트 및 도구 연동을 유연하게 구성할 수 있는 Dify를 조합하는 구성은, 사내 PoC나 소규모 운용에도 적합하다고 느끼고 있습니다.
검증 과정에서는 MAKE(구 Integromat)를 사용하여 노코드로 GPT Slack bot을 만들기(Reiwa Travel Tech Blog / Zenn)를 주로 참고했습니다.
Dify와 Make에 대한 간단한 설명
◼︎Dify에 대하여
Dify는 LLM 앱을 구축 및 공개하기 위한 플랫폼입니다. 챗봇이나 워크플로우(노드를 연결하여 LLM, 지식 베이스, 도구 연동을 정의)를 GUI로 구성하며, REST API나 Webhook을 통해 외부 시스템에서 호출할 수 있습니다. 본 기사에서는 질문문을 받아 답변을 생성하고, 이와 함께 Google 스프레드시트에 추가하는 것까지를 Dify 워크플로우 내에서 마무리하는 것을 상정합니다.
◼︎Make에 대하여
Make(구 Integromat)는 브라우저 상에서 시나리오(모듈을 선으로 연결한 플로우)를 구성하여, Webhook 수신이나 HTTP로 외부 API를 호출하는 등의 처리를 코드를 거의 작성하지 않고 자동화할 수 있는 서비스입니다. 본 기사에서는 Slack에서 도착한 이벤트를 받아 Dify의 API에 요청을 전달하는 '오케스트레이션(Orchestration)' 용도로 Make를 사용하고 있습니다.
결과물 · 동작 이미지 (스크린샷용)
개요
Slack에 문의 내용을 게시하면 그 내용을 Make가 받고, Dify로 연동하는 흐름이 됩니다.
문의 내용과 LLM의 답변은 스프레드시트에 축적됩니다.
<결과물의 워크플로우>
전체 워크플로우 도
요점: 스프레드시트 업데이트는 Make가 아니라 Dify 워크플로우 내의 노드(예: 코드 실행, Sheets용 HTTP / 공식 도구 등)에서 수행합니다.
대략적인 데이터 흐름은 다음과 같습니다.
Slack → Make: Event Subscriptions의 Request URL에 Make의 Custom Webhook을 지정하고, app_mention(※본 건에서는 @verification_dify_and_make) 등의 이벤트를 받는다.
Make → Dify: REST API(예: https://api.dify.ai/v1/workflows/run)를 HTTP 모듈에서 호출하여, 입력 변수에 멘션 문구, 채널 정보 등을 전달한다.
Dify 내 → Google 스프레드시트: 본고의 구성에서는 BATCHGET으로 행 수를 취득 → 다음 행의 범위를 계산 → 쓰기와 같은 처리를 Dify 상의 노드에서 완결시킨다. Make에서 Sheets API를 직접 호출하지 않는 점이 기존의 '오케스트레이터 기능이 모두 포함된 Make' 안과 다릅니다.
◼︎Make의 워크플로우
◼︎Dify의 워크플로우(※한 장에 다 담기지 않아 2장으로 나누었습니다)
<문의 동작>
◼︎기본적인 질문
① Slack에 멘션(@verification_dify_and_make)을 달아 문의 내용을 게시한다.
② Slack의 bot으로부터 답변이 회신된다.
Dify 측의 LLM에서 【답변】, 【지식 베이스 명칭】, 【판별】 포맷으로 답변하도록 지정하고 있습니다.
※【답변】→ 단순한 LLM으로부터의 답변 내용
【지식 베이스 명칭】→ Dify가 답변을 할 때 참조한 지식 베이스 (RAG)의 명칭
【판별】→ 실제 문의 운영을 상정하여, 답변에 문제가 없다면 AI 측에서 「통상」이라고 기재하도록 합니다.
지식 베이스 등이 불충분하여 답변 정확도가 좋지 않다고 판단한 경우에는 「에스컬레이션 필요」라고 기재합니다.
※보충
이때 Dify 측에서는
아래의 「질문 분류기 (Question Classifier)」 노드에서 어떤 종류의 질문인지 분류됩니다.
이번 질문인 「채권 관리 시스템의 목적을 알려주세요.」는 클래스 1인 「사양 질문」으로 분류됩니다.
클래스 1에서 지식 베이스 노드 (SPEC_FAQ)로 진행하여 RAG를 참조합니다.
「SPEC_FAQ」 노드에는 아래의 RAG (텍스트 파일)를 참조하도록 설정되어 있습니다.
채권 관리 시스템 사양·FAQ
대상 범위
- 채권 관리 시스템의 목적·위치 설정 설명
...
「SPEC_FAQ」 노드에서 「LLM1」 노드로 진행합니다.
LLM1은 아래와 같이 설정되어 있습니다.
③ 질문과 답변 내용을 스프레드시트에 축적
※이후부터 이 스프레드시트를 「답변 축적 스프레드시트」라고 호칭합니다.
구현의 포인트
<Slack과 Make: 검증과 통상 이벤트의 분기>
Slack에 특정 멘션을 지정하면 Make로 연결하기 위해 Slack의 Event Subscriptions라는 기능을 사용하고 있습니다.
◼︎ Event Subscriptions 페이지
Event Subscriptions는 Request URL 검증 시 type : url_verification에 대해 challenge 키의 반환이 필요합니다.
◼︎ 샘플 JSON
{
"token": "Jhj5dZrVaK7ZwHHjRyZWjbDl",
"challenge": "3eZbrw1aBm2rZgRNFdxV2595E9CY3gmdALWMmHkvFXO7tYXAYM8P",
...
통상적인 멘션에서는 event_callback이 전달됩니다.
Make 설정에서는 Router 직전에서 한쪽만 통과시키는 필터로 설정하면 다른 쪽 이벤트가 모두 누락되기 때문에, Router에서 먼저 분기하고 루트별로 필터를 다는 형태가 안전했습니다.
검증 루트에서는 Webhook 응답으로 challenge를 그대로 반환하고, 본 처리 루트에서는 event_callback (필요하다면 app_mention)으로 한정하는 패턴입니다.
◼︎ Make의 Router 분기
◼︎ 검증 시의 분기 설정 (type=url_verification 이라면 검증용 루트(4번 Webhook response)가 실행됩니다.)
◼︎ 본 처리 루트의 분기 설정 (type=event_callback 이라면 본 처리 루트(13번 Webhook response 이후의 처리)가 실행됩니다.)
<Dify: 외부에서 호출할 때는 「공개」 상태>
Make에서 Dify의 API를 호출할 경우, 워크플로우 (앱)가 미공개 상태라면 404 또는 「트리거를 찾을 수 없음」과 같은 에러가 발생할 수 있습니다. 에디터 상의 테스트와 외부 (Make)에서 보이는 공개 상태는 다르므로, 연동 확인 시에는 공개 완료 상태인지를 반드시 확인하는 것이 좋습니다.
<Dify: 코드 실행 (Code Execution) 노드>
이번에 코드 실행 노드는 다음 두 곳에서 사용했습니다.
- 코드 실행/셀 취득
- 스프레드시트의 마지막 행을 판별하기 위해 사용
- 코드 실행/답변 정형화
- LLM으로부터의 답변을 정형화하여 OUTPUT 노드로 결과를 전달
각 노드는 JavaScript로 실행됩니다.
① 「코드 실행/셀 취득」에 대하여
<왜 코드 실행을 하는가>
◼︎ 「코드 실행/셀 취득」 노드 이미지
「코드 실행/셀 취득」 노드에서는 답변 축적 스프레드시트의 마지막 행의 다음 행을 취득합니다.
예: A2:B2까지 기재되어 있다면 실행 결과는 「A3:B3」가 반환됩니다.
◼︎ 스프레드시트 (A2:B2까지 기재 완료)
◼︎ Dify의 상세 로그
로그의 「출력 (Output)」 결과로부터 A3:B3이 반환되고 있음을 확인할 수 있습니다.
이 결과를 통해 답변 결과를 마지막 행의 다음 행에 기재할 수 있습니다.
◼︎ 노드 내용
※보충
ssh_body는 「BATCH GET SPREADSHEET」 노드의 실행 결과입니다.
sheet_name은 「시트1」이라는 문구가 저장되어 있는 환경 변수 (Environment Variable)입니다.
回答蓄積スプレッドシート (답변 축적 스프레드시트)
가 시트1을 사용하고 있기 때문에 이 문자열이 들어갑니다.
◼︎ 환경 변수 화면
◼︎ JavaScript 소스
function main({ ssh_body, sheet_name }) {
const values = ssh_body?.[0]?.valueRanges?.[0]?.values ?? [];
const nextRow = values.length + 1;
...
② 「코드 실행/답변을 정형화」에 대하여
<왜 코드 실행을 하는가>
◼︎ 「코드 실행/답변을 정형화」 노드 이미지
◼︎ 노드 내용
LLM으로부터의 답변을 그대로 스프레드시트에 쓰기 (BATCH UPDATE SPREADSHEET 노드 실행)를 하려고 하면 json 포맷이 아니다
라는 에러가 발생하는 경우가 있었습니다.
◼︎ 에러 내용
Output result must be a string, got list
원인으로는 LLM의 답변 결과가 배열 (Array) 형태였기 때문에 JSON 문자열로 변환할 필요가 있었습니다.
그래서 아래와 같은 JavaScript를 실행하여 반드시 JSON 문자열로 변환되도록 했습니다.
function main({ query, text, cell }) {
const sheet = "シート1"; // 실제 시트명으로 변경
const range = `${sheet}!${cell}`;
...
요약
Slack × Make × Dify와 스프레드시트를 조합하면, 채팅 기반의 문의를 **구조화된 로그 (Structured Log)**로 남기기 쉬워집니다. Sheets 업데이트를 Dify 내부에서 완결하면, Make는 「Slack에서 Dify로의 가교 역할」에 전념할 수 있어, LLM 주변의 로직을 한 곳에서 유지보수하기 쉽다는 장점도 있습니다.
적어도 Slack의 이벤트 유형 차이, Dify의 공개 상태, Sheets의 「다음 행」 계산과 JSON의 형태는 초기 단계에서 파악해 두는 것이 안심할 수 있습니다.
동일한 구성을 검토하고 계신 분들께 참고가 되기를 바랍니다.
참고 링크
- MAKE(旧 Integromat)を使ってノーコードで GPT Slack bot を作る(令和トラベル Tech Blog / Zenn)
- Make Apps Documentation — HTTP(Advanced settings の Timeout)
- DifyとGoogleスプレッドシートを連携させて、セルデータを取得してみた
- DifyとMakeによる生成AIシステムインテグレーション開発入門:概念とユースケース
- 【Dify】_簡易的なワークフローを作成
AI 자동 생성 콘텐츠
본 콘텐츠는 Zenn AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기