슈퍼바이저 에이전트가 전체 플로우를 조율하고 서브 에이전트들이 각자의 도구로 병렬 작업을 수행하는 구조가 보편화되면서, 프런트엔드는 단순 대화 UI를 넘어 에이전트의 상태, 의사결정, 근거, 실행 로그를 실시간으로 시각화해야 합니다. 이 글은 챗봇 LLM 프런트엔드 관점에서 React와 Next.js를 선택할 때 발생하는 기술적 고민을 최신 흐름에 맞춰 정리하고, UI/UX 패턴과 구현 관점의 장단점을 균형 있게 풀어냅니다.
왜 멀티 에이전트 UI/UX가 어렵나
멀티 에이전트는 “말풍선 스트리밍”만 잘하면 끝나지 않습니다. 어느 시점에 어떤 서브 에이전트가 어떤 도구를 사용했고, 그 결과가 전체 계획에 어떤 영향을 줬는지, 실패했을 때 루프가 어떻게 수렴했는지를 사용자가 이해할 수 있어야 합니다. 따라서 단일 채팅 타임라인 외에도 플로우 그래프, 태스크 보드, 중간 산출물 뷰, RAG 근거 뷰, 비용·지연(latency) 메트릭까지 함께 노출하는 복합 인터페이스가 필요합니다. 이 복합 뷰를 실시간으로 끊김 없이 업데이트하고, 서버 액션이나 엣지 런타임으로 토큰 스트리밍을 처리하며, 다중 탭·세션 간 상태 일관성을 유지하는 것이 관건입니다.
핵심 화면 구성의 기준선
실무에서 일단 다음 네 가지를 기본 골격으로 잡으면 확장성이 좋아집니다. 첫째, 좌측은 대화 타임라인과 스트리밍, 중앙은 “계획‑실행‑관찰(Plan‑Act‑Observe)” 단계의 이벤트 로그, 우측은 그래프 기반의 에이전트 네트워크와 각 노드의 상태 패널입니다. 둘째, 검색 증거와 파일 미리보기, 이미지·표 보정 같은 중간 산출물은 드로어나 모달로 띄우되, 타임라인과 동기화된 앵커를 둡니다. 셋째, 실시간 상태는 토스트가 아니라 상단 글로벌 스테이터스로 일괄 표출하여 사용자 불안을 줄입니다. 넷째, 실패와 재시도는 델타 패치로 시각화해 “무엇이 바뀌었는지”를 한눈에 보여줍니다.
React로 갈 때의 기술적 고민
CSR 중심의 React SPA는 배포 단순성과 완전한 클라이언트 제어가 강점이지만, 멀티 에이전트에 필요한 스트리밍, 프리페치, SEO, 보안 경계의 분리가 까다로울 수 있습니다. 서버와의 통신은 보통 SSE나 WebSocket으로 풀게 되는데, 탭 복제와 재연결, 백프레셔 제어, 장시간 스트림에서의 토큰 누수, 모바일 절전 모드의 연결 해제 등을 직접 다뤄야 합니다. React Query나 Zustand로 세션 상태를 관리할 수 있지만, 서버에서 이미 계산된 플로우 조각을 부분적으로 주입하고 하이드레이션하는 최적화는 한계가 있습니다. 파일 업로드나 스크린샷‑OCR 같은 무거운 연산을 Web Worker와 WASM으로 옮기는 전략은 유효하지만, 초기 번들 크기와 로딩 타이밍을 잘못 잡으면 “첫 응답이 빠른 챗봇”이라는 사용자 기대를 저버리기 쉽습니다.
Next.js로 갈 때의 기술적 고민
Next.js는 라우팅, 서버 컴포넌트, 스트리밍 렌더링, 서버 액션으로 멀티 에이전트 UI에 필요한 조각들을 프레임워크 레벨에서 제공합니다. 다만 RSC와 클라이언트 컴포넌트의 경계가 처음엔 헷갈리며, 브라우저‑서버 간 상태 공유 전략을 명확히 하지 않으면 “어디서 연산하고 어디서 캐시할지”가 흐려집니다. 또한 장시간 SSE 스트림을 서버 액션으로 직접 노출할 때 런타임 리소스 관리와 타임아웃 정책을 함께 설계해야 하며, 프록시나 엣지 런타임을 어디에 둘지 결정해야 합니다. 조직 내 CI/CD, 모놀리식‑폴리리포 전략, 사내 프록시·보안 게이트웨이와의 궁합도 미리 확인해야 합니다.
스트리밍 UX, 어디서 그릴까
LLM 응답 스트리밍과 에이전트 이벤트 스트리밍은 UX의 성패를 가릅니다. React만 쓸 때는 브라우저에서 직접 SSE를 열고, 청크마다 React Query의 setQueryData로 델타 패치를 적용하는 방식이 일반적입니다. Next.js에선 서버 액션이나 Route Handler에서 스트리밍을 제어하며, 서버 컴포넌트의 Suspense로 초반 레이턴시를 가리고 클라이언트 컴포넌트가 후속 토큰을 점진적으로 렌더링하게 만들 수 있습니다. 슈퍼바이저 로그는 토큰과 다른 레이트를 가지는 경우가 많아 같은 채널로 보내면 UI가 튀므로, 메시지 스트림과 이벤트 스트림을 분리하고 클라이언트에서 타임라인 합성을 수행하는 편이 안전합니다.
그래프 뷰와 타임라인의 동기화
멀티 에이전트 UI의 난이도는 그래프 뷰와 타임라인 싱크입니다. 노드 실행이 시작되면 그래프 노드가 펄스 애니메이션으로 활성화되고, 완료되면 타임라인에 해당 로그 블록이 닻표처럼 고정되어야 합니다. React에서는 d3‑force나 React Flow 같은 라이브러리로 충분히 구현할 수 있지만, 레이아웃 재계산이 잦으면 FPS가 떨어집니다. Next.js를 쓰면 서버에서 그래프의 초기 레이아웃을 계산해 주입하고 클라이언트는 미세 보정만 수행하도록 설계해 초기 TTI를 크게 줄일 수 있습니다. 특히 대규모 플로우에서 초기 스냅샷을 서버 컴포넌트로 렌더하고, 이후 증분은 클라이언트 컴포넌트의 가상화 리스트로 마운트하는 패턴이 실전에서 안정적입니다.
근거, 툴 호출, 코스트 패널의 설계
사용자는 “왜 이런 결론이 났는가”를 알고 싶어합니다. 따라서 도구 호출 파라미터·입출력 미리보기, 사용 토큰·지연 시간, 랭크링 근거, 금칙어 필터링 이력까지 한 화면에서 드릴다운 가능해야 합니다. React에서 모두 클라 사이드로 그리면 빠른 인터랙션이 가능하지만, 민감 데이터가 브라우저에 오래 머뭅니다. Next.js에선 민감한 원본을 서버에서 마스킹 처리해 서버 컴포넌트로 렌더하고, 사용자가 “자세히 보기”를 눌렀을 때 서버 액션으로 단건 감사 로그를 발급하는 식으로 데이터 노출을 최소화할 수 있습니다. 기업형 보안 요구가 있다면 이 차이는 결정적입니다.
멀티테넌트와 캐시 전략
기업 환경에서 테넌트별 프롬프트·툴 설정이 다른 경우가 많습니다. React SPA는 도메인이나 경로 기반으로 테넌트를 분기하여 클라이언트 캐시를 분리하지만, 프리렌더·SEO가 약합니다. Next.js는 라우트 그룹과 동적 세그먼트, 서버 캐시를 활용해 테넌트별 초기 상태를 서버에서 주입하고, Edge‑Cache 키를 테넌트로 분리해 콜드 스타트를 줄일 수 있습니다. 또한 서버 액션과 KV 스토어를 함께 쓰면 멀티탭 간 세션 동기화도 단순해집니다.
성능과 비용의 실제
React 단일 페이지 앱은 CDN 캐시로 정적 파일을 잘 서빙하면 비용이 예측 가능하고 저렴합니다. 다만 LLM 토큰 스트리밍의 네트워크 체류 시간이 길면 브라우저‑백엔드‑모델 게이트웨이 세 구간을 모두 유지해야 하므로, 클라이언트에서 직접 모델 게이트웨이로 붙도록 설계하면 백엔드 비용을 줄일 수 있으나 보안상 위험을 동반합니다. Next.js는 서버 렌더링과 엣지 런타임을 혼용하면서 프리페치와 지연 숨기기가 유리해 사용자 체감 성능이 좋습니다. 반대로 서버 자원 사용이 늘어 요금도 함께 증가할 수 있어, Route 단위로 “서버 컴포넌트로 렌더할 가치가 있는가”를 계속 다이어트해야 합니다.
팀 역량과 운영 복잡도
React는 러닝커브가 낮고 자유도가 높아 빠른 프로토타이핑과 사내 표준 컴포넌트 시스템의 재활용에 강합니다. 운영은 간단하지만 아키텍처 품질은 팀 규율에 좌우됩니다. Next.js는 내장 규약이 많아 장기 유지보수와 규모 확장에 유리합니다. DevRel 문서, 예제, SaaS형 배포 스택과의 친화성도 높습니다. 다만 RSC·서버 액션·엣지·캐시 규약을 반드시 팀 내에 문서화하고, 코드리뷰 체크리스트로 관리하지 않으면 오히려 복잡성이 커집니다.
React를 선택할 시의 명확한 승부처
사내 인증, 프록시, 게이트웨이 제약이 강하고 백엔드가 이미 API 게이트웨이로 잘 추상화되어 있으며, 클라이언트에서의 시각화가 매우 복잡해 WebGL 기반 그래프나 대규모 캔버스 최적화가 핵심일 때 React SPA가 깔끔합니다. 프리렌더·SEO 요구가 크지 않고, 도메인 내부 사용자 대상의 운영툴 성격이라면 더더욱 그렇습니다. 대화 스트리밍, 이벤트 스트림, 파일 미리보기, 이미지 편집, OCR 보정 같은 무거운 인터랙션을 Worker와 WASM으로 전개하는 전략도 제어가 쉽습니다.
Next.js를 선택할 시의 명확한 승부처
엔터프라이즈 테넌트 다변화, 초기 TTI 최적화, 부분 프리렌더링, 퍼블릭 FAQ‑형 지식봇처럼 검색 유입이 중요한 케이스, 그리고 민감한 감사 로그의 서버 측 마스킹과 접근 통제가 필요한 경우 Next.js가 유리합니다. 서버 컴포넌트로 초기 그래프 스냅샷과 요약 패널을 빠르게 보여주고, 클라이언트 컴포넌트가 스트림을 이어받아 세부 로그를 점진적으로 채우면 체감 품질이 크게 올라갑니다. 또한 서버 액션으로 툴 실행을 트리거하면 브라우저 시크릿 보관 부담이 줄고, 권한·감사 추적도 간단해집니다.
공통 아키텍처
백엔드는 FastAPI나 Node 서버에서 SSE/WebSocket으로 두 가지 스트림을 제공합니다. 하나는 답변 토큰, 다른 하나는 에이전트 이벤트입니다. 프런트는 세션 키를 기준으로 두 스트림을 머지해 타임라인과 그래프 상태를 동기화합니다. 중간 산출물은 저장소에 올리고 URL만 스트림으로 흘려 보냅니다. 에러는 치명도와 재시도 가능 여부를 이벤트 메타에 싣고, UI는 동일 블록을 “실패→백오프→재시도→성공” 시퀀스로 덮어씁니다. 이 구조는 React든 Next.js든 동일하게 재사용됩니다.
React로 가는 경우
라우터는 React Router, 데이터 계층은 React Query, 세션 상태는 Zustand를 권장합니다. SSE는 AbortController로 수명 주기를 관리하고, 가상화 리스트로 타임라인을 그리며, 그래프는 React Flow에 레이어드 캔버스를 더해 대규모 노드에서도 FPS를 유지합니다. 보안은 BFF 패턴으로 토큰을 단기 교환하고, 브라우저에는 임시 세션 토큰만 보관합니다. 워커 스레드에서 OCR·토큰화·임베딩 샘플링 같은 무거운 일을 처리해 메인 스레드를 비웁니다. 번들은 코드 스플리팅으로 초기 경로를 최소화하고, 사용자가 그래프 탭을 열 때 라이브러리를 지연 로딩합니다.
Next.js로 가는 경우
App Router를 전제로 서버 컴포넌트에서 초기 세션 메타와 그래프 스냅샷, 최근 대화 요약을 렌더합니다. 클라이언트 컴포넌트는 마운트 즉시 SSE를 붙고, 서버 액션은 툴 실행·파일 업로드·감사 로그 조회 등 권한이 필요한 작업을 담당합니다. Route Handler는 스트리밍 엔드포인트로 분리하여 엣지 런타임에서도 동작하도록 만들고, 캐시 키에 테넌트와 세션을 포함합니다. 민감 데이터는 서버에서 마스킹하고, “자세히 보기”를 누를 때만 1회성 토큰으로 세부 로그를 내려줍니다. 이미지·PDF 미리보기는 서버에서 서명된 URL을 발급해 브라우저 노출 시간을 제한합니다.
판단 가이드: 어떤 팀이 어떤 선택을 할까
사내 툴, 빠른 반복, 시각화 난이도가 높은 팀은 React SPA로 시작해도 충분히 성공합니다. 다만 초기에 스트리밍과 상태 일관성, 보안 경계를 확실히 정하는 것이 중요합니다. 반면, 대외 서비스, 검색 유입, 테넌트별 초기 로딩 최적화, 감사·거버넌스 요구가 강한 팀은 Next.js가 장기적으로 더 안전합니다. 단기적으로 러닝커브가 있지만, 서버 렌더링·캐시·보안 경계가 프레임워크 레벨에서 정리되어 운영이 수월해집니다.
마무리: 정답은 없지만, 우선순위는 있다
멀티 에이전트 UI는 “보여주지 않으면 신뢰받지 못하는” 영역입니다. 어떤 프레임워크를 쓰더라도 타임라인‑그래프‑근거 패널을 실시간으로 동기화하고, 실패와 회복을 시각적으로 설득력 있게 표현하는 경험이 핵심입니다. React는 자유와 제어, Next.js는 일관성과 내장 최적화로 그 목표를 돕습니다. 팀의 우선순위가 성숙한 운영·보안·SEO라면 Next.js, 빠른 실험과 고난도 시각화라면 React가 유리합니다. 중요한 것은 프레임워크보다 “스트림을 어떻게 모델링하고, 어디서 무엇을 렌더링할지”에 대한 팀의 합의입니다. 그 합의만 단단하면 둘 중 어느 선택이든 충분히 훌륭한 멀티 에이전트 챗봇 프런트엔드를 만들 수 있습니다.