fos-blog/study
01 / 홈02 / 카테고리03 / 시리즈
01 / 홈02 / 카테고리03 / 시리즈

카테고리

  • AI 페이지로 이동
    • RAG 페이지로 이동
    • agent 페이지로 이동
    • langgraph 페이지로 이동
    • 사람용 CLI와 AI 에이전트용 CLI는 설계가 다르다
    • agents.md
    • Claude Code 메모리: CLAUDE.md와 .claude/rules를 규칙으로 쓰는 법
    • Claude Code의 Skill 시스템 - 개발자를 위한 AI 자동화의 새로운 차원
    • Claude Code를 5주 더 쓴 결과 — 스킬·CLAUDE.md를 키워가는 방식
    • Claude Code를 11일 동안 쓴 결과 — 데이터로 본 나의 사용 패턴
    • Claude Code 멀티 에이전트 — Teams
    • AI 에이전트와 디자인의 새 컨벤션 — DESIGN.md, Google Stitch, Claude Design
    • Docling — IBM Research 의 문서 파싱 toolkit 상세 정리
    • 하네스 엔지니어링 실전 — 4인 에이전트 팀으로 코딩 파이프라인 구축하기
    • 하네스 엔지니어링 — 오래 실행되는 AI 에이전트를 위한 설계
    • 멀티모달 LLM (Multimodal Large Language Model)
    • AI 에이전트와 함께 MVP 만들기 — dooray-cli 사례
    • 온톨로지에서 코딩 에이전트 컨텍스트까지 — 클래스·관계 설계와 그래프 평가
    • OpenClaw는 context와 memory를 어떻게 관리하나 — 나만의 에이전트를 구성하는 법
    • OpenClaw vs Hermes Agent — 갈아탈까 고민하며 정리한 비교
  • ai 페이지로 이동
    • agent 페이지로 이동
    • [초안] AI 제품 백엔드 안정성 — 지연·비용·권한·관측·도구 실패·폴백/재시도/사람 에스컬레이션
    • [초안] LLM 평가 프레임워크: 골든셋, 회귀 테스트, LLM-as-a-judge, 사람 피드백 루프
  • algorithm 페이지로 이동
    • live-coding 페이지로 이동
    • 분산 계산을 위한 알고리즘
  • architecture 페이지로 이동
    • 시니어 백엔드를 위한 API 설계 실전 스터디 팩
    • API 버저닝과 하위 호환성: 모바일·외부 컨슈머까지 안전하게 진화시키기
    • 캐시 설계 전략 총정리
    • [초안] 커머스 Spring 서비스에 Clean/Hexagonal Architecture를 실용적으로 적용하기
    • [초안] 커머스 도메인 모델링: 주문·재고·노출의 세 축을 분리해서 설계하기
    • 커머스 주문 상태와 데이터 정합성 기본기
    • [초안] 쿠폰/프로모션 동시성과 정합성 기본기 — 선착순·중복 사용 방지·발급/사용/복구
    • [초안] DDD와 도메인 모델링: 시니어 백엔드 관점의 전술/전략 패턴 실전 가이드
    • [초안] Decorator & Chain of Responsibility — 행동을 체인으로 조립하는 두 가지 방식
    • 디자인 패턴
    • [초안] 분산 아키텍처 완전 정복: Java 백엔드 시니어 인터뷰 대비 실전 가이드
    • [초안] 분산 트랜잭션과 Outbox 패턴 — 왜 2PC를 피하고 어떻게 대신할 것인가
    • 분산 트랜잭션
    • [초안] e-Commerce 주문·결제 도메인 모델링: 상태머신, 멱등성, Outbox/Saga 실전 정리
    • [초안] Event Sourcing과 CQRS — 상태가 아니라 변화를 저장한다는 발상
    • [학습중] 금융 거래 취소·정정·대사·일마감 운영
    • [학습중] 금융 거래 상태와 원장 설계
    • [초안] F&B 쿠폰·프로모션·멤버십·포인트 설계
    • [초안] F&B · e-Commerce 디지털 채널 도메인 한 장 정리
    • [초안] F&B 주문/매장/픽업 상태머신 설계
    • [초안] F&B 이커머스 결제·환불·정산 운영 가이드
    • [초안] Hexagonal / Clean Architecture를 Spring 백엔드에 적용하기
    • [초안] 대규모 커머스 트래픽 처리 패턴 — 대규모 회원과 메가 프로모션을 버티는 설계
    • [초안] 레거시 JSP/jQuery 화면과 신규 API가 공존하는 백엔드 운영 전략
    • [학습중] 모듈러 모놀리스에서 MSA로 점진 전환하는 실습
    • [초안] MSA 서비스 간 통신: Redis [Cache-Aside](../database/redis/cache-aside.md) × Kafka 이벤트 하이브리드 설계
    • [초안] Observability 입문: 시니어 백엔드가 장애를 탐지하고 대응하는 방식
    • [초안] Outbox / Inbox Pattern 심화 — 분산 메시징의 정합성 문제를 DB 트랜잭션으로 풀어내기
    • [초안] 결제 도메인 멱등성과 트랜잭션 재시도 기본기
    • [초안] 시니어 백엔드를 위한 Resilience 패턴 실전 가이드 — Timeout, Retry, Circuit Breaker, Bulkhead, Backpressure
    • [초안] Spring Batch vs Event-Driven — 같은 비동기처럼 보이지만 전혀 다른 두 패러다임
    • [초안] Strategy Pattern — 분기문을 없애는 설계, 시니어 백엔드 인터뷰 핵심 패턴
    • [초안] 시니어 백엔드를 위한 시스템 설계 입문 스터디 팩
    • [초안] 템플릿 메서드 패턴 - 백엔드 처리 골격을 강제하는 가장 오래되고 가장 위험한 패턴
    • [초안] 대규모 트래픽 중 무중단 마이그레이션 — Feature Flag + Shadow Mode 실전
  • database 페이지로 이동
    • milvus 페이지로 이동
    • mysql 페이지로 이동
    • opensearch 페이지로 이동
    • qdrant 페이지로 이동
    • redis 페이지로 이동
    • vespa 페이지로 이동
    • 김영한의-실전-데이터베이스-설계 페이지로 이동
    • [초안] DB Connection Pool Saturation과 Thread Pool 격리
    • 커넥션 풀 크기는 얼마나 조정해야 할까?
    • 인덱스 - DB 성능 최적화의 핵심
    • [초안] JPA N+1과 커머스 조회 모델: 주문/메뉴/쿠폰 도메인에서 살아남기
    • [초안] MyBatis 기본기 — XML Mapper, resultMap, 동적 SQL, 운영 패턴 정리
    • [초안] MyBatis와 JPA/Hibernate 트레이드오프 — 레거시 백엔드를 다루는 시니어 관점
    • 한국어 형태소 분석기 Nori vs Lindera — OpenSearch에서 Milvus로 갈 때 어휘 검색은 유지되나
    • 벡터 DB 5종, 아키텍처는 어떻게 다른가
    • 벡터 DB 5종을 실제로 벤치마크했다 — 같은 recall에서 QPS는 얼마나 갈리나
    • 벡터 DB 어떻게 고를까 — OpenSearch · Milvus · Qdrant · Vespa · pgvector 비교
    • 벡터 DB를 실제로 도입한 사례 — 빅테크 프로덕션
    • 역정규화 (Denormalization)
    • 데이터 베이스 정규화
  • devops 페이지로 이동
    • docker 페이지로 이동
    • k8s 페이지로 이동
    • k8s-in-action 페이지로 이동
    • observability 페이지로 이동
    • [초안] 커머스/F&B 채널 장애 첫 5분과 관측성 기본기
    • [초안] 운영 데이터 정합성 장애 대응 — 결제 취소 누락과 중복 적재 런북
    • Envoy Proxy
    • [초안] F&B / e-Commerce 운영 장애 대응과 모니터링 — 백엔드 관점 정리
    • Graceful Shutdown
    • [초안] 시니어 백엔드를 위한 SLO와 Error Budget 기반 장애 대응
  • http 페이지로 이동
    • HTTP Connection Pool
    • HTTPS는 어떻게 안전한가 — TLS, 인증서, 그리고 termination
  • interview 페이지로 이동
    • [초안] AI 서비스 팀 경험 기반 시니어 백엔드 면접 질문 뱅크 — Spring Batch RAG / gRPC graceful shutdown / 캐시 정합성 / 12일 AI 웹툰 MVP
    • Observability — 면접 답변 프레임
    • [초안] 시니어 Java 백엔드 면접 마스터 플레이북 — 김병태
    • [초안] NSC 슬롯팀 경험 기반 질문 은행 — 도메인 모델링·동시성·성능·AI 협업
  • java 페이지로 이동
    • concurrency 페이지로 이동
    • jdbc 페이지로 이동
    • opentelemetry 페이지로 이동
    • spring 페이지로 이동
    • spring-batch 페이지로 이동
    • testing 페이지로 이동
    • 더_자바_코드를_조작하는_다양한_방법 페이지로 이동
    • [초안] Java 동시성 락 정리 — 커머스 메뉴/프로모션 정책 캐시 갱신 관점
    • [초안] JVM 튜닝 실전: 메모리 구조부터 Virtual Threads, GC 튜닝, 프로파일링까지
    • Java의 로깅 환경
    • MDC (Mapped Diagnostic Context)
    • Java StampedLock — 읽기 폭주에도 쓰기가 밀리지 않는 락
    • Virtual Thread와 Project Loom
  • javascript 페이지로 이동
    • typescript 페이지로 이동
    • AbortController
    • Async Iterator와 제너레이터
    • CommonJS와 ECMAScript Modules
    • 제너레이터(Generator)
    • Http Client
    • Node 백엔드 운영 패턴 — Streams 백프레셔, pipe/pipeline, 멱등성 vs 분산 락
    • Node.js
    • npm vs pnpm — 어떤 기준으로 선택했나
    • `setImmediate()`
  • kafka 페이지로 이동
    • [초안] Kafka 기본 개념 — 토픽, 파티션, 오프셋, 복제
    • Kafka를 사용하여 **데이터 정합성**은 어떻게 유지해야 할까?
    • [초안] Kafka 실전 설계: 파티션 전략, 컨슈머 그룹, 전달 보장, 재시도, 순서 보장 트레이드오프
    • [학습중] Kafka 파티션·리밸런스·컨슈머 지연 운영
    • 메시지 전송 신뢰성
    • [초안] Spring Kafka 컨슈머 오프셋 커밋과 트랜잭션 정렬: AckMode, manual ack, 멱등 처리
  • linux 페이지로 이동
    • fsync — 리눅스 파일 동기화 시스템 콜
    • tmux — Terminal Multiplexer
  • mlops 페이지로 이동
    • llm-serving 페이지로 이동
    • serving-frameworks 페이지로 이동
    • Python CUDA 버전 생태계 — nvidia-smi, nvcc, pip, conda가 다 다른 버전을 말하는 이유
    • GPU 컨테이너의 CUDA 버전 호환성 — nvidia-smi부터 이미지 다이어트까지
    • Kubernetes GPU 노드에서 /run tmpfs가 꽉 차서 Pod가 안 뜰 때
    • GPU·CUDA·MPS 기초 — 자바 백엔드 개발자가 처음 만나는 그림
    • Multi-process GPU 워크로드 — 자바 ThreadPool 사용자가 만나는 모델 차이
    • ML 서비스 성능 분석 워크플로 — 자바 백엔드 트러블슈팅과 다른 점
    • 한 GPU 를 여러 프로세스가 나눠 쓰기 — Time-Slicing 과 MPS
  • network 페이지로 이동
    • Connection reset by peer는 누가 보낸 걸까 — 리버스 프록시 홉마다 TCP 연결은 따로 논다
    • L2(스위치)와 L3(라우터)의 역할 차이
    • L4와 VIP(Virtual IP Address)
    • IP Subnet
  • python 페이지로 이동
    • Python async/await — CompletableFuture·Reactor 와 다른 점, 그리고 blocking I/O 함정
    • Python 의존성 관리 — Java Maven/Gradle 사용자가 만나는 첫 충격
    • FastAPI 기초 — Spring Boot 사용자가 빠르게 익히는 법
    • Java 개발자를 위한 Python 심화 — OOP·데코레이터·컨텍스트 매니저
    • PyTorch 기초 — 텐서, 디바이스, 그리고 모델 로딩이 무거운 이유
    • Java 개발자를 위한 Python 문법 핵심
    • ThreadLocal 에서 contextvars 로 — Python 의 요청 컨텍스트 전파
    • OCR 동작 원리 — Layout · Text · Post-process 3단계
    • Python 서버의 RSS 가 안 줄어드는 이유 — gc.collect 의 한계와 malloc_trim
  • rabbitmq 페이지로 이동
    • [초안] RabbitMQ Basics — 실전 백엔드 관점에서 정리하는 메시지 브로커 기본기
    • [초안] RabbitMQ vs Kafka — 백엔드 메시징 선택 기준과 실전 운영 관점
  • resume 페이지로 이동
    • [초안] 김병태 경력기술서
    • [초안] 김병태 포트폴리오
  • security 페이지로 이동
    • [초안] 시니어 백엔드를 위한 보안 / 인증 스터디 팩 — Spring Security, JWT, OAuth2, OWASP Top 10
    • [초안] Spring Security 6.x OAuth2 + JWT 상용 인증 설계 — Grant 선택, Resource Server, Refresh Rotation, 로그아웃
  • task 페이지로 이동
    • ai-service-team 페이지로 이동
    • nsc-slot 페이지로 이동
    • sb-dev-team 페이지로 이동
    • the-future-company 페이지로 이동
  • testing 페이지로 이동
    • [초안] 시니어 Java 백엔드를 위한 테스트 전략 완전 정리 — 피라미드부터 TestContainers, 마이크로벤치, Contract까지
  • thinking 페이지로 이동
    • 좋은 일을 넘어 중요한 일을 하는 법
