나만의 AI 챗봇 만들기
— 웹 검색 + Gradio
이 실습이 끝나면 웹 검색이 가능한 나만의 AI 챗봇이 생긴다. 코드를 직접 작성하지 않고(바이브코딩) 5단계로 기본 챗봇 → 웹 검색 → 스마트 판단 → UI 완성 → HuggingFace Space 배포까지 완주한다.
전체 흐름과 준비
5단계로 챗봇을 완성한다. 웹 검색 챗봇의 구조는 앞 장에서 만든 RAG와 정확히 같다 — 검색 담당이 벡터 DB에서 DuckDuckGo로 바뀔 뿐이다.
기본 챗봇에서 배포까지, 다섯 단계
각 단계는 앞 단계의 한계를 발견하고 그것을 해결하며 나아간다. 코드는 AI에게 요청해서 만들고, 우리는 구조를 이해하고 확인한다.
| 단계 | 내용 | 해결하는 문제 |
|---|---|---|
| Step 1 🔵 | 기본 챗봇 — gr.ChatInterface + HF LLM 연결 | 채팅 UI와 대화 맥락의 뼈대 |
| Step 2 🟡 | 웹 검색 연결 — DuckDuckGo 검색 결과를 답변에 활용 | 학습 데이터 이후의 최신 정보를 모른다 |
| Step 3 🟢 | 스마트 검색 — 검색 필요 여부를 AI가 스스로 판단 | 계산 문제에도 검색이 돌아가는 낭비 |
| Step 4 🟣 | UI 완성 — 출처 표시, 시스템 프롬프트, 모드 선택 | 출처 신뢰성과 챗봇 성격 커스터마이징 |
| Step 5 🏆 | 배포 — HuggingFace Space에 올려서 공유 | 내 PC 밖에서도 쓸 수 있게 |
웹 검색 챗봇 = RAG와 동일한 구조
질문 → DuckDuckGo 검색 → 결과 5개 수집 → LLM 프롬프트에 삽입 → 답변 생성. 이 파이프라인은 앞 장의 RAG와 동일한 구조다. 벡터 DB 대신 DuckDuckGo가 검색을 담당한다.
앞 장(RAG 타로)에서 문서를 벡터 DB에 넣고 유사한 조각을 찾아 프롬프트에 붙였다. 이번 장은 그 "검색" 자리를 웹 검색 엔진이 대신한다. LLM에 지식을 주입하는 방법은 결국 하나 — 프롬프트에 참고자료를 넣어 주는 것 — 이고, 그 자료를 어디서 가져오느냐(내 문서 vs 실시간 웹)만 다르다는 것을 확인하는 것이 이 장의 핵심 관점이다.
실습 준비물 세 가지
폴더 하나, 라이브러리 설치 한 줄, HF 토큰. 이 세 가지면 시작할 수 있다.
- 작업 폴더 my_chatbot을 만든다.
- 라이브러리를 설치한다.
- HF 토큰을 준비한다 (HuggingFace Inference API 호출에 사용).
pip install gradio huggingface_hub duckduckgo-search -q
- my_chatbot 폴더 생성 완료
- 세 라이브러리 설치 오류 없음
- HF 토큰 확보
gr.ChatInterface로 챗봇 뼈대 세우기
Gradio 내장 채팅 UI에 HF LLM을 연결한다. 이 단계가 끝나면 맥락을 기억하는 한국어 챗봇이 돌아간다.
fn(message, history) 하나면 채팅 앱이 된다
gr.ChatInterface는 Gradio의 내장 채팅 UI다. 입력창·전송 버튼·대화 기록이 자동으로 구성되고, 우리는 fn(message, history) → 응답 반환 함수 하나만 만들면 된다.
핵심은 history다. 이전 대화 기록을 LLM에 함께 전달하면 챗봇이 이전 맥락을 기억한다. 전달하지 않으면 매 턴이 첫 대화가 된다.
Gradio gr.ChatInterface로 AI 챗봇을 만들어줘. 조건: - HuggingFace Inference API 사용 (모델: Qwen/Qwen3-8B) - HF_TOKEN은 환경변수에서 로드, 없으면 앱 실행 시 입력창 표시 - 대화 히스토리를 LLM에 전달해서 이전 맥락 유지 (최근 5턴까지만 전달) - 시스템 프롬프트: "당신은 친절한 AI 어시스턴트입니다. 한국어로 답변하세요." - gr.ChatInterface 설정: title "🤖 AI 어시스턴트", description "무엇이든 물어보세요", retry/undo/clear 버튼 표시 파일명: app.py
python app.py
확인 포인트
- 브라우저에 채팅 UI가 열린다
- 한국어로 답변한다
- "방금 말한 거 다시 설명해줘" → 이전 맥락을 유지한다
이 챗봇에게 "오늘 NVIDIA 주가 어때?"라고 물어보면 어떻게 될까. LLM은 학습 데이터 기준으로만 답하므로 최신 정보를 모른다. 이 한계가 다음 단계 — 웹 검색 연결 — 로 이어진다.
모든 질문에 DuckDuckGo 검색 붙이기
실시간 검색 결과를 [참고자료]로 프롬프트 앞에 삽입한다. 이제 챗봇이 오늘의 뉴스에 답한다.
검색 결과를 프롬프트 앞에 붙인다
duckduckgo-search로 실시간 검색을 하고, 결과(제목+URL+요약)를 [참고자료]로 프롬프트 앞에 삽입한다.
예를 들어 "TSMC 오늘 주가 왜 올랐어?"라고 물으면 ① 이 질문으로 검색하고 ② 결과를 수집한 뒤(Reuters, Bloomberg…) ③ [참고자료]+질문 형태의 프롬프트를 만들어 ④ 답변을 생성한다.
app.py에 DuckDuckGo 웹 검색 기능을 추가해줘.
조건:
- duckduckgo_search 라이브러리의 DDGS().text() 사용
- 사용자 메시지로 검색, max_results=5
- 검색 결과를 "[웹 검색 결과] 1. {title} - {url} {body} ..." 형식으로 프롬프트 앞에 삽입,
"위 검색 결과를 참고해서 다음 질문에 답하세요. 출처 URL을 답변 마지막에 표시하세요."
- 검색 실패 시 검색 없이 LLM만으로 답변 (오류 표시 없이 자연스럽게)
- 채팅 UI 하단에 "🔍 검색 중..." 상태 표시 후 답변으로 교체
테스트해 볼 질문
- "NVIDIA 오늘 뉴스 알려줘"
- "삼성전자 최근 반도체 현황은?"
- "오늘 날씨 어때?"
이제 "2+2는?" 같은 단순 계산에도 검색이 돌아간다. 검색이 필요 없는 질문까지 매번 검색하는 낭비가 생겼다. 필요할 때만 검색하게 만드는 것이 다음 단계다.
검색할지 말지, AI가 스스로 판단한다
답변 전에 LLM에게 먼저 "이 질문이 검색이 필요한가?"를 묻는다. YES/NO 한 단어 판단으로 파이프라인이 갈라진다.
판단 프롬프트로 분기하는 파이프라인
LLM에게 먼저 "이 질문이 검색이 필요한가?"를 판단시킨다. 검색이 필요한 질문은 최신 뉴스·시세·날씨·이벤트, 불필요한 질문은 개념 설명·계산·번역·코드·일반 지식이다.
흐름은 이렇다. 질문 → 판단 프롬프트("최신 정보 필요하면 YES 아니면 NO만") → YES면 검색 후 답변, NO면 바로 답변.
app.py에 검색 필요 여부를 AI가 판단하는 기능을 추가해줘.
- 판단 프롬프트: "다음 질문에 답하려면 최신 뉴스, 실시간 데이터, 오늘 날짜 기준 정보가 필요한가요? YES 또는 NO 한 단어만 답하세요. 질문: {message}"
- YES면 DuckDuckGo 검색 후 결과 포함 답변 / NO면 바로 답변
- 답변 상단 표시: 검색 시 "🔍 웹 검색 후 답변" / 미검색 시 "💬 직접 답변"
- 판단 오류 시 기본적으로 검색 실행
확인 포인트 — 두 그룹으로 나눠 테스트
- 검색해야 하는 질문: "NVIDIA 오늘 주가" / "지금 비트코인 얼마야?" / "삼성 최근 인사 발표"
- 검색 불필요한 질문: "반도체가 뭐야?" / "123×456은?" / "파이썬 정렬 방법"
- 답변 상단에 🔍 / 💬 표시가 질문 성격에 맞게 갈라진다
LLM을 답변 생성기가 아니라 판단기(분류기)로 한 번 더 쓰는 패턴이다. "YES 또는 NO 한 단어만"처럼 출력 형식을 강하게 제약하면 LLM의 출력이 코드의 분기 조건으로 쓰일 수 있다. 판단이 애매하면 기본적으로 검색을 실행하게 한 것도 눈여겨보라 — 오판의 비용(불필요한 검색 한 번)이 반대의 비용(틀린 최신 정보)보다 싸기 때문이다.
출처, 설정, 그리고 페르소나
출처를 클릭 가능한 링크로 바꾸고 설정 패널을 단다. 시스템 프롬프트 한 줄이 챗봇의 성격을 통째로 바꾼다.
시스템 프롬프트 = 챗봇의 페르소나
이 단계에서 세 가지를 완성한다. 출처를 클릭 가능한 링크로, 시스템 프롬프트 설정창, 검색 모드 토글(항상/자동/안함).
특히 주목할 것은 시스템 프롬프트다. 같은 모델, 같은 코드라도 시스템 프롬프트만 바꾸면 챗봇의 성격이 완전히 달라진다.
| 시스템 프롬프트 | 챗봇의 성격 |
|---|---|
| 기본 | "친절한 AI 어시스턴트" — 누구에게나 무난한 범용 답변 |
| 반도체 전문가 | "15년 경력 반도체 산업 애널리스트. 기술 용어·수치 중심" — 전문 분석가처럼 답변 |
프롬프트만 바꾸면 챗봇 성격이 달라진다. 코드도, 모델도, 데이터도 그대로인데 페르소나가 바뀐다 — 이것이 이 단계의 핵심 포인트다.
app.py UI를 완성형으로 업그레이드해줘. 1. 출처 링크: 답변 하단 "📎 출처: [Reuters](url) | [Bloomberg](url)" 2. 사이드바 설정 패널 (gr.Accordion): 시스템 프롬프트 textarea / 검색 모드 라디오(🤖 자동 판단(기본), 🔍 항상 검색, 💬 검색 안 함) / 검색 결과 수 슬라이더(1~10, 기본 5) / 모델 선택 드롭다운(Qwen3-8B, Qwen3-4B-Instruct-2507, Mistral-7B-Instruct-v0.3) 3. 대화 내보내기: [대화 저장] 버튼 → txt 다운로드
확인 포인트
- 출처 링크가 클릭된다
- 시스템 프롬프트를 바꾸면 답변 스타일에 반영된다
- "항상 검색" 모드가 동작한다
- 모델을 바꾸면 답변 스타일이 달라진다
- [대화 저장] 버튼으로 txt가 다운로드된다
시스템 프롬프트를 "설정창"으로 꺼낸 순간, 챗봇은 하나의 앱이 아니라 페르소나 갈아끼우기가 가능한 플랫폼이 된다. 반도체 애널리스트, 법률 상담가, 고객센터 상담원 — 같은 코드에 프롬프트만 바꿔 끼우면 된다. 다음 장에서 이 원리를 그대로 사용해 "OO전자 사내 규정 전문 챗봇"을 만든다.
HuggingFace Space에 올려서 공유하기
파일 두 개를 업로드하면 자동으로 빌드된다. URL 하나로 스마트폰에서도, 팀원과 동시에도 쓸 수 있다.
app.py와 requirements.txt, 두 파일이면 끝
배포에 필요한 것은 폴더 안의 두 파일뿐이다.
my_chatbot/ ├── app.py └── requirements.txt (gradio, huggingface_hub, duckduckgo-search)
- huggingface.co 접속 → New Space 클릭
- SDK: Gradio 선택 → 생성
- Settings → Variables and secrets에 HF_TOKEN 추가
- Files 탭에 app.py · requirements.txt 업로드
- 자동 빌드 완료를 기다린 뒤 Space URL 공유 (Public/Private 선택)
확인 포인트
- Space URL로 접속된다
- 스마트폰에서도 접속된다
- 팀원과 동시에 사용해도 동작한다
토큰을 코드에 넣지 않고 Variables and secrets에 넣는 이유를 기억하라. Space의 Files 탭은 공개될 수 있으므로, 코드에 토큰을 하드코딩하면 누구나 내 토큰을 볼 수 있다. Step 1에서 "HF_TOKEN은 환경변수에서 로드"로 요청해 둔 것이 배포 단계에서 그대로 효력을 발휘한다.
완성 기능 정리와 확장 아이디어
다섯 단계로 쌓아 올린 기능 목록을 확인하고, 다음에 붙일 수 있는 확장 방향을 본다.
지금 내 챗봇이 할 수 있는 것
여기서 더 나아가려면
- 반도체 뉴스 DB 연결 — Supabase 기사도 함께 검색하는 웹 + RAG 혼합 구조.
- PDF 업로드 — 문서 기반 대화.
- 이미지 입력 — 차트 분석.
- 음성 입력 — gr.Audio.
하나. 웹 검색 챗봇은 RAG와 동일한 구조다. 검색 결과를 프롬프트에 삽입해 답하게 하는 "검색 → 증강 → 생성"에서, 검색 담당만 벡터 DB에서 DuckDuckGo로 바뀌었다.
둘. LLM은 답변 생성기이자 판단기다. "YES/NO 한 단어만" 같은 제약 프롬프트로 LLM의 출력을 코드의 분기 조건으로 쓸 수 있다.
셋. 시스템 프롬프트가 곧 페르소나다. 코드·모델·데이터를 그대로 두고 프롬프트만 바꾸면 챗봇의 성격이 달라진다.
시스템 프롬프트로 페르소나가 바뀐다는 이 포인트가 그대로 다음 장으로 이어진다 — 다음 장에서는 같은 챗봇 뼈대에 "OO전자 사내 규정 전문가" 페르소나와 규정 문서를 얹어 사내 규정 챗봇을 만든다.
출처 원본 노션 실습 자료: 나만의 AI 챗봇 만들기 (웹 검색 + Gradio)
이 자료는 단일 HTML 파일로 배포되는 실습 가이드다. 프롬프트 블록의 [복사] 버튼으로 AI 요청문을 그대로 복사해 사용하라.