LLMOps 01

LLMOps: 설계-운영-평가, 유기적 순환의 큰 지도

과정 목표가 여러 단어로 흩어져 있어, LLMOps가 정확히 무엇을 묶는 과목인지 흐릿하다.

근거 · 교안 p3-p6

LLMOps: 설계-운영-평가, 유기적 순환의 큰 지도 대표 이미지

1장: LLMOps, 파편화된 목표를 연결하는 ‘설계’의 첫 단추

솔라의 손가락이 노트북 화면의 한 문장 위에서 멈췄다. 화면에는 며칠 전부터 고민하던 LLMOps 과정 소개 글이 떠 있었다. 여러 번 읽어 익숙한 문장이었지만, 볼 때마다 마음 한구석이 답답해지는 기분은 사라지지 않았다.

“LLMOps를 배우면 LLM 시스템의 단계별 핵심 요소와 운영까지 고려한 설계 역량을 갖춘다고 한다.”

솔라는 의자 등받이에 몸을 깊게 묻으며 한숨을 쉬었다. 거실 한편에서 조용히 책을 읽던 언니 루나가 고개를 들었다.

“언니, 나 이것 좀 봐봐. ‘단계별 핵심 요소’, ‘운영까지 고려한 설계’… 말은 정말 그럴듯한데, 그래서 결국 이게 다 무슨 소리인지 모르겠어. 설계, 운영, 평가. 그냥 다 따로따로 잘하면 되는 일들을 괜히 어렵게 묶어놓은 것 같아.”

솔라의 목소리에는 억울함마저 섞여 있었다. 마치 여러 개의 구슬을 손에 쥐여주며 멋진 목걸이를 만들 수 있다고 말하는데, 정작 구슬을 꿸 실은 어디에도 보이지 않는 기분이었다.

루나는 솔라의 노트북 화면을 잠시 들여다보더니, 말없이 일어나 책상 서랍에서 커다란 백지와 굵은 마커펜 몇 개를 꺼내 왔다. 그리고 솔라 앞의 테이블에 백지를 펼쳤다.

“솔라, 네가 직접 새로운 여행 앱을 위한 LLM 챗봇을 만든다고 상상해봐. 백지상태에서 시작하는 거야. 어떤 부품들이 필요할까? 여기 한번 쭉 적어볼래?”

“갑자기? 음… 일단 똑똑한 LLM 모델이 있어야겠지? 그리고 사용자가 말을 걸 채팅창. 대화 내용을 기억해야 하니까 데이터베이스도 필요할 거고. 실시간 여행 정보를 알려주려면 외부 날씨나 교통 API도 연결해야겠다.”

솔라는 신이 나서 마커펜을 들고 백지 위에 단어들을 적어 내려갔다. ‘LLM 모델’, ‘UI(채팅창)’, ‘DB’, ‘외부 API’… 백지 위에는 금세 챗봇을 구성할 법한 요소들이 흩뿌려지듯 채워졌다. 솔라는 만족스러운 얼굴로 루나를 쳐다봤다.

루나는 흩어져 있는 단어들을 가만히 내려다보았다. 그러고는 다른 색 마커를 솔라에게 건네며 말했다.

“좋아. 부품은 다 모인 것 같네. 그럼 이제 이 부품들이 어떻게 서로 말을 주고받으며 일하는지 화살표로 그려볼래? 어떤 순서로 움직여야 우리가 상상한 챗봇이 될까?”

솔라는 자신 있게 펜을 들었다. “그거야 쉽지.”

솔라는 먼저 ‘사용자’에서 ‘UI(채팅창)’로 화살표를 그었다. 그리고 ‘UI’에서 ‘LLM 모델’로 향하는 화살표를 그리려다 순간 멈칫했다.

“어…? 잠깐만. 사용자가 ‘오늘 제주도 날씨 어때?’라고 물으면, LLM 모델이 대답하기 전에 날씨 API를 먼저 호출해야 하잖아. 그럼 화살표가 모델이 아니라 API로 먼저 가야 하나? 아니, 질문의 의도를 파악하는 게 먼저니까 모델로 가는 게 맞나?”

솔라의 손이 허공에서 방황했다. 흩어져 있을 때는 명쾌해 보였던 부품들이 서로 연결되는 순간, 간단해 보이는 질문조차 복잡한 문제로 변해버렸다. 솔라는 잠시 고민하더니, 기존에 적었던 단어들 사이에 ‘사용자 의도 분석기’라는 새로운 상자를 그려 넣었다. 그리고 모든 요청이 일단 이 상자를 거쳐 가게끔 화살표들을 다시 그리기 시작했다.