FOS-BLOG · FOOTERall systems normal·v0.1 · 2026.04.27·seoul, kr
Ffos-blog/study

개발 학습 기록을 정리하는 블로그입니다. 공부하면서 기록하고, 기록하면서 다시 배웁니다.

visitors
01site
  • Home↗
  • Posts↗
  • Categories↗
  • Glossary↗
  • About↗
02policy
  • 소개/about
  • 개인정보처리방침/privacy
  • 연락처/contact
03categories
  • AI↗
  • Algorithm↗
  • DB↗
  • DevOps↗
  • Java/Spring↗
  • JS/TS↗
  • React↗
  • Next.js↗
  • System↗
04connect
  • GitHub@jon890↗
  • Source repositoryjon890/fos-study↗
  • RSS feed/rss.xml↗
  • Newsletter매주 1 회 · 한 편의 글→
© 2026 FOS Study. All posts MIT-licensed.
built with·Next.js·Tailwind v4·Geist·Pretendard·oklch
fos-blog/AI/RAG를 평가에서 역설계하기 — LLM을 위…
aidb

RAG를 평가에서 역설계하기 — LLM을 위한 컨텍스트 제공자는 무엇을 잘해야 하는가

VectorDB와 임베딩 모델을 잘 고르면 RAG 품질도 좋아질 것이라고 생각했다. 지금도 그 생각이 틀렸다고 보지는 않는다. 좋은 검색 기반과 표현 모델은 여전히 중요하다. 다만 정보 검색을 다룬 37가지 회고를 읽으며 빠진 질문 하나가 보였다. 우리가 만드는 시스템은 무엇을 잘해야 하고, 그것을 어떤 평가 기준으로 증명할 것인가? 지금까지는 Vector...

