- Published on
버셀 AI SDK 아키텍처와 구현 방식: Core + UI와 Core + RSC
- Authors
- Name
- Pax Code
- https://x.com/PaxCodeXyz
Table of Contents
서론: 버셀 AI SDK의 UI: 라우트 핸들러 vs. RSC: 서버 액션 방식 비교
버셀 AI SDK는 다양한 사용자 경험을 제공하기 위해 두 가지 주요 방식을 활용합니다. UI는 라우트 핸들러(Route Handlers) 방식을 사용하고, RSC는 서버 액션(Server Actions) 방식을 사용합니다. 이 글에서는 먼저 라우트 핸들러와 서버 액션의 개념을 살펴본 후, 버셀 AI SDK 아키텍처와 구현 방식인 Core + UI와 Core + RSC를 4 Tiers 아키텍처로 나누어 자세히 살펴보겠습니다.
UI와 라우트 핸들러
UI를 구현할 때 라우트 핸들러를 사용하는 방식은 사용자 인터페이스와 API를 명확히 분리하여 복잡한 클라이언트 애플리케이션을 효율적으로 관리할 수 있게 합니다. 라우트 핸들러는 다양한 HTTP 메서드(GET
, POST
, PUT
, DELETE
등)를 사용하여 클라이언트 요청을 처리하고 외부 API와 통신하거나 서버에서 필요한 데이터를 가져와 사용자에게 반환하는 데 유용합니다. 이러한 방식은 특히 다양한 클라이언트 애플리케이션(예: 웹, 모바일)에서 동일한 API를 재사용할 때 적합합니다.
RSC와 서버 액션
RSC(React Server Components)를 구현할 때 서버 액션을 사용하는 방식은 서버 측에서 컴포넌트를 렌더링하고 클라이언트로 스트리밍하는 과정을 간소화합니다. 서버 액션은 주로 서버에서 데이터를 변경하거나 리소스를 생성, 업데이트하는 작업을 수행하는 데 사용됩니다. 이러한 방식은 데이터 변형 작업을 쉽게 수행하고 캐시 무효화와 같은 고급 기능을 지원하여 더 나은 사용자 경험을 제공합니다.
이제 라우트 핸들러와 서버 액션의 개념과 차이점을 살펴본 후, 버셀 AI SDK 아키텍처의 구현 방식을 4 Tiers 아키텍처로 나누어 자세히 설명하겠습니다.
라우트 핸들러 vs. 서버 액션
Next.js에서 클라이언트와 서버 간의 데이터 교환 및 컴포넌트 렌더링을 위한 두 가지 방법은 라우트 핸들러와 서버 액션입니다. 각 방법의 개념, 차이점, 그리고 어떤 시나리오에서 사용하는 것이 좋은지 먼저 설명하겠습니다.
라우트 핸들러 (Route Handlers)
라우트 핸들러는 서버 측에서 클라이언트 요청을 처리하는 방법으로 REST API를 작성하는 데 사용됩니다. 이 방식은 페이지 라우터(Page Router)를 사용하는 이전 Next.js 버전(v13.4 이전)의 API 라우트
와 거의 유사합니다. 라우트 핸들러는 다양한 HTTP 메서드(GET
, POST
, PUT
, DELETE
등)를 사용할 수 있으며 서버에서 데이터를 가져오거나 데이터를 변경하는 데 사용됩니다.
장점은 다음과 같습니다.
- 다양한 HTTP 메서드 지원:
GET
,POST
,PUT
,DELETE
등 다양한 HTTP 메서드를 지원하여 복잡한 API를 구축할 수 있습니다. - 클라이언트 외부 호출 가능: 다른 클라이언트 애플리케이션(예: React Native, 다른 웹 애플리케이션)에서 호출할 수 있는 API를 생성할 수 있습니다.
- 응답 형식 유연성:
JSON
,텍스트
,커스텀 형식
등 다양한 응답 형식을 반환할 수 있습니다. - 독립적 기능: 클라이언트와 서버 간의 명확한 분리로 코드의 재사용성이 높아집니다.
예시 코드에서는 GET
메소드를 사용하여 외부 서버에서 데이터를 가져와 JSON
으로 반환하는 코드입니다.
export async function GET(request) {
const { searchParams } = new URL(request.url);
const id = searchParams.get('id');
const res = await fetch(`http://www.example.com/product/${id}`, {
headers: {
'Content-Type': 'application/json',
'API-Key': process.env.DATA_API_KEY,
},
});
const product = await res.json();
return Response.json({ product });
}
서버 액션 (Server Actions)
서버 액션은 Next.js 13.4 이후 버전의 앱 라우터(App Router)에서만 사용할 수 있는 방법입니다. 서버 액션은 클라이언트에서 서버 측 코드를 호출하는 고수준의 추상화입니다. 주로 서버에서 데이터를 변경하거나 리소스를 생성 또는 업데이트하는 데 사용됩니다. 서버 액션은 내부적으로 POST
HTTP 메서드를 사용하며 클라이언트에서 직접 함수처럼 호출할 수 있습니다.
장점은 다음과 같습니다.
- 고수준 추상화: 서버 데이터 변형 작업을 쉽게 수행할 수 있습니다.
- 단순성: 설정이 간단하며 데이터 변형 작업을 위해 별도의 API 엔드포인트를 작성할 필요가 없습니다.
- 캐시 무효화:
revalidatePath
및revalidateTag
와 같은 유틸리티를 사용하여 특정 페이지 또는 태그의 캐시를 무효화할 수 있습니다.
예시 코드는 아래와 같습니다.
'use server'
export async function updateUser(userId, formData) {
// 서버 측 데이터 변경 로직
}
// Client Component
'use client'
import { updateUser } from './actions';
export function UserProfile({ userId }) {
const updateUserWithId = updateUser.bind(null, userId);
return (
<form action={updateUserWithId}>
<input type="text" name="name" />
<button type="submit">Update User Name</button>
</form>
);
}
두가지 방식 비교 및 사용 시나리오
라우트 핸들러를 사용할 때
- API 노출이 필요한 경우: 외부 클라이언트에서 호출할 수 있는 API를 작성해야 할 때
- 복잡한 서버 로직: 다양한 HTTP 메서드와 응답 형식을 지원해야 할 때
- 다양한 클라이언트 지원: Next.js 애플리케이션 외의 다른 클라이언트(예: 모바일 앱)에서도 동일한 서버 로직을 재사용해야 할 때
서버 액션을 사용할 때
- 단순 데이터 변형: 주로 데이터를 생성, 업데이트 또는 삭제하는 작업이 필요할 때
- 웹 앱 내 클라이언트-서버 간의 간단한 인터랙션: 클라이언트에서 서버의 데이터를 간단하게 변경하고 싶을 때
- 캐시 무효화가 필요한 경우: 데이터 변형 후 특정 페이지나 태그의 캐시를 무효화해야 할 때
라우트 핸들러와 서버 액션은 각각의 장점과 사용 사례가 있습니다. 라우트 핸들러는 복잡한 API와 다양한 클라이언트를 지원해야 할 때 적합하며, 서버 액션은 단순한 데이터 변형 작업과 클라이언트-서버 간의 간단한 인터랙션에 적합합니다. 프로젝트의 요구사항과 상황에 따라 두 가지 방법을 적절히 사용하면 됩니다.
버셀 AI SDK 아키텍처와 구현 방식: Core + UI와 Core + RSC
버셀 AI SDK를 이용한 개발을 위해 웹 아키텍처를 네 개의 주요 계층으로 구성하여 설명하겠습니다. 이러한 4 Tiers 아키텍처를 살펴보고 Core + UI와 Core + RSC 방식의 구현 방식과 그 차이점을 논의하겠습니다.
AI SDK 사용을 위한 4 Tiers 아키텍처 구성 요소
Client Tier
- 역할: 사용자 브라우저에서 실행되는 클라이언트 사이드 렌더링(CSR)을 담당합니다.
- 기능: 사용자 인터페이스를 제공하고 사용자와의 상호작용을 처리합니다.
- 장점: 빠른 인터페이스 반응 시간, 사용자 디바이스의 성능에 맞춘 렌더링 가능.
Server Tier
- 역할: Node.js 서버 기반으로 서버 사이드 렌더링(SSR)을 수행하고 AI SDK Core가 실행됩니다.
- 기능: 서버 측에서 데이터를 처리하고 클라이언트에 전달할 준비를 합니다.
- 장점: 데이터 보안이 뛰어나며, 클라이언트의 낮은 성능에서도 빠른 실행 결과를 제공합니다.
AI Provider Tier
- 역할: AI 벤더사가 운영하는 서버에서 AI 기능을 제공합니다.
- 기능: AI 모델을 사용하여 데이터 분석, 처리 및 결과를 생성합니다.
- 장점: 고성능 AI 모델 사용 가능, 최신 AI 기술 적용 가능.
3rd Party Service Tier
- 역할: 특정 서비스(예: 날씨 정보)를 제공하는 외부 서비스 계층입니다.
- 기능: 다양한 외부 API를 통해 부가적인 데이터를 제공합니다.
- 장점: 다양한 서비스와 쉽게 통합 가능, 확장성 높음.
첫번째 아키텍처 방식
대규모 언어 모델을 이용을 위해서는 Server Tier와 AI Provider Tier 간의 연동이 필요합니다. 이 연동은 Core + UI와 Core + RSC 방식 모두에서 동일하게 이루어집니다.
AI 기능이 특정 컴포넌트와 연동되어 렌더링될 때 이 렌더링이 Server Tier에서 수행된다면 Server Tier와 3rd Party Service Tier 간의 관계가 형성됩니다. 이러한 방식은 Core + UI와 Core + RSC 모두에 적용될 수 있습니다.
이 아키텍처에서로 구성할 때 Core + UI
와 Core + RSC
의 동작 방식의 공통점은 AI 기능 연동을 위해 Server Tier
와 AI Provider Tier
가 연동되어 AI 기능을 수행합니다.
Core + RSC 방식
에서는 서버 측에서 컴포넌트를 렌더링하여 클라이언트로 스트리밍합니다. 이는 서버에서 컴포넌트를 미리 렌더링한 후 클라이언트로 전송하는 방식입니다.
- 장점:
- 데이터 보안: 서버에서 렌더링되므로 데이터가 안전하게 유지됩니다.
- 빠른 초기 로드: 서버에서 미리 렌더링된 결과를 전달하므로 클라이언트의 초기 로드 속도가 빠릅니다.
- 스트리밍 지원: 채팅 시 생성되는 컴포넌트도 스트리밍 가능하여 사용자 경험 향상.
- 단점:
- 서버 부하: 서버에서 모든 렌더링을 처리하므로 서버의 런타임과 네트워크 부하가 증가합니다.
- SEO 제한: 실시간으로 생성되는 UI는 SEO에 큰 영향을 미치지 않음.
이 아키텍처로 Core + UI 방식
을 구현할 때는 3rd Party Service Tier
에서 받은 데이터를 Client Tier
에게 넘겨줘서 이 데이터에 대한 렌더링을 Server Tier
에서 할수도 있고 Client Tier
에서 할 수 있습니다.
두번째 아키텍처 방식
이 아키텍처는 Core + UI 방식
에서만 사용 가능하며 특징은 클라이언트 측에서 데이터를 받아서 렌더링됩니다. 이는 클라이언트 측에서 데이터를 받아와서 사용자에게 보여주는 방식입니다.
- 장점:
- 서버 부하 분산: 클라이언트에서 데이터를 처리하므로 서버의 부하가 줄어듭니다.
- 유연성: 클라이언트에서 다양한 UI 컴포넌트를 쉽게 렌더링할 수 있습니다.
- 단점:
- 보안 문제: 데이터가 클라이언트로 직접 전달되므로 보안에 유의해야 합니다.
- 클라이언트 성능 의존: 클라이언트 디바이스의 성능에 따라 렌더링 성능이 달라질 수 있습니다.
첫번째와 두번째의 최적의 아키텍처 선택
적합한 아키텍처 구성은 웹 애플리케이션의 목적과 요구 사항에 따라 달라집니다. 다음은 각 방법의 사용 시나리오입니다.
Core + RSC
가 적합한 경우는 다음과 같습니다.
- 데이터 보안이 중요한 경우: 민감한 데이터를 처리하는 애플리케이션
- 빠른 초기 로드가 필요한 경우: 초기 로딩 속도가 중요한 애플리케이션
- 스트리밍 지원이 필요한 경우: 실시간 스트리밍 기능이 중요한 애플리케이션
Core + UI
가 적합한 경우은 다음과 같습니다.
- 실시간 상호작용이 중요한 경우: 사용자와의 빠른 상호작용이 필요한 애플리케이션
- 서버 부하 분산이 필요한 경우: 많은 사용자가 동시에 접속하여 서버 부하가 우려되는 경우
- 유연한 UI 렌더링이 필요한 경우: 다양한 UI 컴포넌트를 클라이언트 측에서 자유롭게 렌더링해야 하는 경우
버셀 AI SDK 아키텍처는 다양한 계층 간의 상호작용을 통해 최상의 사용자 경험을 제공합니다. Core + UI와 Core + RSC 방식은 각각의 장점과 단점이 있으며 애플리케이션의 요구 사항에 따라 적절히 선택하여 사용할 수 있습니다. 웹 애플리케이션의 목적과 요구 사항을 명확히 이해하고 이에 따라 최적의 아키텍처를 구성하는 것이 중요합니다. 이를 통해 효율적이고 효과적인 웹 애플리케이션을 구축할 수 있습니다.