사용자의 입력은 ‘UI’를 거쳐 ‘의도 분석기’로 들어온다. ‘의도 분석기’는 질문이 단순 대화인지, 정보 검색인지 판단한다. 정보 검색이라면 ‘외부 API’를 호출하고, 그 결과를 포함해 ‘LLM 모델’에게 자연스러운 답변 생성을 요청한다. 마지막으로 모델이 만든 답변이 다시 ‘UI’를 통해 사용자에게 전달되고, 이 모든 과정은 ‘DB’에 기록된다.

복잡하게 엉킨 실타래가 풀리는 것처럼, 솔라는 화살표를 하나씩 그려나가며 비로소 질서를 찾아갔다. 한참 동안 집중해서 그림을 그리던 솔라가 마침내 펜을 내려놓았다.

“알겠다…!”

솔라의 눈이 반짝였다.

“이게 ‘설계’구나. 그냥 부품들을 나열하는 게 아니었어. 각 부품이 어떤 역할을 하고, 어떤 순서로 정보를 주고받을지, 이 전체적인 ‘흐름’과 ‘구조’를 먼저 그리는 것. 이게 시작이었네. 나는 그냥 구슬만 보고 있었는데, 언니는 구슬을 꿰는 방법에 대해 물어본 거였어. 이 지도가 없으면 ‘운영’을 할 수도, ‘평가’를 할 기준도 없는 거였네.”

처음의 답답함은 사라지고, 흩어져 있던 단어들이 하나의 의미로 연결되는 명쾌함이 그 자리를 채웠다. ‘운영까지 고려한 설계’라는 문장이 이제는 뜬구름 잡는 소리가 아니라, 너무나 당연한 순서로 느껴졌다.

루나가 조용히 고개를 끄덕였다. “그 지도 위에서 우리는 길을 잃지 않고 다음 목적지로 갈 수 있는 거지.”

솔라는 자신이 그린 복잡한 화살표와 상자들이 담긴 지도를 뿌듯하게 바라보았다. 하지만 그 뿌듯함과 함께 새로운 질문이 고개를 들었다.

“지도는 그렸는데… 이 멋진 지도가 진짜 길 위를 달리는 자동차가 되려면… 이제 뭘 해야 하지? 막상 청사진을 그려놓고 보니, 이걸 어떻게 현실에서 실제로 움직이게 할 수 있을지 또 막막해지네.”

2장: ‘실행’: 설계도를 현실로 만드는 첫 걸음

다음 날 아침, 솔라는 어젯밤 루나와 함께 그렸던 복잡한 시스템 설계도를 테이블 위에 펼쳐두고, 노트북 화면에 코드를 띄워놓고 있었다. 어제의 뿌듯함은 온데간데없고, 백지 위에 그려진 명쾌한 화살표들과 모니터 속 알 수 없는 명령어들 사이의 거리가 아득하게만 느껴졌다. 화면 한쪽에는 ‘웹 애플리케이션 배포하기’라는 제목의 튜토리얼이 열려 있었다.

솔라는 마른침을 삼키며 중얼거렸다. “배포(Deploy)…” 그녀는 설계도의 ‘UI’ 상자와 ‘LLM 모델’ 상자를 손가락으로 짚어 보았다. 그리고 다시 화면의 코드를 쳐다봤다. “이 코드를 서버에 올리면… UI는 뜨겠지. 그럼 모델은? 데이터베이스는 어떻게 연결하고? 그냥 ‘배포’ 버튼 하나 누르면 이 모든 게 알아서 착착 움직이는 건가?” 설계도 위의 각 부품들이 마치 서로를 모르는 낯선 사람들처럼 흩어져 보였다.

그때, 커피 향과 함께 루나가 다가와 솔라의 노트북 화면과 설계도를 번갈아 보았다.

“멋진 설계도 위에 진짜 자동차를 올리려고 하는구나. 그런데 지금은 자동차를 도로에 올리는 것보다, 자동차의 시동을 거는 법부터 고민하는 것 같네.”

솔라는 루나의 말에 고개를 들었다. “시동? 일단 서버에 올려야 시동을 걸든 말든 하지 않아? ‘실행’이라는 게 결국 배포하는 거잖아.”

그 말에 루나는 설계도를 손가락으로 톡톡 두드렸다. “배포는 이 설계도로 지은 건물을 어딘가에 세워두는 일이야. 우리가 하려는 건 그 건물에 불을 켜고, 문을 열고, 손님을 맞이하는 일이지. 자, 시뮬레이션 한번 해볼까?”

