ReactNextCentral
Published on

버셀 AI SDK 아키텍처와 구현 방식: Core + UI와 Core + RSC

버셀 AI SDK 아키텍처는 클라이언트와 서버 간의 효율적인 데이터 교환과 렌더링을 제공합니다. 이 글에서는 4 Tiers 아키텍처 관점에서 각 방식의 구성 요소와 차이점을 설명합니다.
버셀 AI SDK 아키텍처와 구현 방식: Core + UI와 Core + RSC
Authors
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 등)를 사용할 수 있으며 서버에서 데이터를 가져오거나 데이터를 변경하는 데 사용됩니다.

장점은 다음과 같습니다.

  1. 다양한 HTTP 메서드 지원: GET, POST, PUT, DELETE 등 다양한 HTTP 메서드를 지원하여 복잡한 API를 구축할 수 있습니다.
  2. 클라이언트 외부 호출 가능: 다른 클라이언트 애플리케이션(예: React Native, 다른 웹 애플리케이션)에서 호출할 수 있는 API를 생성할 수 있습니다.
  3. 응답 형식 유연성: JSON, 텍스트, 커스텀 형식 등 다양한 응답 형식을 반환할 수 있습니다.
  4. 독립적 기능: 클라이언트와 서버 간의 명확한 분리로 코드의 재사용성이 높아집니다.

예시 코드에서는 GET 메소드를 사용하여 외부 서버에서 데이터를 가져와 JSON으로 반환하는 코드입니다.

route-handler.js
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 메서드를 사용하며 클라이언트에서 직접 함수처럼 호출할 수 있습니다.

장점은 다음과 같습니다.

  1. 고수준 추상화: 서버 데이터 변형 작업을 쉽게 수행할 수 있습니다.
  2. 단순성: 설정이 간단하며 데이터 변형 작업을 위해 별도의 API 엔드포인트를 작성할 필요가 없습니다.
  3. 캐시 무효화: revalidatePathrevalidateTag와 같은 유틸리티를 사용하여 특정 페이지 또는 태그의 캐시를 무효화할 수 있습니다.

예시 코드는 아래와 같습니다.

actions.js
'use server'

export async function updateUser(userId, formData) {
  // 서버 측 데이터 변경 로직
}
page.jsx
// 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>
  );
}

두가지 방식 비교 및 사용 시나리오

라우트 핸들러를 사용할 때

  1. API 노출이 필요한 경우: 외부 클라이언트에서 호출할 수 있는 API를 작성해야 할 때
  2. 복잡한 서버 로직: 다양한 HTTP 메서드와 응답 형식을 지원해야 할 때
  3. 다양한 클라이언트 지원: Next.js 애플리케이션 외의 다른 클라이언트(예: 모바일 앱)에서도 동일한 서버 로직을 재사용해야 할 때

서버 액션을 사용할 때

  1. 단순 데이터 변형: 주로 데이터를 생성, 업데이트 또는 삭제하는 작업이 필요할 때
  2. 웹 앱 내 클라이언트-서버 간의 간단한 인터랙션: 클라이언트에서 서버의 데이터를 간단하게 변경하고 싶을 때
  3. 캐시 무효화가 필요한 경우: 데이터 변형 후 특정 페이지나 태그의 캐시를 무효화해야 할 때

라우트 핸들러와 서버 액션은 각각의 장점과 사용 사례가 있습니다. 라우트 핸들러는 복잡한 API와 다양한 클라이언트를 지원해야 할 때 적합하며, 서버 액션은 단순한 데이터 변형 작업과 클라이언트-서버 간의 간단한 인터랙션에 적합합니다. 프로젝트의 요구사항과 상황에 따라 두 가지 방법을 적절히 사용하면 됩니다.


버셀 AI SDK 아키텍처와 구현 방식: Core + UI와 Core + RSC

버셀 AI SDK를 이용한 개발을 위해 웹 아키텍처를 네 개의 주요 계층으로 구성하여 설명하겠습니다. 이러한 4 Tiers 아키텍처를 살펴보고 Core + UI와 Core + RSC 방식의 구현 방식과 그 차이점을 논의하겠습니다.

AI SDK 사용을 위한 4 Tiers 아키텍처 구성 요소

  1. Client Tier

    • 역할: 사용자 브라우저에서 실행되는 클라이언트 사이드 렌더링(CSR)을 담당합니다.
    • 기능: 사용자 인터페이스를 제공하고 사용자와의 상호작용을 처리합니다.
    • 장점: 빠른 인터페이스 반응 시간, 사용자 디바이스의 성능에 맞춘 렌더링 가능.
  2. Server Tier

    • 역할: Node.js 서버 기반으로 서버 사이드 렌더링(SSR)을 수행하고 AI SDK Core가 실행됩니다.
    • 기능: 서버 측에서 데이터를 처리하고 클라이언트에 전달할 준비를 합니다.
    • 장점: 데이터 보안이 뛰어나며, 클라이언트의 낮은 성능에서도 빠른 실행 결과를 제공합니다.
  3. AI Provider Tier

    • 역할: AI 벤더사가 운영하는 서버에서 AI 기능을 제공합니다.
    • 기능: AI 모델을 사용하여 데이터 분석, 처리 및 결과를 생성합니다.
    • 장점: 고성능 AI 모델 사용 가능, 최신 AI 기술 적용 가능.
  4. 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 모두에 적용될 수 있습니다.

