포스트

AI Agent의 Observability와 RAG

AI Agent의 Observability와 RAG

오늘은 Weights & Biases(W&B)에서 공개한 ‘생성형 AI 애플리케이션의 평가와 관측성’ 백서를 보며 생성형 AI 시스템, 특히 요즘 많이 등장하는 AI 에이전트 같은 애플리케이션들을 어떻게 하면 더 똑똑하고 안정적으로 만들 수 있을지 깊이 고민해봤다. 핵심은 ObservabilityRAG(Retrieval-Augmented Generation) 두 가지인데, 단순히 개념을 아는 것을 넘어 실제 시스템을 운영할 때 맞닥뜨릴 수 있는 어려움들과 그를 헤쳐나갈 방법들을 연결 지어 생각해보니 훨씬 유익했다.


생성형 AI 시스템에서 Observability의 중요성

생성형 AI 기술이 발전하면서 정말 다양한 AI 애플리케이션들이 나오고 있다. 그런데 막상 시스템을 만들고 나면 이런 의문이 들 때가 많다. ‘이 응답은 왜 이렇게 나왔지?’, ‘사용자가 질문을 했는데 왜 엉뚱한 대답을 하지?’, ‘모델이 제대로 작동하는 건가?’

이런 질문들은 사실 시스템의 내부 작동 과정이 투명하게 보이지 않기 때문에 생기는 어려움이다. 일반적인 클라우드 애플리케이션에서 CPU 사용률이나 메모리 사용량 같은 지표를 모니터링하는 것처럼, 생성형 AI 애플리케이션에서는 단순히 입출력만 보는 것을 넘어 “모델이 어떤 근거(Retrieved Evidence)를 가지고 어떤 흐름을 거쳐 답변을 생성했는지” 를 추적할 수 있어야 한다. 모델에 주어진 프롬프트나 컨텍스트가 최종 결과에 어떻게 영향을 미쳤는지 깊이 있게 파악하는 것이 중요하다는 것을 알게 되었다.

이러한 불투명성 문제를 해결하기 위해 필요한 것이 바로 Observability다. 시스템의 내부 상태와 작동 과정을 상세히 들여다볼 수 있게 하는 방법론인데, 나는 이걸 “시스템의 속마음을 읽는 능력” 이라고 이해했다.

시스템을 개발하는 단계에서부터 이 능력이 중요하다. 복잡한 생성형 AI 애플리케이션은 시스템 프롬프트, RAG 설정, 외부 API 연동 등 여러 구성 요소들이 얽혀있다. 이 구성 요소들이 어떻게 상호작용하는지 명확하게 파악하고, 세부 요소 하나하나까지 체계적으로 버전 관리를 해야 나중에 문제가 생겼을 때 원인을 찾아내기가 쉽다. 또한, 시스템에 오고 가는 모든 입출력 데이터를 꼼꼼히 추적하고, 각 입출력 간의 관계를 명확하게 파악하는 것이 필수적이다. 특히 여러 AI 에이전트가 협업하는 시스템이라면, 에이전트 간의 상호작용 과정과 전체적인 플로우를 일관성 있게 기록해야만 높은 수준의 추적성과 디버깅 능력을 확보할 수 있다.

시스템을 배포한 이후에는 또 다른 어려움에 직면할 수 있다. 개발 단계에서 미처 예상하지 못했던 사용자들의 장문 질문, 새로운 도메인에 대한 확장된 대화, 혹은 LLM의 학습 시점 이후에 등장한 정보(모델의 컷오프 날짜 문제) 등으로 인해 문제가 발생할 수 있기 때문이다. 이런 상황에서 ‘왜 이런 문제가 발생했지?’를 빠르게 알아내려면, 매일 사용자 질문 내용, 모델의 중간 상태, 최종 응답 과정을 서로 연결하여 기록하고, 오류 발생 시 신속하게 파악할 수 있는 체계가 필요하다. 모델의 입력, 출력, 중간 추론 과정, 그리고 심지어 사용자 평가까지 통합적으로 관리할 수 있다면, 이 데이터를 바탕으로 프롬프트 최적화, RAG 설정 수정, 모델 버전 조정 및 재배포를 신속하게 진행할 수 있다. 커서AI(Cursor AI)가 ‘Accept’와 ‘Reject’ 버튼을 통해 사용자 피드백을 자연스럽게 반영하는 루프를 잘 구현한 것처럼, 사용자들의 반응을 시스템 개선에 적극적으로 활용하는 것이 정말 중요하다고 느꼈다.