루나는 설계도의 ‘사용자’라고 쓰인 동그라미를 가리켰다. “사용자가 우리 챗봇 앱을 처음 켰어. 가장 먼저 뭐가 필요하지?”

“음… 사용자가 글씨를 입력할 채팅창? 그러니까 UI가 화면에 보여야지.” 솔라가 대답했다.

“좋아. 그럼 UI라는 부품에 전원이 켜졌다고 상상해보자.” 루나는 UI 상자 위에 작은 포스트잇을 붙였다. “이제 사용자가 ‘오늘 제주도 날씨 어때?‘라고 입력하고 ‘전송’ 버튼을 눌렀어. 그 다음엔 뭐가 일어나야 해?”

솔라는 자기가 그렸던 화살표를 따라갔다. “입력된 질문이 ‘사용자 의도 분석기’로 가야 해.”

“그럼 ‘사용자 의도 분석기’에도 전원이 들어와 있어야겠네?” 루나는 ‘사용자 의도 분석기’ 상자 위에도 포스트잇을 붙였다. 솔라는 잠시 생각하더니 고개를 끄덕였다.

루나가 계속 질문을 던졌다. “의도 분석기가 ‘날씨 정보 검색’이라는 의도를 파악했어. 그 다음은?”

“외부 날씨 API를 호출해서 제주도 날씨 데이터를 가져와야지.”

“그 API는 항상 우리 요청을 받을 준비가 되어 있어야 하고?”

“당연하지.”

“가져온 날씨 데이터를 가지고 자연스러운 답변 문장을 만들려면?”

“LLM 모델이 깨어 있어야 해. 모델을 메모리에 미리 올려놓고, 요청이 오면 바로 처리할 수 있는 상태로.” 솔라는 스스로 ‘LLM 모델’ 상자 위에 포스트잇을 붙였다. 그리고 잠시 후, ‘DB’ 상자 위에도 포스트잇을 하나 더 붙였다.

“아, 그리고 이 모든 대화 내용을 기록하려면 데이터베이스 연결도 미리 활성화되어 있어야 하네.”

솔라는 포스트잇이 붙은 상자들을 멍하니 바라보았다. 처음에는 그저 하나의 덩어리로 생각했던 ‘실행’이라는 과정이, 실제로는 각 부품들이 각자의 위치에서 깨어나 서로 신호를 주고받을 준비를 마친 상태라는 것을 깨달았다.

“알겠다…!” 솔라의 목소리에 활기가 돌았다. “나는 ‘실행’이 그냥 완성된 프로그램을 서버에 던져놓는 일회성 이벤트라고 생각했어. ‘배포’ 버튼 누르면 끝나는 걸로. 그런데 그게 아니었네. UI, 의도 분석기, LLM 모델, DB… 이 모든 부품들이 각자 살아 움직이면서 서로 통신할 준비를 마친 상태, 그 생명력이 부여된 상태 자체가 ‘실행’이었구나. 가게 문을 여는 거랑 똑같네. 간판만 걸어놓는 게 아니라, 조명도 켜고, 계산기도 켜고, 직원들도 각자 자리에 서 있어야 장사를 시작할 수 있는 거잖아.”

솔라는 ‘배포’라는 단어에 갇혀 있던 자신의 생각이 얼마나 좁았는지 깨달았다. 설계도를 현실로 만든다는 것은 단순히 코드를 어딘가에 복사해두는 행위가 아니었다. 설계된 시스템의 모든 구성 요소에 숨을 불어넣어, 사용자의 요청에 언제든 응답할 수 있는 살아있는 유기체로 만드는 과정이었다.

루나는 만족스러운 듯 커피를 한 모금 마셨다. “맞아. 그게 바로 ‘실행 활성화’야. 설계도라는 정적인 청사진이, 사용자에게 가치를 전달할 수 있는 동적인 시스템으로 깨어나는 순간이지.”

새로운 깨달음에 대한 흥분도 잠시, 솔라의 미간에 다시 새로운 질문의 그림자가 드리워졌다.

“좋아. 가게 문도 열었고, 직원들도 다 깨어있어. 그런데… 손님이 들어와서 물건에 대해 물어봤는데 직원이 엉뚱한 대답을 하면 어떡하지? 지금 우리 시스템이 살아 움직인다는 건 알겠는데, 그래서 얘가 지금 일을 잘 하고 있는 건지, 안에서 무슨 일이 벌어지고 있는지는 어떻게 알아? 그냥 깜깜한 상자 같아.”

3장: ‘추적’: 시스템의 심장을 들여다보는 눈