graph LR subgraph A[Client Tier] A1[웹 브라우저] end subgraph B[Server Tier] B1[서버 액션 또는 라우트 핸들러] B2[웹 서버] end subgraph C[AI Provider Tier] C1[대규모 언어 모델] end subgraph D[3rd Party Service Tier] D1[실시간 날씨 정보 제공] end A --> B B --> C B --> D

이 아키텍처에서로 구성할 때 Core + UICore + RSC의 동작 방식의 공통점은 AI 기능 연동을 위해 Server TierAI Provider Tier가 연동되어 AI 기능을 수행합니다.

Core + RSC 방식에서는 서버 측에서 컴포넌트를 렌더링하여 클라이언트로 스트리밍합니다. 이는 서버에서 컴포넌트를 미리 렌더링한 후 클라이언트로 전송하는 방식입니다.

  • 장점:
    • 데이터 보안: 서버에서 렌더링되므로 데이터가 안전하게 유지됩니다.
    • 빠른 초기 로드: 서버에서 미리 렌더링된 결과를 전달하므로 클라이언트의 초기 로드 속도가 빠릅니다.
    • 스트리밍 지원: 채팅 시 생성되는 컴포넌트도 스트리밍 가능하여 사용자 경험 향상.
  • 단점:
    • 서버 부하: 서버에서 모든 렌더링을 처리하므로 서버의 런타임과 네트워크 부하가 증가합니다.
    • SEO 제한: 실시간으로 생성되는 UI는 SEO에 큰 영향을 미치지 않음.

이 아키텍처로 Core + UI 방식을 구현할 때는 3rd Party Service Tier에서 받은 데이터를 Client Tier에게 넘겨줘서 이 데이터에 대한 렌더링을 Server Tier에서 할수도 있고 Client Tier에서 할 수 있습니다.

두번째 아키텍처 방식

graph LR subgraph E[Client Tier] E1[웹 브라우저] end subgraph F[Server Tier] F1[라우트 핸들러] F2[웹 서버] end subgraph G[AI Provider Tier] G1[대규모 언어 모델] end subgraph H[3rd Party Service Tier] H1[실시간 날씨 정보 제공] end E --> F F --> G E --> H

이 아키텍처는 Core + UI 방식에서만 사용 가능하며 특징은 클라이언트 측에서 데이터를 받아서 렌더링됩니다. 이는 클라이언트 측에서 데이터를 받아와서 사용자에게 보여주는 방식입니다.

  • 장점:
    • 서버 부하 분산: 클라이언트에서 데이터를 처리하므로 서버의 부하가 줄어듭니다.
    • 유연성: 클라이언트에서 다양한 UI 컴포넌트를 쉽게 렌더링할 수 있습니다.
  • 단점:
    • 보안 문제: 데이터가 클라이언트로 직접 전달되므로 보안에 유의해야 합니다.
    • 클라이언트 성능 의존: 클라이언트 디바이스의 성능에 따라 렌더링 성능이 달라질 수 있습니다.

첫번째와 두번째의 최적의 아키텍처 선택

적합한 아키텍처 구성은 웹 애플리케이션의 목적과 요구 사항에 따라 달라집니다. 다음은 각 방법의 사용 시나리오입니다.

Core + RSC가 적합한 경우는 다음과 같습니다.

  • 데이터 보안이 중요한 경우: 민감한 데이터를 처리하는 애플리케이션
  • 빠른 초기 로드가 필요한 경우: 초기 로딩 속도가 중요한 애플리케이션
  • 스트리밍 지원이 필요한 경우: 실시간 스트리밍 기능이 중요한 애플리케이션

Core + UI가 적합한 경우은 다음과 같습니다.

  • 실시간 상호작용이 중요한 경우: 사용자와의 빠른 상호작용이 필요한 애플리케이션
  • 서버 부하 분산이 필요한 경우: 많은 사용자가 동시에 접속하여 서버 부하가 우려되는 경우
  • 유연한 UI 렌더링이 필요한 경우: 다양한 UI 컴포넌트를 클라이언트 측에서 자유롭게 렌더링해야 하는 경우

버셀 AI SDK 아키텍처는 다양한 계층 간의 상호작용을 통해 최상의 사용자 경험을 제공합니다. Core + UI와 Core + RSC 방식은 각각의 장점과 단점이 있으며 애플리케이션의 요구 사항에 따라 적절히 선택하여 사용할 수 있습니다. 웹 애플리케이션의 목적과 요구 사항을 명확히 이해하고 이에 따라 최적의 아키텍처를 구성하는 것이 중요합니다. 이를 통해 효율적이고 효과적인 웹 애플리케이션을 구축할 수 있습니다.