결국 개발부터 배포까지 전 과정에서 종합적인 Observability 체계를 갖추는 것이 신뢰할 수 있는 고품질 AI 서비스를 꾸준히 제공하기 위한 필수적인 기반이라는 것을 다시 한번 깨달았다.

생성형 AI 어플리케이션 개발 워크플로우


RAG(Retrieval-Augmented Generation)

거대 언어 모델(LLM)들은 정말 놀라운 성능을 보여주지만, 치명적인 한계가 있다. 바로 “학습 시점 이후의 최신 정보”나 “기업 내부의 비공개 데이터”에 대해서는 정확한 답변을 제공하기 어렵다는 점이다. 마치 몇 년 전까지만 공부했던 사람이 최신 뉴스나 우리 회사의 내부 규정에 대해서는 잘 모르는 것과 비슷한 상황이다. 이러한 LLM의 ‘지식 컷오프’ 문제를 해결하지 못하면 실제 비즈니스에 적용하기가 어렵다.

이러한 LLM의 지식 한계를 극복하기 위해 등장한 기술이 바로 RAG(Retrieval-Augmented Generation) 이다. RAG는 LLM이 답변을 생성하기 전에 외부 데이터 소스에서 관련 정보를 찾아 참조할 수 있도록 돕는 기술이다. 쉽게 말해, LLM에게 궁금한 것이 있으면 도서관(외부 데이터 소스)에 가서 책(정보)을 찾아보고 답하게 하는 방식이다.

RAG 시스템은 다음과 같은 간단한 흐름으로 작동한다.

RAG 시스템의 작동 원리

  1. 사용자가 질문을 입력한다.
  2. 검색 시스템이 외부 데이터 소스에서 질문과 관련된 정보를 찾아온다.
  3. 검색된 정보를 바탕으로 LLM이 최종 답변을 생성한다.

이 과정을 통해 LLM은 자신이 학습하지 않은 최신 정보나 특정 도메인의 비공개 데이터에도 접근할 수 있게 되어 훨씬 더 신뢰성 있는 답변을 제공할 수 있게 된다. 국내 금융사의 생성형 AI 솔루션, LG CNS의 온보딩 챗봇, 콜센터 챗봇, 금융사의 민원 회신 문서 자동 생성, 이메일 자동 회신 등 최신 정보 활용이나 내부 데이터 연동이 필수적인 다양한 산업 분야에서 RAG가 활발하게 활용되고 있다는 점을 보면서 RAG의 중요성을 다시 한번 실감했다.

RAG 시스템의 평가

RAG 시스템을 만들었다고 해서 바로 서비스에 투입할 수 있는 건 아니다. 이 시스템이 충분히 신뢰할 만한 품질을 갖추고 있는지 객관적으로 평가하는 과정이 필수적이다. 이 평가 과정이 생각보다 많은 시간과 노력을 필요로 하며, 단순히 이론적인 평가를 넘어 실제 서비스 상황에서도 적용 가능한 실용적인 평가 방법을 고려해야 한다는 점이 인상 깊었다.

RAG 시스템은 정보를 검색하는 Retriever 단계와 검색된 정보를 바탕으로 답변을 생성하는 Generator 단계로 크게 나뉜다. 그래서 시스템 전체에 대한 통합 평가뿐만 아니라, 각 컴포넌트 단위로 세분화된 평가를 병행하는 것이 중요하다. 예를 들어, 사용자가 부정확한 답변을 받았을 때, “Retriever가 적절한 정보를 못 찾아서 그런 건지, Generator가 정보를 제대로 활용하지 못한 건지, 아니면 프롬프트 설계 자체가 잘못된 건지” 원인을 명확하게 파악하려면 이처럼 세분화된 평가가 반드시 필요하다.

RAG 시스템의 개발과 평가는 일반적으로 다음과 같은 절차를 따른다.