2026.07.29·13 min read·7 views

VectorDB와 임베딩 모델을 잘 고르면 RAG 품질도 좋아질 것이라고 생각했다. 지금도 그 생각이 틀렸다고 보지는 않는다. 좋은 검색 기반과 표현 모델은 여전히 중요하다.

다만 정보 검색을 다룬 37가지 회고를 읽으며 빠진 질문 하나가 보였다.

우리가 만드는 시스템은 무엇을 잘해야 하고, 그것을 어떤 평가 기준으로 증명할 것인가?

지금까지는 VectorDB, 임베딩, HNSW, 하이브리드 검색, 재순위화를 각각 공부했다. 이제는 LLM 앞에서 이 구성요소들을 묶는 시스템을 컨텍스트 제공자(context provider)로 정의하고, 목표와 평가에서 구성을 역으로 설계해보려 한다.

벡터 DB 선택 기준과 벡터 DB 벤치마크가 제품과 ANN을 비교했다면, 이 글은 그 위에서 무엇을 최적화해야 하는지 묻는다.

이 글은 다음 질문에 답하기 위한 이정표다.

  • 컨텍스트 제공자는 LLM에 무엇을 보장해야 하는가.
  • 검색 품질과 최종 답변 품질을 왜 분리해서 평가해야 하는가.
  • 평가 결과를 BM25, 벡터 검색, 필터, 재순위화, 청킹 같은 구성요소 선택으로 어떻게 연결할 것인가.

