생성형 사용자 인터페이스(Generative UI)
생성형 사용자 인터페이스(Generative UI)
생성형 사용자 인터페이스(generative UI)는 대규모 언어 모델(LLM)이 텍스트를 넘어 "UI를 생성"하도록 허용하는 과정이에요. 모델이 단순히 답변만 주는 게 아니라, 상황에 맞는 인터페이스를 직접 만들어 내기 때문에 사용자에게 더 몰입감 있고 AI 네이티브한 경험을 만들어 줍니다. 이 개념이 어떻게 동작하는지, 그리고 채팅 인터페이스에 어떻게 적용하는지 살펴볼게요.
출처: 공식문서
본문
generative UI는 대략 이렇게 흘러가요.
- 모델에 프롬프트나 대화 기록과 함께 도구(tool) 목록을 제공합니다.
- 모델은 문맥에 따라 도구를 호출하기로 결정할 수 있어요.
- 도구가 호출되면 실행되고 데이터를 돌려줍니다.
- 그 데이터를 React 컴포넌트에 넘겨 렌더링할 수 있어요.
예를 들어 "샌프란시스코 날씨가 어때?"라는 질문에 모델이 getWeather("San Francisco") 도구를 호출하고, 반환된 날씨 데이터를 받아 <WeatherCard> 같은 컴포넌트로 화면에 그려 주는 식이에요.
기본 채팅 구현
먼저 클라이언트에서 useChat 훅으로 채팅 입력과 메시지를 관리합니다.
'use client';
import { useChat } from '@ai-sdk/react';
import { useState } from 'react';
export default function Page() {
const [input, setInput] = useState('');
const { messages, sendMessage } = useChat();
// ...
}
채팅 요청과 모델 응답을 처리할 API 라우트를 만듭니다. 이 라우트는 streamText로 채팅 메시지를 처리하고 모델 응답을 클라이언트로 스트리밍해요.
import {
convertToModelMessages,
createUIMessageStreamResponse,
isStepCount,
streamText,
toUIMessageStream,
UIMessage,
} from 'ai';
export async function POST(request: Request) {
const { messages }: { messages: UIMessage[] } = await request.json();
const result = streamText({
model: "xai/grok-4.6",
instructions: 'You are a friendly assistant!',
messages: await convertToModelMessages(messages),
stopWhen: isStepCount(5),
});
return createUIMessageStreamResponse({
stream: toUIMessageStream({ stream: result.stream }),
});
}
도구 만들기
채팅을 동적 UI로 확장하기 전에, 모델이 특정 동작(예: 날씨 정보 가져오기)을 수행할 수 있게 해주는 도구와 그에 대응하는 React 컴포넌트를 만듭니다. ai/tools.ts 파일에 도구를 정의하고, API 라우트의 streamText에 tools를 넘겨주면 돼요.
import { tools } from '@/ai/tools';
// ...
const result = streamText({
model: "xai/grok-4.6",
instructions: 'You are a friendly assistant!',
messages: await convertToModelMessages(messages),
stopWhen: isStepCount(5),
tools,
});
날씨 컴포넌트 렌더링하기
모델이 도구를 호출했는지 확인하려면 UIMessage 객체의 parts 배열에서 도구 관련 파트를 찾아야 해요. AI SDK 5.0부터 도구 파트는 제네릭 타입 대신 tool-${toolName} 같은 타입 이름을 사용합니다. parts 배열의 각 파트 타입에 맞춰 컴포넌트를 조건부로 렌더링하면, 모델 응답에 따라 UI가 동적으로 바뀌는 대화형 채팅이 완성돼요.
- 입력 상태는 내장
input/handleInputChange대신useState로 직접 관리. - 메시지 전송은
handleSubmit대신sendMessage사용. - 각 메시지의
parts배열을 확인해 콘텐츠 타입별로 렌더링.
더 알아보기
- 도구 호출 시 모델이
stopWhen: isStepCount(5)로 다단계 호출을 제한하는 예시. - 서버에서 생성형 UI를 표시하고 싶다면 AI SDK RSC(
@ai-sdk/rsc) 참고. - 스트림 프로토콜 페이지에서 UI 메시지 스트림이 어떻게 전달되는지 확인.