LLMOps 18

Supervisor 패턴 안에서 HITL 중앙 통제하기

Worker가 위험을 발견하면 직접 사람에게 넘기면 된다고 보기 쉽다.

근거 · 교안 p52-p54

Supervisor 패턴 안에서 HITL 중앙 통제하기 대표 이미지

1장: 워커 직접 호출, 무엇이 문제일까?

솔라의 손가락이 노트북 화면의 한 문장 위를 맴돌고 있었다. 문장은 짧고 단호했다.

[Worker가 HITL을 호출하면 흐름이 분산되고, 정책 통제가 깨진다.]

솔라는 미간을 찌푸렸다. 거실 한쪽에서 조용히 책을 읽던 언니 루나에게 고개를 돌렸다.

“언니, 이거 좀 이상해. 이해가 안 돼.”

루나는 책에서 눈을 떼고 솔라의 노트북 화면을 물끄러미 바라보았다.

“어떤 게?”

“시스템을 만들 때, AI 워커(Worker)가 스스로 해결 못 하는 위험한 상황을 만나면 사람의 개입(HITL)을 요청할 수 있잖아. 그런데 여기서는 워커가 직접 사람을 부르면 안 된대. 흐름이 분산되고 정책 통제가 깨진다고. 아니, 문제를 발견한 당사자가 바로 도움을 요청하는 게 가장 효율적인 거 아니야? 우물쭈물하다가 보고 체계 다 거치면 시간만 더 걸리지.”

솔라의 목소리에는 ‘이건 너무나 명백한 비효율이다’라는 확신이 묻어났다. 가장 빠른 길을 일부러 막아 놓은 이상한 규칙처럼 보였다.

루나는 잠시 생각하더니, 소파 테이블 위를 손으로 가리켰다.

“솔라, 우리 저녁에 있을 대규모 연회를 준비하는 아주 크고 바쁜 주방을 상상해 보자.”

“주방?”

“응. 총괄 셰프가 한 명 있고, 그 아래에 여러 명의 담당 요리사들이 각자 스테이크, 수프, 샐러드, 디저트 파트를 맡고 있어. 총괄 셰프는 모든 요리가 정확한 시간에, 정해진 순서와 품질로 나갈 수 있도록 전체 계획을 짜고 지휘하는 사람이야. 일종의 슈퍼바이저(Supervisor)지.”

솔라는 고개를 끄덕였다. 머릿속에 분주하게 움직이는 요리사들과 그들을 지휘하는 날카로운 눈빛의 셰프가 그려졌다.

“그런데 스테이크를 굽던 요리사가 문제를 발견했어. 오늘 들어온 고기 질이 평소와 달라서, 원래 레시피대로 구우면 딱딱해질 것 같은 거야. 이건 연회의 중요한 메인 요리니, 그냥 넘어갈 수 없는 문제지.”

“그렇지. 그럼 당장 사람한테 물어봐야지. HITL이 필요한 순간이네.”

솔라가 맞장구를 쳤다.

“그래. 솔라 네 말대로라면, 이 스테이크 담당 요리사는 어떻게 해야 할까?”

루나의 질문에 솔라는 망설임 없이 대답했다.

“당연히 연회 담당 지배인을 찾아가야지! ‘고기 상태가 이러이러한데, 그냥 진행할까요, 아니면 다른 메뉴로 바꿀까요?’ 하고 직접 물어보는 게 가장 빠르잖아.”

“좋아. 그럼 그 요리사가 앞치마를 풀고 주방을 뛰쳐나가 지배인을 찾아다닌다고 해보자.”

루나는 솔라의 시나리오를 그대로 받아 이야기를 이어갔다.

“그 순간, 주방에서는 무슨 일이 일어날까? 첫째, 스테이크 파트는 완전히 멈춰 섰어. 둘째, 바로 옆에서 소스를 만들던 요리사는 스테이크가 언제 나올지 몰라 자기 일의 속도를 조절할 수가 없지. 셋째, 총괄 셰프는 지금 자기 요리사 한 명이 어디로 사라졌는지, 그리고 가장 중요한 메인 요리에 무슨 문제가 생겼는지조차 파악하지 못하고 있어. 다른 요리사들에게 다음 지시를 내릴 수도 없게 됐지.”

솔라의 표정이 조금씩 변하기 시작했다. 효율적이라고 생각했던 행동이 만들어내는 연쇄적인 혼란이 눈앞에 그려지는 듯했다.