이 평가 기준을 Neo4j 기반 관계 탐색에 적용하는 실습은 Neo4j GraphRAG로 에이전트 컨텍스트 제공자 만들기에서 이어간다.

원문에서 남은 것은 검색 도구 목록이 아니었다

원문에는 BM25부터 벡터 검색, 임베딩, 필터, 재순위화, 청킹, 검색 평가까지 37가지 교훈이 나온다. 각 항목도 유용하지만, 내게 더 크게 남은 것은 항목 사이의 관계였다.

계층원문에서 다룬 것시스템에서 맡는 역할
표현dense·sparse·multi-vector 임베딩질문과 문서를 비교할 수 있는 형태로 만든다
후보 생성BM25, ANN, 메타데이터 필터넓은 문서 집합에서 후보를 빠르게 찾는다
후보 정제하이브리드 검색, 재순위화의미와 키워드를 합치고 중요한 근거를 위로 올린다
컨텍스트 조립top_k, 청크 크기, 확장 문맥제한된 토큰 안에 LLM이 실제로 읽을 근거를 만든다
평가precision, recall, MRR, nDCG각 단계가 목표에 도달했는지 확인한다

이 구조로 보면 벡터 검색은 RAG의 동의어가 아니다. RAG의 R은 검색(retrieval)이고, 벡터 검색은 후보를 찾는 여러 방법 중 하나다.

이 글에서는 dense vector 검색을 중심으로 후보를 만드는 RAG를 편의상 벡터 RAG라고 부른다. 이 표현은 후보 생성 방식을 설명할 뿐, RAG 전체 아키텍처나 품질 목표를 뜻하지 않는다.

BEIR 벤치마크에서도 BM25는 강한 기준선이었다. 재순위화와 late interaction 계열은 평균적으로 높은 zero-shot 성능을 보였지만 계산 비용도 더 컸다. 따라서 “벡터냐 키워드냐”보다 “어떤 질문에서 어떤 조합이 목표를 만족하는가”가 더 정확한 질문이다.

컨텍스트 제공자를 하나의 컴포넌트로 본다

RAG 원 논문은 생성 모델의 매개변수 기억과 외부의 비매개변수 기억을 결합했다. 제품 관점에서 보면 두 기억 사이에 하나의 명시적인 경계가 생긴다.

이 관점에서 컨텍스트 제공자의 출력은 단순한 List<String>이 아니다. LLM이 답을 만들 수 있도록 정리된 근거 묶음이다.

근거 묶음은 최소한 다음 정보를 가져야 한다.

  • 질문에 답하는 데 필요한 내용
  • 원문과 문서 식별자 같은 출처 정보
  • 갱신 시각과 버전
  • 접근 권한을 통과했다는 근거
  • 검색 점수와 재순위화 점수
  • LLM에 전달될 순서와 토큰 크기

여기서부터 성공 조건도 달라진다. 가까운 벡터를 빨리 찾는 것만으로는 충분하지 않다.

컨텍스트 제공자는 다음을 함께 만족해야 한다.

  • 충분성: 답에 필요한 근거가 빠지지 않는다.
  • 집중도: 불필요한 문서가 근거를 밀어내지 않는다.
  • 추적 가능성: 어떤 답이 어느 원문에서 왔는지 확인할 수 있다.
  • 정합성: 최신 문서와 권한 범위가 색인에 반영된다.
  • 예산 준수: 지연, 비용, 토큰 제한 안에서 동작한다.
  • 무근거 감지: 답할 근거가 없을 때 그 사실을 숨기지 않는다.

이 여섯 가지가 먼저고, VectorDB와 검색 방식은 이를 달성하기 위한 수단이다.

