Multi-Agent 08

Multi-Agent 아키텍처: State, 통신, Graph 관점에서 설계하기

패턴을 라이브러리 기능 이름으로만 외우면 설계 판단이 남지 않는다.

근거 · 교안 p22-p24

Multi-Agent 아키텍처: State, 통신, Graph 관점에서 설계하기 대표 이미지

1장: 모델이 아닌 아키텍처: Multi-Agent 설계의 진짜 중요성

솔라는 모니터에 떠 있는 코드 예제와 다이어그램들을 번갈아 보며 미간을 찌푸렸다. LangChain, LangGraph… 여러 에이전트가 협력해서 복잡한 작업을 처리한다는 개념은 흥미로웠다. 하지만 막상 직접 여행 계획을 짜주는 챗봇을 만들려니 첫 단계부터 막막했다. 화면에는 ‘라우터(Router)’, ‘슈퍼바이저(Supervisor)’, ‘팀(Team)’ 같은 그럴듯한 이름의 패턴들이 나열되어 있었다.

“언니, 이거 그냥 이름만 다른 거 아니야?”

결국 솔라는 거실에서 책을 읽고 있던 루나에게 노트북을 들고 가 화면을 불쑥 내밀었다.

“멀티 에이전트 아키텍처 패턴이라는데, 설명을 읽어봐도 다 비슷해 보여. 그냥 에이전트들을 순서대로, 혹은 조건에 따라 연결하는 거잖아. 어떤 상황에 뭘 써야 할지 감이 안 와. 그냥 라이브러리 개발자들이 붙여놓은 함수 이름 목록 같아.”

솔라의 목소리에는 짜증이 섞여 있었다. 그녀의 말대로, 문서에 나온 설명들은 각 패턴의 고유한 철학보다는 기능적 측면에만 초점이 맞춰져 있었다.

루나는 솔라의 노트북 화면을 잠시 들여다보더니, 고개를 들어 솔라를 바라보았다.

“솔라, 그 패턴 이름들은 잠시 잊어봐. 대신 네가 만들고 싶은 ‘여행 계획 챗봇’이 실제로 어떻게 작동해야 할지 상상해 보자.”

루나는 테이블 위에 놓인 메모지와 펜을 가져왔다.

“사용자가 ‘제주도로 2박 3일 여행 갈 건데, 항공권이랑 숙소 좀 알아봐 줘’라고 요청했어. 그럼 어떤 에이전트들이 필요할까?”

“음… ‘항공권 검색 에이전트’랑 ‘숙소 검색 에이전트’가 필요하겠지?”

솔라가 대답하자, 루나는 메모지에 네모 두 개를 그리고 각각 ‘항공권’과 ‘숙소’라고 적었다.

“좋아. 그럼 이 둘은 어떤 순서로 일해야 할까? 솔라가 아까 말한 ‘라우터’ 패턴을 쓴다고 상상해 봐. 사용자의 요청이 들어오면, 라우터가 먼저 항공권 에이전트를 호출하고, 그다음 숙소 에이전트를 호출하겠지?”

루나는 ‘항공권’ 박스에서 ‘숙소’ 박스로 향하는 화살표를 그었다. 단순하고 명확한 흐름이었다. 솔라는 고개를 끄덕였다. 처음 생각했던 그림과 정확히 같았다.

“그런데 만약 사용자가 조건을 추가하면 어떨까?”

루나의 질문에 솔라는 잠시 멈칫했다.

“예를 들어, ‘해변 근처에 반려견 동반 가능한 숙소가 있을 경우에만 항공권을 예약해 줘’라고 한다면?”

순간 솔라의 머릿속이 복잡해졌다. 루나가 그린 단순한 화살표로는 이 문제를 해결할 수 없었다. 항공권 에이전트가 먼저 실행되면, 숙소 예약 가능 여부를 알 수 없다. 그렇다고 숙소 에이전트를 먼저 실행하자니, 원하는 날짜의 항공권이 없을 수도 있었다.