“그뿐만이 아니야. 지배인을 만난 요리사는 ‘고기가 이상해요!’라고 말하겠지. 하지만 지배인이 ‘그럼 대안은? 다른 고기는 있나? 메뉴를 바꾸면 전체 코스 시간은 어떻게 되나?’ 하고 물었을 때, 그 요리사는 대답할 수 있을까?”

“아니… 그건 총괄 셰프만 아는 정보니까.”

“맞아. 결국 지배인은 단편적인 문제만 전달받았을 뿐, 해결을 위한 어떤 결정도 내릴 수 없어. 결국 다시 총괄 셰프를 찾아와야만 하지. 어때? 한 명의 요리사가 ‘빨리’ 행동한 결과가, 주방 전체의 흐름을 엉망으로 만들고 의사결정은 오히려 더 지연시켰어.”

루나는 말을 마치고 다시 솔라의 노트북 화면을 가리켰다.

[Worker가 HITL을 호출하면 흐름이 분산되고, 정책 통제가 깨진다.]

솔라는 아까와는 전혀 다른 눈으로 그 문장을 다시 읽었다. 요리사가 주방을 뛰쳐나가는 순간, 주방 전체의 작업 ‘흐름이 분산’되는 장면이 떠올랐다. 그리고 ‘이런 경우엔 차선책인 양고기 스테이크로 대체하고, 조리 시간을 5분 단축한다’ 같은 총괄 셰프의 비상 대응 계획, 즉 ‘정책’이 요리사의 단독 행동으로 인해 완전히 무시당하는 상황. 그것이 바로 ‘정책 통제가 깨진다’는 것의 의미였다.

“아…”

솔라의 입에서 작은 탄성이 터져 나왔다.

“한 명의 워커가 보기에는 가장 빠른 길이, 시스템 전체로 보면 최악의 경로가 될 수 있다는 거구나. 각자의 위치에서 멋대로 소리치기 시작하면, 전체를 지휘하는 사람은 상황 파악도, 통제도 할 수 없게 되니까.”

이제 솔라는 워커가 왜 직접 사람을 불러서는 안 되는지 분명히 이해했다. 분산된 호출은 효율이 아니라 혼돈을 낳을 뿐이었다. 하지만 그 순간, 새로운 의문이 고개를 들었다.

“알겠어. 워커가 마음대로 사람을 부르면 안 되는 이유는 이제 알겠는데… 그럼 총괄 셰프는, 그러니까 슈퍼바이저는 도대체 언제, 어떤 기준으로 사람을 부르기로 결정하는 거야? ‘아, 이건 내가 해결 못 하겠다’는 감으로? 아니면 여기에도 명확한 규칙이 있는 걸까?”

2장: 정책 통제를 위한 Supervisor의 역할

솔라의 노트 위에는 어젯밤 루나와 나눴던 ‘주방’ 비유가 간단한 도식으로 그려져 있었다. 여러 명의 ‘요리사(Worker)’가 있고, 그들을 지휘하는 ‘총괄 셰프(Supervisor)’가 정점에 있었다. 하지만 그림은 어딘가 이상했다. 솔라는 ‘스테이크 담당 요리사’에게서 뻗어 나가는 두 개의 화살표를 그려 넣었다. 하나는 총괄 셰프에게로, 다른 하나는 주방 밖의 ‘지배인(Human)’에게로 향해 있었다.

이 그림이야말로 솔라의 머릿속에 남은 혼란 그 자체였다. 워커가 직접 사람을 부르면 안 된다는 건 알겠다. 그럼 워커는 문제를 슈퍼바이저에게 보고한다. 여기까지는 좋다. 하지만 그 슈퍼바이저는 대체 무슨 일을 하는 걸까? 단순히 보고를 받고, ‘아, 이건 사람이 필요하겠군’ 싶으면 그대로 지배인에게 전달하는 역할? 그렇다면 결국 한 단계 더 거치는 보고 체계일 뿐, 특별한 ‘패턴’이라고 부를 것까지 있을까. 솔라는 연필 끝으로 두 개의 화살표를 톡톡 건드렸다.

“언니, 이 그림 좀 봐. 결국 총괄 셰프는 그냥 중간 전달자 아니야?”

솔라의 목소리에 루나가 다가와 노트를 들여다보았다.

“스테이크 요리사가 총괄 셰프에게 문제를 보고하고, 총괄 셰프가 다시 지배인을 부른다… 네 생각은 이렇다는 거지?”

