Contents
see ListRAG가 답을 못 찾는 이유는 모델보다 검색 단계에 있는 경우가 많다
사내 문서, 매뉴얼, 규정처럼 자주 바뀌는 정보를 LLM에 연결할 때 RAG(Retrieval-Augmented Generation)를 사용한다. 기본 구조는 문서를 작게 나누어 임베딩하고, 질문과 가까운 조각을 검색한 뒤 그 내용만 모델에 전달하는 방식이다. 그러나 단순히 PDF를 일정 글자 수로 잘라 벡터 DB에 넣으면 검색 결과가 문맥을 잃거나, 비슷하지만 다른 부서의 문서가 섞여 답변 신뢰도가 낮아진다.
품질을 높이는 순서는 모델 교체가 아니라 문서 정규화, 청크 설계, 메타데이터 필터, 검색 재순위화, 근거 검증이다. 각 단계가 분리되어 있어야 특정 질문에서 왜 잘못된 답이 나왔는지 추적하고 개선할 수 있다.
1. 청크는 고정 글자 수보다 의미 단위로 나눈다
청크가 너무 크면 하나의 벡터에 여러 주제가 섞여 검색 정확도가 떨어진다. 너무 작으면 답변에 필요한 조건과 예외가 서로 다른 청크로 흩어진다. 먼저 문서의 제목, 소제목, 표, 목록, 코드 블록을 구조적으로 추출하고, 같은 절 안에서 문단 단위로 묶는다. 일반 안내 문서는 400~800 토큰 수준에서 시작하고, 앞뒤 문맥을 10~20% 겹치게 두는 방식이 실무적으로 다루기 쉽다.
다만 숫자 기준을 절대 규칙으로 쓰면 안 된다. 계약 조건, 장애 대응 절차, API 파라미터처럼 문장 하나의 정확성이 중요한 내용은 항목 전체를 하나의 청크로 유지해야 한다. 청크에는 원문만 넣지 말고 문서 제목과 절 제목을 앞에 붙여 임베딩하면 질문과 문서의 관계가 더 선명해진다.
function makeChunk(documentTitle, sectionTitle, body, sourceUrl) { return { text: `[문서] ${documentTitle} [절] ${sectionTitle} ${body}`, metadata: { sourceUrl, documentTitle, sectionTitle, updatedAt: '2026-08-10', accessLevel: 'internal' } }; }2. 메타데이터는 필터와 인용을 위해 설계한다
벡터 유사도만으로 검색하면 오래된 정책, 폐기된 제품, 권한이 다른 조직의 문서가 함께 나올 수 있다. 모든 청크에 문서 ID, 문서 유형, 부서, 제품, 버전, 게시일, 갱신일, 상태, 권한 범위를 저장한다. 검색 전에는 사용자 조직과 접근 권한으로 필터링하고, 검색 후에는 최신 버전과 활성 상태를 확인한다.
특히 운영 규정은 유효 시작일과 종료일을 별도 필드로 둔다. 단순한 updatedAt 정렬만으로는 예약된 정책 변경이나 과거 기준 조회를 안전하게 처리할 수 없다. 답변 화면에는 문서 제목, 절 제목, 갱신일, 원문 링크를 함께 표시해 사용자가 근거를 직접 확인할 수 있게 한다.
3. 1차 벡터 검색 뒤에 재순위화를 둔다
벡터 검색은 의미가 비슷한 후보를 빠르게 찾는 데 적합하지만, 질문의 핵심 조건을 모두 반영하지 못할 수 있다. 예를 들어 운영 환경에서 API 키를 교체하는 절차라는 질문에 개발용 키 발급 안내가 더 가깝게 잡힐 수 있다. 그래서 1차로 넓게 20개 정도를 가져오고, 질문과 청크를 함께 읽는 재순위화 모델 또는 규칙으로 상위 5개를 다시 고른다.
const candidates = await vectorStore.search({ query: userQuestion, topK: 20, filter: { accessLevel: user.accessLevel, status: 'active' } }); const ranked = await reranker.rank({ query: userQuestion, documents: candidates.map((item) => item.text) }); const contexts = ranked.slice(0, 5).map((item) => candidates[item.index]);재순위화 비용이 부담되면 모든 질문에 적용하지 말고, 검색 점수 차이가 작거나 답변 실패 이력이 많은 문서 유형에만 적용할 수 있다. 제품명, 버전, 오류 코드처럼 정확한 문자열이 중요한 질문은 키워드 검색(BM25) 결과와 벡터 검색 결과를 함께 합치는 하이브리드 검색도 효과적이다.
4. 생성 단계에는 답변 범위를 명확히 제한한다
모델에게 모르면 모른다고 답하라고만 지시하는 것으로는 부족하다. 전달한 문맥 안에서만 답하고, 근거 청크별 인용을 붙이며, 필요한 절차나 수치가 문맥에 없으면 추가 확인을 요청하도록 출력 형식을 강제해야 한다. 문맥 간 내용이 충돌하면 최신 문서 또는 명시적으로 우선순위가 높은 문서를 선택하게 하고, 그 판단 근거도 남긴다.
운영 환경에서는 검색된 청크 ID, 검색 점수, 재순위 점수, 최종 인용, 사용자 피드백을 로그로 저장한다. 이 로그는 개인정보와 비밀값을 제거한 뒤 품질 평가에 사용한다. 질문 세트별로 정답 근거가 상위 5개 안에 들어오는 비율과, 근거 없는 답변 비율을 측정하면 변경 효과를 비교할 수 있다.
배포 전 체크리스트
- 문서 구조를 보존한 청크와 제목·절 정보를 함께 임베딩했는가
- 권한, 상태, 버전, 유효 기간 메타데이터를 검색 필터에 적용했는가
- 벡터 검색 후보에 재순위화 또는 키워드 검색 결합을 적용했는가
- 답변마다 사용한 원문 근거를 인용하고, 근거가 없을 때 추측하지 않게 했는가
- 대표 질문으로 검색 적중률과 근거 없는 답변 비율을 지속 측정하는가
ai
| No | 작성일 | Title |
|---|---|---|
| 2079 | 2026. 01. 13. | Claude Code CLAUDE.md 완벽 가이드 - 프로젝트 설정의 핵심 |
| 1993 | 2025. 11. 30. | AI Agent 개발 - AutoGPT, CrewAI, LangGraph |
| 1992 | 2025. 11. 30. | Fine-tuning vs RAG - 언제 무엇을 선택할까 |
| 1991 | 2025. 11. 30. | AI 코드 리뷰 자동화 - GitHub Actions와 LLM 연동 |
| 1990 | 2025. 11. 30. | Vector Database 비교 - Pinecone, Chroma, Weaviate |
| 1989 | 2025. 11. 30. | AI 이미지 생성 - DALL-E, Midjourney, Stable Diffusion |
| 1988 | 2025. 11. 30. | 로컬 LLM 실행하기 - Ollama와 LM Studio |
| 1987 | 2025. 11. 30. | OpenAI API 활용 - 함수 호출과 Assistant API |
| 1986 | 2025. 11. 30. | LangChain 프레임워크 완벽 가이드 |
| 1985 | 2025. 11. 30. | RAG(Retrieval-Augmented Generation) 구현 가이드 |