생성형 UI

Generative UI

모델이 순수 텍스트 대신, 그 답에 맞는 구조화된 인터페이스(카드, 표, 버튼)를 직접 조립해 응답으로 보여주는 방식.

다른 이름: Dynamic UI responseRich response cardsTool UI
···
html
<div class="wrap">
  <div class="bubble">강남역 근처 조용한 카페 찾아줄게요</div>
  <div class="card" id="card">
    <div class="sk" id="sk"><div class="skimg"></div><div class="skl w70"></div><div class="skl w40"></div></div>
    <div class="real" id="real">
      <div class="img"></div>
      <div class="info">
        <strong>루프탑 브루잉</strong>
        <span class="meta">★ 4.7 · 도보 4분</span>
        <button class="cta">길찾기</button>
      </div>
    </div>
  </div>
</div>
css
.wrap{width:min(280px,94%);display:grid;gap:9px}
.bubble{padding:9px 12px;border-radius:12px;border-bottom-left-radius:4px;background:var(--surface);border:1px solid var(--line);color:var(--fg);font-size:11.5px}
.card{position:relative;height:96px;border-radius:12px;overflow:hidden;border:1px solid var(--line);background:var(--surface)}
.sk{position:absolute;inset:0;padding:12px;display:grid;grid-template-columns:44px 1fr;gap:10px;align-items:start;opacity:1;transition:opacity .3s}
.skimg{width:44px;height:44px;border-radius:9px;background:var(--line);animation:pulse 1.1s ease-in-out infinite}
.skl{height:8px;border-radius:4px;background:var(--line);margin-top:6px;animation:pulse 1.1s ease-in-out infinite}
.w70{width:70%}.w40{width:40%}
@keyframes pulse{50%{opacity:.4}}
.real{position:absolute;inset:0;padding:10px;display:grid;grid-template-columns:60px 1fr;gap:10px;align-items:center;opacity:0;transition:opacity .3s}
.card[data-ready] .sk{opacity:0}
.card[data-ready] .real{opacity:1}
.img{width:60px;height:60px;border-radius:10px;background:linear-gradient(135deg,var(--accent-2),var(--accent))}
.info{display:grid;gap:3px}
.info strong{font-size:12px;color:var(--fg)}
.meta{font-size:10px;color:var(--muted)}
.cta{margin-top:3px;justify-self:start;padding:4px 10px;border-radius:999px;border:0;background:var(--accent);color:#fff;font-size:10px;font-weight:700;cursor:pointer}
js
const card = document.getElementById('card');
function run() {
  card.removeAttribute('data-ready');
  setTimeout(() => card.setAttribute('data-ready', ''), 1200);
}
run();
setInterval(run, 3400);

"강남역 근처 카페 추천해줘"에 대한 가장 좋은 답은 문장이 아니라 사진·평점·거리·"길찾기" 버튼이 있는 카드일 수 있습니다. 생성형 UI는 모델이 답의 내용뿐 아니라 그 내용을 어떤 형태(카드, 목록, 비교표, 폼)로 보여줄지까지 함께 결정하고, 그 형태에 맞는 실제 인터페이스 컴포넌트가 렌더링됩니다.

구현은 보통 모델이 자유 형식 텍스트 대신 정해진 스키마의 구조화된 데이터(JSON)를 반환하고, 클라이언트가 그 데이터 형태에 맞는 미리 만들어둔 컴포넌트에 꽂아 넣는 식입니다. 즉 모델이 실제 HTML/CSS를 처음부터 생성하는 게 아니라, "이 상황엔 이 컴포넌트를 이 데이터로 채워라"를 고르는 쪽에 가깝습니다 — 그래야 일관된 디자인 시스템 안에서 결과가 나옵니다.

버튼이 눌리면(예: "장바구니 담기") 그 행동이 다시 대화의 일부로 모델에 전달돼 다음 응답에 반영될 수 있어야 이 패턴이 완전해집니다. 카드만 예쁘게 뜨고 그 안의 상호작용이 대화 맥락과 단절돼 있으면 반쪽짜리입니다.

언제 쓰나

답이 본질적으로 구조를 가진 경우(제품 비교, 예약, 일정, 위치)에 씁니다. 설명이나 의견처럼 산문이 자연스러운 답에 억지로 카드를 씌우면 오히려 읽기 불편해집니다.