“음… 그럼 숙소 에이전트가 먼저 실행되고… 만약 적절한 숙소가 없으면, 항공권 에이전트는 아예 실행되면 안 되겠네. 그리고 만약 사용자가 대화 중간에 ‘아, 날짜를 다음 주로 바꿀게’라고 하면… 항공권이랑 숙소 둘 다 처음부터 다시 검색해야 하나?”

솔라는 자기가 뱉은 말을 곱씹으며 중얼거렸다. 간단한 일직선 구조로는 도저히 감당할 수 없는 복잡성이었다. 항공권 검색 결과는 숙소 검색에 영향을 주고, 숙소 검색 결과는 최종 항공권 예약 결정에 영향을 미쳤다. 한 에이전트의 작업이 실패했을 때, 전체 과정을 어떻게 되돌릴 것인지도 문제였다.

루나는 말없이 솔라가 스스로 문제의 구조를 깨닫도록 기다려 주었다.

“바로 그 지점이야.”

솔라가 더 이상 말을 잇지 못하자 루나가 입을 열었다. 그녀는 펜으로 ‘항공권’과 ‘숙소’ 박스 주변을 크게 원으로 감쌌다.

“지금 우리가 부딪힌 문제는 ‘항공권 검색 에이전트’의 언어 모델이 최신이 아니라거나, ‘숙소 검색 에이전트’의 검색 성능이 나빠서 생긴 게 아니야. 세계 최고의 모델을 가져다 써도, 이 구조 자체의 문제는 해결되지 않아.”

루나의 펜 끝이 두 박스를 잇는 화살표와, 그 주변에 솔라가 머릿속으로 그렸을 복잡한 되돌림과 조건들을 가리키고 있었다.

“문제는 이 에이전트들이 어떻게 서로 정보를 주고받고, 누가 언제 일할지 결정하는 구조, 즉 아키텍처에 있어. 성능이 좋고 유지보수가 편한 멀티 에이전트 시스템을 만드는 건, 개별 에이전트의 똑똑함이 아니라 바로 이 아키텍처 설계에 달려 있는 거야.”

그제야 솔라는 무릎을 쳤다. 자신이 놓치고 있던 것이 무엇인지 명확해졌다. 패턴의 이름이나 라이브러리의 함수 시그니처가 아니었다. 각 패턴이 어떤 종류의 ‘협업’ 문제를 해결하기 위해 고안되었는지, 그 본질적인 설계 철학을 이해해야 했다. 단순히 에이전트를 교체하는 것과, 에이전트들이 일하는 방식 자체를 바꾸는 것은 전혀 다른 차원의 문제였다.

“아… 알겠다. ‘라우터’나 ‘슈퍼바이저’ 같은 이름들은 그냥 기능 목록이 아니라, 방금 우리가 고민했던 ‘조건부 실행’이나 ‘작업 되돌리기’ 같은 복잡한 상호작용을 어떤 철학으로 풀어낼지에 대한 해답지 같은 거였구나. 나는 부품의 성능만 생각했는데, 진짜 중요한 건 그 부품들을 연결하는 조립 설명서, 즉 뼈대였어.”

솔라는 루나가 그렸던 단순한 다이어그램을 바라보았다. 이제는 그 위에 보이지 않는 수많은 조건과 제약, 정보의 흐름들이 얽혀 있는 것처럼 보였다.

“그럼 제대로 된 설계를 하려면 뭘 기준으로 판단해야 해? 방금처럼 ‘정보를 주고받는 방식’이나 ‘일하는 순서를 정하는 규칙’ 같은 것들을 체계적으로 생각하는 방법이 있을 거 아냐?”

솔라의 질문에 루나는 희미하게 미소 지었다. 진짜 질문이 시작될 차례였다.

