본문으로 건너뛰기
취준생을 위한 n8n 실전 워크플로우 레시피 · 32/44시리즈 보기 →

내 문서로 답하는 RAG 챗봇 — n8n으로 임베딩부터 검색까지

· 약 9분
Datapopcorn CEO / AI automation educator
이 글과 연결된 글 보기
7편 · 20개 연결
100%
n8n Data Table 처음 써보기 — 트렌드 3개를 합쳐 매일 아침 분석 주제 뽑는 워크플로우n8n으로 정적 웹서버 운영하기 — 수료증 발급부터 진위 확인까지, 멱등 처리로 안전하게벡터DB 없이 실시간으로 사이트를 읽는 챗봇 — 경복대학교 안내 챗봇 해부n8n으로 반복업무 자동화 포트폴리오 만들기내 문서로 답하는 RAG 챗봇 — n8n으로 임베딩부터 검색까지구글시트에 쌓인 데이터를 인스타그램 카드뉴스로 — n8n 시트 인스타그램 자동발행서브워크플로우를 Tool로 감싸 AI Agent에게 서버 점검시키기 — 그리고 시스템 프롬프트만으로는 부족한 이유

드래그로 이동 · 휠/두 손가락으로 확대 · 방향키로 글 선택 · 0으로 맞춤. 실선: 본문 링크, 점선: 시리즈·주제의 대표 연결.

표시된 글 7편 목록
전체 글 연결 탐색

문서를 올리면 청크로 잘라 벡터로 바꿔 Supabase에 저장하고, 채팅창에 질문을 던지면 AI Agent가 그 벡터 스토어를 도구로 불러와 관련 조각을 찾아 답하는 RAG 챗봇을 n8n으로 만들 수 있습니다. 노드 하나하나는 낯설지 않지만, "저장"과 "검색"이 서로 다른 트리거로 완전히 분리돼 있다는 구조를 직접 조립해보면 RAG가 면접 답변용 용어가 아니라 손에 잡히는 파이프라인이 됩니다.

이 워크플로우 하나로 보여줄 수 있는 것​

이 시리즈에서 슬랙 대화를 Supabase에 쌓는 편은 그냥 저장이었고, 명함 OCR 편은 Structured Output Parser로 AI의 답을 정해진 형식으로 강제하는 법을 다뤘습니다. 이번 편은 그 저장을 "검색 가능한" 형태로 바꾸고, AI Agent가 언제 검색할지를 스스로 판단하게 만드는 편이라 이 시리즈에서 개념이 가장 많이 들어갑니다. 그만큼 면접에서 값어치도 큽니다.

"RAG 써봤어요"라는 말에는 보통 "구체적으로 뭘 했는데요?"가 따라옵니다. 이 워크플로우를 만들어보면 다음 네 가지를 노드 이름으로 답할 수 있게 됩니다.

  • 문서 로드와 청크 분할 — 긴 문서를 통째로 넘기지 않고 왜 잘라야 하는지 이해한 경험
  • 임베딩 — 텍스트를 벡터(숫자 배열)로 바꿔 의미 기반 검색이 가능하게 만든 경험
  • 벡터 스토어를 도구로 쓰기 — 저장과 검색을 분리하고, LLM이 필요할 때만 검색을 호출하게 설계한 경험
  • 대화 메모리 — 챗봇이 직전 대화를 기억하며 이어가게 만든 경험

이 네 가지를 하나로 묶으면 "RAG가 뭔가요?"라는 질문에 "문서를 청크로 쪼개 벡터로 바꿔 저장해두고, 질문이 오면 그 벡터 공간에서 가장 가까운 조각을 찾아 LLM에 같이 넣어주는 구조입니다"라고 바로 답할 수 있습니다.

배경​

