본문으로 건너뛰기

© 2026 Molayo

Dev.to헤드라인2026. 06. 08. 17:58

React 개발자에서 AI 엔지니어로: 실제로 무엇이 변하는가

요약

React 개발자가 AI 엔지니어로 전환하기 위한 실질적인 경로를 제시합니다. AI 개발의 핵심이 모델 학습이 아닌 API 호출과 데이터 처리에 있음을 강조하며, TypeScript 생태계의 강점을 활용한 접근법을 설명합니다.

핵심 포인트

  • AI 개발의 핵심은 모델 학습보다 API 호출 및 데이터 처리에 있음
  • TypeScript와 Zod를 활용한 LLM 구조화된 출력 검증의 이점
  • 컨텍스트 윈도우 관리와 토큰 단위 사고의 중요성

React 개발자에서 AI 엔지니어로: 실제로 무엇이 변하는가

몇 년 전, 제 매니저는 회사가 AI에 올인할 것이라고 발표했습니다. 모두가 고개를 끄덕였습니다. 회의가 끝난 후, 우리 중 몇 명은 복도에 모여 서로 눈빛을 교환했습니다. '누가 실제로 이걸 하게 될까?'

문제는 동기 부여가 아니었습니다. 문제는 어떻게 해야 할지 파악하기 위해 자리에 앉는 순간 마주하게 되는 벽이었습니다. AI 개발은 Python의 영역처럼 보였습니다. 우리의 기술 스택(Stack)은 TypeScript였습니다. 팀원 중 누구도 Python을 작성하지 않았고, Python을 쓰는 사람을 채용하는 것은 패배를 인정하는 것처럼 느껴졌습니다. 그래서 "AI 전환"은 반복적으로 제기되지만, 그만큼 반복적으로 보류되는 주제가 되었습니다.

저는 직접 파고들기 시작했습니다. 특별한 사명감 때문이 아니라, 제가 준비되었든 아니든 이 변화가 다가오고 있다는 느낌 때문이었습니다.

제가 발견한 것은 저를 놀라게 했습니다.

모든 것을 바꾼 통찰

많은 자료를 읽고 실험을 수행한 끝에, 저는 모든 것을 재구성하는 하나의 통찰에 도달했습니다.

대부분의 애플리케이션에서, AI 개발은 근본적으로 API를 호출하는 것에 관한 것입니다.

자신만의 모델을 학습(Training)시킨다고요? 그것은 대부분의 기업이 감당할 수 없는 범위를 넘어선 수백만 달러의 컴퓨팅(Compute) 비용이 듭니다. 오픈 소스(Open-source) 모델을 자체 호스팅(Self-hosting)하는 것? 가능은 하지만 운영 측면에서 복잡합니다. AI 제품을 구축하는 실질적인 경로는 OpenAI, Anthropic, 그리고 Google이 제공하는 API를 호출하는 것입니다. 그들은 자신들의 최고의 모델들을 토큰(Token) 단위로 과금되는 HTTP 엔드포인트(Endpoints)로 래핑(Wrapped)해 두었습니다.

그리고 HTTP 엔드포인트를 호출하고, JSON을 처리하며, 비동기 스트림(Async streams)을 다루는 것 — 이것은 프론트엔드(Frontend) 개발자들이 매일 하는 일과 정확히 일치합니다.

Python도 이를 할 수 있습니다. TypeScript도 할 수 있습니다. 이미 프론트엔드 생태계에 익숙한 사람에게 전환 비용(Switching cost)은 거의 제로에 가깝습니다.

그뿐만이 아닙니다. TypeScript는 AI 애플리케이션 개발에서 진정한 강점을 가집니다. LLM(대규모 언어 모델)의 구조화된 출력(Structured outputs)은 엄격한 검증(Validation)이 필요한데, Zod는 TypeScript와 완벽하게 결합됩니다. 프론트엔드와 백엔드 간에 타입을 공유하면 LLM 응답이 UI 렌더링을 구동해야 할 때 마찰을 제거할 수 있습니다. 이것은 임시방편이 아닙니다. 아주 적합한 조합입니다.