“응. 어차피 사람이 개입해야 할 문제라면, 총괄 셰프는 그냥 문제를 전달하는 우체부 같아. 정책 통제는 알겠는데, 책임자가 바뀐 것 말고 역할 자체가 뭐가 다른지 모르겠어. ‘슈퍼바이저’라는 이름만 거창하게 붙인 것 같아.”

솔라의 비판은 날카로웠다. 슈퍼바이저가 단순히 상위 보고 체계에 불과하다면, 그 존재 이유는 희미해진다.

루나는 잠시 솔라의 그림을 보더니, 연필을 집어 들었다. 그녀는 스테이크 요리사 옆에 ‘수프 요리사’와 ‘디저트 요리사’를 작게 그려 넣었다.

“상황을 좀 더 복잡하게 만들어보자. 솔라 네가 총괄 셰프야.”

“내가?”

“응. 방금 세 명의 요리사로부터 거의 동시에 보고가 들어왔어.”

루나는 각 요리사 옆에 작은 말풍선을 그렸다.

  • 스테이크 요리사: “고기 등급이 낮아, 계획대로 조리 시 질겨질 위험이 있습니다.”
  • 수프 요리사: “예상보다 손님이 빨리 몰려, 수프가 식기 시작했습니다.”
  • 디저트 요리사: “필수 재료인 특제 초콜릿 재고가 바닥났습니다.”

루나는 솔라를 보며 물었다. “자, 총괄 셰프. 이제 어떻게 할 거지? 네가 생각하는 ‘전달자’ 역할에 충실하게, 이 세 가지 보고를 모두 지배인에게 달려가서 전달할 거야?”

솔라는 순간 말문이 막혔다. 세 개의 메시지를 들고 허둥지둥 지배인을 찾아가는 자신의 모습이 그려졌다. 그건 지난 장에서 스테이크 요리사 한 명이 일으켰던 혼란과 본질적으로 다르지 않았다. 아니, 오히려 세 배의 혼란을 한꺼번에 전달하는 셈이다.

“아니… 그렇게는 안 할 것 같아.”

“그럼?”

“일단… 내가 판단을 해야지. 세 문제 중에서 뭐가 가장 시급하고 중요한지. 수프가 식는 건 지금 당장 내보내면 해결될 수도 있고, 디저트 재료는 다른 걸로 대체할 수 있는지 내가 먼저 알아봐야 해. 고기 문제는… 코스 전체에 영향을 주니까 가장 중요할 수도 있고. 이 모든 상황을 종합해서, ‘지배인을 호출해서 메뉴 변경을 논의해야 한다’거나, ‘아니다, 내가 가진 권한 내에서 해결 가능하다’는 결정을 내려야지. 그냥 보고를 넘기진 않아.”

솔라의 대답이 끝나자, 루나가 조용히 말했다.

“바로 그거야. 슈퍼바이저는 단순한 보고 체계나 전달자가 아니야. 시스템의 모든 상태를 보고받아 전체적인 상황을 파악하고, 정해진 ‘정책’에 따라 다음 행동을 결정하는 **중앙 의사결정자(Central Decision-Maker)**야.”

루나는 솔라가 그렸던, 요리사에게서 지배인으로 직접 향하던 화살표를 지우개로 깨끗이 지웠다. 이제 모든 보고는 오직 총괄 셰프에게로만 향했다. 그리고 총괄 셰프에게서 다른 요리사들에게, 혹은 주방 밖으로 나가는 결정의 화살표가 새로 생겨났다.

“슈퍼바이저는 워커들의 실행 흐름 자체를 통제해. ‘다시 시도해라’, ‘다른 방법을 써라’, ‘작업을 중단하고 대기해라’ 같은 지시를 내리지. 그리고 ‘사람의 개입이 꼭 필요하다’는 판단이 설 때, 오직 그때만 HITL을 호출하는 거야. 즉, HITL 호출 여부마저도 슈퍼바이저의 통제하에 있는 중요한 결정 중 하나일 뿐이야.”

솔라는 지워진 화살표의 흔적과 새로 그려진 그림을 번갈아 보았다. 슈퍼바이저의 역할이 ‘보고받는 자’에서 ‘결정하고 통제하는 자’로 바뀌는 순간이었다. 단순히 책임자의 이름이 바뀐 것이 아니라, 시스템의 의사결정 구조 자체가 근본적으로 달라진다는 의미였다.