같은 recall도 무엇을 정답으로 삼느냐에 따라 다르다

기존 벡터 DB 벤치마크에서는 ANN의 recall@k를 측정했다. 완전탐색으로 구한 진짜 최근접 벡터와 ANN 결과가 얼마나 겹치는지 보는 값이다.

RAG 검색에서 필요한 재현율은 정답이 다르다. 가까운 벡터가 아니라 답에 필요한 근거를 얼마나 찾았는지 봐야 한다.

구분정답 집합답하는 질문
ANN recall완전탐색의 최근접 벡터 ID근사 인덱스가 정확한 벡터 검색을 얼마나 재현하는가
evidence recall사람이 표시한 필수 근거답에 필요한 정보를 얼마나 회수했는가
context recallLLM에 실제 전달된 필수 근거토큰 제한과 조립을 거친 뒤에도 근거가 남았는가

ANN recall이 높아도 임베딩 공간에서 가까운 문서가 사용자의 의도와 관련 없을 수 있다. 반대로 ANN recall이 조금 낮더라도 필요한 근거가 안정적으로 들어오면 RAG 목표에는 충분할 수 있다.

따라서 recall이라는 지표 이름만 보고 같은 품질을 측정한다고 생각하면 안 된다. 정답 집합이 무엇인지 먼저 적어야 지표가 의미를 가진다.

최종 답변 하나만 평가하면 원인을 잃는다

RAG는 모듈형 시스템이다. 검색이 실패할 수도 있고, 검색은 성공했는데 LLM이 근거를 무시할 수도 있다.

최종 답변 정확도 하나로 평가하면 두 실패를 구분하지 못한다.

  • 필요한 근거를 못 찾았는데 LLM의 내부 지식으로 우연히 맞힐 수 있다.
  • 필요한 근거를 찾았는데 LLM이 잘못 읽어 틀릴 수 있다.
  • 후보에는 근거가 있었지만 토큰 예산을 맞추는 과정에서 잘릴 수 있다.
  • 답은 자연스럽지만 권한 밖 문서나 오래된 문서에 근거할 수 있다.

평가 지점을 컴포넌트 경계마다 두어야 한다.

RAGAS는 검색된 문맥의 관련성, 답변의 근거 충실성, 답변 관련성을 분리했다. ARES도 문맥 관련성, 답변 충실성, 답변 관련성을 별도 판정하며 컴포넌트별 평가를 시도했다. RAGChecker는 검색과 생성 모듈을 더 세밀한 진단 지표로 나눈다.

공통점은 전체 시스템을 하나의 점수로 뭉개지 않는다는 데 있다.

작은 예제로 평가 경계를 나눠본다

어떤 질문에 답하려면 근거 A와 B가 모두 필요하다고 하자. 후보 검색은 문서 다섯 개를 반환했고 그 안에 A, B가 모두 들어 있다.

text
후보 검색 결과: [X, A, Y, B, Z]
필수 근거:      [A, B]

이때 후보 단계의 지표는 다음처럼 계산된다.

text
evidence recall@5 = 2 / 2 = 1.0
candidate precision@5 = 2 / 5 = 0.4

검색은 필수 근거를 모두 찾았지만 잡음이 많다. 재순위화가 A, B를 앞으로 올리면 순위 품질은 좋아진다.

text
재순위화 결과: [A, B, X, Y, Z]

그런데 컨텍스트 조립기가 토큰 제한 때문에 A만 LLM에 전달했다고 하자.

text
LLM 전달 결과: [A]
context recall = 1 / 2 = 0.5

후보 검색의 재현율은 1.0이었지만, 컨텍스트 제공자로서의 재현율은 0.5가 됐다. 검색기만 보면 성공이고 시스템 경계를 보면 실패다.

여기에 LLM이 근거에 없는 C까지 답한다면 생성 단계의 근거 충실성도 실패한다. 이처럼 각 경계에서 값을 남겨야 어떤 구성요소를 바꿔야 하는지 알 수 있다.

평가 기준표는 목표와 실패 비용에서 시작한다

평가 기준표(rubric)를 만들 때 지표 목록부터 고르면 순서가 뒤집힌다. 먼저 사용자에게 어떤 실패가 가장 비싼지 정해야 한다.

예를 들어 사내 지식 검색이라면 다음 질문이 먼저다.

  • 필요한 문서를 놓치는 것과 관련 없는 문서를 섞는 것 중 어느 쪽이 더 치명적인가.
  • 근거가 없을 때 답하지 않는 것이 허용되는가.
  • 최신성 지연을 몇 분 또는 몇 시간까지 허용할 수 있는가.
  • 접근 권한 오류는 품질 저하인가, 즉시 실패해야 하는 안전 위반인가.
  • 답변 속도와 품질 사이에서 허용할 예산은 얼마인가.

이 질문에 답한 뒤 평가를 네 묶음으로 나눈다.

통과 조건

가중 평균으로 상쇄하면 안 되는 조건이다.

목표측정 예기본 판정
권한 보호권한 밖 문서 노출률한 건도 허용하지 않는 통과 조건
출처 추적전달된 청크의 원문·버전 식별 가능 여부누락 시 실패
색인 정합성삭제·갱신 반영 지연서비스가 정한 최신성 목표로 판정
예산 보호최대 토큰, 시간 제한 초과제한 초과 시 실패 또는 강등