RAG 시스템 개발 흐름

  1. 요구사항 정의: 어떤 문제를 해결하고자 하는지, 시스템이 달성해야 할 정확도, 비용, 속도 등의 목표를 분명히 한다.
  2. 개발 및 평가 데이터 준비: 시스템에 입력할 질문과 기대하는 출력을 쌍으로 구성한 데이터를 준비한다.
  3. 평가 체계 구축 및 반복 개선: 평가 체계를 구축하고, 초기 버전의 시스템을 만들어 목표에 도달할 때까지 반복적으로 개선해 나간다. 이때 End-to-End 정확도 평가와 함께 속도 및 운영 비용 모니터링도 병행한다.
  4. 소규모 그룹 대상 릴리즈 및 모니터링: 시스템이 어느 정도 목표 수준에 도달하면, 실제 사용 환경과 유사한 소규모 사용자 그룹에게 먼저 릴리즈하여 실제 사용 데이터를 수집하고 사용자 피드백을 반영한다.
  5. 운영을 위한 개발: 기밀 데이터 유출, 프롬프트 인젝션 같은 보안 리스크를 꼼꼼히 점검하고 데이터 보호 및 시스템 신뢰성, 가용성을 확보한다.
  6. 운영 단계에서의 지속적인 모니터링 및 개선: 본격적인 운영이 시작된 이후에도 시스템을 꾸준히 모니터링하고 사용자 피드백과 새로운 요구사항을 수렴하여 장기적인 품질 향상을 도모한다.

RAG 성능 저하를 극복하는 방법

RAG 시스템은 사용자의 질문을 받는 순간부터 최종 응답을 생성하는 전 과정에서 다양한 최적화가 필요하다는 것을 알게 되었다. 마치 정교한 시계처럼 각 부품들이 유기적으로 잘 맞물려야 최고의 성능을 낼 수 있는 것이다.

RAG 시스템을 실제 업무에 적용할 때 종종 다음과 같은 어려움들을 마주하게 된다.

  • 모호한 질문 (쿼리): 사용자의 질문이 너무 모호하거나 구체적이지 않아서 시스템이 의도와 다른 정보를 검색하는 경우가 발생한다.
  • 부족한 인덱스 최적화: 데이터를 효율적으로 나누거나(청크 분할) 정보를 벡터로 변환하는(임베딩) 품질이 충분하지 않아 검색 성능이 떨어진다.
  • 미흡한 리랭킹: 검색된 결과들이 많을 때, 가장 관련성 높은 정보를 상위에 제대로 배치하지 못해 사용자가 필요한 정보를 찾기 어렵다.
  • 일관성 없는 응답: LLM의 특성상 때때로 답변의 일관성이 떨어지거나, 검색된 정보를 정확히 반영하지 못하는 경우가 발생한다.

이런 문제들을 해결하기 위해 RAG 시스템의 각 단계를 면밀히 살펴보고 개선하는 전략이 필요하다.

RAG 처리 플로우

Image from rag-from-scratch