“아… 슈퍼바이저는 워커의 상사가 아니라, 시스템의 두뇌 같은 거구나. 모든 정보를 모아서 전체 상황을 이해하고, 뭘 할지 직접 결정하는 역할. 사람을 부를지 말지도 그 결정 중 하나고.”

이제 솔라는 왜 HITL이 중앙에서 통제되어야 하는지, 그리고 그 역할을 왜 슈퍼바이저가 맡아야 하는지 명확하게 이해했다. 그것은 단순한 보고 라인을 만드는 것이 아니라, 분산된 정보 속에서 일관된 정책을 집행할 유일한 주체를 세우는 일이었다.

하지만 새로운 그림을 보던 솔라의 눈에 다시 궁금증이 어렸다.

“좋아, 슈퍼바이저가 중앙 의사결정자라는 건 알겠어. 그런데… 그 똑똑한 총괄 셰프는 대체 어떤 기준으로 판단하는 거지? ‘고기 등급이 낮고, 재시도 횟수가 3번을 넘었으면 사람을 부른다’ 같은 구체적인 규칙이라도 있는 걸까?”

3장: Supervisor의 HITL 트리거와 State 제어

다음 날 아침, 솔라의 노트북 옆에는 어제 그린 ‘총괄 셰프’ 도식이 놓여 있었다. 하지만 그림 위에는 새로운 글씨가 덧씌워져 있었다. 솔라는 총괄 셰프, 즉 슈퍼바이저의 머리 위에 말풍선을 그리고 그 안에 자신만의 규칙을 적어 넣는 중이었다. 어젯밤 잠들기 전 떠올랐던 ‘구체적인 규칙’에 대한 질문을 스스로 해결해보려는 시도였다.

그녀가 적은 규칙은 명료했다.

만약 (워커의 결과가 ‘REJECTED’) 그리고 (재시도 횟수 >= 3) 이면: 사람을 호출한다 (call_human).

솔라는 만족스러운 듯 고개를 끄덕였다. 감이나 모호한 판단이 아니라, 이렇게 명확한 조건에 따라 시스템이 움직인다면 예측 가능하고 안정적일 터였다. 이제 HITL 개입은 더 이상 갑작스러운 에러 알림이 아니라, 정해진 절차처럼 보였다.

“언니, 슈퍼바이저가 사람을 부르는 기준, 이런 식으로 만들면 되는 거 아닐까?”

솔라가 자신의 노트를 보여주자, 주방에서 커피를 내리고 있던 루나가 다가와 들여다보았다.

“‘거절’이 세 번 이상 누적되면 사람을 부른다. 아주 구체적이고 좋은 규칙이네.”

루나는 칭찬하는 듯했지만, 그녀의 시선은 ‘사람을 호출한다’는 마지막 줄에 머물러 있었다.

“좋아. 그럼 이 규칙대로 시스템이 움직인다고 상상해보자. 워커가 세 번의 시도 끝에 또다시 ‘REJECTED’ 결과를 받았어. 슈퍼바이저는 네가 쓴 규칙에 따라 ‘call_human’ 함수를 실행했지. 이제 사람에게 알림이 갔어. 그 다음은?”

“그 다음?”

솔라는 당연하다는 듯이 대답했다. “사람이 확인하고 어떻게 할지 알려주겠지. ‘그 계획은 폐기하고 다른 방법으로 해’ 라든가, ‘그 정도는 괜찮으니 그냥 진행해’ 라고.”

“맞아. 사람은 ‘수정(REVISE)’이나 ‘승인(APPROVE)’, 혹은 ‘중단(ABORT)’ 같은 결정을 내릴 거야. 그럼 그 결정은 누가 듣지?”

“음… 슈퍼바이저가 듣나?”

“그렇겠지. 좋아, 사람이 ‘새로운 계획으로 수정하라’고 응답했어. 이제 슈퍼바이저는 뭘 해야 할까? 네가 쓴 규칙에는 그 다음 행동이 정의되어 있지 않은데.”

루나의 지적에 솔라는 자신의 노트를 다시 들여다봤다. 정말이었다. 자신의 규칙은 사람을 부르는 것에서 끝나 있었다. 마치 화재경보기가 울리기만 할 뿐, 그 소리를 듣고 누가 무엇을 해야 하는지에 대한 계획은 전혀 없는 것과 같았다. 시스템은 사람을 호출한 채, 다음 지시를 기다리며 영원히 멈춰있을 것이다.