검색 품질

후보 생성과 순위화가 필수 근거를 잘 찾는지 본다.

질문지표 후보
필수 근거를 놓치지 않았는가evidence recall@k
상위 후보에 유용한 문서가 집중됐는가candidate precision@k
중요한 문서가 더 위에 있는가nDCG@k
첫 정답이 얼마나 빨리 나오는가MRR
질문 유형별 약점이 다른가유형별 recall·precision

모든 지표를 동시에 높이는 것이 목표는 아니다. 후보 생성 단계는 재현율을 우선하고, 비싼 재순위화 단계는 정밀도와 순위를 높이는 식으로 역할을 나눌 수 있다.

컨텍스트 조립 품질

검색 결과가 좋아도 LLM 입력으로 바꾸는 과정에서 품질이 다시 떨어질 수 있다.

질문지표 후보
토큰 제한 뒤에도 필수 근거가 남았는가조립 후 context recall
같은 내용이 반복되는가중복 청크 비율
잡음이 유용한 근거를 밀어내는가불필요 토큰 비율
문서 순서에 따라 답이 흔들리는가근거 위치별 정확도
작은 청크가 앞뒤 문맥을 잃었는가단독 청크와 확장 문맥의 성능 차이

Lost in the Middle은 긴 컨텍스트를 제공한다고 모델이 모든 위치의 정보를 동등하게 쓰는 것은 아님을 보였다. 관련 문서 수를 늘려 검색 재현율을 높여도 답변 성능은 그보다 먼저 포화될 수 있었다. 따라서 top_k를 키우는 것은 단순한 품질 향상 손잡이가 아니다.

생성과 사용자 결과

컨텍스트 제공자 바깥의 지표도 함께 봐야 한다. 그래야 제공한 근거가 실제 답변에 기여했는지 알 수 있다.

질문지표 후보
답변의 주장이 근거에 포함되는가근거 충실성(faithfulness)
질문에 맞는 답을 했는가답변 관련성
정답 또는 필수 주장과 일치하는가정확성, claim recall
근거가 없을 때 답변을 거절하는가무응답·거절 정확도
인용이 실제 원문을 지지하는가인용 정합성

근거 충실성이 높다고 답이 참인 것은 아니다. 오래된 문서를 충실히 요약하면 근거에는 충실하지만 현실과는 틀릴 수 있다. 그래서 색인 정합성과 답변 정확성을 따로 본다.

하나의 종합 점수보다 통과 조건과 진단 지표를 둔다

초기부터 모든 항목에 가중치를 주고 RAG 품질 82점처럼 합치고 싶어질 수 있다. 하지만 가중치는 아직 정하지 못한 제품 우선순위를 숫자로 숨길 뿐이다.

권한 유출 한 건을 높은 검색 재현율로 상쇄할 수는 없다. 검색 지연이 짧다고 오래된 근거가 정답이 되는 것도 아니다.

초기 평가판은 다음 두 종류로 나누는 편이 낫다.

  • 통과 조건: 권한, 출처, 최신성, 예산처럼 위반 자체가 실패인 항목
  • 진단 지표: 재현율, 정밀도, 순위, 충실성처럼 구성 대안을 비교하는 항목

종합 점수는 실패 비용과 사용자 목표가 충분히 쌓인 뒤에 만들어도 늦지 않다.

평가 데이터는 실제 질문의 실패 형태를 담아야 한다

공개 벤치마크는 검색 방식의 일반적인 성질을 비교하는 데 유용하다. 하지만 우리 컨텍스트 제공자를 결정하는 것은 우리 문서와 질문이다.

평가셋은 적어도 다음 질문 유형을 나눠 가져야 한다.

  • 고유명사, 오류 코드, 문서 번호처럼 정확한 문자열이 중요한 질문
  • 표현은 다르지만 의미가 같은 질문
  • 두 문서 이상의 근거를 합쳐야 하는 질문
  • 날짜, 조직, 문서 종류 같은 메타데이터 조건이 있는 질문
  • 접근 권한에 따라 정답 문서가 달라지는 질문
  • 최신 문서만 정답이 되는 질문
  • 저장소에 답이 없어 거절해야 하는 질문
  • 오타나 구어체가 섞인 질문

각 평가 항목에는 다음 정보를 둔다.

yaml
query: 사용자가 묻는 질문
query_type: semantic | exact | multi_hop | filtered | unanswerable
required_evidence:
  - source_id: 답에 반드시 필요한 문서
    required_claims: [필수 주장]
forbidden_sources: [권한 또는 최신성 때문에 나오면 안 되는 문서]
expected_behavior: answer | abstain
latency_budget_ms: 서비스 목표
token_budget: LLM 입력 한도

정답을 현재 청크 ID에만 묶으면 청킹 방식을 바꿀 때 평가셋도 함께 깨진다. 가능하면 원문 문서와 필수 주장 단위로 정답을 두고, 실행 시점의 청크가 그 주장을 포함하는지 판정한다.

실제 사용자 질문을 기본으로 삼고, 부족한 실패 유형만 합성 데이터로 보충한다. 합성한 질문과 정답 문서는 사람이 표본 검토해야 한다.