솔라는 자신의 노트북 화면을 노려보고 있었다. 화면 한가득 알아볼 수 없는 문자열이 가득했다. 어제 ‘실행 활성화’에 성공한 여행 챗봇 시스템의 서버 로그였다. 시스템은 분명 살아 움직이고 있었지만, 그 속은 칠흑 같은 어둠이었다. 솔라는 일부러 시스템에 애매한 질문을 던져 오류를 유발했다. ‘제주도 말고 거기 날씨는?’ 그러자 로그 창에 새로운 줄이 찍혔다. [ERROR] Intent classification failed. No location entity found.

이게 전부였다. 어느 사용자의 어떤 질문 때문에, 시스템의 어느 부분에서 문제가 시작되었는지 도무지 알 길이 없었다. 설계도 위에서 명쾌하게 움직이던 화살표들은 온데간데없고, 그저 깜깜한 상자 안에서 무언가 잘못되었다는 희미한 비명 소리만 들려오는 듯했다. 솔라는 답답한 마음에 머리를 헝클어뜨렸다. 그 모습을 지켜보던 루나가 태블릿에서 눈을 뗐다. 어제 포스트잇이 붙어있던 시스템 설계도를 솔라 쪽으로 밀어주며 입을 열었다.

“그 깜깜한 상자 안에 우리가 직접 조명을 설치하면 어떨까? 문제의 원인을 찾는 탐정이 아니라, 모든 과정을 지켜보는 관객이 되어보는 거야.”

“관객? 난 그냥 에러 로그만 확인하면 될 줄 알았는데… 문제가 생겼을 때만 들여다보는 거 아니었어?”

솔라는 문제 발생 시 사후에 로그를 뒤지는 것이 당연하다고 생각했다. 루나는 고개를 저으며 솔라가 그렸던 설계도의 출발점, ‘사용자’ 동그라미를 손가락으로 가리켰다.

“사용자가 ‘오늘 제주도 날씨 어때?’라고 질문을 던지는 순간부터 여행이 시작된다고 상상해봐. 이 질문이 우리 시스템 안을 여행하는 동안, 각 경유지에서 기념사진을 찍는 거야. 솔라, 네가 사진사야. 어디서, 어떤 사진을 찍고 싶어?”

솔라는 잠시 어리둥절했지만, 이내 루나의 의도를 파악하고 옆에 놓인 깨끗한 A4 용지에 펜을 가져갔다.

“음… 첫 번째 경유지는 ‘UI(채팅창)’이겠지? 여기서는 사용자가 입력한 질문 그대로, ‘오늘 제주도 날씨 어때?‘라는 문장을 사진 찍어둬야겠어. 시간도 함께. ‘오후 2시 15분 3초’.”

솔라는 용지에 첫 번째 사진 프레임을 그리고 내용을 적었다.

“좋아. 다음 경유지는 ‘사용자 의도 분석기’네. 여기서는 어떤 사진을 찍을까?” 루나가 물었다.

“의도 분석기가 무슨 일을 했는지 찍어야지!” 솔라는 신이 나서 두 번째 프레임을 그렸다. “입력된 문장에서 ‘날씨 질문’이라는 의도를 파악했고, ‘제주도’라는 장소와 ‘오늘’이라는 시간 정보를 뽑아냈다는 사실. 이 세 가지 정보를 모두 찍어둘래.”

펜이 망설임 없이 움직였다. 솔라는 다음 경유지인 ‘외부 API 호출’ 단계에 세 번째 프레임을 그렸다. “여기서는 우리 시스템이 날씨 API에 보낸 요청 그대로를 찍어야 해. ‘장소=제주, 날짜=오늘’이라는 정보가 담긴 요청. 그리고 API가 우리에게 돌려준 응답도. ‘맑음, 최고 25도’ 같은 거.”

네 번째 프레임은 ‘LLM 모델’ 차례였다. “모델한테는 최종적으로 어떤 문장을 만들어달라고 요청했는지, 그 프롬프트 전문이 필요해. ‘제주도의 오늘 날씨 정보(맑음, 25도)를 바탕으로 친절한 안내 문구를 생성해줘.’ 같은 요청 문장. 그리고 모델이 생성한 답변, ‘오늘 제주도 날씨는 화창하고 최고기온은 25도랍니다! 여행하기 딱 좋은 날씨네요!’ 이것도 빠짐없이 찍어야지.”

마지막으로 솔라는 이 모든 과정의 시작과 끝, 그리고 각 단계를 거치는 데 걸린 시간까지 꼼꼼하게 기록했다. 용지 위에는 한 사용자의 질문이 시스템 안에서 어떻게 변환되고 처리되는지의 여정이 한눈에 들어오는 파노라마 사진처럼 펼쳐져 있었다.