위 그림은 RAG 시스템의 처리 플로우를 도식화한 것이다. W&B 자료에서는 RAG 처리 플로우를 크게 6가지 단계로 나누고 각 단계별 개선 기법들을 제시했는데, 이 부분이 특히 실용적이었다.

  1. 쿼리 확장 (Query Enhancement):
    • 어떤 문제를 해결할까? 사용자의 모호한 질문 때문에 검색 품질이 떨어지는 문제를 해결한다.
    • 어떻게 해결할까? 사용자가 입력한 쿼리를 시스템이 가장 잘 이해할 수 있는 형태로 변환하여, 모호함을 없애고 관련성이 높은 정보를 얻을 확률을 높이는 방법이다. 예를 들어, Multi-query를 사용해 하나의 쿼리를 여러 관점에서 분할하여 병렬로 처리하거나, RAG-Fusion으로 여러 검색 결과를 통합하여 더 정확한 답변을 도출한다. 복잡한 쿼리는 Decomposition으로 간단한 서브 쿼리로 분해하고, 한 번 검색 결과를 검토한 후 필요하면 쿼리를 다시 수행하는 Step-back 기법도 있다. 심지어 가설을 생성하고 이를 토대로 추가 정보를 검색하는 HyDE도 있다.
  2. 라우팅 (Routing):
    • 어떤 문제를 해결할까? 모호한 쿼리나 인덱스 최적화 부족으로 인해 잘못된 데이터 소스에서 정보를 찾거나 시스템 성능이 저하되는 문제를 해결한다.
    • 어떻게 해결할까? 쿼리를 가장 적합한 데이터 소스나 검색 엔진으로 효율적으로 분배하는 과정이다. 이를 통해 검색 정확도를 높이고, 시스템 전체의 효율성과 확장성을 확보할 수 있다. 명확한 규칙에 따라 데이터 소스를 선택하는 Logical routing과 쿼리의 의미를 분석하여 검색 대상을 결정하는 Semantic routing 기법이 있다.
  3. 쿼리 구성 (Query Construction):
    • 어떤 문제를 해결할까? 모호한 쿼리가 다양한 형식의 데이터베이스에 맞게 최적화되지 않아 검색 품질이 저하되는 문제를 해결한다.
    • 어떻게 해결할까? 검색 대상 데이터베이스의 특성에 맞춰 최적의 쿼리를 생성하는 과정이다. VectorDB, RDB, GraphDB 등 데이터베이스 형식에 따라 임베딩 생성이나 구조화된 쿼리 변환을 수행한다. 예를 들어, VectorDB에서는 쿼리 자체를 최적화하여 임베딩 공간에서 고정밀 검색을 실현하는 Self-query retriever를 사용하고, RDB에서는 자연어 쿼리를 SQL 형식으로 변환하는 Text-to-SQL을, GraphDB에서는 자연어 쿼리를 Cypher 쿼리로 변환하는 Text-to-Cypher를 활용한다.
  4. 인덱스 최적화 (Indexing):
    • 어떤 문제를 해결할까? 데이터 인덱스가 제대로 최적화되지 않아 검색 품질이 낮아지거나 시스템 성능이 떨어지는 문제를 해결한다.
    • 어떻게 해결할까? 검색 성능과 확장성을 높이기 위해 데이터를 저장하는 구조와 전략을 최적화하는 과정이다. 데이터를 적절히 나누고(청크 분할) 표현 형식을 최적화함으로써 검색 정확도를 향상시킬 수 있다. 데이터를 의미에 맞게 적절한 단위로 분할하는 Chunk Optimization, 상위 문서나 다양한 벡터 표현을 병행하여 다각적인 검색을 구현하는 Multi-representation indexing, 특정 태스크에 맞게 임베딩 모델을 미세 조정하는 Specialized Embeddings, 데이터의 계층적 인덱스를 설계하여 효율적인 검색과 리소스 사용을 최적화하는 Hierarchical Indexing 등이 여기에 해당한다.
  5. 검색 (Retrieval):
    • 어떤 문제를 해결할까? 모호한 쿼리나 리랭킹의 부족으로 인해 관련성 높은 정보가 제대로 찾아지지 않는 문제를 해결한다.
    • 어떻게 해결할까? 사용자 쿼리에 대해 가장 관련성 높은 정보를 찾아내고 그 결과를 정제하는 단계이다. 검색 결과의 순위를 재평가하여 최적의 정보를 상위에 노출하는 Ranking 기법(예: Re-Rank, RankLLM)과 검색 결과를 세분화하여 정보의 일관성과 품질을 높이는 Refinement 기법(예: CRAG)을 함께 활용한다. 사용자 쿼리나 문맥에 따라 동적으로 검색을 최적화하는 Active Retrieval도 중요하다.
  6. 생성 (Generation):
    • 어떤 문제를 해결할까? LLM의 태생적인 한계로 인해 응답의 일관성이 떨어지거나, 검색된 정보를 정확히 반영하지 못하는 문제를 해결한다.
    • 어떻게 해결할까? RAG 시스템의 최종 단계로, 검색된 정보를 기반으로 사용자에게 최적의 답변을 제공한다. 자기 개선형 생성 기법을 도입하면 응답의 일관성과 정확성을 더욱 높일 수 있다. Active Retrieval의 한 종류인 Self-RAG는 검색과 생성 프로세스를 통합하여 동적이고 적응적인 응답 생성을 가능하게 한다. 쿼리에 따라 문서 검색의 필요성을 판단하고 생성 품질을 점검하여 할루시네이션(환각) 억제와 답변 품질 향상에 매우 효과적이라고 한다.

오늘 공부한 내용을 다시 한번 돌아보니, 생성형 AI 시스템을 만드는 것은 단순히 LLM을 가져다 쓰는 것을 넘어, 그 시스템이 어떻게 작동하고 어떤 정보를 활용하는지 투명하게 파악하고, 발생할 수 있는 여러 문제들을 각 단계별로 꼼꼼하게 개선해 나가는 과정의 연속이라는 것을 느꼈다.

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.