본문으로 건너뛰기

© 2026 Molayo

Qiita헤드라인2026. 06. 05. 11:32

RAG의 실패는 벡터 DB만으로는 추적할 수 없다: ClickHouse로 10만 건의 AI 로그를 초 단위로 감사하기

요약

RAG 시스템의 성능 저하와 실패 원인을 분석하기 위해 ClickHouse를 활용한 관측성(Observability) 구축 방법을 다룹니다. 벡터 DB를 넘어 프롬프트 버전, 검색 품질, 지연 시간, 비용 등을 시계열 로그로 통합 관리하는 설계 방안을 제시합니다.

핵심 포인트

  • 벡터 DB만으로는 프롬프트 버전별 품질 및 비용 추적이 어려움
  • ClickHouse를 활용해 10만 건의 합성 RAG 트레이스 분석
  • 프롬프트, 검색, 지연 시간, 비용을 통합한 감사 스키마 설계
  • AI 앱의 안정적 운영을 위한 시계열 로그 기반의 관측성 중요성

이 기사는 Qiita Tech Festa 2026의 「AI 시대의 데이터베이스, 무엇이 변하는가?」 참여를 상정한 구현 기사입니다.

AI 시대의 데이터베이스에서 변하는 것은 「벡터 검색(Vector Search)이 가능한가」만이 아닙니다. 실운용에서 곤란한 점은 다음과 같은 질문에 답할 수 없다는 것입니다.

  • 어떤 프롬프트(Prompt) 버전부터 환각(Hallucination)률이 높아졌는가
  • 검색 스코어(Score)가 낮을 때, 답변 품질은 어느 정도 떨어지는가
  • 어떤 지식 문서가 실패 답변과 연결되기 쉬운가
  • 새로운 에이전트(Agent) 버전은 정말로 출시해도 괜찮은가
  • 비용(Cost)·지연(Latency)·인용 누락을 동일한 화면에서 추적하고 있는가

이번에는 로컬 Docker 상의 ClickHouse에 합성 RAG 트레이스(Trace) 10만 건을 투입하여, RAG의 실패를 감사하기 위한 스키마와 SQL을 만들었습니다.

먼저 중요한 전제를 적습니다. 이 기사의 로그는 실제 고객 데이터가 아니라 재현 가능한 합성 데이터입니다. 모델명·비용·실패율도 검증용으로 만든 값이며, 특정 서비스의 실측 품질을 나타내는 것이 아닙니다. 이 기사의 주안점은 AI 앱의 실패를 관측하기 위해 어떤 열(Column)을 남기고, 어떤 SQL로 의사결정을 하는가입니다.

관측하고 싶은 것벡터 DB만으로는 약한 점ClickHouse에 남길 열SQL의 결과물
프롬프트 저하검색 결과는 추적할 수 있어도, 프롬프트 버전별 품질 차이가 보이기 어렵다prompt_version , hallucination_flag , citation_missing출시 판정
검색 품질top-k의 내용만으로는 실패율과의 상관관계가 나오지 않는다retrieval_top_score , retrieval_score_gap , feedback_score검색 임계값 재검토
지연(Latency)생성·검색·캐시 중 어디가 느린지 분해하기 어렵다latency_ms , retrieval_ms , generation_ms , cache_hitSLO 모니터링
지식 오염어떤 문서가 실패 답변에 자주 나오는지 집계하기 어렵다retrieved_doc_ids , failure_reason문서 개정 우선순위
비용(Cost)1회 답변 단위로는 보여도, 버전별·일별 증가를 추적하기 어렵다prompt_tokens , completion_tokens , cost_usd예산 게이트

결론적으로 AI 시대의 DB는 「검색 대상의 저장 장소」만으로는 부족합니다. 모델·프롬프트·검색·평가·비용을 동일한 시계열 로그로서 감사할 수 있는 것이 중요해집니다.

이번 검증 환경입니다.

항목
OSmacOS + Docker Desktop
...

ClickHouse 공식 문서에서는 MergeTree 계열 엔진을 높은 수집 속도와 대규모 데이터용 테이블 엔진으로 설명하고 있습니다. 이번과 같이 추가(Append) 중심인 AI 로그에는 궁합이 좋습니다.

로컬에서는 다음과 같은 구성으로 했습니다.

tmp/clickhouse-rag-observability/
├── Makefile
├── docker-compose.yml
...

실행 커맨드는 이것뿐입니다.

cd tmp/clickhouse-rag-observability
make all ROWS=100000

하고 있는 일은 단순합니다.

  • clickhouse/clickhouse-server:latest를 Docker로 기동한다
  • Node.js로 합성 RAG 트레이스를 JSONEachRow 형식으로 생성한다
  • ClickHouse에 투입한다
  • 6개의 감사 SQL을 실행하여 TSV와 실행 시간을 저장한다

ClickHouse의 JSONEachRow는 1행 1JSON의 NDJSON/JSONLines 형식으로 다룰 수 있기 때문에 애플리케이션 로그 투입에 적합합니다.

참고: JSONEachRow

테이블은 다음과 같이 만들었습니다.