“응, 바로 그게 설계의 핵심이야. 우리는 보통 세 가지 관점에서 그 질문에 답을 찾아. 에이전트들이 ‘상태(State)‘를 어떻게 공유하고, 서로 어떻게 ‘통신(Communication)‘하며, 전체 작업 흐름이 어떤 ‘그래프(Graph)’ 구조를 가지는지.”

2장: 설계의 3대 축: State, 통신, Graph

루나는 어젯밤의 메모지를 다시 테이블 위에 펼쳤다. 하지만 이번에는 뭔가 달랐다. ‘항공권’과 ‘숙소’ 에이전트를 그렸던 공간 옆에, 루나는 반듯한 세 개의 열을 만들어 두었다. 각 열의 맨 위에는 각각 ‘상태(State)’, ‘통신(Communication)’, ‘그래프(Graph)’라고 적혀 있었다. 그리고 그 옆에는 솔라가 어제 언급했던 ‘Router’, ‘Supervisor’, ‘Network’ 패턴의 이름이 적힌 작은 카드들이 놓여 있었다.

솔라는 잠시 그 카드들과 빈칸으로 채워진 표를 번갈아 보았다. 어젯밤 루나가 마지막에 던졌던 세 개의 키워드였다. 솔라는 잠시 생각하더니 자신감 있게 ‘Router’ 카드를 집어 ‘그래프’ 열 아래에 가져다 댔다.

“라우터는 요청을 어디로 보낼지 경로를 정해주니까, 이건 ‘그래프’ 문제 아니야? 그리고 슈퍼바이저는 전체 작업을 감독하니까… 에이전트들한테 계속 말을 걸겠지? 이건 ‘통신’에 가깝고. 네트워크는… 음, 여러 에이전트가 함께 일하니까 이것도 ‘그래프’인가?”

솔라는 카드를 이리저리 옮기며 고개를 갸웃거렸다. 명쾌하게 맞아떨어지는 느낌이 아니었다. 각 패턴이 하나의 개념에만 속하는 것 같지 않았다. 그녀의 미간이 다시 좁혀졌다.

“이거… 딱 나눠지지가 않는데? 서로 조금씩 겹치는 것 같아.”

루나는 솔라가 부딪힌 지점을 정확히 짚었다는 듯 조용히 입을 열었다.

“분류하는 게 아니야, 솔라. 이 세 가지 렌즈로 각 패턴의 특징을 ‘묘사’해 보는 거야. 하나의 건축물을 보고 ‘창문은 어떤가?’, ‘벽의 재료는 무엇인가?’, ‘건물의 전체 구조는 어떤가?‘라고 묻는 것처럼. 이 세 관점은 패턴을 나누는 상자가 아니라, 패턴의 본질을 파헤치는 질문지 같은 거야.”

루나는 ‘Router’ 카드를 테이블 중앙으로 가져왔다.

“자, 라우터 패턴을 이 세 가지 관점으로 다시 보자. 첫 번째, 상태. 라우터는 에이전트들에게 일을 시킬 때, 이전 작업의 결과나 전체 진행 상황을 전부 알려줄까?”

솔라는 잠시 고민했다. “아니. 그냥 ‘이런 요청이 왔으니 네가 처리해’ 하고 작업을 넘겨주는 게 전부일 것 같은데. 각 에이전트는 자기 일만 알지, 다른 에이전트가 뭘 했는지는 모를 거야.”

“맞아. 상태가 거의 공유되지 않지. 각 에이전트가 독립적으로 일하는 거야.”

루나는 이번엔 ‘Supervisor’ 카드를 가져왔다. “그럼 슈퍼바이저는 어떨까? 어제 우리가 고민했던 ‘해변 근처 숙소가 없으면 항공권 예약을 취소하는’ 문제처럼 말이야.”

“아, 슈퍼바이저는 모든 걸 알고 있어야겠네! 숙소 검색 결과를 보고 항공권 예약을 진행할지 말지 결정해야 하니까. 모든 에이전트의 작업 내용이 한곳에 모이는 거대한 ‘작업 일지’가 있는 느낌이야.”