일반 챗봇은 학습된 지식으로만 답합니다. 그래서 회사 내부 문서나 최근 발표 자료처럼 모델이 모르는 내용을 물어보면 모르거나, 더 나쁘게는 그럴듯하게 지어냅니다. RAG(Retrieval-Augmented Generation)는 질문이 들어올 때마다 관련 문서 조각을 먼저 찾아 LLM에게 "이 내용을 참고해서 답해"라고 같이 넘겨주는 방식으로 이 문제를 풉니다. 이 워크플로우는 워크플로우 이름부터 "유즈케이스(4)"이고 캔버스 제목 스티키에도 "내 문서 기반으로 답변하는 챗봇 만들기(w/Supabase)"라고 적혀 있는, 데이터팝콘 n8n 인스턴스의 교육용 예제입니다. 설치나 기본 노드 설명은 n8n으로 반복업무 자동화 포트폴리오 만들기에 정리돼 있으니, 이 글에서는 RAG 구조 자체만 다룹니다.

구조 — Trigger / Task / Target​

이 워크플로우는 트리거가 두 개입니다. 하나는 문서를 저장하는 흐름이고, 하나는 질문을 받는 흐름입니다. 두 흐름이 완전히 분리돼 있고, 오직 Supabase의 벡터 테이블 하나로만 연결된다는 점이 RAG 구조의 핵심입니다.

  • Trigger — 저장은 Form 업로드, 질의응답은 채팅 메시지 수신. 서로 다른 시점에 각자 따로 실행됩니다
  • Task — 저장 쪽은 로드 → 분할 → 임베딩 → 저장을 한 번에 처리하고, 질의 쪽은 Agent가 필요하다고 판단할 때만 벡터 스토어를 호출해 검색합니다
  • Target — 저장은 Supabase documents 테이블. 질의는 Agent가 Chat Trigger로 답을 돌려보내는 동시에 Postgres에 대화 기록을 남깁니다

만들기​

1. Supabase에 벡터 테이블 준비하기​

n8n의 Supabase Vector Store 노드는 테이블과 검색 함수가 미리 있어야 동작합니다. Supabase의 LangChain 연동 가이드가 제공하는 SQL을 SQL Editor에서 그대로 실행하면 됩니다.

create extension vector with schema extensions;

create table documents (
id bigserial primary key,
content text,
metadata jsonb,
embedding extensions.vector(1536)
);

create function match_documents (
query_embedding extensions.vector(1536),
match_count int default null,
filter jsonb DEFAULT '{}'
) returns table (id bigint, content text, metadata jsonb, similarity float)
language plpgsql
as $$
#variable_conflict use_column
begin
return query select id, content, metadata,
1 - (documents.embedding <=> query_embedding) as similarity
from documents
where metadata @> filter
order by documents.embedding <=> query_embedding
limit match_count;
end;
$$;

vector(1536)은 OpenAI 임베딩 모델이 뽑아내는 벡터 차원 수와 맞춘 값입니다. 다른 임베딩 모델을 쓰면 이 숫자도 바꿔야 합니다.

2. Form Trigger — 업로드 받을 문서 정의​

Form Trigger 노드에서 폼 제목을 정하고, 필드를 파일 타입 하나로만 둡니다. 원본은 필드 이름을 file로, 필수 항목으로 설정해뒀습니다. 이 폼이 곧 "내 문서 저장소에 무엇을 넣을지"를 결정하는 입구입니다.

3. Default Data Loader + Text Splitter — 청크로 쪼개기​

업로드된 파일은 Default Data Loader 노드(Data Type: Binary)로 읽어들이고, 여기에 Recursive Character Text Splitter가 서브 노드로 연결됩니다. 청크로 자르는 이유는 두 가지입니다. 첫째, 임베딩 모델과 LLM 모두 한 번에 넣을 수 있는 글자 수에 한계가 있습니다. 둘째, 검색은 문서 전체가 아니라 조각 단위로 이뤄지기 때문에, 조각이 너무 크면 관련 없는 내용까지 딸려 오고 너무 작으면 문맥이 끊깁니다. 원본은 Chunk Size·Overlap을 커스터마이즈하지 않고 노드 기본값을 그대로 씁니다. 직접 만든다면 문서 성격에 맞춰 이 두 값을 조절해보는 걸 권합니다.

