Mastra를 사용하여 TypeScript로 프로덕션 AI 에이전트 구축하기: 2026년 단계별 가이드
요약
TypeScript 기반의 AI 에이전트 프레임워크인 Mastra를 사용하여 프로덕션급 에이전트를 구축하는 방법을 소개합니다. 복잡한 오케스트레이션 로직을 줄여 개발 생산성을 높이는 방법과 프로젝트 설정 과정을 단계별로 안내합니다.
핵심 포인트
- Mastra는 TypeScript 우선 프레임워크로 개발자 친화적인 문법을 제공합니다.
- 도구 호출 루프, 이력 관리 등 복잡한 로직을 코드 양을 획기적으로 줄여 해결합니다.
- 40개 이상의 모델 제공자를 지원하는 강력한 모델 라우터를 갖추고 있습니다.
- 필요 시 Vercel AI SDK를 직접 호출하여 세밀한 제어가 가능합니다.
Mastra를 사용하여 TypeScript로 프로덕션 AI 에이전트 구축하기: 2026년 단계별 가이드.
지난달 저는 Anthropic SDK를 직접 사용하여 순수 TypeScript로 AI 에이전트를 연결하는 데 오후 시간을 보냈습니다. 코드는 작동했지만, 도구 디스패치 루프(tool dispatch loop), 대화 기록 배열(conversation history array), 재시도 로직(retry logic) 등 모든 부분을 제가 직접 구현해야 했습니다. 에이전트가 흥미로운 작업을 수행하기 전까지 약 400줄의 코드가 필요했습니다.
Mastra는 이를 약 60줄로 줄여줍니다. 24k개 이상의 GitHub stars를 보유하고, 활발한 릴리스 주기(2026년 5월 기준 88회 릴리스)를 가지며, 하나의 API를 통해 40개 이상의 제공업체와 통신하는 모델 라우터(model router)를 갖춘 TypeScript 우선(TypeScript-first) 에이전트 프레임워크입니다. 이 튜토리얼은 커스텀 도구와 지속성 메모리(persistent memory)를 갖춘 실행 가능한 에이전트를 만드는 제로 베이스 단계부터 시작합니다. 이 기사의 모든 코드는 실제로 작동합니다.
요약 (TL;DR)
| 단계 | 구축 내용 | 소요 시간 |
|---|---|---|
| 설치 | Mastra가 연결된 스캐폴딩된 프로젝트 | 5분 |
| ... |
1. 스택에서 Mastra의 위치
순수 SDK 호출은 완전한 제어권을 제공하지만, 도구 호출 루프(tool call loop), 이력 관리(history management), 에러 처리(error handling), 재시도(retries)와 같은 오케스트레이션 레이어(orchestration layer)를 직접 작성해야 합니다. LangChain이나 LlamaIndex와 같은 프레임워크가 이를 해결해주지만, Python 우선(Python-first) 성향이 강하며 TypeScript 포팅 버전은 Python 버전에 비해 뒤처지는 경향이 있습니다.
Mastra는 TypeScript에서 시작합니다. 기본 요소(primitives)들이 클래스(classes), Zod 스키마(Zod schemas), 비동기 함수(async functions)와 같이 TypeScript 개발자들이 이미 알고 있는 것들과 직접적으로 매핑됩니다. 프레임워크 자체가 TypeScript 버전이기 때문에 포팅 지연(port-lag)이 존재하지 않습니다.
트레이드오프(trade-off)는 다른 모든 프레임워크와 마찬가지입니다. 제어권을 속도와 맞바꾸는 것입니다. 프로토타입과 대부분의 프로덕션 에이전트의 경우, 이 거래는 가치가 있습니다. 프레임워크의 도구 디스패치나 메모리 동작이 정확한 요구 사항과 일치하지 않는 경우, 언제든지 레이어를 하나 낮추어 Mastra가 내부적으로 래핑(wrap)하고 있는 Vercel AI SDK를 직접 호출할 수 있습니다.
2. 프로젝트 설정
Mastra의 스캐폴더(scaffolder)는 필요한 모든 것을 생성합니다:
npm create mastra@latest
위저드(wizard)는 프로젝트 이름, 모델 제공자(model provider), 그리고 스타터 예제 파일(starter example files) 포함 여부를 묻습니다. 제공자(OpenAI, Anthropic, Google 또는 지원되는 40개 이상의 제공자 중 하나)를 선택하세요. 이 튜토리얼에서는 Anthropic을 사용하겠습니다.
위저드가 완료된 후:
cd my-agent
npm install
.env 파일을 열고 키를 추가하세요:
ANTHROPIC_API_KEY=sk-ant-...
생성된 프로젝트 구조는 다음과 같습니다:
src/
mastra/
index.ts # Mastra 인스턴스
...
스타터 파일(starter files)의 이름을 바꾸거나 교체할 수 있습니다. 루트 엔트리 포인트(root entry point)인 src/mastra/index.ts는 Mastra 런타임(runtime)에 에이전트(agents)와 도구(tools)를 등록합니다:
// src/mastra/index.ts
import { Mastra } from "@mastra/core";
import { supportAgent } from "./agents/support-agent";
...
이것이 전체 설정입니다. YAML도, 설정 파일(config files)도, 암기해야 할 팩토리 함수(factory functions)도 없습니다.
3. 첫 번째 에이전트 정의하기
Mastra에서 에이전트(agent)는 Agent 클래스의 인스턴스입니다. 에이전트에 id, name, model, 그리고 instructions를 부여합니다. instructions는 시스템 프롬프트(system prompt) 역할을 합니다.
// src/mastra/agents/support-agent.ts
import { Agent } from "@mastra/core/agent";
...
model 필드는 Mastra의 라우터(router) 형식인 provider/model-id를 사용합니다. 이는 Anthropic에서 OpenAI로 전환하는 것이 단 한 줄의 변경만으로 가능하다는 것을 의미합니다. 모델 ID를 별칭(alias)이 아닌 날짜가 포함된 버전으로 고정하여, 모델이 업그레이드될 때의 시점을 직접 제어할 수 있도록 하세요.
애플리케이션 코드에서 에이전트를 호출하려면:
import { mastra } from "./mastra";
const agent = mastra.getAgentById("support-agent");
...
generate는 모델 작업이 완료된 후 전체 응답을 반환합니다. 채팅 UI를 위한 스트리밍(streaming)이 필요한 경우 stream으로 교체하세요:
const stream = await agent.stream("온보딩 흐름은 어떻게 되나요?");
for await (const chunk of stream.textStream) {
process.stdout.write(chunk);
...
두 메서드 모두 { text, toolCalls, toolResults, usage }를 반환합니다. usage 객체는 호출당 토큰 수(token counts)를 제공하며, 프로덕션(production) 환경에서는 이를 로그로 남겨야 합니다.
4. 커스텀 도구 추가하기
도구(Tools)는 에이전트가 텍스트 생성 이상의 행동을 취할 수 있게 하는 수단입니다. 도구는 id, 모델이 언제 호출할지 결정하는 데 사용하는 description (설명), Zod에 의해 검증되는 inputSchema (입력 스키마), 그리고 execute (실행) 함수를 가집니다.
다음은 가상의 데이터베이스에서 ID로 계정을 조회하는 도구의 예시입니다:
// src/mastra/tools/account-lookup.ts
import { createTool } from "@mastra/core/tools";
import { z } from "zod";
...
tools 배열에 추가하여 에이전트에 도구를 연결합니다:
// src/mastra/agents/support-agent.ts
import { Agent } from "@mastra/core/agent";
import { accountLookupTool } from "../tools/account-lookup";
...
이제 모델은 컨텍스트(context) 내에서 해당 도구를 인식합니다. 사용자가 "제 계정 ACC-00000001의 플랜이 잘못 표시되고 있어요"라고 말하면, 에이전트는 account-lookup을 호출하여 계정 기록을 가져온 뒤, 응답하기 전에 이를 추론(reasoning) 과정에 포함합니다. 도구 호출은 response.toolCalls에서, 결과는 response.toolResults에서 확인할 수 있습니다.
Zod 스키마는 두 가지 역할을 수행합니다. 첫째, 모델에게 도구가 무엇을 기대하는지 알려줍니다 (설명과 필드 이름이 모델의 도구 명세(tool spec)에 나타납니다). 둘째, execute 함수가 실행되기 전에 모델의 출력을 검증합니다. 만약 모델이 잘못된 형식의 accountId를 보내면, Mastra는 코드가 실행되기 전에 해당 호출을 거부합니다.
5. 메모리 추가하기
메모리(memory)가 없다면, agent.generate를 호출할 때마다 매번 백지 상태에서 시작하게 됩니다. 에이전트는 사용자가 두 메시지 전에 무엇을 말했는지 알지 못합니다. 고객 지원 에이전트(support agent)의 경우, 이는 멀티턴 대화(multi-turn conversations)를 즉시 불가능하게 만듭니다.
Mastra의 @mastra/memory 패키지는 세 가지 계층을 추가합니다: 메시지 히스토리 (최근 N회의 대화), 워킹 메모리 (대화 사이에 추출되어 저장된 주요 사실), 그리고 시맨틱 리콜 (semantic recall, 과거 대화에 대한 벡터 검색). 대부분의 에이전트에게는 메시지 히스토리만으로도 충분합니다.
패키지와 스토리지 백엔드(storage backend)를 설치합니다:
npm install @mastra/memory @mastra/libsql
에이전트에 메모리를 연결합니다:
// src/mastra/agents/support-agent.ts
import { Agent } from "@mastra/core/agent";
import { Memory } from "@mastra/memory";
...
에이전트를 호출할 때 resource와 thread를 전달합니다. resource는 사용자를 식별하며, thread는 특정 대화를 격리합니다:
const response = await agent.generate(
"What plan am I on?",
{
...
첫 번째 턴에서 에이전트는 히스토리(history)가 없습니다. 두 번째 턴에서는 해당 resource와 thread로부터 마지막 20개의 메시지를 가져옵니다. 사용자가 "아까 했던 말에 이어서 말하자면"이라고 말하면, 에이전트는 '아까'가 무엇을 의미하는지 알 수 있습니다.
LibSQL은 개발 시 로컬 SQLite 파일에 기록합니다. 프로덕션(production) 환경에서는 DATABASE_URL을 Turso 연결 문자열로 지정하기만 하면, 동일한 코드가 다른 변경 없이 분산 SQLite 데이터베이스에 기록됩니다.
6. 로컬 실행 및 배포
개발 서버:
npx mastra dev
이 명령은 에이전트들에 대한 REST API와 4111 포트에서 브라우저 기반의 스튜디오(studio)를 포함하는 로컬 서버를 시작합니다. 스튜디오에서는 에이전트에 메시지를 보내고, 도구 호출(tool calls)을 검사하며, 메모리 상태(memory state)를 읽을 수 있습니다. 이 스튜디오는 매우 유용해서 저는 UI가 없는 에이전트 작업을 할 때도 사용합니다.
프로덕션을 위해서는 두 가지 옵션이 있습니다.
첫 번째는 Mastra 클라우드 배포(cloud deploy)로, 에이전트를 관리형 서비스(managed service)로 패키징합니다:
npx mastra deploy
두 번째는 셀프 호스팅(self-hosting)입니다. @mastra/express를 추가하고 기존 Express 앱에 Mastra 서버를 마운트(mount)하세요:
npm install @mastra/express
// src/index.ts
import express from "express";
import { MastraServer } from "@mastra/express";
...
MastraServer.init()은 /api 하위에 에이전트 엔드포인트(endpoints)를 등록합니다. 추가적인 라우팅(routing) 코드 없이도 에이전트를 HTTP를 통해 호출할 수 있게 됩니다. 이를 Railway, Fly.io 또는 Dockerfile을 지원하는 모든 Node.js 호스트에 배포하세요.
결론
Mastra는 모든 TypeScript 에이전트 프로젝트의 초기 300줄을 차지하는 오케스트레이션 (orchestration) 스캐폴딩 (scaffolding)을 제거합니다. 로우 SDK (raw SDK) 호출을 통해 도구 디스패치 (tool dispatch) 및 대화 기록 관리 (conversation history management)에 소비했던 3시간이 Mastra를 사용하면 약 15분으로 단축됩니다.
이 프레임워크는 에이전트가 단순히 프로토타입을 만드는 곳이 아니라, 실제로 프로덕션 (production) 환경에 배포되는 언어로서 TypeScript에 베팅하고 있습니다. 이러한 베팅은 제가 프로덕션 코드베이스에서 목격하는 현상을 반영합니다. Python은 여전히 학습 (training)과 연구 (research) 분야를 지배하고 있습니다. TypeScript는 에이전트가 연결되는 웹 서비스 (web services)를 지배합니다.
위에서 설명한 스택에 제가 추가하고 싶은 주요 사항은 다음과 같습니다: 모든 생성 (generate) 호출 시 response.usage를 로그로 남겨서, 프로덕션 환경에서 에이전트가 세션당 실제로 얼마의 비용을 발생시키는지 확인할 수 있도록 하세요. 이 수치는 첫 주에 대부분의 팀을 놀라게 할 것입니다.
현재 여러분의 에이전트 스택은 어떤 모습인가요? 로우 SDK (raw SDK), 프레임워크, 아니면 자체 개발한 무언가인가요? 어떤 부분에서 병목 현상 (pressure points)이 발생하는지 궁금합니다.
GDS K S · thegdsks.com · X에서 팔로우 @thegdsks
오케스트레이션 레이어 (orchestration layer)는 두 번쯤 다시 작성해 보기 전까지는 아무도 이야기하지 않는 부분입니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기