평가셋의 개수보다 중요한 것은 실패 유형별로 사례가 있고, 변경 뒤 같은 사례를 다시 실행할 수 있는가다.

LLM 평가자는 자동화 도구이지 정답지가 아니다

RAGAS는 정답 답변 없이도 빠르게 평가할 수 있는 지표를 제안했다. ARES는 합성 데이터와 소량의 사람 표기를 결합해 평가자를 보정했다. 이 접근은 반복 실험의 비용을 낮춘다.

하지만 LLM 평가 결과를 그대로 통과 조건으로 쓰면 평가자의 오류가 시스템 기준이 된다. RAGChecker는 기존 자동 지표보다 사람 판단과 더 높은 상관을 보였다고 보고한다. 그 결과가 사람 평가를 완전히 대체한다는 뜻은 아니다.

골든셋, 회귀 검사, LLM 평가자, 사람 검토를 연결하는 일반적인 흐름은 LLM 평가 프레임워크에 별도로 정리했다.

그래서 평가 수단도 역할을 나눈다.

  • 권한, 문서 버전, 인용 원문 존재 여부는 결정적인 코드로 검사한다.
  • 필수 근거 recall은 사람이 표시한 문서·주장과 비교한다.
  • 답변 충실성과 관련성처럼 의미 판단이 필요한 항목은 LLM 평가자로 확장한다.
  • LLM 평가자는 사람이 표시한 작은 검증 집합과 정기적으로 일치도를 확인한다.
  • 평가 프롬프트와 평가 모델 버전도 결과와 함께 기록한다.

평가자 자체도 교체 가능한 컴포넌트로 보는 편이 안전하다.

평가가 구성요소를 선택하게 만든다

평가가 준비되면 “무엇을 붙여야 하는가”가 증상에서 나온다.

관측된 실패먼저 확인할 구성요소
문서 번호·오류 코드 질문을 놓친다BM25, tokenizer, exact match, sparse 검색
동의어·의역 질문을 놓친다임베딩 모델, dense 검색, 질의 변환
두 유형을 번갈아 놓친다하이브리드 검색과 결과 융합
필수 근거는 후보에 있지만 순위가 낮다재순위화, RRF, 점수 정규화
권한·날짜 조건에서 결과가 새거나 사라진다메타데이터 필터와 필터 적용 방식
필요한 문장이 청크 경계에서 잘린다청크 전략, parent-child, sentence window
후보에는 있었는데 LLM 입력에서 빠진다컨텍스트 조립, 토큰 예산, 중복 제거
컨텍스트를 늘릴수록 답이 나빠진다top_k, 재순위화, 문서 순서, 잡음 제거
품질은 충분하지만 지연과 비용이 높다VectorDB, 인덱스, 양자화, 캐시
근거가 없는데도 답한다임계값, 무응답 정책, 생성 프롬프트, 출력 검증

OpenSearch로 RAG 검색 품질 높이기에서 정리한 하이브리드 검색, 재순위화, sentence window도 이 표 안에 들어온다. 세 기법을 모두 붙이는 것이 목표가 아니다. 각 기법이 해결해야 할 실패를 평가셋으로 재현하고, 개선 여부를 측정하는 것이 목표다.

아키텍처는 기능 목록이 아니라 실패에 대한 가설 묶음이 된다.

VectorDB 비교의 의미도 달라진다

평가 중심으로 본다고 VectorDB의 중요성이 사라지는 것은 아니다. VectorDB는 후보 생성의 처리량, 필터 표현력, 검색 기능, 데이터 관리, 운영 비용을 결정한다.

달라지는 것은 선택 순서다.

먼저 BM25나 현재 벡터 검색으로 기준선을 만든다. 어떤 질문에서 실패하는지 확인한 뒤 하이브리드 검색, 필터, 재순위화 같은 기능 요구가 나온다. 그 요구와 운영 예산을 만족하는 제품을 비교한다.

예를 들어 ANN 처리량이 열 배 높은 제품은 지연 목표가 병목일 때 강한 선택이다. 하지만 청킹 때문에 필수 근거가 애초에 색인되지 않았다면 처리량 차이는 답변 품질을 고치지 못한다.

VectorDB 비교는 여전히 필요하다. 다만 “어떤 제품이 가장 좋은가”가 아니라 우리 평가 기준을 어떤 비용으로 만족하는가를 비교해야 한다.

지금 세우려는 첫 번째 이정표

아직 어떤 검색 조합이 정답이라는 가치관은 없다. 대신 다음 순서로 판단을 쌓을 수는 있다.

  • 컨텍스트 제공자의 입력과 출력 계약을 정의한다.
  • 실제 질문과 실패 유형으로 작은 평가셋을 만든다.
  • 후보 검색, 재순위화, 컨텍스트 조립, 생성 경계의 결과를 모두 기록한다.
  • 현재 구성으로 기준선을 측정한다.
  • 가장 큰 실패 한 종류를 고르고 구성요소 하나만 바꾼다.
  • 같은 평가셋으로 품질, 지연, 비용 변화를 다시 잰다.

첫 평가판에서는 실행 순서뿐 아니라 다음 산출물을 남긴다.

  • 질문 유형과 실패 비용을 정리한 평가 항목표
  • 원문 문서와 필수 주장을 연결한 근거 라벨
  • 권한, 최신성, 출처, 예산에 대한 통과 조건
  • 후보, 재순위화 결과, 최종 컨텍스트를 잇는 추적 로그
  • 구성별 점수보다 실패 유형을 먼저 보여주는 비교 보고서

