AI 블로그 완성기(2)- 삽질의 연속...
AI 요약
본 블로그 포스트는 RAG 챗봇 개발 과정에서 발생하는 삽질 문제들을 다룹니다. 로컬 LLM의 한계, 프롬프트 엔지니어링 제한, 한국어 응답에 대한 중국어 혼동 등 여러 가지 삽질을 통해 모델의 성능과 사용자 경험에 대한 개선 방안을 제시합니다. 특히, 시스템 프롬프트를 활용하여 삽질 문제를 해결하고, 검색 정확도 향상 및 응답 속도 개선을 위한 노력이 강조됩니다. 또한, 앞으로의 계획과 포트폴리오 블로그 개발에 대한 의견을 제시하며, 완벽하지 않지만 실제로 사용하는 것을 통해 발전할 수 있다는 점을 강조합니다.
AI 블로그 완성기(2)- 삽질의 연속...
이전 편에서는 포트폴리오 블로그에 RAG 챗봇을 기획하고 구현하는 과정을 다뤘습니다. 아키텍처도 깔끔하게 설계했고, 코드도 잘 돌아갔습니다.
문제는 "잘 돌아가는 것"과 "잘 작동하는 것"이 다르다는 걸 깨달은 이후부터였습니다.
삽질 1: 로컬 LLM의 환각 (Hallucination)
qwen2.5:7b 모델은 기본적인 대화 능력은 괜찮았지만, RAG 컨텍스트를 벗어나는 질문에 대해서는 자신 있게 거짓말을 했습니다.
사용자: "Gats는 어떤 회사에서 일했나요?"
챗봇: "Gats는 네이버에서 3년간 AI 엔지니어로 근무했습니다."
블로그 어디에도 없는 정보를 만들어냅니다. 7B 모델의 한계이기도 하고, 시스템 프롬프트만으로 환각을 완전히 억제하기는 어렵다는 걸 체감했습니다.
대응 방법
시스템 프롬프트에 강력한 제약을 추가했습니다.
"주어진 컨텍스트에 없는 정보는 절대 만들어내지 마세요.
모르면 '해당 정보는 블로그에서 찾을 수 없습니다'라고 답하세요."
완전히 해결되지는 않았지만 빈도가 크게 줄었습니다. 결국 모델 크기의 한계라서, 프롬프트 엔지니어링으로 커버할 수 있는 범위에는 한계가 있었습니다.
삽질 2: 한국어 응답에 중국어가 섞이는 문제
이건 정말 당황스러웠습니다. 한국어로 질문하면 응답 중간에 갑자기 중국어 문자가 등장합니다.
"이 블로그는 AI 엔지니어의 포트폴리오로서 各种 프로젝트를 소개하고 있습니다."
qwen2.5는 중국 Alibaba에서 개발한 모델이라 중국어 학습 데이터의 비중이 높습니다. 한국어와 중국어가 유사한 한자 기반이다 보니 모델이 가끔 혼동하는 것으로 보입니다.
대응 방법
응답 후처리로 CJK 문자를 필터링하는 정규식을 적용했습니다.
// 중국어/일본어 문자 필터링
const filtered = response.replace(
/[\u4e00-\u9fff\u3040-\u309f\u30a0-\u30ff]/g,
''
);
단순한 해결책이지만 효과적이었습니다. 다만 한자를 의도적으로 사용해야 하는 맥락에서는 문제가 될 수 있어서, 장기적으로는 한국어에 더 강한 모델로 교체하는 게 맞다고 생각합니다.
삽질 3: 청킹 전략의 시행착오
처음에는 단순히 글자 수(500자)로 잘랐습니다. 결과는 처참했습니다.
-
문장 중간에서 잘리는 청크
-
코드 블록이 반으로 쪼개지는 청크
-
제목과 본문이 다른 청크에 들어가는 경우
검색 품질이 떨어지니 챗봇 응답도 엉뚱해졌습니다.
개선 과정
-
마크다운 구조 인식: 헤딩(##) 단위로 먼저 분할
-
최소/최대 길이 설정: 200~500자 범위로 조정
-
컨텍스트 주입: 각 청크에 원본 포스트 제목을 prefix로 추가
-
코드 블록 보호: 코드 블록은 분할하지 않고 통째로 하나의 청크로 처리
이 개선만으로 검색 정확도가 체감상 크게 올라갔습니다.
삽질 4: 응답 속도
7B 모델이라 가벼울 거라 기대했지만, CPU 환경에서의 추론 속도는 생각보다 느렸습니다.
| 환경 | 첫 토큰까지 | 전체 응답 |
|---|---|---|
| GPU (RTX 3060) | ~1초 | ~5초 |
| CPU (서버) | ~5초 | ~20초 |
포트폴리오 블로그 서버에는 GPU가 없습니다. 20초를 기다리는 사용자는 없을 겁니다.
대응 방법
-
스트리밍 필수: 전체 응답을 기다리지 않고 토큰 단위로 즉시 표시
-
응답 길이 제한:
num_predict: 400으로 최대 토큰 수 제한 -
Temperature 낮추기: 0.1로 설정해 불필요한 탐색 줄이기
-
타이핑 애니메이션: 1.5초 딜레이 + 20ms 타이핑으로 체감 대기 시간 완화
완전한 해결은 아니지만, UX 관점에서 "참을 수 있는 수준"까지는 개선했습니다.
배운 점
1. 로컬 LLM은 "가능하다"와 "실용적이다" 사이에 큰 간극이 있다
Ollama로 7B 모델을 돌리는 건 기술적으로 가능합니다. 하지만 프로덕션 수준의 품질을 기대하기는 어렵습니다. 포트폴리오 챗봇처럼 제한된 도메인 + 낮은 트래픽 환경에서는 쓸 만하지만, 범용적인 서비스에는 부적합합니다.
2. 프롬프트 엔지니어링의 한계
시스템 프롬프트로 모델의 행동을 제어할 수 있지만, 모델 자체의 능력을 넘어서는 제어는 불가능합니다. 7B 모델에게 GPT-4 수준의 판단력을 기대하는 건 무리입니다.
3. 그래도 직접 해봐야 안다
이 모든 삽질이 "로컬 LLM은 이런 거구나"를 체감하게 해줬습니다. 블로그 글이나 유튜브 영상으로는 알 수 없는 감각입니다. 모델의 한계를 직접 경험했기 때문에, 앞으로 프로젝트에서 어떤 LLM을 선택해야 할지 판단하는 기준이 생겼습니다.
4. 완벽하지 않아도 괜찮다
이 챗봇은 완벽하지 않습니다. 가끔 엉뚱한 답을 하고, 느리고, 한계가 명확합니다. 하지만 그 불완전함 자체가 포트폴리오의 일부입니다. "로컬 LLM으로 이 정도까지 할 수 있다"는 것, 그리고 "한계를 인지하고 있다"는 것을 보여주는 게 오히려 더 솔직하고 설득력 있는 포트폴리오라고 생각합니다.
앞으로의 계획
-
한국어에 특화된 더 나은 모델 탐색 (예: EXAONE, SOLAR)
-
청크 검색에 키워드 기반 하이브리드 검색 추가
-
사용자 질문 패턴 분석을 통한 FAQ 자동 생성
-
GPU 서버 확보 시 모델 업그레이드
불완전한 시스템이지만, 그래서 더 발전시킬 여지가 많습니다. 다음에 의미 있는 개선이 이루어지면 후속편으로 돌아오겠습니다.
댓글 (0)
아직 댓글이 없습니다.