솔라의 눈이 반짝였다. ‘상태’라는 관점이 두 패턴의 차이를 명확하게 갈랐다. 하나는 독립적이고, 다른 하나는 중앙 집중적이었다.

“그럼 두 번째, ‘통신’ 관점으로 볼까?” 루나가 질문을 이어갔다. “에이전트끼리 어떻게 대화하지?”

“라우터는… 에이전트끼리 대화할 필요가 없잖아. 라우터가 에이전트에게, 에이전트가 라우터에게만 말하면 돼. 하지만 슈퍼바이저 패턴에서는 모든 통신이 슈퍼바이저를 거쳐야 해. 에이전트 A가 B에게 직접 말을 거는 게 아니라, A가 슈퍼바이저에게 보고하면 슈퍼바이저가 B에게 지시하는 방식이지.”

솔라는 이어서 ‘Network’ 카드를 가리켰다. “네트워크 패턴은 이름 그대로 서로 직접 통신하는 거겠구나. 마치 팀원들끼리 자유롭게 의견을 주고받는 것처럼.”

“정확해. 마지막으로 ‘그래프’ 관점. 전체 작업 흐름이 어떻게 생겼을까?”

“라우터는 단순한 분기문 같아. A 조건이면 1번, B 조건이면 2번으로 가는 갈림길. 슈퍼바이저는… 계속 일을 시키고 결과를 보고 다시 판단하니까, 빙글빙글 도는 루프(Loop) 구조가 만들어질 수 있겠어. 작업이 끝날 때까지 계속 순환하는 거지. 네트워크는… 예측하기 어려워. 누가 누구에게 말을 걸지 모르니까, 거미줄처럼 복잡하게 얽힌 모양일 것 같아.”

솔라는 세 개의 카드를 나란히 놓고, 세 개의 관점(상태, 통신, 그래프)으로 각 패턴을 설명한 내용을 머릿속으로 정리했다. 이제야 안개가 걷히는 기분이었다. 패턴 이름들은 단순히 기능 목록이 아니었다. ‘상태를 어떻게 관리할 것인가?’, ‘서로 어떻게 소통할 것인가?’, ‘전체 작업 흐름을 어떻게 그릴 것인가?‘라는 핵심 설계 질문에 대한 서로 다른 ‘답안지 세트’였던 것이다.

“아, 알겠다! ‘상태’, ‘통신’, ‘그래프’는 서로 다른 개념이 아니라, 하나의 아키텍처를 분석하는 세 개의 다른 창문 같은 거구나. 그리고 각 패턴은 이 창문들로 들여다봤을 때 보이는 풍경이 저마다 다른 거고. 나는 이걸 그냥 별개의 이름표라고만 생각했어.”

솔라는 뿌듯한 표정으로 표를 바라보았다. 이제 어떤 아키텍처를 보더라도 이 세 가지 기준을 가지고 분석할 수 있을 것 같았다. 하지만 이내 새로운 질문이 고개를 들었다.

“좋아, 이제 각 패턴이 어떻게 다른지는 알겠어. 그런데… 그래서 뭘 선택해야 하는 건데? 언제 중앙 집중적인 상태 관리가 좋고, 언제 에이전트끼리 직접 통신하게 만드는 게 유리한 거야? 이 멋진 분석 도구를 가지고, 실제 문제를 풀려면 어떤 ‘선택’을 해야 하는 거지?”

분석의 틀은 얻었지만, 결정의 기준은 여전히 보이지 않았다. 루나는 솔라의 다음 질문을 기다렸다는 듯, 작게 고개를 끄덕였다. 진짜 설계의 고민은 이제부터 시작이었다.

3장: 관점에서 패턴으로: 최적의 아키텍처 선택