CREATE DATABASE IF NOT EXISTS rag_observability;
CREATE TABLE rag_observability.rag_traces
(
...

포인트는 queryanswer...

의 전체를 중심으로 하지 않는 것입니다. 전체 내용은 별도의 스토리지로 분리해도 좋으며, ClickHouse 측에는 감사에 필요한 컬럼을 남깁니다.

prompt_version
: 프롬프트 변경의 영향을 확인 -
retrieval_top_score
: 검색 품질과 실패율의 상관관계를 확인 -
retrieved_doc_ids
: 실패와 관련된 문서를 특정 -
hallucination_flag
: 평가 결과를 집계 가능하게 함 -
citation_missing
: 인용 누락을 별도 지표로 취급 -
latency_ms, cost_usd
: 품질뿐만 아니라 운영 측면의 저하를 확인

먼저, 프롬프트 버전별로 환각률, 인용 누락률, 지연 시간, 비용을 확인하는 SQL입니다.

SELECT
prompt_version,
count() AS traces,
...

결과입니다.

prompt_versiontraceshallucination_rate_pctcitation_missing_rate_pctavg_latency_msp95_latency_mstotal_cost_usdavg_feedbacktop_failure_reasons
v1_baseline24,04518.6814.561206.6199912.91553.40missing_citation, stale_doc, prompt_overfit
...

여기서 중요한 점은, 평균 피드백만 본다면 v3_agentic은 나빠 보이지 않는다는 것입니다. 하지만 v2_grounded와 비교하면 환각률, 인용 누락률, 지연 시간이 동시에 악화되었습니다. AI 기능의 출시 판정 시에는 단일 지표가 아니라 여러 지표의 차이를 확인해야 합니다.

다음으로, 검색 점수를 버킷(bucket)화하여 실패율을 확인합니다.

WITH
multiIf(
retrieval_top_score < 0.55, 'low(<0.55)',
...

결과입니다.

score_buckettraceshallucination_rate_pctcitation_missing_rate_pctavg_feedbackavg_latency_ms
low(<0.55)5,25836.7123.703.251296.5
...

retrieval_top_score < 0.55 버킷에서는 환각률이 36.71%까지 상승했습니다. 이 결과를 바탕으로 다음과 같은 가드레일(guard)을 설계할 수 있습니다.

  • top score가 0.55 미만이면 답변을 생성하지 않고, 추가 질문으로 전환
  • 0.55에서 0.70 사이는 "근거가 약함" 라벨을 부여
  • 보안이나 계약 관련 의도(intent)에서는 임계값을 높임
  • 검색 점수와 인용 누락을 별도의 메트릭(metric)으로 모니터링

벡터 DB는 검색 후보를 반환합니다. 하지만 검색 후보가 최종 답변의 실패에 어떻게 영향을 미쳤는지를 장기적으로 보려면, 검색 로그와 평가 로그를 동일한 분석 기반에 남겨야 합니다.

AI 에이전트는 편리하지만, 너무 느려지면 프로덕트에 적용할 수 없습니다. 모델과 프롬프트 버전별로 p95/p99를 확인합니다.

modelprompt_versiontracesavg_latency_msp95_latency_msp99_latency_msmax_latency_ms
reasoning-largev3_agentic4,3622053.02476.02586.42738
...

여기서는 reasoning-large + v3_agentic이 가장 무거웠으며, p95가 2476ms였습니다. 출시 판정 시에는 "정확도가 조금 더 좋다"는 점뿐만 아니라, p95 지연 시간의 증가분을 예산(budget) 내에 두어야 합니다.

RAG 운영에서 놓치기 쉬운 것이 문서 단위의 품질입니다. 답변이 망가졌을 때 프롬프트만 수정하더라도, 오래된 문서나 모호한 런북(runbook)이 섞여 있으면 문제가 재발합니다.

ClickHouse의 arrayJoin을 사용하면, retrieved_doc_ids

의 배열을 문서 단위의 행으로 전개할 수 있습니다. 공식 문서에서도 arrayJoin은 1개의 행을 배열 요소의 수만큼 여러 행으로 전개하는 함수로 설명되어 있습니다.

SELECT
doc_id,
count() AS retrieved_count,
...

결과 중 일부입니다.

doc_idretrieved_counthallucination_counthallucination_rate_pctavg_top_scorefrequent_intentstop_failure_reasons
kb_current_migration_0343376719.880.756migrationmissing_citation, stale_doc, prompt_overfit
...

이러한 랭킹이 있으면 "프롬프트를 수정한다"뿐만 아니라 "어떤 문서를 수정할 것인가"까지 구체화할 수 있습니다. 특히 securitymigration과 같은 고위험 의도(intent)에서는 데이터에 기반하여 문서 리뷰의 우선순위를 결정할 수 있습니다.

마지막으로, 프롬프트 버전의 출시 판정을 위한 SQL을 작성해 보겠습니다. 여기서는 v3_agenticv2_grounded와 비교했습니다.

SELECT
'v3_agentic_vs_v2_grounded' AS comparison,
round((avgIf(hallucination_flag, prompt_version = 'v3_agentic') - avgIf(hallucination_flag, prompt_version = 'v2_grounded')) * 100, 2) AS hallucination_delta_pct,
...

결과입니다.

comparisonhallucination_delta_pctcitation_missing_delta_pctp95_latency_delta_mscost_delta_per_1000_tracesrelease_decision
v3_agentic_vs_v2_grounded2.081.14172.00.184447hold

이 예시에서는 hold입니다. 이유는 p95 지연 시간(latency)은 허용 범위 내에 있지만, 환각률(hallucination rate)과 인용 누락률(citation missing rate)의 증가분이 임계값을 초과했기 때문입니다.

이러한 형식을 갖춰두면, AI 기능 리뷰가 "왠지 좋아 보인다"에서 "이 SQL을 통과하면 출시(ship)"로 바뀝니다.

10만 건이지만, 로컬 Docker 환경에서도 감사 쿼리는 모두 짧은 시간 안에 완료되었습니다.

QueryElapsed seconds
prompt regression0.005
...

물론 운영 환경에서는 데이터 건수, 파티션(partition), ORDER BY, 압축, 구체화된 뷰(materialized view), 분산 구성에 따라 수치가 달라집니다. 그럼에도 불구하고 RAG 로그와 같이 추가형(append-only), 시계열(time-series), 집계 중심의 데이터에서는 ClickHouse를 "AI 관측 DB"로 사용하는 가치가 충분합니다.

RAG/AI 에이전트의 로그를 ClickHouse에 넣으려 한다면, 처음에 다음 사항들을 결정해 두는 것이 나중에 큰 도움이 됩니다.

  • trace_id를 모든 서비스에서 공통으로 사용한다
  • prompt_versionmodel을 반드시 남긴다
  • 검색 결과는 본문이 아니라 doc_id와 점수(score)를 남긴다
  • hallucination_flag는 수동 평가, LLM 평가, 자동 테스트 중 무엇인지 명시한다
  • citation_missing을 환각(hallucination)과는 별도의 지표로 분리한다
  • latency_ms를 검색, 생성, 도구 실행으로 나눈다
  • cost_usd 또는 추정 토큰(token) 수를 남긴다
  • 출시 전후를 비교할 수 있도록 실험군과 대조군을 동일한 테이블에 넣는다
  • 개인정보나 기밀 문서는 ClickHouse에 직접 넣지 않고, 마스킹(masking) 처리된 메타데이터를 넣는다
  • 실패 문서 랭킹을 주간 지식(knowledge) 개선 태스크로 연결한다

이번 검증을 통해 RAG 운영 시 발생하기 쉬운 실패 사례를 5가지로 정리할 수 있습니다.

실패 패턴증상대책
검색 스코어(Search Score)만 확인top-k는 반환되지만 답변 품질이 개선되지 않음retrieval_top_scorehallucination_flag를 동일한 테이블에서 확인
프롬프트(Prompt)만 수정실패하는 문서가 계속 남음arrayJoin(retrieved_doc_ids)를 사용하여 문서별 실패율을 확인
평균 지연 시간(Latency)만 확인p95/p99에서 UX(사용자 경험)가 무너짐quantile(0.95), quantile(0.99)를 릴리스 게이트(Release Gate)에 포함
인용 누락을 환각(Hallucination)과 혼재어떤 품질 문제인지 판단할 수 없음hallucination_flagcitation_missing을 분리
비용을 나중에 확인품질 개선과 동시에 운영비가 급증함cost_usd를 버전별·일별로 집계

AI 시대의 데이터베이스는 단순히 "벡터를 저장할 수 있는 DB"가 아닙니다. RAG나 AI 에이전트(Agent)를 프로덕션 환경에서 운영하려면 검색, 생성, 평가, 지연 시간, 비용, 문서 품질을 횡단적으로 살펴봐야 합니다.

이번 10만 건 벤치마크를 통해 ClickHouse로 다음과 같은 판단이 가능했습니다.

  • 프롬프트 버전별 환각률·인용 누락률·지연 시간을 비교
  • 검색 스코어가 낮은 버킷(Bucket)의 실패율 확인
  • 실패와 관련된 문서를 랭킹화
  • p95 지연 시간과 품질 차이로 릴리스 여부 결정
  • AI 로그를 "나중에 읽는 로그"가 아닌 "ship/hold를 결정하는 데이터"로 전환

RAG의 정밀도 개선은 모델 선정이나 프롬프트 개선만으로는 부족합니다. AI의 실패를 SQL로 감사(Audit)할 수 있는 상태로 만드는 것이 AI 시대의 데이터베이스에 요구되는 역할이라고 생각합니다.

  • Qiita Tech Festa 2026: 「AI 시대의 데이터베이스, 무엇이 변하는가?」에 대해 이야기하자!
  • ClickHouse Docs: MergeTree table engine
  • ClickHouse Docs: JSONEachRow
  • ClickHouse Docs: arrayJoin function
  • ClickHouse Docs: topK
  • ClickHouse Docs: quantile

AI 자동 생성 콘텐츠

본 콘텐츠는 Qiita AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0