RAG란 Retrieval Augmented Generator의 약자. 검색 증강 생성이라는 건데 풀어서 생각하면 RAG의 의미를 더 쉽게 이해할 수 있다. 생성형 AI 기술이기에, RAG라는 기술도 chatGPT나 Gemini처럼 답변을 생성(Generate)한다. 그럼 chatGPT 그리고 Gemini와 RAG의 차이는 무엇인가.
파운데이션 모델은 대규모 데이터세트를 기반으로 훈련한다. 이렇게 훈련된 모델은 자신의 학습 데이터를 기반으로 답변을 생성한다. 여기서 문제가 발생한다. 학습데이터라는 게 결국 현재까지 그리고 앞으로도 만들어질 모든 지식을 총라한 게 아니기 때문에, 답변에 최신성 문제(혹은 지식 단절 문제)가 발생한다. 그렇다면 이 문제는 어떻게 해결할 수 있는가?
방법 중 하나는 최신 데이터를 계속해서 학습시키는 것이다. 그러나 이 방법은 시간과 비용이 너무나도 많이 발생한다. 그럼 다른 대안이 있는가? 그게 바로 RAG이다. 쉽게 말해 모델에게 오픈북 시험을 보는 것과 비슷하다. 사용자가 입력한 명령어에 대해 먼저 책을 한번 찾아보고1️⃣ 이를 기반으로 답변2️⃣하도록 하는 기술이다.
결국 데이터를 검색하고(Retriever), 이를 기반으로 답변을 생성하는 게(Generator)가 핵심이라 할 수 있다.
1️⃣ Retriever: 사용자 질문에 맞는 정보를 Vertor DB에서 검색해 오는 역할 2️⃣ Generator(LLM): 검색된 정보를 바탕으로 자연스럽게 문장을 생성하는 역할
사용자 질문에 맞는 정보를 찾아오는 과정은 다음과 같다.
1. 사용자 질문을 숫자로 변환환다.
2. Vector DB에서 숫자와 유사한 값을 가진 정보를 검색한다.
3. 찾아온 정보와 사용자 질문을 파운데이션 모델에게 전달한다.
4. 파운데이션 모델이 응답을 생성한다.
여기서 숫자로 변환하는 과정은 임베딩 모델이 수행한다. 임베딩 모델이라는 거는 정보를 벡터화한다는 걸 의미하는데, 쉽게 말해 숫자로 변환한다는 거다. 컴퓨터는 자연어를 이해하지 못하기 때문에 이러한 처리 과정을 진행한다.
RAG는 사용자 질문을 벡터화하고 이와 관련된 정보를 Vector DB에서 찾는다. 따라서 Vector DB에 정보가 준비되어야 한다. AI가 참고해야하는 정보도 벡터화되어 있어야 한다는 걸 의미한다. 이 벡터화는 임베딩 모델이 수행한다. 그럼 문서나 자료를 임베딩모델한테 전달하기만 하면 될까? 그렇진 않다. 주어진 자료를 벡터화하는 건 임베딩 모델이 수행하겠지만, 자료를 얼만큼 줄 것인가는 전략적으로 결정해야 한다.
자료를 얼만큼씩 줄것인가에 대한 것이 바로 청킹인데, 이 과정을 책에 비유할 수 있다. 책 한장에는 한정된 텍스트가 들어간다. 한장을 채우면 다음장에는 전 페이지와 연결되는 내용이 적혀있고, 그렇게 한장 한장을 넘기며 책을 읽는다. 한 페이지에 책의 내용을 담을 수 없기에 여러 장에 내용을 정리하고 이를 묶어 책이 된다. 마찬가지로 정보도 너무 크면 여러 페이지로 나눠야 한다. 이렇게 나누는 걸 청킹이라 한다.
청킹된 데이터를 임베딩 모델에 전달하면 모델이 이걸 벡터화하여 벡터DB에 저장한다. 이렇게 데이터가 준비됐다면, 사용자 질문에 답변을 생성하기 전에 준비된 DB를 한번 조회하고 이를 기반으로 답변하도록 워크플로우를 구현하면 된다. 이때 사용자 질문을 벡터화하는 것도 데이터 준비 과정에서 사용했던 임베딩 모델과 동일한 걸 사용한다. 그리고 사용자 쿼리와 관련된 정보를 탐색한다. 이것도 종류가 있는데 콘텐츠에 따라 성능이 달라지기에 테스트 과정이 필요하다.(Vector DB검색 종류: ANN 검색, kNN검색) 그리고 이렇게 검색된 데이터와 사용자쿼리를 종합하여 파운데이션 모델에게 전달하면 해당 모델이 답변을 생성한다.
- Schedule Trigger: 트리거 노드이다. 매일 특정 시간에 해당 Work flow가 실행되도록 한다.
- RSS Read: 영어 신문을 수집하는 노드다. 해당 프로젝트에서는 The Guardian의 RSS 주소를 기반으로 영어 신문을 수집하도록 하였다.
- Limit: RSS로 영어 신문을 불러오면 너무 많은 기사를 불러온다. 본인이 했을 때는 115개의 Item, 그러니깐 115개의 기사를 불러왔다. 이 Item 개수를 제한하는 노드이다. 이번 프로젝트에서는 3개로 제한했다.
- Message a model: 수집된 기사를 학습용 콘텐츠로 변환하는 노드이다. 이번 프로젝트에서는 Gemini-2.0-flash 모델을 사용했다. 해당 모델을 사용한 이유는 무료이기 때문이다.
- Code in Javascript: Message a model 노드에서 작업한 결과 JSON 문자열 하나가 출력된다. 근데 나는 해당 문자열에서 Content와 URL를 분리하고 싶었다. 그래서 하나의 문자열 내에서 Content와 URL을 파싱하는 노드를 하나 추가했다.
- HTTP Request: 위에 작업된 결과를 카카오톡으로 발송하는 노드이다.
Schedule Trigger
하루에 한번 발송하는 걸로 설정했다.
해당 노드에서는 시간대도 설정할 수 있는데, 중요한 점이 아마 컨테이너 이미지 다운로드할 때 그냥 다운로드 받았으면, 미국 뉴욕 시간대로 설정될 것이다.
Options로 가보면 System Message를 추가할 수 있다. 여기서는 배경, 역할, 지침 등을 설정한다. 그니깐 User에서 명령문을 작성하는데 System Message 따라 작성해달라고 하면 AI가 여기에 작성된 내용을 기반으로 결과를 출력한다.
나는 System Message를 아래와 같이 작성했다.
You are an **expert ESL Instructor** tasked with analyzing an English news article and extracting key learning elements for Korean students. Given the full content of one RSS feed item, generate a **high-quality, self-study educational material**.
[INPUT] The full content of one RSS feed item, including article text, title, and URL.
[TASK INSTRUCTIONS] 1. **Role Confirmation:** You are an **expert ESL Instructor**. 2. **Summarize the Article** summarize the article's core information. Be factful and clear. **No hallucinations** 3. **Extract Key Sentences (3):** Identify the 3 most important sentences that summarize the article's core information. Be factful and clear. **No hallucinations** 4. **Extract Key Vocabulary (3):** Select the **3 most essential and reusable vocabulary words/phrases** for an ESL learner. Provide concise Korean definitions (한글 뜻). Be factful and clear. **No hallucinations** 5. **Character Limit:** The **VISIBLE text content** within the 'Text' field (i.e., the Article Title, all English sentences, all Korean translations, all Vocabulary, and all Korean definitions) **must not exceed 200 characters** (including spaces). **Exclude all Markdown formatting characters** (`#`, `*`, `-`, `\n`) from this character count. **Exclude all JSON formatting characters** ('{', '}','"Text"') from this character count. The 'URL' field content does not count toward this limit. 6. **Output Format:** Output the extracted content **ONLY** in the following JSON structure. The educational material must be strictly within the "Text" field. **The entire output must be wrapped in a JSON markdown code block.**
Message a model 노드에서는 JSON 형식으로 반환하는데 처리 결과는 Text라는 하나의 문자열로 반환한다. 근데 나는 기사의 URL은 따로 HTTP Request 노드에서 사용하고 싶었고, 그래서 문자열에서 Content와 URL을 분리하기 위해 해당 노드를 추가했다. Set Node는 JSON 형식의 문자열 파싱 기능을 제공하지 않기 때문에 Code in Javascript 노드로 추가했다.
추가로, Limit 노드에서 Item을 3개로 설정했고, 따라서 Message a model에서도 Model에게 요청이 총 3번 간다. 그 결과 출력 Item도 3개로 유지된다. 따라서 해당 노드에서 Mode는 Run Once for Each Item으로 하여 각 Item에게 해당 코드를 따르도록 하였다.
// AI 모델의 출력 문자열을 가져옵니다.
const resultString = $json.candidates[0].content.parts[0].text;
// 1. 문자열에서 JSON 코드 블록 마크다운을 제거합니다.
let jsonString = resultString.trim();
if (jsonString.startsWith('```json\n')) {
jsonString = jsonString.substring('```json\n'.length);
}
if (jsonString.endsWith('\n```')) {
jsonString = jsonString.substring(0, jsonString.length - '\n```'.length);
}
jsonString = jsonString.trim();
let parsedJson;
try {
// 2. 정리된 JSON 문자열을 JavaScript 객체로 파싱합니다.
parsedJson = JSON.parse(jsonString);
} catch (error) {
console.error("Critical JSON Parsing Error (Code Block Cleaned):", error);
// 파싱 오류 발생 시 오류 메시지를 담아 반환합니다.
// 이 경우에도 단일 객체 반환 규칙을 지킵니다.
return { json: { Text: "Error: JSON Parsing Failed", URL: "N/A" } };
}
// 3. 파싱된 객체에서 'Text'와 'URL' 필드만 추출하여 다음 노드로 전달합니다.
const output = {
Text: parsedJson.Text,
URL: parsedJson.URL
};
// 4. 다음 노드로 전달합니다. (Run Once for each item 모드에 맞게 단일 객체 반환)
return {
json: output
};
HTTP Request
위 노드들에서 작업한 결과를 카카오톡으로 발송하는 노드이다. Header Parameter와 Body Parameter는 카카오톡 디벨로퍼스에서 제공하는 양식을 따라 작성하면 된다. 왠만한 내용은 유튜버 시민개발자 구씨의 영상(카톡으로 자동화 가능?! n8n으로 카카오톡 연동 방법 공개)을 따라가면 된다. (최고의 Hands-on 영상이다 👍) 근데 버튼 커스터마이징을 원한다면 알아둬야 하는게 있다. 바로 플랫폼 등록할 때 URL이다. 앱 > 일반에서 플랫폼 > Web URL을 등록할 수 있는데, 이게 왜 중요하냐? 이거 등록 안해두면 HTTP Request로 button URL을 정상적으로 보내줘도 카카오톡에서는 해당 URL로 바로가기가 안된다. 결국 도메인을 카카오톡 디벨로퍼스의 앱 설정에서 등록해 놔야지 카카오톡 메신저 안에서 해당 URL로 보내준다는 것이다.
kakao developers > 문서 > 메시지 템플릿 > 기본 템플릿 > Link이 URL이 카카오톡 디벨로퍼스 앱 설정에 등록되어 있어야 한다.카카오톡 디벨로퍼스 > 앱 > 일반 여기에 등록되어 있어야 한다.
2025년 10월 5일 기준, 설정 가능한 항목은 8개이다. 그리고 각 항목별로 설정하는 범위가 조금 다르다.
1. Models: OpenAI에서 사용할 수 있는 모든 모델 목록을 불러올 수 있는가에 대한 설정 - None: 해당 api key로 접근할 경우, key 발급 주체가 되는 계정이 사용할 수 있는 모델 목록을 조회할 수 없다
*api를 통해 특정 모델로만 접근하고, 모델명을 직접 명시할 수 있는 경우, None 사용 - Read: 해당 api key로 접근할 경우, key 발급 주체가 되는 계정이 사용할 수 있는 모델 목록을 조회할 수 있다
*n8n의 Credentials로 api key 등록할 때는 Read 권한을 줘야 한다.
2. Model Capabilities: LLM에게 명령할 수 있는가에 대한 설정 - None: 해당 api key로 접근할 경우, key 발급 주체가 되는 계정이 사용할 수 있는 생성형 모델들에게 명령할 수 없다 - Write: 해당 api key로 접근할 경우, key 발급 주체가 되는 계정이 사용할 수 있는 생성형 모델들에게 명령할 수 있다
3. Assistants: GPT에서 설정 및 생성한 Assistant에 대한 접근 권한 설정 - None: 해당 api key로 접근할 경우, key 발급 주체가 되는 계정의 GPT Assistant를 사용할 수 없다 - Read: 해당 api key로 접근할 경우, key 발급 주체가 되는 계정의 GPT Assistant의 최근 출력 결과나 설정 정보 등을 읽어올 수 있다 - Write: 해당 api key로 접근할 경우, key 발급 주체가 되는 계정의 GPT Assistant에게 명령할 수 있다
4. Threads: 대화 히스토리에 대한 접근 권한 설정 - None: 해당 api key로 접근할 경우, key 발급 주체가 되는 계정의 이전 대화내역 혹은 명령 및 출력 이력을 불러올 수 없다 (Thread API 사용 불가능 하고, 1회성 대화만 가능 = chatCompletion만 가능) - Read: 해당 api key로 접근할 경우, key 발급 주체가 되는 계정의 이전 대화내역 혹은 명령 및 출력 이력을 보기만 할 수 있다 (이전 대화 내역 기반으로 명령 불가) - Write: 해당 api key로 접근할 경우, key 발급 주체가 되는 계정의 이전 대화내역 혹은 명령 및 출력 이력을 불러올 수 있고 대화를 이어갈 수 있다 (이전 대화 내역 기반 명령 가능)
5. Evals: 모델 성능 평가에 대한 접근 권한 설정 - None: 해당 api key로 접근할 경우, 모델 평가 기능에 접근 불가 - Read: 해당 api key로 접근할 경우,모델 평가 결과 조회 가능 - Write: 해당 api key로 접근할 경우,모델 평가 가능
6. Fine-tuning: 커스텀 모델 관련 권한 설정 - None: 해당 api key로 접근할 경우, key 발급 주체가 되는 계정의 커스텀 모델에 접근할 수 없고, 커스텀 모델을 생성할 수 없다. - Read: 해당 api key로 접근할 경우, key 발급 주체가 되는 계정의 커스텀 모델에 접근할 수 있으나, 커스텀 모델을 생성할 수는 없다. - Write: 해당 api key로 접근할 경우, key 발급 주체가 되는 계정의 커스텀 모델에 접근할 수 있고, 커스텀 모델을 생성할 수도 있다
7. Files: 모델에게 파일 업로드 또는 파일 다운로드에 대한 권한 설정 - None: 해당 api key로 접근할 경우, 파일을 업로드하거나 이미 업로드된 파일을 다운로드할 수 없다. - Read: 해당 api key로 접근할 경우, 파일을 업로드할 수 없으나 이미 업로드된 파일을 다운로드할 수 있다. - Write: 해당 api key로 접근할 경우, 파일을 업로드할 수 있고 이미 업로드된 파일을 다운로드할 수 있다.
8. Responses API: 텍스트, 이미지, 오디오 응답을 한번에 출력할 수 있는 통합 인터페이스 권한 설정 (멀티 모달) - None: 해당 api key로 접근할 경우, 텍스트와 이미지 등을 동시에 명령할 수 없고 출력 결과도 복합 양식(예: 텍스트+이미지)으로 출력될 수 없다. - Read: 현재 실질적 동작은 거의 없음 (응답 로그/결과만 조회용으로 설계 중) - Write: 해당 api key로 접근할 경우, 텍스트와 이미지 등을 동시에 명령할 수 있고, 출력 결과도 복합 양식으로 출력될 수 있다.