4. Embeddings OpenAI + Supabase Vector Store — 벡터로 바꿔 저장​

Embeddings OpenAI 노드가 청크를 숫자 벡터로 바꾸고, Supabase Vector Store 노드(Mode: Insert)가 그 벡터를 1번에서 만든 documents 테이블에 넣습니다. 이 세 노드(Data Loader, Text Splitter, Embeddings)는 전부 Supabase Vector Store 노드에 서브 노드로 매달리는 구조라, 실제로 Form 제출 이벤트가 흐르는 메인 라인은 Form Trigger에서 Supabase Vector Store 노드 하나로 바로 이어집니다.

임베딩 비용은 토큰당 과금입니다. OpenAI의 text-embedding-3-small 모델은 공식 가격 기준 2026년 8월 현재 100만 토큰당 0.02달러로, PDF 몇 장을 임베딩해도 몇 센트 수준입니다. Supabase는 무료 티어가 공식 가격 페이지 기준 데이터베이스 500MB까지 무료지만, 1주일 동안 활동이 없으면 프로젝트가 일시정지된다는 점은 알아두는 게 좋습니다.

5. Chat Trigger + AI Agent — 질문 받을 창구​

Chat Trigger 노드(Public 옵션 켬)가 로그인 없이도 열리는 채팅 URL을 만들어줍니다. 여기로 들어온 메시지가 AI Agent 노드로 넘어가고, Agent에는 Chat Model로 OpenAI(gpt-4o-mini)가 연결돼 있습니다.

6. Supabase Vector Store를 도구로 연결하기​

여기가 RAG의 핵심입니다. 저장할 때 쓴 것과 같은 Supabase Vector Store 노드를 Mode: Retrieve As Tool로 하나 더 추가해 Agent의 도구로 연결합니다. 원본은 Tool Name을 apple_reports_2025Q1, Tool Description을 "Analysis 2025-Q1 apple reports"로 적어뒀습니다. Agent는 이 이름과 설명만 보고 "지금 질문에 이 도구가 필요한지"를 스스로 판단합니다. 즉 사용자가 매번 "문서에서 찾아줘"라고 지시하지 않아도, 질문 내용이 이 설명과 관련 있어 보이면 Agent가 알아서 벡터 스토어를 호출해 관련 청크를 가져오고, 그 내용을 근거로 답을 만듭니다. 저장은 4번에서 끝났고, 검색은 질문이 들어올 때마다 이 도구 호출로 새로 일어난다는 점에서 두 흐름이 분리돼 있습니다.

7. Postgres Chat Memory — 직전 대화 기억하기​

Agent에 Postgres Chat Memory 노드를 Memory로 연결하면, 같은 대화 세션 안에서 이전 질문·답변을 기억하고 이어갑니다. 주의할 점은 이 노드가 Supabase API 키가 아니라 별도의 Postgres 접속 정보(호스트·포트·계정)를 요구한다는 것입니다. Supabase 프로젝트는 REST API와 Postgres 프로토콜을 둘 다 열어두는데, Vector Store 노드는 API 쪽을, Memory 노드는 Postgres 프로토콜 쪽을 씁니다. 처음 만들 때 이 둘을 같은 자격 증명으로 착각하기 쉬운 지점입니다.

원본 캔버스에 남아 있는 흔적​

