Mastra — TypeScript-фреймворк для создания AI-агентов

от автора

в
Время чтения: 3 мин.

Еще недавно интеграция LLM в веб-приложение обычно выглядела довольно просто: отправляем запрос в API модели, получаем текст и показываем его пользователю.

Но как только хочется сделать не просто чат, а полноценного AI-агента, быстро появляются дополнительные задачи: вызов функций приложения, хранение истории, работа с файлами, выполнение последовательности действий, RAG, MCP, стриминг, несколько агентов и наблюдаемость.

Все это можно собирать самостоятельно. Но для TypeScript уже существует фреймворк, который объединяет эти задачи в одну систему — Mastra.

Официальный сайт: mastra.ai
Исходный код: GitHub — mastra-ai/mastra

Что такое Mastra

Mastra — open-source TypeScript-фреймворк для разработки приложений на базе LLM и AI-агентов.

Если проводить аналогию с обычной веб-разработкой, вызов API языковой модели — это примерно fetch(). Он решает одну конкретную задачу, но вокруг реального приложения все равно приходится строить инфраструктуру.

Mastra предлагает более высокий уровень абстракции:

LLM
 ↓
Agent
 ├── Instructions
 ├── Tools
 ├── Memory
 ├── Workflows
 ├── RAG
 └── MCP

При этом Mastra не является отдельной языковой моделью. Она работает поверх существующих моделей и позволяет подключать разных провайдеров через единый интерфейс.

По сути, это backend-фреймворк для той части приложения, где решения принимает LLM.

Agent

Центральная сущность Mastra — Agent.

Простейший агент выглядит примерно так:

import { Agent } from '@mastra/core/agent'

export const assistant = new Agent({
    id: 'assistant',
    name: 'Assistant',

    instructions: `
        Ты помощник пользователя.
        Отвечай коротко и по существу.
    `,

    model: 'openai/gpt-5.5',
})

Сам по себе такой агент пока мало отличается от обычного обращения к LLM.

Интереснее становится, когда мы начинаем давать ему инструменты.

В Mastra агент предназначен именно для открытых задач, где заранее неизвестна точная последовательность действий: модель сама решает, какие инструменты вызвать, сколько действий выполнить и когда закончить работу.

Tools

Допустим, у нас есть административная панель интернет-магазина.

Пользователь пишет:

Покажи последние пять заказов.

Языковая модель сама по себе не имеет доступа к нашей базе данных. Поэтому ей необходимо предоставить инструмент.

Упрощенно это может выглядеть так:

const getOrders = createTool({
    id: 'get-orders',

    description: 'Получить список заказов',

    inputSchema: z.object({
        limit: z.number().default(5),
    }),

    execute: async ({ limit }) => {
        return orderService.findLatest(limit)
    },
})

После этого инструмент подключается к агенту:

export const assistant = new Agent({
    id: 'assistant',
    name: 'Assistant',

    instructions: `
        Ты помощник администратора интернет-магазина.
    `,

    model: 'openai/gpt-5.5',

    tools: {
        getOrders,
    },
})

Теперь пользователь может написать:

Какие были последние заказы?

Модель понимает, что для ответа нужны данные, вызывает getOrders, получает результат и формирует ответ.

Схема получается такой:

Пользователь
     ↓
   Agent
     ↓
    LLM
     ↓
нужны данные
     ↓
   Tool
     ↓
наш backend
     ↓
результат
     ↓
    LLM
     ↓
Пользователь

Именно tools превращают обычный чат с моделью в интерфейс управления приложением.

Агент не должен заменять бизнес-логику

Здесь есть важный архитектурный момент.

Не стоит помещать бизнес-логику непосредственно внутрь tools.

Плохой вариант:

execute: async ({ campaignId }) => {
    // 200 строк работы с БД
}

Лучше оставить tool тонким:

execute: async ({ campaignId }) => {
    return campaignService.getStatistics(campaignId)
}

Тогда структура приложения остается привычной:

Mastra Agent
     ↓
    Tool
     ↓
Application Service
     ↓
Repository / API / Database

Mastra в такой архитектуре становится еще одним транспортным слоем приложения.

REST-контроллер вызывает сервис по HTTP-запросу.

CLI-команда вызывает тот же сервис из консоли.

А Mastra Tool позволяет вызвать его по решению языковой модели.

Это довольно удобное разделение ответственности.

Workflows

Не каждую задачу стоит отдавать агенту.

Представим процесс:

создать кампанию
      ↓
проверить бюджет
      ↓
создать размещения
      ↓
подключить площадки
      ↓
запустить кампанию

Можно дать модели пять tools и попросить самостоятельно выполнить их в правильном порядке.

Но если порядок известен заранее, надежнее описать его явно.

Для этого в Mastra существуют workflows.

Например:

const workflow = createWorkflow({
    id: 'campaign-create',
    inputSchema,
})
    .then(validateCampaign)
    .then(createCampaign)
    .then(createPlacements)
    .then(connectPublishers)
    .commit()

Получается полезное разделение:

Agent

подходит для задачи:

"Разберись, почему кампания плохо откручивается"

А:

Workflow

лучше использовать для:

"Создай кампанию по стандартному процессу"

То есть Agent выбирает путь, а Workflow описывает известный путь. Сама документация Mastra рекомендует workflows для заранее определенных многошаговых процессов.

Memory

Для нормального чата одного массива messages довольно быстро становится недостаточно.

Например:

— Покажи кампании за сегодня.
— Только активные.
— А теперь сравни их со вчерашним днем.

Последние две команды невозможно нормально интерпретировать без предыдущего контекста.

Mastra предоставляет отдельный механизм памяти. В актуальном API доступны, в частности, хранение последних сообщений, semantic recall и observational memory.

Концептуально это выглядит так:

