
Day 2: Generative UI Gen 1 — AG-UI를 활용한 정적 컴포넌트 (Static Components)
요약
에이전트가 직접 UI 코드를 생성하는 대신, 미리 정의된 컴포넌트를 선택하고 데이터를 채워 넣는 Gen 1 방식의 정적 생성형 UI(AG-UI)를 소개합니다. AG-UI는 에이전트와 프론트엔드 간의 양방향 이벤트 스트림을 통해 안정적인 사용자 인터페이스를 구현하는 프로토콜입니다.
핵심 포인트
- Gen 1 방식은 디자인 시스템과 접근성을 유지하며 LLM의 환각 위험을 최소화함
- AG-UI는 에이전트와 사용자를 연결하는 에이전트-프론트엔드 통신 프로토콜임
- SSE를 활용한 양방향 이벤트 스트림으로 메시지, 도구 호출, 상태 변화를 전달함
- 특정 프레임워크에 종속되지 않는 와이어 프로토콜로서의 중요성을 가짐
지난 1년 동안 LLM이 사용자 인터페이스(User Interface)를 어떻게 재작성했는지에 대한 6부작 시리즈의 Day 2입니다. Day 0에서는 채팅이 왜 한계에 부딪혔는지 다루었고, Day 1에서는 바이브 코딩(Vibe coding) 툴체인을 다루었습니다. 오늘은 진정한 변화인, 런타임(Runtime)에 UI를 렌더링하는 에이전트(Agent)에 대해 알아봅니다.
제어와 자유의 축 (The control–freedom axis)
모든 생성형 UI(Generative UI) 아키텍처는 한 가지 질문에 답합니다: 인터페이스를 에이전트에게 얼마나 신뢰하고 맡길 것인가?
Gen 1 — 정적 생성형 UI(Static generative UI) — 는 가장 안전한 답을 제시합니다: 그리 많이는 아니다. 에이전트는 UI 코드를 직접 생성하지 않습니다. 대신 당신이 구축한 컴포넌트(Component) 중에서 선택하고, 그 안에 데이터를 채워 넣습니다. 당신의 디자인 시스템(Design system)은 온전하게 유지되며, 접근성(Accessibility) 작업도 보존됩니다. LLM의 환각(Hallucination)이 할 수 있는 최악의 상황은 잘 작동하는 컴포넌트에 이상한 데이터를 넣는 것뿐입니다.
이것이 AG-UI가 표준화하는 패턴이며, 대부분의 프로덕션 팀이 시작해야 할 지점입니다.
AG-UI의 실체
AG-UI (CopilotKit 팀에서 만든 Agent–User Interaction protocol)는 MCP가 에이전트-도구(Agent-tool) 통신에 역할을 하는 것과 마찬가지로, 에이전트-프론트엔드(Agent-frontend) 통신을 위한 역할을 합니다. 사고 모델(Mental model)은 다음과 같습니다:
- MCP는 에이전트를 도구(Tools)에 연결합니다.
- A2A는 에이전트를 서로 연결합니다.
- AG-UI는 에이전트를 사용자(Users)에게 연결합니다.
이는 모든 에이전트 기반 백엔드(Agentic backend)와 당신의 프론트엔드 사이의 양방향 이벤트 스트림(Bidirectional event stream, 일반적으로 SSE)입니다. 에이전트는 메시지, 도구 호출(Tool calls), 상태 변화(State deltas), 라이프사이클 신호(Lifecycle signals)와 같은 타입이 지정된 이벤트(Typed events)를 방출하고, 당신의 UI는 이에 반응합니다. 이는 이미 LangChain, Microsoft Agent Framework, AWS, Mastra, PydanticAI 전반에 걸쳐 채택되었으며, 이는 매우 중요합니다. 당신은 특정 프레임워크에 거는 것이 아니라, 와이어 프로토콜(Wire protocol)에 거는 것이기 때문입니다.
구축하기: 항공권 검색 에이전트
Day 0에서 다루었던 항공권 예시를 실제로 구현해 봅시다. 프론트엔드는 에이전트가 호출할 수 있는 컴포넌트인 _렌더링 가능한 액션 (renderable action)_을 등록합니다.
"use client"
import { useCopilotAction } from "@copilotkit/react-core"
...
이것이 핵심 비결의 전부입니다. showFlights는 에이전트의 도구 상자(toolbox)에 포함된 하나의 도구(tool)가 됩니다. 다만 API를 호출하는 대신, 이를 "호출"하면 대화창 내에 여러분의 FlightCardList 컴포넌트가 인라인으로 렌더링되며, 인자(arguments)가 도착함에 따라 스트리밍 방식으로 나타납니다 (status를 통해 완료 시점을 알 수 있습니다).
백엔드는 React에 대해 알 필요도 없고 신경 쓸 필요도 없습니다. LangGraph 에이전트는 그저 도구를 호출할 뿐입니다:
from langchain_core.tools import tool
@tool
...
사용자가 "금요일 아침 오스틴행 항공편"이라고 물으면, 텍스트 문단이 아닌 정렬 가능한 카드와 예약 버튼이 나타납니다. 동일한 모델을 사용하면서도 인터페이스는 근본적으로 개선되었으며, 에이전트는 UI 코드를 단 한 줄도 작성하지 않았습니다.
컴포넌트뿐만 아니라 상태(State)를 스트리밍하기
import { useCoAgent } from "@copilotkit/react-core"
function ResearchProgress() {
...
에이전트의 작업 내용이 읽기 힘든 전사(transcript) 형태로 스크롤되어 지나가 버린다는 Day 0의 불만을 기억하시나요? 이것이 바로 그 해결책입니다. 전사 내용은 대화를 위해 유지하되, 진행 바(progress bars), 단계 목록(step lists), 부분적 결과(partial results)와 같은 라이브 패널을 통해 에이전트가 실제로 무엇을 하고 있는지 보여줍니다. 단순히 뒤에 덧붙이는(append-only) 방식이 아닌 임의 접근(Random access)이 가능해집니다.
제대로 구현된 Human-in-the-loop
Gen 1은 Day 0의 가장 무서운 문제였던, 즉 텍스트 더미를 훑어보며 에이전트의 액션을 승인해야 했던 문제도 해결합니다. renderAndWaitForResponse를 사용하면 에이전트는 사용자가 실제 컴포넌트를 통해 동작할 때까지 일시 중지됩니다:
useCopilotAction({
name: "confirmBooking",
renderAndWaitForResponse: ({ args, respond }) => (
...
이제 구매 승인은 "사용자가 채팅 어딘가에서 OK라고 말했다"가 아니라, 큰 글씨의 가격과 두 개의 버튼이 있는 카드로 나타납니다. 실제 돈이 오가거나 파괴적인 작업(destructive operations)이 포함되는 경우, 이 패턴 하나만으로도 Gen 1의 가치는 충분합니다.
한계 (즉, Gen 2가 존재하는 이유)
정적 생성 UI (Static generative UI)에는 한계가 있으며, 그 한계에 매우 빠르게 도달하게 됩니다:
- 모든 컴포넌트를 사전에 예측해야 합니다. 에이전트는 당신이 미리 구축해 놓은 것만 보여줄 수 있습니다. 새로운 상황이 발생하면 다시 텍스트로 퇴보하게 됩니다.
- 크로스 플랫폼(Cross-platform)은 재구현을 의미합니다. 당신의
FlightCardList는 React 기반입니다. 모바일 팀은 이를 다시 만들어야 합니다. Slack 통합 기능은 이를 전혀 사용할 수 없습니다. - 조합의 폭발(Combinatorics bite) 문제가 발생합니다. 여행 에이전트는 항공권 × 호텔 × 예산 × 비교 × 지도 등의 조합이 필요할 수 있습니다. 모든 변형(variant)을 구축하고 유지 관리하는 것은 프론트엔드 팀의 풀타임 업무가 될 것이며, 이는 우리가 탈피하려고 했던 바로 그 문제입니다.
당연히 다음 질문이 떠오를 것입니다: 만약 에이전트가 모든 화면을 미리 구축하지 않고도, 그리고 원시 요소(primitives) — 카드, 리스트, 폼 — 로부터 UI를 *구성(compose)*할 수 있다면 어떨까요? 원시 코드 실행 권한을 직접 넘겨주지 않고도 말이죠. 그것이 바로 선언적 생성 UI (declarative generative UI), Google의 A2UI이며, 내일 다룰 주제입니다.
다음 예고
- Day 3: Generative UI Gen 2 — A2UI를 활용한 선언적 명세 (declarative specs)
- Day 4: Generative UI Gen 3 — MCP 앱 및 개방형 인터페이스 (open-ended surfaces)
- Day 5: 채팅을 넘어 — 캔버스 인터페이스 (canvas interfaces), 적응형 UX (adaptive UX), 그리고 다가올 보안 비용 문제
오늘 Gen 1을 직접 사용해보고 싶다면: npx copilotkit@latest init 명령어를 통해 약 5분 만에 작동하는 AG-UI 환경을 구축할 수 있습니다. 내일 뵙겠습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기