실제로 배워야 할 것들

프론트엔드에서 AI 엔지니어링으로의 전환은 다섯 가지 새로운 영역을 포함합니다. 각 영역에 대한 솔직한 견해는 다음과 같습니다.

1. LLM의 작동 방식 (생각보다 복잡하지 않음)

AI 애플리케이션을 구축하기 위해 트랜스포머 (Transformers)의 수학적 원리를 이해할 필요는 없습니다. 하지만 반드시 이해해야 할 사항은 다음과 같습니다.

컨텍스트 윈도우 (Context windows). 시스템 프롬프트 (System prompt), 대화 기록, 검색된 문서 등 LLM에 보내는 모든 정보는 고정된 크기의 컨텍스트 윈도우 내에서 공간을 차지하기 위해 경쟁합니다. 이 윈도우 안에 무엇을 담을지 관리하는 것이 AI 엔지니어링의 큰 부분입니다. 대화 기록을 적절히 자르지(truncate) 않는 채팅 애플리케이션은 결국 조용히 실패하게 될 것입니다.

문자가 아닌 토큰 (Tokens). LLM은 토큰 단위로 사고합니다. "TypeScript"는 1개의 토큰일 수 있지만, "supercalifragilistic"는 6개의 토큰일 수 있습니다. 가격 책정은 토큰당 이루어지며, 속도 제한 (Rate limits) 또한 토큰 기준이고, 컨텍스트 윈도우 역시 토큰 단위로 측정됩니다. 지속적으로 수학 계산을 하지 않더라도 토큰 수에 대한 직관이 필요합니다.

온도 (Temperature) 및 샘플링 (Sampling). 온도가 높을수록 더 창의적이지만 (동시에 덜 신뢰할 수 있는) 출력이 나옵니다. 온도가 낮을수록 더 결정론적 (Deterministic)입니다. 구조화된 출력 (JSON 응답, 양식 채우기 등)을 원한다면 온도를 0에 가깝게 설정해야 합니다. 창의적인 작업에는 온도를 높여야 합니다. 이것은 여러분이 끊임없이 조절하게 될 다이얼입니다.

2. 프롬프트 엔지니어링 (예술보다는 공학에 가까움)

프롬프트 엔지니어링 (Prompt engineering)은 모호하고 신비로운 무언가라는 나쁜 평판을 가지고 있습니다. 하지만 실제로는 엄격한 사양 (Specification)을 작성하는 것에 더 가깝습니다.

실제로 효과가 있는 방법들은 다음과 같습니다:

형식에 대해 명시적으로 말하기. JSON을 원한다면 그렇게 말하고 예시를 보여주세요. 불렛 리스트를 원한다면 그렇게 말하세요. LLM은 모호한 요청보다 형식 지정 지침을 훨씬 더 안정적으로 따릅니다.

XML 스타일의 구분자 사용하기. <context>, <user_input>, <instructions>와 같이 콘텐츠를 태그로 감싸면 LLM과 사용자 모두에게 모호함을 없애줍니다. 이는 또한 프롬프트 인젝션 (Prompt injection) 방어에도 도움이 됩니다.

Few-shot 예시가 긴 지시문보다 효과적입니다. LLM에게 원하는 바를 산문 형태로 설명하는 것보다 두세 개의 입출력 (input/output) 쌍 예시를 보여주는 것이 더 잘 작동합니다. 이는 직관에 어긋나 보일 수 있지만 일관된 결과가 나타납니다.

Zod로 구조화된 출력 (structured output)을 검증하세요. LLM이 특정 형태의 JSON을 반환해야 할 때, Zod 스키마 (schema)를 정의하고 이를 사용하여 응답을 검증하세요. 검증에 실패하면 에러 메시지와 함께 재시도(retry)를 수행합니다. 이 루프는 놀라울 정도로 신뢰할 수 있습니다.

import { z } from 'zod';