솔라의 표정이 굳어졌다. HITL 개입을 단순한 ‘알림’ 절차로 생각했던 자신의 허점이 드러나는 순간이었다.

“아… 호출만 하고 끝이 아니구나. 사람의 응답을 받아서 다시 작업을 이어가게 만들어야 하네.”

“바로 그거야. 슈퍼바이저의 진짜 역할은 단순히 특정 조건에 맞춰 사람을 부르는 ‘트리거’ 역할에서 그치지 않아.”

루나는 솔라의 노트에 있던 call_human 부분을 연필로 가볍게 그어 지웠다. 대신 그 자리에 다른 단어를 적었다.

상태를 ‘HUMAN_REVIEW’로 전환한다.

“상태… 전환?”

“응. 슈퍼바이저는 시스템의 전체 **상태(State)**를 관리하는 지배자야. 워커가 작업을 수행하는 상태는 ‘실행 중(RUNNING)’. 네가 정한 조건, 즉 ‘REJECTED 3회’는 ‘사람을 호출’하는 이벤트가 아니라, 시스템의 상태를 ‘실행 중’에서 ‘사람의 검토 대기 중(HUMAN_REVIEW)’으로 바꾸라는 신호인 거지.”

루나는 노트를 돌려 솔라 앞에 놓고, 작은 도표를 그리기 시작했다.

현재 상태 (Current State)발생 이벤트 (Trigger Event)다음 상태 (Next State)
RUNNINGREJECTED가 3회 이상 발생HUMAN_REVIEW
HUMAN_REVIEW사람이 ‘수정(REVISE)’ 지시RUNNING
HUMAN_REVIEW사람이 ‘중단(ABORT)’ 지시ABORTED

“이렇게 보면 어때? 슈퍼바이저는 상태 기계(State Machine)를 운영하는 것과 같아. 어떤 상태에서 어떤 이벤트가 발생하면, 다음 상태로 넘어갈지를 결정하지. ‘사람 호출’은 이 상태 전환 과정의 일부일 뿐이야. ‘HUMAN_REVIEW’ 상태에 진입했을 때의 약속된 행동인 거지.”

이제야 모든 조각이 맞춰지는 기분이었다. 슈퍼바이저가 중앙에서 모든 것을 통제한다는 말의 의미가 훨씬 더 깊게 다가왔다. 워커의 실행 흐름뿐만 아니라, 사람이라는 예측 불가능한 외부 요소의 개입마저도 ‘상태 전환’이라는 규칙 안으로 끌어들여 관리하는 것. 그것이 바로 슈퍼바이저의 진짜 힘이었다. 사람의 판단은 시스템을 중단시키는 예외가 아니라, 시스템이 다음 상태로 나아가기 위해 사용하는 또 하나의 정보였다.

“그렇구나… 슈퍼바이저는 단순히 ‘사람 불러!’라고 소리치는 게 아니었어. ‘지금부터 시스템은 사람의 결정을 기다리는 상태에 돌입한다’고 선언하고, 그 결정에 따라 다시 ‘실행 상태로 돌아간다’거나 ‘모든 것을 중단한다’는 식으로 전체 흐름을 계속해서 책임지는 거였구나.”

솔라는 루나가 그려준 표를 가만히 들여다보았다. 이것이야말로 HITL 개입을 안정적으로 시스템에 통합하는 구체적인 메커니즘이었다.

솔라는 자신의 노트북을 열었다. 그리고 ‘Supervisor 패턴 기반 HITL 제어 로직 설계 문서 초안’이라는 제목의 새 문서를 만들었다. 그녀는 더 이상 단 한 줄짜리 if-then 규칙을 적지 않았다. 대신, 방금 배운 상태 전환 표를 직접 그리기 시작했다.

첫 번째 행. Current State: RUNNING, Trigger Event: 치명적 오류 감지 AND 재시도 횟수 >= max_iterations, Next State: HUMAN_REVIEW, Action: 현재 작업 일시 중지, 검토 요청 전송.

그리고 두 번째 행을 채워 넣으며, 솔라는 혼잣말처럼 중얼거렸다. Current State: HUMAN_REVIEW, Trigger Event: 사람의 ‘계획 수정’ 입력, Next State: RUNNING

그녀의 손가락이 만들어내는 것은 단순한 메모가 아니었다. 그것은 분산된 혼돈을 질서 있는 제어로 바꾸는, 중앙 의사결정자의 설계도였다.