“알겠다…!”

솔라는 자신이 그린 그림을 보며 무릎을 쳤다.

“나는 그냥 ‘에러 발생!’이라는 결과만 보고 있었어. 문제가 터진 후에야 깜깜한 상자를 열고 단서를 찾으려고 했던 거야. 그런데 이렇게 각 단계마다 사진을 찍어두니까, 에러가 나든 안 나든 모든 과정이 투명하게 보이잖아. 이걸 ‘추적’이라고 하는 거구나. 문제가 생기면 어디서부터 잘못됐는지 바로 알 수 있고, 문제가 없더라도 우리 시스템이 우리가 의도한 대로 잘 움직이고 있는지 확인할 수 있는 거야. 이건 그냥 로그 확인이 아니야. 시스템의 혈관을 따라 흐르는 혈액의 움직임을 실시간으로 들여다보는 내시경 같은 거였어.”

단순히 사후에 훑어보는 기록이 아니었다. 시스템의 심장 박동과 혈류를 실시간으로 관찰하는 행위, 바로 ‘추적(Trace)’이었다. 설계도 위의 정적인 상자들이 동적인 흐름으로 바뀌는 순간이었다. 솔라가 겪었던 ‘깜깜한 상자’에 대한 답답함은 사라지고, 시스템의 내부를 환히 들여다볼 수 있다는 자신감이 그 자리를 채웠다.

루나가 조용히 고개를 끄덕였다. “맞아. 그 각 시점의 사진이 ‘스냅샷(Snapshot)‘이고, 그 사진들을 시간 순서대로 엮은 한 편의 여행기가 바로 ‘트레이스(Trace)‘지. 이제 우리는 길을 잃어도 어디서부터 길을 잘못 들었는지 단번에 알 수 있어.”

솔라는 자신이 완성한 ‘추적 지도’를 뿌듯하게 내려다보았다. 사용자 질문 하나가 남긴 선명한 발자국들이었다. 하지만 곧 새로운 궁금증이 고개를 들었다.

“좋아, 이제 모든 걸 투명하게 볼 수 있게 됐어. 이 발자국들이 정말 많이 쌓이면… 어떤 발자국이 ‘좋은’ 거고, 어떤 게 ‘나쁜’ 건지 어떻게 판단하지? ‘오늘 제주도 날씨는 25도’라고 딱딱하게 대답한 추적 데이터랑, ‘여행하기 딱 좋은 날씨네요!’라고 친절하게 답한 추적 데이터가 있는데, 후자가 더 좋다는 건 어떻게 증명할 수 있을까? 그냥 내 기분으로 판단할 순 없잖아.”

4장: ‘평가’: 추적 데이터로 시스템 가치를 측정하다

다음 날, 거실 테이블은 솔라가 벌여놓은 작은 전쟁터 같았다. 어제 루나와 함께 만들었던 ‘추적 지도’ 수십 장이 두 무더기로 나뉘어 있었다. 한쪽 무더기 위에는 솔라가 꾹꾹 눌러쓴 포스트잇이 붙어 있었다. ‘성공! 🙂’. 다른 쪽 무더기 위에는 ‘실패 🙁’라는 글씨가 시무룩하게 적혀 있었다. 시스템이 내놓은 다양한 답변들을 하나하나 추적 데이터로 출력해서, 솔라 나름의 기준으로 분류해 본 것이었다.

하지만 솔라의 표정은 조금도 개운하지 않았다. 그녀는 ‘성공’ 무더기의 맨 위에 있는 추적 데이터 한 장과, ‘실패’ 무더기의 맨 위에 있는 데이터 한 장을 나란히 놓고 노려보고 있었다.

  • 추적 A (성공 🙂): 최종 답변: “오늘 제주도 날씨는 맑음, 최고기온 25도입니다. 여행하기 좋은 날씨네요!”
  • 추적 B (실패 🙁): 최종 답변: “요청하신 제주도의 금일 기상 정보는 다음과 같습니다: 최고 25도, 날씨 맑음.”

솔라는 미간을 찌푸렸다. “분명히 B도 틀린 말은 아니란 말이지. 정보는 정확하게 다 들어있는데… 그냥 딱딱해서 ‘실패’로 분류했어. A는 친절하니까 ‘성공’이고. 근데 이게 내 기분 탓인가? 개발자 기분에 따라 시스템 성능이 결정되는 건 아니잖아. 이걸 어떻게 객관적으로 증명하지?”

