RAG 자동생성 부터 챗봇 서비스 까지

✔️ "이젠 AI가 알아서 다 해줍니다." 자연어(채팅) 한마디로 '우리 회사 내부 문서' 기반의 RAG 챗봇 시스템을 A to Z까지 자동으로 구축하는 모든 과정을 공개합니다! LLM의 환각(Hallucination) 증상 때문에 AI 도입을 망설였거나, 사내 데이터를 기반으로 한 전문적인 답변을 원하셨나요? 데이터베이스 생성부터 문서 저장, 챗봇 UI 연동까지, 복잡했던 RAG 시스템 구축을 n8n 에이전트가 전부 대신해 드립니다. 이 영상 하나로, 코딩 지식 없이 나만의 지식 베이스 챗봇을 완성하고 웹사이트에 적용까지 해보세요.

May 14, 2025
 
✏️

핵심개념 정리 : RAG 엔지니어링

RAG(검색증강생성)는 LLM 챗봇과 대화 컨텍스트를 저장되어 있는 지식기반으로 강화하여 정화하고 최신의 정보를 바탕으로 답변을 할수 있도록 만드는 방법론입니다.
LLM 엔지니어링의 근간을 이루는 기술로,
개발자가 아닌 일반인들도 RAG를 n8n 워크플로만으로 쉽게 구축할수 있도록 정리했습니다.
다른 자료들과 다른점은, 여기서는 개념으로 이해하되, 기술 장벽을 최소화하기 위해 RAG를 만드는 MCP를 도입했습니다.
notion image
notion image
notion image
notion image
notion image
page icon

n8n 챗봇 플로팅 버튼 임베드 라이브러리 사용법

n8n-widget-bot
dandacompanyUpdated Oct 14, 2025
  • 라이브러리 코드 스니펫