솔라의 질문이 남긴 침묵 속에서, 루나는 어제 썼던 메모지를 옆으로 밀어내고 새로운 메모지를 꺼내 들었다. ‘상태’, ‘통신’, ‘그래프’라는 렌즈로 패턴을 분석하는 법은 알았지만, 그래서 어떤 문제를 만났을 때 무엇을 선택해야 할지에 대한 막막함이 솔라의 얼굴에 그대로 남아 있었다.

루나는 질문에 직접 답하는 대신, 펜으로 새 메모지에 간결한 문장을 적어 솔라 앞으로 밀었다.

과제: 실시간 뉴스 분석 시스템

  1. 특정 키워드의 최신 뉴스 기사를 수집한다. (에이전트 A)
  2. 수집된 기사를 한 문단으로 요약한다. (에이전트 B)
  3. 요약된 내용의 감성(긍정/부정)을 분석한다. (에이전트 C)
  4. 최종 리포트를 생성한다. (에이전트 D)

※ 특수 조건: 만약 감성 분석 결과가 ‘부정’일 경우, 연관된 ‘긍정적’ 관점의 다른 기사를 즉시 찾아 리포트에 함께 포함시켜야 한다.

솔라는 새로운 문제를 잠시 들여다보았다. 이전의 여행 계획 봇보다는 구조가 명확해 보였다.

“흠… 이건 그냥 순서대로 하면 되는 거 아니야? 기사 수집하고, 요약하고, 분석하고, 리포트 쓰고. 간단한데?”

솔라는 자신 있게 펜을 들어 네 개의 상자를 그리고 화살표로 이었다. A에서 B로, B에서 C로, C에서 D로 향하는 깨끗한 일직선이었다. 그녀는 이것이 가장 직관적인 해결책이라고 생각했다. 지난번에 이야기했던 ‘라우터’ 패턴처럼, 작업을 순차적으로 연결하는 방식이었다.

루나는 말없이 솔라가 그린 다이어그램을 보다가, 펜 끝으로 마지막 ‘특수 조건’ 문장을 톡톡 가리켰다.

“이 흐름에서, 에이전트 C가 ‘부정’이라는 결과를 내놓으면, 그 다음은 어떻게 되지? 누가 ‘긍정적 관점의 다른 기사를 찾아오라’는 새로운 일을 시작시켜?”

순간 솔라의 손이 멈칫했다. 그녀가 그린 일직선 위에는 그런 결정을 내릴 주체가 없었다. 에이전트 C는 자신의 분석 결과를 D에게 넘기고 임무를 마칠 뿐, 전체 작업 흐름을 되돌리거나 새로운 에이전트를 호출할 권한이 없었다. 문제가 다시 원점으로 돌아온 기분이었다.

“분석의 기준이 선택의 기준이 되려면, 저울처럼 양쪽을 비교해야 해.”

루나가 입을 열었다. 그녀는 솔라가 그린 다이어그램 옆에 세 가지 질문을 나란히 적었다.

  • State: 에이전트의 독립성이 중요한가, 전체 정보의 통합성이 중요한가?
  • Communication: 중앙 통제가 효율적인가, 에이전트 간 직접 전달이 효율적인가?
  • Graph: 단순한 Chain(사슬) 구조로 충분한가, 복잡한 Graph 구조가 필요한가?

“이 세 가지 저울로 방금 그 뉴스 분석 시스템 문제를 다시 재어보자.”

솔라는 루나가 제시한 세 개의 저울을 보며 다시 생각에 잠겼다. 첫 번째, ‘State’ 저울부터였다.

“감성 분석 결과인 ‘부정’이라는 정보는… 리포트를 만드는 D뿐만 아니라, 새로운 긍정 기사를 찾아야 할 미지의 에이전트 E에게도 알려져야 해. 특정 에이전트만 아는 지역적 정보가 아니라, 시스템 전체의 흐름을 바꾸는 핵심 정보야. 그렇다면… 독립성보다는 통합성 쪽으로 저울이 기우네.”