그때 조용히 다가온 루나가 솔라의 손에 들린 두 장의 추적 지도를 내려다보았다. 그리고는 말없이 새 노트를 펼쳐 두 개의 세로줄을 그어 세 개의 칸을 만들었다. 첫 칸에는 ‘추적 데이터’, 두 번째 칸에는 ‘규칙 기반’, 세 번째 칸에는 ‘의미 기반’이라고 적었다.

“솔라, 네가 지금 하고 있는 건 ‘평가’야. 그런데 좋은 평가를 하려면 좋은 채점 기준표가 먼저 필요해. 감으로 채점하면, 나중에 왜 이 점수가 나왔는지 아무에게도 설명할 수 없게 되니까.”

루나는 솔라가 들고 있던 추적 데이터 A와 B를 가져와 노트의 ‘추적 데이터’ 칸 아래에 나란히 놓았다.

“자, 먼저 ‘규칙 기반 평가’부터 해보자. 이 챗봇이 ‘반드시’ 지켜야 하는 규칙은 뭘까? 절대로 틀리면 안 되는 거.”

솔라는 잠시 생각하더니 대답했다. “일단 ‘제주도’라는 장소와 ‘오늘’이라는 날짜를 정확히 인식해야 해. 그리고 날씨 API에서 받아온 ‘25도’라는 숫자랑 ‘맑음’이라는 사실. 이 네 가지 정보는 무조건 답변에 포함되어야지.”

“좋아. 그 기준에 따르면, A와 B는 어때?”

솔라는 두 답변을 꼼꼼히 살폈다. “둘 다 네 가지 핵심 정보는 빠짐없이 담고 있어. 규칙 기반으로는 둘 다 합격이네.” 솔라는 ‘규칙 기반’ 칸에 A와 B 모두 동그라미를 쳤다. 하지만 여전히 무언가 해결되지 않은 기분이었다.

루나가 이번에는 ‘의미 기반’이라고 쓰인 마지막 칸을 가리켰다.

“그럼 이번엔 우리 챗봇의 존재 이유를 생각해 보자. 이 챗봇은 왜 만들었지? 단순히 날씨 정보를 알려주는 기계가 목표였나?”

“아니.” 솔라는 고개를 저었다. “여행자에게 도움이 되는 친절한 안내자. 그게 우리의 목표였어.”

“그렇다면 ‘친절한 안내자’라는 목표에 더 가까운 답변은 어느 쪽이지? 어떤 기준으로 그렇게 판단할 수 있을까?”

루나의 질문에 솔라의 머릿속이 환해졌다. 성공/실패라는 이분법적 사고에 갇혀 있던 시야가 트이는 느낌이었다.

“알겠다! ‘친절함’이라는 기준을 추가하면 돼! 그리고… 여행자에게 도움이 되는 ‘추가 정보’가 있는지도 볼 수 있겠네. 예를 들면 ‘여행하기 좋은 날씨네요!’ 같은 말.”

솔라는 펜을 들어 ‘의미 기반’ 칸 아래에 ‘친절함’, ‘유용성’이라는 새로운 평가 항목을 적었다. 그리고 다시 두 답변을 채점하기 시작했다.

  • 추적 A: 친절함(O), 유용성(O) -> “여행하기 좋은 날씨”라는 코멘트가 있다.
  • 추적 B: 친절함(X), 유용성(△) -> 정보는 있지만, 안내자 역할은 부족하다.

채점표가 완성되자, 왜 A가 B보다 더 ‘좋은’ 답변인지 명확하게 드러났다. 더 이상 솔라의 ‘기분 탓’이 아니었다. 비즈니스 목표(‘친절한 안내자’)에 기반한 명백한 근거가 생긴 것이다.

“이거였구나…!”

솔라의 목소리가 들떴다. 그녀는 자신이 만들었던 ‘성공’과 ‘실패’ 포스트잇을 떼어버렸다.

“나는 평가가 그냥 모델이 정답을 맞혔는지, 숫자가 정확한지를 따지는 시험 문제 풀이 같은 거라고만 생각했어. 하지만 진짜 ‘평가’는, 우리 시스템이 우리가 정한 역할과 목표를 얼마나 잘 수행하는지 측정하는 거였어. 단순히 맞고 틀리고의 문제가 아니라, ‘얼마나 더 나은가’를 다각적으로 재는 자였네. 규칙 기반 평가는 시스템의 기본기를, 의미 기반 평가는 시스템의 가치를 증명하는 거였어.”

솔라는 이제 추적 데이터를 바라보는 눈이 달라져 있었다. 이전에는 그저 시스템의 행적을 기록한 발자국으로 보였다면, 이제는 시스템의 건강 상태와 잠재력을 진단할 수 있는 상세한 의료 기록지처럼 느껴졌다.

