Search
moon
sun

사내 지식으로 Agentic RAG 만들기 (3/3) : 관측 가능한 RAG, 운영되는 도구로

URL
생성 일시
2026/10/10 01:06
최종 편집 일시
2026/10/10 01:06
태그
여기어때
파일과 미디어
|| 글. 박이슬(스노우) / 공통플랫폼개발팀 안녕하세요, 여기어때컴퍼니 공통플랫폼개발팀 스노우입니다. 1편에서는 Confluence와 Jira에 흩어진 문서를 모아 검색 가능한 형태로 바꿨고, 2편에서는 그 위에 LightRAG와 Navigator를 얹었습니다. 여기까지 오면 질문을 던졌을 때 답이 돌아옵니다. 그런데 만들고 나서 가장 오래 붙잡고 있었던 건 검색이 아니었습니다. 만든 것이 제대로 동작하는지 확인하는 일이었습니다. 이번 편은 그 이야기입니다. 질의를 던졌을 때 무엇이 오갔는지 보이게 만들고, 그게 맞는 답인지 채점하고, 그렇게 검증한 검색을 에이전트가 쓸 수 있게 내보내기까지. 그리고 마지막에는 그렇게 만든 도구가 지금 어디에서 어떻게 쓰이고 있는지까지의 이야기입니다. LLM Observability와 LLM 평가하기 LLM과 RAG는 잘 돌아가고 있는지 눈으로 확인하기 어려운 시스템입니다. LLM의 입출력은 자연어이다 보니, 지금 모델이 좋은 답변을 했는지 못했는지를 판단하기가 굉장히 어렵습니다. 답이 그럴듯하면 맞아 보입니다. 근거 문서들을 함께 돌려주니 더 그래 보입니다. 실제로는 엉뚱한 문서를 집어왔는데도 모델이 매끄럽게 문장을 만들어내면, 읽는 사람은 그걸 알아차리기가 어렵습니다. 비용도 마찬가지입니다. 문서 하나를 처리하는 데 LLM 호출이 몇 번이나 붙는지, 그게 한 달에 얼마가 되는지는 청구서가 오기 전까지 알 수 없습니다. 이런 문제점을 해결해주는 도구로써 최근에 LLM에 특화된 APM(Application Performance Monitoring)들이 나왔습니다. 그 중 저희는 Langfuse를 선택했습니다. LLM 애플리케이션에 특화된 오픈소스 관측 플랫폼으로, 요청 하나가 어떤 경로를 거쳤는지를 trace 단위로 기록하고 보여주는 모니터링 툴입니다. Langfuse trace 추적 예시 일반적인 APM과 다른 점은, 프롬프트와 응답 전문, 사용 토큰, 모델별 단가에 따른 비용이 호출마다 남는다는 점입니다. 검색 → 프롬프트 조립 → 생성으로 이어지는 여러 단계를 하나의 trace로 묶어 보여주기 때문에, 어느 단계에서 시간이 걸렸고 어디서 토큰이 나갔는지를 한 화면에서 확인할 수 있습니다. RAG 평가 파이프라인 구축 Langfuse를 붙이면서 어디에 시간과 비용이 나가는지 보이게 됐습니다. 다만 검색 결과가 좋은지 나쁜지는 여전히 알 수 없었습니다. trace에 남는 건 무엇이 오갔는지, 그게 맞는 답인지가 아니기 때문입니다. Langfuse에는 Experiment라는 이름으로 해당 기능을 지원하고 있습니다. 데이터셋을 만들고, 평가체계를 구축하고, 실험을 돌려 결과를 남기는 것까지 하나의 플랫폼 안에서 가능합니다. 이번 프로젝트에서는 이 기능을 최대한 활용하였습니다. 무엇을 물어볼 것인가 RAG 시스템을 평가하기 위해선, 먼저 평가대상인 질문-답변 쌍을 제작해야했습니다. 검색이 실패하는 방식은 하나가 아니기 때문에 먼저 사내 지식을 기반으로 답변할 수 있는 질문 유형을 일곱 가지로 나누고, 유형별로 질문과 정답 쌍을 작성했습니다. 유형을 나눠서 데이터셋을 생성한다면, 평가 이후 어디가 약한지가 점수와 함께 드러날 것이라고 생각했습니다. 검색이 제대로 됐는가 질문셋이 준비됐으니 이제 확인할 차례입니다. RAG에서 답이 틀리는 경로는 크게 둘인데, 애초에 엉뚱한 문서를 가져왔거나 문서는 맞는데 모델이 잘못 읽은 경우입니다 앞쪽은 정보 검색 분야에서 오래 쓰인 지표들로 확인할 수 있습니다. Recall@5 : 정답 문서가 상위 5개 안에 들어왔는가 Hit Rate : 정답 문서를 한 번이라도 회수했는가 MRR : 정답 문서가 몇 번째로 올라왔는가 질문마다 정답 문서를 지정해뒀기 때문에 리트리버가 돌려준 목록과 대조하면 자동으로 계산됩니다. Langfuse Python SDK로 데이터셋을 불러와 실험을 돌리고, 이 지표들을 계산하는 evaluator를 붙였습니다. LLM을 거치지 않으니 빠르고, 같은 입력에는 항상 같은 값이 나옵니다. 그래서 답은 좋