다음은 ‘Communication’ 저울이었다.

“만약 에이전트 C가 직접 다른 에이전트들에게 ‘이거 부정이야!’라고 외치고 다닌다면 너무 복잡해져. 누가 그 말을 듣고 행동해야 할지 규칙을 정하기 어려워. 차라리 C는 한 명에게만 보고하고, 그 보고를 받은 ‘누군가’가 다음 행동을 결정하는 게 깔끔해. 중앙 통제직접 전달보다 낫겠어.”

마지막으로 ‘Graph’ 저울. 솔라는 자신이 그렸던 일직선 다이어그램을 바라보았다.

“내가 그린 건 단순한 Chain 구조였지. 하지만 ‘부정일 경우’라는 조건 때문에 흐름이 갈라져야 해. 어떨 땐 A→B→C→D로 끝나지만, 어떨 땐 A→B→C→(새로운 E)→D로 가야 하니까. 이건 더 이상 사슬이 아니라, 조건에 따라 경로가 바뀌는 Graph 구조야.”

솔라는 세 가지 저울의 눈금을 모두 확인하고 나서야 무릎을 쳤다.

“아! 알겠다! 문제의 요구사항을 이 세 가지 저울로 재어보니까, ‘상태는 통합적으로 관리하고, 통신은 중앙에서 통제하며, 작업 흐름은 그래프 구조를 가져야 한다’는 결론이 나오잖아! 그리고 이 모든 특징을 가진 패턴이 바로… **슈퍼바이저(Supervisor)**였어!”

솔라는 이제껏 패턴의 이름을 외우고, 그 기능에 자신을 맞추려 했다는 사실을 깨달았다. 하지만 진실은 정반대였다. 해결해야 할 문제의 본질을 ‘State’, ‘Communication’, ‘Graph’라는 관점으로 철저히 분석하면, 가장 적합한 아키텍처 패턴이 자연스럽게 모습을 드러내는 것이었다. 패턴은 미리 정해진 정답지가 아니라, 설계 원칙에 따라 도출되는 결과물이었다.

흥분을 가라앉힌 솔라는 책상 한쪽에 놓여있던, 처음 이 모든 고민을 시작하게 했던 ‘여행 계획 챗봇’ 아이디어가 적힌 메모지를 끌어당겼다. 그녀는 더 이상 어떤 패턴을 써야 할지 막막해하지 않았다.

대신, 깨끗한 페이지를 새로 펼쳐 맨 위에 ‘여행 계획 챗봇 아키텍처 설계’라고 적었다. 그리고 그 아래에, 루나가 했던 것처럼 세 개의 질문을 나란히 적었다.

  • State: 항공권과 숙소 정보는 서로에게 영향을 줌. 사용자가 날짜를 바꾸면 둘 다 초기화되어야 함. → 통합성 필요.
  • Communication: 숙소 검색 결과(반려견 동반 가능 여부)에 따라 항공권 예약을 ‘취소’하거나 ‘진행’하는 결정이 필요함. → 중앙 통제 필요.
  • Graph: 단순 순서가 아님. 조건부 실행(‘숙소가 있을 때만’), 실패 시 되돌리기, 반복(날짜 변경)이 필수적임. → Graph 구조 필요.

솔라는 자신이 내린 분석 결과를 보며 만족스러운 미소를 지었다. 답은 명확했다. 그녀는 세 항목 아래에 결론을 적어 넣었다.

“결론: Supervisor 패턴 기반으로 설계한다.”

이제 솔라의 손은 망설임 없이 움직였다. 복잡하게 얽힌 정보의 흐름과 조건들을 제어하는 중앙 슈퍼바이저를 중심으로, 각자의 역할을 수행하는 에이전트들을 하나씩 그려나가기 시작했다. 더 이상 라이브러리가 제공하는 기능 목록에 휘둘리지 않았다. 그녀는 스스로의 판단 기준으로 시스템의 뼈대를 세우고 있었다.