User
 ↓
Thread
 ↓
Memory
 ↓
Agent

То есть состояние диалога становится частью инфраструктуры агента, а не набором самостоятельно написанных костылей вокруг API модели.

RAG

Еще одна типичная задача — дать агенту доступ к большому объему информации.

Например:

документация
статьи
инструкции
FAQ
описания товаров
внутренние регламенты

Засовывать все это в system prompt невозможно и не нужно.

Используется RAG:

Документы
    ↓
 chunking
    ↓
 embeddings
    ↓
vector storage
    ↓

Запрос пользователя
    ↓
semantic search
    ↓
релевантные фрагменты
    ↓
LLM

Mastra предоставляет инструменты для построения такой схемы, поэтому RAG не приходится полностью собирать отдельно от агента.

MCP

Особенно интересно наличие поддержки Model Context Protocol.

MCP позволяет стандартизировать взаимодействие AI-приложений с внешними инструментами и источниками данных.

Вместо жесткой связи:

Agent → конкретный API

можно получить:

Agent
  ↓
 MCP
  ↓
External tools

Причем Mastra умеет не только использовать MCP-инструменты, но и создавать MCP-серверы, через которые можно публиковать собственные tools и другие возможности приложения.

Это интересно для систем, где один набор инструментов должен использоваться разными AI-клиентами.

Например:

                ┌─ Web chat
                │
Backend ─ MCP ──┼─ IDE
                │
                ├─ Telegram bot
                │
                └─ другой агент

Несколько агентов

Необязательно делать одного огромного агента с сотней инструментов.

Систему можно разделить по специализациям:

Supervisor
   │
   ├── Analytics Agent
   │      ├── statistics
   │      └── reports
   │
   ├── Campaign Agent
   │      ├── campaigns
   │      └── placements
   │
   └── Support Agent
          ├── documentation
          └── knowledge base

Пользователь при этом по-прежнему может видеть один чат.

Разделение агентов остается внутренней архитектурой приложения.

В актуальной Mastra для таких сценариев есть supervisor agents и механизмы координации агентов.

Как это использовать с Vue

Mastra не требует писать frontend на React.

Например, приложение может выглядеть совершенно обычно:

Vue / Nuxt
     ↓
HTTP / Stream
     ↓
Mastra
     ↓
Agent
     ↓
Tools
     ↓
Backend services

То есть Vue остается интерфейсом:

const response = await fetch('/api/chat', {
    method: 'POST',

    body: JSON.stringify({
        message: text.value,
    }),
})

А вся агентная логика работает на сервере.

Это особенно удобно, если основной стек уже TypeScript:

Vue
  +
Node.js
  +
Mastra

Не приходится заводить отдельный Python-сервис только ради AI-части приложения.

Отдельный сервис или часть существующего backend

Оба варианта возможны.

Для небольшого приложения Mastra можно держать рядом с остальным backend:

src/
├── modules/
├── services/
├── repositories/
└── mastra/
    ├── agents/
    ├── tools/
    └── workflows/

В более крупной системе мне больше нравится отдельный слой:

Vue
 ↓
Application API
 ↓
Mastra
 ↓
Internal API / MCP
 ↓
основной backend

В этом случае агент вообще не знает, как устроена база данных.

Он работает только с публичными возможностями системы:

getCampaignStatistics
createPlacement
findPublisher
generateReport

Такую архитектуру проще контролировать и безопаснее развивать.

Что с production

Агентное приложение сложно отлаживать обычным console.log.

Нужно понимать:

какой prompt получил агент;
какую модель вызвал;
какой tool выбрал;
с какими аргументами;
сколько занял запрос;
где произошла ошибка;
каким получился результат.

Поэтому в Mastra есть observability, traces, metrics, logs, evals и scorers.

Это важная часть фреймворка: AI-приложение рассматривается не как один вызов API, а как система, поведение которой необходимо наблюдать и тестировать.

Быстрый старт

Создать проект можно через CLI:

npm create mastra@latest

После установки получается обычный TypeScript-проект, который можно запускать локально и постепенно добавлять agents, tools и workflows. Именно этот способ сейчас рекомендует сам проект.

Когда Mastra действительно полезна

Mastra имеет смысл, когда приложение выходит за пределы простого:

llm.generate(prompt)

Например, если нужен:

  • чат с историей;
  • вызов backend-функций;
  • агент, самостоятельно выбирающий действия;
  • стриминг ответа;
  • RAG;
  • MCP;
  • workflows;
  • несколько специализированных агентов;
  • наблюдаемость и тестирование поведения AI.

Для одного запроса к модели подключение полноценного фреймворка будет избыточным.

Но если AI становится отдельным интерфейсом к приложению, количество собственной инфраструктуры начинает быстро расти. Именно эту инфраструктуру Mastra и пытается стандартизировать.

Итог

Мне нравится смотреть на Mastra не как на очередную библиотеку для вызова LLM, а как на application framework для AI-части backend.

Обычное приложение уже имеет:

HTTP → Controller → Service → Database

С появлением AI добавляется еще один путь:

Chat → Agent → Tool → Service → Database

А поверх него постепенно возникают memory, workflows, RAG, MCP, tracing и evals.

Можно написать все это самостоятельно. Иногда это действительно будет лучшим решением.

Но если нужен полноценный агент внутри TypeScript-приложения, Mastra дает достаточно интересный набор готовых архитектурных примитивов и при этом не заставляет менять привычный Node.js/TypeScript-стек.

Именно поэтому на Mastra стоит смотреть не как на «обертку над ChatGPT», а как на инфраструктуру для нового типа интерфейса приложения — интерфейса, в котором пользователь формулирует цель, а система сама решает, какие доступные ей действия необходимо выполнить.


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Сколько будет 10 + 5?