const ResponseSchema = z.object({
...

3. RAG (실제 제품을 위한 핵심 패턴)

벡터 검색 (Vector search)과 RAG (Retrieval-Augmented Generation, 검색 증강 생성)는 위협적으로 들릴 수 있지만, 핵심 패턴은 간단합니다:

  1. 문서가 수집(ingest)될 때, 이를 청크 (chunks)로 나누고 각 청크를 벡터 임베딩 (vector embedding, 고차원 숫자 배열)으로 변환합니다.
  2. 이러한 벡터들을 유사도 검색 (similarity search)을 지원하는 데이터베이스(PostgreSQL을 사용 중이라면 pgvector)에 저장합니다.
  3. 사용자가 질문을 하면, 질문을 벡터로 변환하고 가장 유사한 청크들을 찾습니다.
  4. 해당 청크들을 LLM의 컨텍스트 (context)에 주입하고, 이를 바탕으로 답변하도록 요청합니다.

이것이 바로 LLM에게 회사의 내부 문서, 제품 카탈로그, 또는 LLM이 학습될 당시에는 존재하지 않았던 기타 데이터에 대한 지식을 제공하는 방법입니다.

작동하는 RAG 데모와 실제 운영 환경의 RAG 시스템 사이의 간극은 주로 정밀도 (precision)에 관한 것입니다. 순수 벡터 검색은 고유 명사, 버전 번호, 모델 이름과 같은 정확한 용어에 대해 사각지대가 있습니다. 벡터 검색과 함께 BM25 키워드 검색을 추가하는 것 (하이브리드 검색, hybrid retrieval)이 이 문제의 대부분을 해결합니다. 그 위에 리랭커 (reranker)를 추가하면 정밀도를 더욱 향상시킬 수 있습니다.

TypeScript 개발자에게: pgvector는 이미 알고 있는 모든 PostgreSQL 클라이언트와 함께 작동합니다. 임베딩 (Embeddings)은 그저 배열일 뿐입니다. 이 스택의 "무서운" 부분들은 대부분 익숙한 인프라입니다.

4. 에이전트 (Agents, 흥미로워지는 지점)

에이전트 (Agent)란 함수 호출, 파일 읽기, 웹 검색 등의 행동을 취할 수 있고, 그 결과에 기반하여 다음에 무엇을 할지 추론할 수 있는 LLM을 의미합니다.

핵심 루프 (The core loop):

  1. LLM이 목표(goal)와 사용 가능한 도구(tools) 목록을 수신합니다.
  2. LLM이 어떤 도구를 어떤 인자(arguments)와 함께 호출할지 결정합니다.
  3. 도구가 실행되고, 그 결과가 다시 LLM으로 전달됩니다.
  4. LLM이 다음 단계(또 다른 도구 호출 또는 최종 답변)를 결정합니다.

이것을 ReAct 루프 (Reasoning + Acting, 추론 + 행동)라고 부릅니다. TypeScript 예시:

async function runAgent(goal: string, tools: Tool[]): Promise<string> {
  const messages: Message[] = [
    { role: 'system', content: buildSystemPrompt(tools) },
...

에이전트 개발의 어려운 점은 코드가 아닙니다. 신뢰성 (에이전트가 명확하지 않은 방식으로 실패함), 우아한 에러 처리 (도구가 실패하거나 LLM이 잘못된 결정을 내림), 그리고 언제 멈춰야 할지를 아는 것 (무한 루프는 실제적인 문제입니다)입니다. 이것들은 AI 연구 문제가 아니라 엔지니어링 문제입니다.

5. 프로덕션 격차 (The Production Gap)

작동하는 데모와 실제 프로덕션 AI 애플리케이션 사이의 격차는 주로 다음 네 가지 요소에서 발생합니다:

관찰 가능성 (Observability). 프롬프트(prompt)는 무엇이었나? 출력(output)은 무엇이었나? 토큰(token)은 얼마나 사용되었나? 모든 LLM 호출에 대해 이를 기록해야 합니다. 전통적인 애플리케이션 모니터링 도구는 LLM을 위해 설계되지 않았습니다. LangFuse와 같이 목적에 맞게 제작된 도구를 사용하세요.

비용 제어 (Cost control). LLM은 토큰 단위로 과금됩니다. 여러 차례 대화가 오가는 에이전트 세션은 수만 개의 토큰을 소비할 수 있습니다. 속도 제한(rate limiting)과 할당량(quotas)이 없다면, 단 한 명의 사용자가 월간 예산을 모두 소진할 수 있습니다.

보안 (Security). 사용자 입력이 프롬프트에 직접 들어갑니다. 프롬프트 인젝션 (Prompt injection)은 실제 존재하는 공격 유형입니다. 입력 검증(input validation), 구조화된 프롬프트 설계, 그리고 출력 검증(output validation)이 필요합니다.

스트리밍 (Streaming). 사용자들은 출력이 생성되는 대로 확인하기를 기대합니다. 완전한 응답을 위해 10초를 기다리는 것은 응답이 정확하더라도 서비스가 고장 난 것처럼 느껴집니다. HTTP 기반의 SSE (Server-Sent Events)가 자연스러운 선택입니다. 이는 서버에서 클라이언트로 푸시를 보낼 때 사용하는 것과 동일한 패턴입니다.

사고 모델의 전환 (The Mental Model Shift)

가장 큰 변화는 기술적인 것이 아닙니다. LLM이 비결정론적 (non-deterministic)이라는 사실을 받아들이는 것입니다.

일반적인 소프트웨어에서는 동일한 입력값을 가진 함수가 항상 동일한 출력값을 생성합니다. LLM은 그렇게 작동하지 않습니다. 동일한 프롬프트(prompt)라도 호출할 때마다 다른 응답을 생성할 수 있습니다. 때로는 그 응답이 틀릴 수도 있고, 때로는 아주 자신만만하게 틀린 답을 내놓기도 합니다.

이러한 특성은 테스트 방식과 설계 방식을 변화시킵니다. 정확한 출력값을 단언(assert)하는 단위 테스트(unit test)를 작성할 수 없습니다. 대신 속성(properties)을 테스트해야 합니다. 응답에 필요한 필드가 포함되어 있는가? 예상된 길이 내에 있는가? 유효성 검사 스키마(validation schema)를 통과하는가? 여러분은 재시도 로직(retry logic)을 구축하고, 우아한 성능 저하(graceful degradation)를 설계해야 합니다.

코드가 작동하거나 작동하지 않거나 둘 중 하나였던 커리어를 보내온 사람에게, 이는 처음에는 진심으로 불편한 경험입니다. LLM의 응답을 결정론적 함수(deterministic functions)로 취급하는 것을 멈추고, 똑똑하지만 신뢰할 수 없는 서비스에 대한 네트워크 호출(network calls)처럼 취급하기 시작하면 훨씬 쉬워집니다. 네트워크 요청이 예상치 못한 콘텐츠를 반환한다고 해서 프로그램이 충돌하는 코드를 작성하지는 않을 테니까요.

변하지 않은 것들

여러분이 알고 있는 도구들은 여전히 유효합니다. TypeScript의 타입 시스템(type system), Node.js의 비동기 모델(async model), PostgreSQL, Docker, REST API, CI/CD 파이프라인까지 모두 마찬가지입니다.

여러분이 알고 있는 패턴들도 여전히 적용됩니다. 입력 유효성 검사(Input validation), 에러 핸들링(Error handling), 속도 제한(Rate limiting), 캐싱(Caching), 로깅(Logging) 등이 그것입니다.

AI 개발은 고유한 특성과 실패 모드(failure modes)를 가진 새로운 범주의 컴포넌트인 LLM을 추가할 뿐입니다. 하지만 이를 둘러싼 인프라(infrastructure)는 여러분이 수년간 구축해 온 것과 동일한 인프라입니다.

우리 팀을 가로막았던 Python이라는 장벽은 실재하지 않았습니다. 우리에게는 필요한 모든 것이 있었습니다.

이 기사는 프론트엔드 및 풀스택 개발자를 위해 TypeScript로 AI 에이전트, RAG 시스템, MCP 서버를 구축하는 실무 가이드인 From Frontend to AI Engineering의 서문과 도입부를 각색하였습니다.

AI 자동 생성 콘텐츠

본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0