<script src="https://cdn.jsdelivr.net/npm/n8n-widget-bot@latest/dist/n8n-widget-bot.min.js"></script> <script> document.addEventListener('DOMContentLoaded', function() { FloatingChatWidget.init({ themeColor: '#4C4CBBFF', title: '단테 지식베이스 챗봇', placeholder: '메세지를 입력하세요...', welcomeMessage: '안녕하세요! 무엇을 도와드릴까요?', position: 'bottom-right', fontFamily: 'Noto Sans KR, Arial, sans-serif', resizable: true, // Enable resize feature minWidth: 300, // Minimum width maxWidth: 600, // Maximum width minHeight: 400, // Minimum height maxHeight: 800, // Maximum height apiUrl: 'https://n8n.dantelabs.pro/webhook/7add635d-b495-453a-8da5-ad62a7040ff9/chat' // 변경하세요. }); }); </script>
  • 샘플 랜딩페이지 코드 (home.html)
    • 코드
      <!DOCTYPE html> <html lang="ko"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Dante Labs</title> <!-- FontAwesome CDN --> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> <style> * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; background: linear-gradient(180deg, #0a0e27 0%, #1a1f3a 100%); color: #fff; line-height: 1.6; overflow-x: hidden; } /* Navigation */ nav { position: fixed; top: 0; width: 100%; background: rgba(10, 14, 39, 0.95); backdrop-filter: blur(10px); z-index: 1000; padding: 1rem 0; box-shadow: 0 2px 20px rgba(0,0,0,0.3); } .nav-container { max-width: 1200px; margin: 0 auto; padding: 0 2rem; display: flex; justify-content: space-between; align-items: center; } .logo { font-size: 1.5rem; font-weight: bold; background: linear-gradient(45deg, #667eea 0%, #764ba2 100%); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; text-decoration: none; } .nav-links { display: flex; gap: 2rem; align-items: center; } .nav-links a { color: #fff; text-decoration: none; transition: color 0.3s; font-size: 0.95rem; } .nav-links a:hover { color: #667eea; } .contact-btn { background: linear-gradient(45deg, #667eea 0%, #764ba2 100%); padding: 0.5rem 1.5rem; border-radius: 25px; color: white !important; transition: transform 0.3s; } .contact-btn:hover { transform: translateY(-2px); box-shadow: 0 5px 15px rgba(102, 126, 234, 0.4); } /* Hero Section */ .hero { margin-top: 80px; padding: 4rem 2rem; min-height: 80vh; display: flex; align-items: center; position: relative; overflow: hidden; } .hero-container { max-width: 1200px; margin: 0 auto; width: 100%; position: relative; z-index: 2; } .hero-content { text-align: center; } .hero h1 { font-size: clamp(2.5rem, 5vw, 4rem); margin-bottom: 1.5rem; background: linear-gradient(45deg, #667eea 0%, #764ba2 100%); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; animation: fadeInUp 1s ease-out; } .hero-description { font-size: 1.2rem; margin-bottom: 2rem; opacity: 0.9; max-width: 700px; margin-left: auto; margin-right: auto; animation: fadeInUp 1s ease-out 0.2s; animation-fill-mode: backwards; } .cta-button { display: inline-block; background: linear-gradient(45deg, #667eea 0%, #764ba2 100%); color: white; padding: 1rem 2.5rem; border-radius: 30px; text-decoration: none; font-size: 1.1rem; font-weight: 500; transition: all 0.3s; animation: fadeInUp 1s ease-out 0.4s; animation-fill-mode: backwards; } .cta-button:hover { transform: translateY(-3px); box-shadow: 0 10px 30px rgba(102, 126, 234, 0.4); } /* Services Section */ .services { padding: 4rem 2rem; background: rgba(26, 31, 58, 0.5); } .section-title { text-align: center; font-size: 2.5rem; margin-bottom: 3rem; background: linear-gradient(45deg, #667eea 0%, #764ba2 100%); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; } .services-grid { max-width: 1200px; margin: 0 auto; display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 2rem; } .service-card { background: rgba(255, 255, 255, 0.05); padding: 2rem; border-radius: 15px; backdrop-filter: blur(10px); transition: transform 0.3s, box-shadow 0.3s; border: 1px solid rgba(255, 255, 255, 0.1); } .service-card:hover { transform: translateY(-5px); box-shadow: 0 15px 30px rgba(0, 0, 0, 0.3); background: rgba(255, 255, 255, 0.08); } .service-icon { font-size: 3rem; margin-bottom: 1rem; display: block; } .service-title { font-size: 1.3rem; margin-bottom: 1rem; color: #fff; } .service-description { color: rgba(255, 255, 255, 0.7); line-height: 1.6; } /* Stats Section */ .stats { padding: 4rem 2rem; background: linear-gradient(45deg, rgba(102, 126, 234, 0.1), rgba(118, 75, 162, 0.1)); } .stats-container { max-width: 1200px; margin: 0 auto; text-align: center; } .stats-intro { max-width: 700px; margin: 0 auto 3rem; } .stats-intro h2 { font-size: 2rem; margin-bottom: 1rem; } .stats-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 2rem; margin-top: 3rem; } .stat-item { padding: 1.5rem; } .stat-number { font-size: 2.5rem; font-weight: bold; background: linear-gradient(45deg, #667eea 0%, #764ba2 100%); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; margin-bottom: 0.5rem; } .stat-label { color: rgba(255, 255, 255, 0.7); } /* Customer Reviews */ .reviews { padding: 4rem 2rem; background: rgba(26, 31, 58, 0.3); } .reviews-container { max-width: 1200px; margin: 0 auto; } .reviews-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 2rem; } .review-card { background: rgba(255, 255, 255, 0.05); padding: 2rem; border-radius: 15px; backdrop-filter: blur(10px); border: 1px solid rgba(255, 255, 255, 0.1); } .review-header { display: flex; align-items: center; margin-bottom: 1rem; } .review-avatar { width: 50px; height: 50px; border-radius: 50%; background: linear-gradient(45deg, #667eea 0%, #764ba2 100%); margin-right: 1rem; display: flex; align-items: center; justify-content: center; font-weight: bold; } .review-text { color: rgba(255, 255, 255, 0.9); font-style: italic; margin-bottom: 1rem; } .review-stars { color: #ffd700; } /* CTA Section */ .cta-section { padding: 5rem 2rem; text-align: center; background: linear-gradient(45deg, rgba(102, 126, 234, 0.2), rgba(118, 75, 162, 0.2)); } .cta-section h2 { font-size: 2.5rem; margin-bottom: 1rem; background: linear-gradient(45deg, #667eea 0%, #764ba2 100%); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; } .cta-section p { font-size: 1.2rem; margin-bottom: 2rem; color: rgba(255, 255, 255, 0.9); } /* Footer */ footer { padding: 2rem; text-align: center; background: rgba(10, 14, 39, 0.95); color: rgba(255, 255, 255, 0.6); } /* Animations */ @keyframes fadeInUp { from { opacity: 0; transform: translateY(30px); } to { opacity: 1; transform: translateY(0); } } /* Background Animation */ .hero::before { content: ''; position: absolute; top: 0; left: 0; width: 100%; height: 100%; background-image: radial-gradient(circle at 20% 50%, rgba(102, 126, 234, 0.2) 0%, transparent 50%), radial-gradient(circle at 80% 50%, rgba(118, 75, 162, 0.2) 0%, transparent 50%); animation: pulse 15s ease-in-out infinite; } @keyframes pulse { 0%, 100% { opacity: 0.5; transform: scale(1); } 50% { opacity: 0.8; transform: scale(1.1); } } /* Mobile Responsive */ @media (max-width: 768px) { .nav-links { display: none; } .mobile-menu { display: block; } .hero h1 { font-size: 2rem; } .hero-description { font-size: 1rem; } .services-grid, .reviews-grid { grid-template-columns: 1fr; } .stats-grid { grid-template-columns: repeat(2, 1fr); } } /* Scroll Animation */ .scroll-animate { opacity: 0; transform: translateY(30px); transition: opacity 0.6s, transform 0.6s; } .scroll-animate.visible { opacity: 1; transform: translateY(0); } </style> </head> <body> <!-- Navigation --> <nav> <div class="nav-container"> <a href="#" class="logo">Dante Labs</a> <div class="nav-links"> <a href="#">Home</a> <a href="#">Profile</a> <a href="#">Resources</a> <a href="#">Classes</a> <a href="#" class="contact-btn">Contact</a> </div> </div> </nav> <!-- Hero Section --> <section class="hero"> <div class="hero-container"> <div class="hero-content"> <h1>Dante Labs: AI automation</h1> <p class="hero-description"> Discover the potential of intelligent agents that make your daily life easier.<br> From the concept and practical use of MCP to the latest trends in AI - Dante Labs delivers it all in a fun and easy-to-understand way. </p> <a href="#" class="cta-button">Get Started</a> </div> </div> </section> <!-- Services Section --> <section class="services"> <h2 class="section-title">Technology & Services</h2> <div class="services-grid"> <div class="service-card scroll-animate"> <span class="service-icon">📚</span> <h3 class="service-title">Fullstack Reference</h3> <p class="service-description">Hands-on examples with Python, TypeScript, serverless, and more</p> </div> <div class="service-card scroll-animate"> <span class="service-icon">💻</span> <h3 class="service-title">Open Source Templates</h3> <p class="service-description">Sample repositories integrating LangChain, OpenAI, Claude</p> </div> <div class="service-card scroll-animate"> <span class="service-icon">👥</span> <h3 class="service-title">Code Review & Q&A</h3> <p class="service-description">Accelerate your growth with community feedback</p> </div> <div class="service-card scroll-animate"> <span class="service-icon">🎓</span> <h3 class="service-title">MCP Lectures & Workshops</h3> <p class="service-description">Concept lectures for beginners, advanced hands-on for professionals</p> </div> <div class="service-card scroll-animate"> <span class="service-icon">🤝</span> <h3 class="service-title">Consulting & Partnership</h3> <p class="service-description">Agent design and automation consulting, in-house training programs</p> </div> <div class="service-card scroll-animate"> <span class="service-icon">📖</span> <h3 class="service-title">Custom Curriculum</h3> <p class="service-description">Understand → Apply → Expand, a 3-step curriculum</p> </div> </div> </section> <!-- Stats Section --> <section class="stats"> <div class="stats-container"> <div class="stats-intro"> <h2>Real-World Automation Journey with Dante Labs</h2> <p>Sharing 15 years of practical experience from major enterprises!</p> <p>💠 Lecturing experience at Inflearn, Visang Education, Kookmin University, and more</p> <p>No more theory-only lectures. Learn living automation you can use right away in the field.</p> </div> <div class="stats-grid"> <div class="stat-item scroll-animate"> <div class="stat-number">7.5K+</div> <div class="stat-label">Subscribers</div> </div> <div class="stat-item scroll-animate"> <div class="stat-number">15 Year+</div> <div class="stat-label">Industry Experience</div> </div> <div class="stat-item scroll-animate"> <div class="stat-number">1.4M</div> <div class="stat-label">Views</div> </div> <div class="stat-item scroll-animate"> <div class="stat-number">4.8+</div> <div class="stat-label">Student Rating</div> </div> </div> </div> </section> <!-- Customer Reviews --> <section class="reviews"> <div class="reviews-container"> <h2 class="section-title">Customers Say About Us</h2> <div class="reviews-grid"> <div class="review-card scroll-animate"> <div class="review-header"> <div class="review-avatar">Y</div> <div class="review-name">Y*ho</div> </div> <p class="review-text">"Explaining the MCP concept with real-world examples helped our entire dev team level up."</p> <div class="review-stars">⭐⭐⭐⭐⭐</div> </div> <div class="review-card scroll-animate"> <div class="review-header"> <div class="review-avatar">P</div> <div class="review-name">P*jun</div> </div> <p class="review-text">"Thanks to Dante Labs, I built a data pipeline in just 3 hours."</p> <div class="review-stars">⭐⭐⭐⭐⭐</div> </div> <div class="review-card scroll-animate"> <div class="review-header"> <div class="review-avatar">K</div> <div class="review-name">K*yeon</div> </div> <p class="review-text">"Even as a developer, learning marketing automation gave me a new perspective. The n8n and Claude integration was especially impressive!"</p> <div class="review-stars">⭐⭐⭐⭐⭐</div> </div> </div> </div> </section> <!-- CTA Section --> <section class="cta-section"> <h2>Ready to level up your AI automation skills?</h2> <p>Stop wasting time on repetitive tasks tomorrow, next week, or next month.<br> Dante Labs will help you level up your AI automation!</p> <a href="#" class="cta-button">Contact Us</a> </section> <!-- Footer --> <footer> <p>© 2025 dante-labs. All rights reserved.</p> </footer> <script> // Smooth scrolling for navigation links document.querySelectorAll('a[href^="#"]').forEach(anchor => { anchor.addEventListener('click', function (e) { e.preventDefault(); const target = document.querySelector(this.getAttribute('href')); if (target) { target.scrollIntoView({ behavior: 'smooth' }); } }); }); // Scroll animations const observerOptions = { threshold: 0.1, rootMargin: '0px 0px -50px 0px' }; const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { entry.target.classList.add('visible'); } }); }, observerOptions); // Observe all elements with scroll-animate class document.querySelectorAll('.scroll-animate').forEach(el => { observer.observe(el); }); // Counter animation for stats function animateValue(element, start, end, duration) { let startTimestamp = null; const step = (timestamp) => { if (!startTimestamp) startTimestamp = timestamp; const progress = Math.min((timestamp - startTimestamp) / duration, 1); const value = Math.floor(progress * (end - start) + start); element.textContent = element.dataset.suffix ? value + element.dataset.suffix : value; if (progress < 1) { window.requestAnimationFrame(step); } }; window.requestAnimationFrame(step); } // Animate stats when they come into view const statsObserver = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting && !entry.target.animated) { entry.target.animated = true; const statNumbers = entry.target.querySelectorAll('.stat-number'); statNumbers.forEach(stat => { const text = stat.textContent; if (text.includes('K')) { const value = parseFloat(text) * 1000; stat.dataset.suffix = '+'; animateValue(stat, 0, value / 1000, 2000); setTimeout(() => { stat.textContent = text; }, 2100); } else if (text.includes('M')) { stat.textContent = text; } else if (text.includes('Year')) { stat.textContent = text; } else if (text.includes('+')) { stat.textContent = text; } }); } }); }, { threshold: 0.5 }); document.querySelectorAll('.stats-grid').forEach(el => { statsObserver.observe(el); }); // Parallax effect for hero section window.addEventListener('scroll', () => { const scrolled = window.pageYOffset; const parallax = document.querySelector('.hero'); if (parallax) { parallax.style.transform = `translateY(${scrolled * 0.5}px)`; } }); // Add hover effect to service cards document.querySelectorAll('.service-card').forEach(card => { card.addEventListener('mouseenter', function() { this.style.transform = 'translateY(-10px) scale(1.02)'; }); card.addEventListener('mouseleave', function() { this.style.transform = 'translateY(0) scale(1)'; }); }); </script> </body> </html>
page icon

webhook 주소를 커스텀 도메인으로 변경하는 방법

  • duckdns.org 또는 Desec.io 를 이용해서 무료 도메인을 발급받습니다.(유료도메인이 있다면 더 좋습니다)
    • Desec.io의 경우 공인ip주소를 입력 A 레코드를 생성하고 저장합니다. 서브도메인을 사용해도 됩니다. 비워두면 루트 도메인을 그대로 사용합니다.
    • duckdns.org의 경우 공인ip주소를 입력하고 update ip 버튼을 누릅니다.
    •  
  • caddy 를 사용해서 호스팅 중이라면, 아래 예시처럼 작성합니다.
    • sudo -i # 루트 사용자로 변경 nano /etc/caddy/Caddyfile # 나노 편집기 실행
      # 가장 아래 부분에 이 스니펫을 추가합니다. dantelabs-pro.duckdns.org { # 발급받은 유/무료 도메인 주소 기재 @root path / route { rewrite @root /webhook/home # 웹훅 주소에서 경로 부분만 기재 reverse_proxy 127.0.0.1:5670 { header_up X-Forwarded-Proto {scheme} header_up X-Forwarded-Host {host} header_up X-Forwarded-For {remote} } } }
  • caddy 재실행
    • systemctl reload caddy