원본 워크플로우를 열어보면 저장 흐름에 입력이 두 갈래로 들어옵니다. Form Trigger 말고도 HTTP Request 노드가 하나 더 있는데, https://www.apple.com/newsroom/pdfs/fy2025-q1/FY25_Q1_Consolidated_Financial_Statements.pdf를 그대로 받아와 같은 Supabase Vector Store 노드로 흘려보냅니다. 애플의 2025 회계연도 1분기 실적 발표 PDF를 테스트 문서로 저장해뒀다는 뜻이고, 검색용 도구 이름이 apple_reports_2025Q1인 것도 이 문서와 짝이 맞습니다. 즉 이 워크플로우는 "내 문서"의 예시로 실제 공개된 재무제표 PDF를 넣고 검증한 흔적을 그대로 캔버스에 남겨둔 셈입니다.

Agent에는 벡터 스토어 말고도 도구가 두 개 더 붙어 있습니다. 하나는 질문에 맞춰 Chart.js 차트를 그려주는 서브워크플로우 도구고, 하나는 아무 코드도 채워지지 않은 빈 Code Tool입니다. 둘 다 RAG의 핵심 흐름과는 별개라 이 글에서는 다루지 않지만, Agent 하나에 도구를 여러 개 매달아 상황에 맞게 골라 쓰게 하는 구조를 보여주는 흔적으로 남겨둡니다. AI Agent의 시스템 메시지도 "You are a helpful assistant"라는 기본값 그대로라, 실제로 쓰려면 이 부분부터 손볼 여지가 있습니다.

한계​

  • 답변 근거 강제 없음 — 시스템 메시지가 기본값이라 Agent가 벡터 스토어에서 못 찾은 내용도 자기 지식으로 채워 답할 수 있습니다. "제공된 도구에서 찾은 내용에서만 답하고, 없으면 모른다고 답하라"는 지시를 시스템 메시지에 추가하는 게 RAG 챗봇에서는 사실상 필수입니다.
  • 중복 저장 — Supabase Vector Store가 Insert 모드라, 같은 문서를 두 번 올리면 같은 청크가 두 번 쌓입니다. 문서를 갱신하는 흐름을 만들려면 기존 청크를 지우고 다시 넣는 단계가 따로 필요합니다.
  • 청크 설정 기본값 — Chunk Size·Overlap을 손대지 않았습니다. 표가 많은 문서나 문단이 짧은 문서는 기본값이 안 맞을 수 있어 직접 만든다면 몇 가지 값으로 테스트해보는 게 좋습니다.
  • 공개 채팅 URL — Chat Trigger가 Public으로 켜져 있어 URL만 알면 누구나 접속할 수 있습니다. 실습에는 괜찮지만 내부 문서를 넣은 챗봇이라면 인증을 붙여야 합니다.

포트폴리오·면접 포인트​

포트폴리오에는 자기소개서나 이력서 PDF를 직접 업로드해서 만든 챗봇을 올려보는 걸 권합니다. "이 문서로 답하는 챗봇을 만들었다"는 결과물 자체가 RAG를 설명하는 근거가 됩니다.

면접에서 "RAG를 파인튜닝 대신 쓰는 이유가 뭔가요?"라는 질문이 오면, 파인튜닝은 모델 가중치 자체를 바꿔야 해 비용과 시간이 들지만 RAG는 문서만 갈아 끼우면 답변 내용이 바로 바뀐다는 점, 그리고 어떤 문서 조각을 근거로 답했는지 추적할 수 있어 검증이 쉽다는 점을 답하면 됩니다. 여기에 "저장과 검색을 분리해서 설계했다"는 이 워크플로우의 구조까지 덧붙이면, 개념만 아는 사람과 실제로 조립해본 사람의 차이가 드러납니다.

다음 액션​

이번 편에서는 Agent가 n8n 안의 벡터 스토어를 도구로 불러 썼습니다. 다음 편에서는 이 관계를 뒤집어, n8n 워크플로우 자체를 MCP 서버로 만들어 다른 에이전트가 이 워크플로우를 도구로 호출하게 만드는 법을 다룹니다. 도구를 부르는 쪽과 도구가 되는 쪽을 둘 다 만들어보면, 요즘 채용 공고에 자주 보이는 "MCP 경험"을 실제 경험으로 채울 수 있습니다.