최근 LLM 기반 서비스들의 약점을 RAG(Retrieval-Augmented Generation)으로 보완하는 방법이 등장하면서, 실제 서비스에서도 이를 적용하는 사례가 종종 눈에 띈다. RAG 기반 LLM 서비스를 개발할 때 허들이 되는 것들 중 하나는, 과연 어떤 LLM 모델과 프롬프트, VectorDB, Retrieval 방식을 조합해 사용해야 하는지 결정하는 일이다. LLM 모델의 경우 여러 벤치마크 점수가 존재하기도 하고, VectorDB 역시 각각의 장단점이 어느 정도 알려져 있는 등 각 요소에 대한 평가는 상대적으로 수월할 수 있지만, 실제로 이들을 조합한 서비스를 만들었을 때 그 성능을 어떤 잣대로 평가해야 하는지는 오롯이 관계자들이 정해야 하는 부분이다. 만약 서비스에서 다루는 데이터가 수치형 데이터가 많이 포함되어있는 구조화된 텍스트인 경우, 일반적인 벤치마크로는 실제 성능을 충분히 반영하지 못하기도 한다.
이번 글에서는 LLM과 RAG를 활용한 서비스를 평가하기 위한 프레임워크를 설계했던 경험을 러프하게 풀어보고자 한다.
RAG 기반 LLM 서비스의 구조
개발자가 작성한 소스 코드의 품질을 평가하는 시스템을 예로 들어보자. 이 가상의 서비스는 입력된 코드에서 다양한 low-level feature를 추출하고, 이를 기반으로 코드의 high-level feature를 도출한 후, 최종적으로 코드 품질에 대한 평가 텍스트(assessment text)를 제공하는 서비스이다.
- Low-level feature: 코드에서 추출된 기계적 지표
- ex) 코드의 라인 수, 순환 복잡도, 중첩 깊이, 변수 명명 규칙 준수율 등
- High-level feature: 사람이 이해할 수 있는 지표
- ex) 코드 가독성, 유지 보수성, 확장성 등
- Assessment text: 코드 품질에 대한 전반적인 평가와 개선 사항 제안
- ex) "이 코드는 가독성이 높지만, 모듈화가 부족하여 유지 보수가 어렵습니다."
서비스 작동 방식은 다음과 같다.
- VectorDB(Reference Data)에 특정 코드에 대한 low-level feature, high-level feature, assessment text가 저장되어 있는 상태에서, input data가 들어오면 코드 분석 툴을 사용해 low-level feature를 추출한다.
- 추출된 low-level feature를 기반으로, refernece data 중 유사한 코드 K개를 검색하고, VectorDB에서 유사도 검색을 통해 품질이 비슷한 코드를 찾는다
- 검색된 코드들의 low-level feature, high-level feature, assessment text를 참고하여, 입력 코드의 high-level feature와 assessment text를 LLM을 통해 생성한다.
서비스 평가 프레임워크 설계
위와 같은 서비스를 개발할 때 예상되는 문제점과 평가가 필요한 항목을 매칭시켜보면 다음과 같다.
- 숫자값을 포함하고 있는 정형화된 텍스트가 input으로 주어졌을 때, 일반적인 text-embedding model을 통해 retrieval을 수행하면 성능이 높지 않을 것이다 - Retrieval 성능 평가
- LLM이 low-level feature를 보고 생성한 high-level feature의 정확도가 높지 않을 수 있다(ML 모델을 개발해 결합하는 것이 더 나을 수 있다) - High-level feature 생성 성능 평가
- LLM이 생성한 assessment text의 정확도가 높지 않을 수 있다 - Assessment text 생성 성능 평가
- 같은 input data이더라도 high-level feature, assessment text가 다르게 생성될 수 있다(temperature를 0으로 설정하더라도) - 결과의 일관성 평가
이렇게 파트 별로 평가 항목을 정의해두고 나면, 테스트를 진행한 후 프롬프트를 개선해야 하는지, Retrieval 로직을 변경해야 하는지, LLM 모델을 개선해야 하는지 가늠해볼 수 있다.
1. Retrieval 성능 평가
- input data의 코드와 유사한 케이스로 뽑힌 코드들의 품질 등급이 일치하는지 평가
- 검색된 코드들의 low-level feature 값의 차이를 계산하고, 차이가 작을 수록 검색이 잘 되었다고 평가
- 만약 이 부분에서 평가 결과가 좋지 않다면 retrieval 방법을 변경해보자는 의사결정을 할 수 있다. text-embedding 모델을 변경해보거나, VectorDB를 변경해볼 수도 있고, 아예 low-level feature를 정형데이터로 변형해 코사인 유사도를 기반으로 유사 케이스를 추출해 볼수도 있다.
2. Generation 성능 평가
- LLM이 생성한 high-level feature가 실제 코드의 특성과 얼마나 일치하는지 평가(accuracy, f1 score 등)
- RAGAS 등을 통해 LLM이 생성한 assessment text의 정확성(vs gound truth), 관련성(vs context) 등을 정량적으로 평가
- 만약 이 부분의 평가지표가 낮게 나온다면, LLM model을 변경해보거나 프롬프트 엔지니어링을 시도해볼 수 있다.
3. 결과의 일관성 평가
- 동일한 입력 코드에 대해 여러 번 분석을 수행하여, retrieval 결과, high-level feature, assessment text가 얼마나 일관적으로 생성되는지 평가
- Retrieval, generation 중 어떤 부분의 일관성이 좋지 않은지 확인한 후 retrieval → generation 순으로 일관성을 개선해 나가볼 수 있다.
결론
RAG 기반 LLM 서비스를 개발할 때, 최초의 의사결정은 당시의 SOTA model과 가장 널리 알려진 retrieval 방법 등을 차용해 진행될 수 있다. 그러나 개발을 진행하다보면 어떤 부분을 개선해야할지, 현재의 성능은 정확히 어느 정도인지 평가하기 위해 각 요인들을 평가할 수 있는 테스트 프레임워크가 필요한 단계가 온다. 위의 예시는 서비스 구조를 단순화시킨 예시로, 각 평가 파트에서의 추가적인 평가 방법과 구체적인 개선 전략이 있을 수 있지만, 비슷한 고민을 하는 분들이 이 글을 통해 LLM 기반 서비스의 평가 설계에 아이디어를 얻어갈 수 있었으면 한다.
Share article