루나는 만족스러운 듯 고개를 끄덕였다. “그렇게 측정된 점수들이 모여서 우리 시스템의 현재 가치를 보여주는 성적표가 되는 거지.”

솔라는 자신이 만든 채점 기준표를 뿌듯하게 바라보았다. 이 기준표만 있다면, 수천, 수만 개의 추적 데이터도 일관된 기준으로 분석할 수 있을 것 같았다. 그런데 문득, 새로운 질문이 머리를 스쳤다.

“좋아. 이제 우리 시스템이 어떤 부분에서 F 학점을 받고, 어떤 부분에서 A+를 받는지 알게 됐어. 이 성적표를 받았는데… 그래서 이제 뭘 해야 하지? 규칙 기반 평가에서 계속 틀린다면 뭐가 문제고, 의미 기반 평가 점수가 낮으면 뭘 고쳐야 하는 거야? 이 점수표를 들고 어디로 가야 우리 시스템을 더 똑똑하게 만들 수 있을지, 갑자기 또 막막해지네.”

5장: ‘개선’: LLMOps 순환의 완성, 더 나은 시스템을 향하여

테이블 위는 솔라가 며칠에 걸쳐 만들어낸 결과물들로 가득했다. 맨 왼쪽에는 복잡한 화살표로 얽힌 첫 번째 ‘설계도’가, 그 옆에는 시스템의 여행기를 담은 ‘추적 지도’ 여러 장이, 그리고 맨 오른쪽에는 동그라미와 엑스 표시가 매겨진 ‘평가 채점표’가 놓여 있었다. 솔라는 그 채점표를 손에 들고 심각한 표정으로 설계도를 노려보고 있었다. 그녀의 손가락은 채점표에서 ‘의미 기반 평가: 낮음’이라고 적힌 항목과 설계도의 ‘LLM 모델’ 상자를 번갈아 가리키고 있었다.

“규칙 기반 평가는 거의 다 통과했는데, 의미 기반 평가 점수가 계속 낮게 나와. 답변이 너무 딱딱하다는 거야. 결국 이 모델이 문제네. 더 창의적이고 말을 예쁘게 하는 모델로 바꿔야 하나? 아니면 모델을 우리 목표에 맞게 다시 학습시켜야 하나?” 솔라는 중얼거렸다. 낮은 점수를 받은 성적표를 들고, 곧장 문제 학생을 지목하듯 모델을 탓하고 있었다. ‘개선’이란 당연히 문제가 있는 부품을 교체하거나 수리하는 것이라고, 솔라는 믿어 의심치 않았다.

그 모습을 지켜보던 루나가 조용히 다가왔다. 루나는 솔라의 손에 들린 채점표를 잠시 보더니, 말없이 테이블 위에 흩어져 있던 결과물들을 한데 모아 순서대로 배열했다. 맨 왼쪽부터 ‘설계도’, 그 다음은 포스트잇이 붙었던 ‘실행’ 시뮬레이션의 기억, 그 옆에 ‘추적 지도’, 그리고 마지막으로 ‘평가 채점표’까지. 마치 사건 현장에 흩어진 증거들을 시간 순으로 정리하는 수사관 같았다.

“솔라, 네 말이 맞을 수도 있어. 모델이 문제일 수도 있지. 하지만 성급하게 범인을 지목하기 전에, 우리가 걸어온 길을 처음부터 다시 한번 돌아보는 건 어떨까? 이 성적표는 최종 결과일 뿐, 원인은 다른 곳에 숨어있을지도 몰라.”

루나는 ‘의미 기반 평가: 낮음’이라는 결과가 나온 추적 지도 한 장을 집어 들었다. 그 지도에는 “오늘 제주도 날씨는 화창하고 최고기온은 25도랍니다! 여행하기 딱 좋은 날씨네요!”라는 좋은 답변 대신, “요청하신 제주도의 금일 기상 정보는 다음과 같습니다: 최고 25도, 날씨 맑음.”이라는 딱딱한 답변이 기록되어 있었다.

“이 답변을 만든 건 LLM 모델이야. 그런데 이 모델은 이런 답변을 만들라는 ‘요청’을 받았기 때문에 이렇게 행동했겠지? 우리가 찍어둔 추적 사진을 다시 보자. 모델은 최종적으로 어떤 요청을 받았지?”

솔라는 루나의 말에 추적 지도의 네 번째 프레임, ‘LLM 모델’에게 전달된 요청 부분을 자세히 들여다봤다. 거기에는 이렇게 쓰여 있었다. ‘제주도의 오늘 날씨 정보(맑음, 25도)를 바탕으로 안내 문구를 생성해줘.’