이 과정이 반복되면 “하이브리드 검색이 좋다” 같은 일반론이 우리 시스템의 판단으로 바뀐다.

지금 내게 필요한 것은 VectorDB에 대한 믿음을 버리는 일이 아니다. VectorDB와 임베딩이 좋다는 말을 무엇이 얼마나 좋아졌을 때 참이라고 부를지 정하는 일이다.

컨텍스트 제공자의 목표를 먼저 적고, 평가에서 컴포넌트를 역설계한다. 이것이 VectorDB 비교와 RAG 공부 다음에 놓을 이정표다.

참고 링크

저장소 안에서 이어 읽기

  • 벡터 DB 어떻게 고를까
  • 벡터 DB 5종을 실제로 벤치마크했다
  • OpenSearch로 RAG 검색 품질 높이기
  • RAG 환각 제어
  • LLM 평가 프레임워크

외부 자료

  • 37 Things I Learned About Information Retrieval in Two Years at a Vector Database Company
  • Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks
  • BEIR: A Heterogeneous Benchmark for Zero-shot Evaluation of Information Retrieval Models
  • RAGAS: Automated Evaluation of Retrieval Augmented Generation
  • ARES: An Automated Evaluation Framework for Retrieval-Augmented Generation Systems
  • RAGChecker: A Fine-grained Framework for Diagnosing Retrieval-Augmented Generation
  • Lost in the Middle: How Language Models Use Long Contexts
on this page
  • 01원문에서 남은 것은 검색 도구 목록이 아니었다
  • 02컨텍스트 제공자를 하나의 컴포넌트로 본다
  • 03같은 recall도 무엇을 정답으로 삼느냐에 따라 다르다
  • 04최종 답변 하나만 평가하면 원인을 잃는다
  • 05작은 예제로 평가 경계를 나눠본다
  • 06평가 기준표는 목표와 실패 비용에서 시작한다
  • 통과 조건
  • 검색 품질
  • 컨텍스트 조립 품질
  • 생성과 사용자 결과
  • 07하나의 종합 점수보다 통과 조건과 진단 지표를 둔다
  • 08평가 데이터는 실제 질문의 실패 형태를 담아야 한다
  • 09LLM 평가자는 자동화 도구이지 정답지가 아니다
  • 10평가가 구성요소를 선택하게 만든다
  • 11VectorDB 비교의 의미도 달라진다
  • 12지금 세우려는 첫 번째 이정표
  • 13참고 링크
  • 저장소 안에서 이어 읽기
  • 외부 자료
tags
#심화

이런 글도

  • 권한·최신성·성능을 포함한 Neo4j 운영 설계
    운영 설계의 결론은 학습 환경과 제품 환경을 분리하는 것이다. Neo4j Community Edition은 로컬 학습과 단일 인스턴스 실습에 충분할 수 있지만, 사내 컨텍스트 제공자가 권한, 가용성, 백업, 운영 보안을 요구하면 Enterprise 또는 Aura 기능 범위를 따로 검토해야 한다. Text2Cypher는 특히 조심해야 한다. 읽기 전용 권한,...
    🤖 ai
    ai
    2026.07.30
  • GraphRAG 평가와 벡터 RAG 제거 실험
    GraphRAG 평가는 "답이 맞았다" 하나로 끝나면 안 된다. 이 글의 결론은, 그래프 구축 품질, 후보와 근거 회수, 최종 컨텍스트 정밀도와 재현율, 출처·최신성·권한·지연·비용을 단계별로 나누고, 반드시 벡터 전용 기준선과 제거 실험으로 비교해야 한다는 것이다. 그래프를 만들었다는 사실은 성공 기준이 아니다. 벡터 RAG가 놓친 관계형 질문에서, 권한...
    🤖 ai
    ai
    2026.07.30
  • 에이전트를 위한 Neo4j 컨텍스트 제공자 설계
    컨텍스트 제공자는 검색기를 감싼 얇은 함수가 아니다. 이 글의 결론은, 사내 에이전트에 붙이는 Neo4j 컨텍스트 제공자는 읽기 전용 도구이며 ACL 선필터, 출처, 최신성, 토큰 예산, 시간 제한, 출력 계약을 함께 보장해야 한다는 것이다. 그래프 탐색은 유용하지만 위험도 크다. 관계 경로가 답처럼 보일수록, 그 경로를 누가 볼 수 있고 어떤 원문이 지지...
    🤖 ai
    ai
    2026.07.30
  • 벡터·전문·그래프 탐색을 결합한 하이브리드 검색
    벡터 검색만으로 놓치는 질문은 대부분 "가까운 문장"이 아니라 "연결된 사실"을 요구한다. 이 글의 결론은 단순하다. Neo4j GraphRAG의 하이브리드 검색은 벡터와 전문 검색으로 후보를 넓히고, VectorCypherRetriever나 HybridCypherRetriever로 관계를 확장한 뒤, 최종 컨텍스트는 반드시 원문 Document와 Chun...
    🤖 ai
    ai
    2026.07.30

댓글 (0)