솔라의 눈이 동그래졌다. “어? 여기엔 ‘친절하게’나 ‘여행자에게 말하듯이’ 같은 말이 없네. 그냥 정보로 문장을 만들어달라고만 되어 있잖아.”

“그렇지. 그럼 이 요청 문장은 누가 만들었지?”

솔라의 시선은 추적 지도를 거슬러 올라가 ‘사용자 의도 분석기’ 단계로 향했다. 그곳에서 날씨 정보를 조합해 LLM에 보낼 프롬프트를 만들고 있었다. 솔라는 그제야 깨달았다. 모델은 죄가 없었다. 모델은 단지 지시받은 대로 일했을 뿐이다.

“그럼… 의도 분석기 코드를 고쳐야 하는 거구나! 모델에 보낼 요청문에 ‘친절한 여행 안내자처럼 답변해줘’라는 문구를 추가하도록!”

솔라는 당장이라도 노트북을 열어 코드를 수정할 기세였다. 하지만 루나는 솔라를 막아서며, 배열의 맨 왼쪽에 있던 첫 번째 ‘설계도’를 손가락으로 가리켰다.

“맞아. 그것도 좋은 개선 방법이야. 하지만 한 걸음만 더 뒤로 가보자. 우리가 맨 처음에 이 시스템을 구상했을 때, 이 설계도에 그런 약속을 적어두었던가? ‘의도 분석기는 LLM 모델에게 친절한 톤을 유지하도록 요청해야 한다’는 규칙 말이야.”

솔라는 자기가 처음 그렸던 설계도를 들여다보았다. ‘의도 분석기’에서 ‘LLM 모델’로 향하는 화살표만 덩그러니 있을 뿐, 그 화살표가 어떤 종류의 정보를, 어떤 스타일로 전달해야 하는지에 대한 규칙은 어디에도 없었다. 그저 ‘연결된다’는 사실만 존재할 뿐이었다.

그 순간, 솔라의 머릿속에서 모든 조각이 맞춰졌다.

“알겠다…!”

솔라의 손이 ‘평가 채점표’에서 시작해 ‘추적 지도’, ‘실행’, 그리고 마침내 ‘설계도’로 이어지는 거대한 화살표를 허공에 그렸다.

“나는 계속 선을 따라가기만 했어. 설계하고, 실행하고, 추적하고, 평가하면 끝. 그리고 평가에서 문제가 생기면 그 부분만 고치면 된다고 생각했어. 모델 점수가 낮으면 모델을, 코드에 버그가 있으면 코드를. 그런데 아니었네. 평가 결과는 종착역이 아니라, 다시 출발점으로 돌아가는 이정표였어! 이 낮은 점수는 우리에게 ‘모델을 바꿔!’라고 말하는 게 아니라, ‘너희의 설계도에 빈틈이 있어!’라고 알려주는 신호였던 거야.”

솔라는 마커펜을 들고 처음 그렸던 설계도를 수정하기 시작했다. ‘의도 분석기’에서 ‘LLM 모델’로 가는 화살표 위에 ‘친절한 여행 가이드 페르소나 유지’라고 명확히 적어 넣었다. 그러고는 평가(Evaluate)에서 설계(Design)로 돌아오는 커다란 순환 화살표를 그렸다. 흩어져 있던 점들이 마침내 하나의 원, 살아있는 고리가 되었다.

Design, Run, Trace, Evaluate… 그리고 마지막 단계인 Improve(개선)는 이 순환 자체였다.

“‘운영까지 고려한 설계’라는 게 바로 이 뜻이었구나.” 솔라는 며칠 전 자신을 답답하게 했던 문장을 나지막이 읊조렸다. “설계를 할 때부터, 나중에 우리가 무엇을 추적하고, 어떤 기준으로 평가하며, 그 결과에 따라 어떻게 개선할지를 미리 생각해야 한다는 뜻이었어. 이 모든 과정이 처음부터 하나의 흐름으로 연결되어 있다는 걸 모르면, 길을 잃을 수밖에 없는 거였어.”

솔라의 손에 들린 것은 더 이상 단순한 설계도가 아니었다. 그것은 ‘설계-실행-추적-평가-개선’이 유기적으로 순환하는, 살아 숨 쉬는 시스템의 ‘운영 지도’였다. 파편화된 단어의 나열이 아니라, 목표를 향해 끊임없이 나아가는 유기적인 순환의 흐름. 솔라는 이제 길을 잃지 않고 다음 목적지로 갈 수 있는 자신만의 지도를 손에 넣었다.