Как создать свой первый MCP-сервер с Novita AI

Как создать свой первый MCP-сервер с Novita AI

Протокол контекста модели (MCP) быстро становится одной из самых обсуждаемых концепций в мире ИИ. Несмотря на свою относительную новизну, он уже привлёк внимание разработчиков и крупных технологических компаний.

Созданный компанией Anthropic, MCP — это открытый стандартный протокол, аналогичный другим протоколам, таким как HTTP. Однако, если HTTP предназначен для подключения пользователей к ресурсам через сервер и веб-браузер (или HTTP-клиент), то MCP предназначен для подключения больших языковых моделей (LLM) к внешним инструментам и данным.

Предположим, у вас есть чат-бот, и вы хотите, чтобы он мог получать доступ к GitHub. Вы хотите, чтобы пользователи могли через чат-бота создавать задачи (issues), закрывать их, добавлять комментарии или просматривать существующие pull request’ы. Чтобы чат-бот мог выполнять все эти действия, ему потребуется доступ к инструментам.

Здесь на помощь приходит MCP-сервер.

MCP-сервер размещает несколько инструментов, которые чат-бот может вызывать с помощью своей внутренней LLM, чтобы получить доступ к этим возможностям. В случае с GitHub мы можем использовать официальный MCP-сервер GitHub для выполнения всех вышеупомянутых задач.

В этой статье мы создадим MCP-сервер с использованием Novita API. С помощью этого MCP-сервера любое приложение, поддерживающее протокол MCP, сможет получить доступ ко всем LLM, доступным на Novita, генерировать изображения, создавать видео и выполнять синтез речи.

Понимание архитектуры MCP

Архитектура MCP

Архитектура MCP [источник]

Архитектура MCP похожа на типичную клиент-серверную модель. Она включает четыре важных компонента:

  • MCP-клиент
  • MCP-сервер
  • MCP-транспорт
  • MCP-хост

MCP-клиент

MCP-клиент служит коммуникационным шлюзом между AI-приложением и MCP-сервером. После установки соединения приложение получает доступ ко всем инструментам и ресурсам, которыми владеет сервер.

MCP-сервер

MCP-сервер содержит все инструменты и данные, которые клиент может предоставить AI-приложению. Он включает:

  • Инструменты (Tools)
  • Ресурсы (Resources)
  • Промпты (Prompts)

Инструменты

Инструменты предоставляют LLM внешние возможности, которых у них обычно нет, например, возможность узнавать время, обновлять и читать данные из базы данных, получать информацию о погоде и многое другое. По сути, это определённые программистом функции, которые можно вызывать.

MCP-сервер может содержать несколько инструментов. Эти инструменты позволяют LLM действовать как агент благодаря возможности выполнять различные действия.

Инструменты управляются агентом и могут предусматривать необязательный контроль со стороны человека во время использования. Они похожи на POST-запросы в протоколе HTTP, поскольку приводят к побочным эффектам.

Ресурсы

Ресурсы — это предназначенные только для чтения фрагменты информации, которые предоставляют данные AI-приложению. Они аналогичны HTTP GET-запросам, так как не должны вызывать побочных эффектов. Ресурсы предназначены для управления приложением, которое решает, как пользователи или агент будут с ними взаимодействовать. Примерами ресурсов могут служить содержимое файлов, ответы API и записи из баз данных.

Промпты

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

Все это составляет MCP-сервер. В этой статье мы реализуем только инструменты, так как они являются наиболее широко используемой частью MCP-сервера.

MCP-транспорт

MCP-транспорт — это способ взаимодействия MCP-клиента с MCP-сервером. Взаимодействие может происходить локально (когда и клиент, и сервер работают на одной машине) или удалённо (когда они находятся на разных устройствах). В настоящее время MCP поддерживает два основных механизма транспорта:

  • STDIO: В этом режиме MCP-сервер и клиент работают на одной машине и общаются через стандартный ввод и вывод.
  • SSE: В этом режиме MCP-сервер работает поверх HTTP. HTTP POST используется для отправки сообщений на сервер, а Server-Sent Events — для отправки сообщений с сервера клиенту.
  • Streamable HTTP: Этот режим также использует HTTP, но полагается на HTTP GET и POST запросы. Он переключается на SSE только тогда, когда необходимо передать несколько сообщений от сервера клиенту в потоковом режиме.

Стандартный ввод/вывод

MCP-транспорт с использованием STDIO

MCP-транспорт с использованием STDIO [источник]

Подпись: MCP-транспорт с использованием STDIO [источник]

MCP-клиент и сервер могут взаимодействовать через стандартный ввод и вывод (STDIO). При использовании STDIO и клиент, и сервер работают на одной машине. Клиент записывает все запросы в stdin, а сервер записывает ответы в stdout.

Streamable HTTP

MCP-транспорт с использованием Streamable HTTP

MCP-транспорт с использованием Streamable HTTP [источник]

Streamable HTTP позволяет MCP-клиенту и серверу взаимодействовать по HTTP. Он использует метод HTTP POST для отправки запросов от клиента и получения ответов от сервера. При необходимости он может опционально переключиться на Server-Sent Events (SSE) для потоковой передачи сообщений с сервера клиенту.

Streamable HTTP хорошо подходит для удаленного взаимодействия между клиентом и сервером и является заменой устаревшего MCP-транспорта SSE.

MCP-хост

Отличие MCP от типичной клиент-серверной архитектуры заключается в роли хоста. Спецификация MCP определяет её как архитектуру клиент-хост-сервер. Это связано с тем, что клиент и хост составляют фронтальную часть архитектуры. MCP-хост состоит из двух важных компонентов:

  • MCP-клиент(ы)
  • Большая языковая модель

Задача MCP-клиента — получать с сервера инструменты, ресурсы и промпты, необходимые LLM. После того как ресурсы собраны, они помещаются в контекст модели. Один MCP-хост может иметь несколько клиентов, каждый из которых подключен к своему собственному MCP-серверу.

MCP-хост также можно рассматривать как приложение, с которым работает пользователь, и которое может выполнять другие функции. Например, Claude Desktop — это MCP-хост, функционирующий как чат-бот; Cursor — это MCP-хост, который также служит IDE; а Claude Code — это MCP-хост, предназначенный для AI-агента по написанию кода.

Работа с MCP-сервером

Прежде чем мы приступим к созданию нашего MCP-сервера, давайте посмотрим, как работать с существующим MCP-сервером. Мы будем использовать Python MCP SDK для взаимодействия с novita-mcp-server.

На момент написания этой статьи novita-mcp-server предоставляет следующие инструменты:

  • Инструмент для вывода списка всех кластеров Novita
  • Инструмент для вывода списка продуктов GPU-инстансов Novita
  • Инструмент для вывода списка всех запущенных GPU-инстансов
  • Инструмент для создания новых GPU-инстансов

Давайте убедимся в этом, написав простой скрипт, который подключается к MCP-серверу через STDIO и выводит список всех доступных на сервере инструментов.

Для начала установим MCP SDK: pip install "mcp[cli]"

После установки SDK создадим файл с именем client.py. Затем сделаем все необходимые импорты:

from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
import os

Затем мы используем StdioServerParameters для установки параметров запуска нашего MCP-сервера через stdio. novita-mcp-server реализован на Node.js, поэтому для его использования нам нужно запустить его с помощью команды npx. Также необходимо сохранить наш API-ключ Novita в переменной окружения NOVITA_API_KEY.

# Create server parameters for stdio connection
server_params = StdioServerParameters(
   command="npx",
   args=["-y", "@novitalabs/novita-mcp-server"],
   env={"NOVITA_API_KEY":  os.environ["NOVITA_API_KEY"]},
)

Далее создадим асинхронную функцию. Внутри функции мы передадим параметры сервера в функцию stdio_client, которая создаст контекст, возвращающий потоки чтения и записи. Эти потоки позволяют нам читать из stdio и записывать в stdio соответственно.

async def run():
   async with stdio_client(server_params) as (read, write):
       async with ClientSession(read, write) as session:
           # Initialize the connection
           await session.initialize()

           # List available tools
           tools = await session.list_tools()
           print("Available tools:", tools)

Эти потоки затем используются для создания сессии с помощью класса ClientSession. После создания сессии мы можем её инициализировать и затем вывести список всех инструментов на сервере.

Чтобы запустить эту программу, нам просто нужно использовать библиотеку asyncio для вызова функции run. Вот полный код:

from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
import os

# Create server parameters for stdio connection
server_params = StdioServerParameters(
   command="npx",
   args=["-y", "@novitalabs/novita-mcp-server"],
   env={"NOVITA_API_KEY":  os.environ["NOVITA_API_KEY"]},
)

async def run():
   async with stdio_client(server_params) as (read, write):
       async with ClientSession(read, write) as session:
           # Initialize the connection
           await session.initialize()

           # List available tools
           tools = await session.list_tools()
           print("Available tools:", tools)

if __name__ == "__main__":
   import asyncio

   asyncio.run(run())

Выполнив скрипт, мы увидим все инструменты на MCP-сервере Novita.

Этот пример демонстрирует, как использовать MCP-клиент. Мы могли бы добавить LLM в этот пример и фактически превратить его в хост, но это не является целью данного руководства. Основное внимание уделяется созданию MCP-сервера.

Создание MCP-сервера с помощью FastMCP

В Python MCP SDK есть два способа создания MCP-серверов. Один — с использованием низкоуровневого сервера, другой — с помощью FastMCP. FastMCP — это класс в составе MCP Python SDK, вдохновлённый FastAPI, который упрощает создание MCP-серверов.

Давайте используем FastMCP для создания нашего MCP-сервера. Прежде чем начать, давайте определим функциональность нашего MCP-сервера. Текущий MCP-сервер Novita реализует только инструменты для управления GPU. Давайте попробуем построить сервер на основе Novita API, который выходит за рамки управления GPU.

Вместо этого давайте создадим MCP-сервер, предоставляющий доступ к моделям на платформе Novita. Наш MCP-сервер будет содержать только инструменты, без ресурсов и промптов. Вот список инструментов, которые будут на сервере:

  • list_models: Этот инструмент выведет список всех больших языковых моделей на платформе Novita.
  • get_model: Этот инструмент получит и использует конкретную большую языковую модель.
  • text2image: Этот инструмент сгенерирует изображение по заданному промпту.
  • task_result: Этот инструмент будет использоваться для получения статуса выполняемой задачи по её ID.
  • text_to_speech: Этот инструмент преобразует предоставленный текст в речь.
  • generate_video: Этот инструмент сгенерирует видео по заданному промпту.

Теперь, когда мы знаем, какие инструменты будем создавать, давайте начнём создавать наш сервер. Сначала создайте файл с именем server.py и добавьте в него следующий код:

import os
import sys
from mcp.server.fastmcp import FastMCP
import requests
import uvicorn
from starlette.applications import Starlette
from starlette.routing import Mount

base_url = "https://api.novita.ai/v3"

headers = {
   "Content-Type": "application/json",
   "Authorization": f"Bearer {os.environ['NOVITA_API_KEY']}"
}

mcp = FastMCP("Novita_API")

Таким образом, мы импортировали необходимые модули, определили базовый URL и заголовки для API и создали экземпляр класса FastMCP. Перейдём к созданию наших инструментов.

list_models

Чтобы создать инструмент в FastMCP, нужно декорировать функцию методом tool из экземпляра FastMCP. Функция list_models выполняет вызов к конечной точке списка моделей, чтобы получить список моделей. Ответ затем соответствующим образом форматируется, чтобы его можно было передать вызвавшей его LLM.

@mcp.tool()
def list_models() -> str:
   """
   List all available models from the Novita API.
   """

   url = base_url + "/openai/models"

   response = requests.request("GET", url, headers=headers)
   data = response.json()["data"]
  
   text = ""
   for i, model in enumerate(data, start=1):
       text += f"Model id: {model['id']}\
"
       text += f"Model description: {model['description']}\
"
       text += f"Model type: {model['model_type']}\
\
"
  
   return text

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

get_model

Этот инструмент используется для доступа к развернутым LLM на Novita. Он принимает ID модели и промпт для модели. Он использует конечную точку чат-завершений Novita API.

@mcp.tool()
def get_model(model_id: str, message):
   """
   Provide a model ID and a message to get a response from the Novita API.
   """

   url = base_url + "/openai/chat/completions"

   payload = {
       "model": model_id,
       "messages": [
           {
               "content": message,
               "role": "user",
           }
       ],
       "max_tokens": 200,
       "response_format": {
           "type": "text",
       },
   }

   response = requests.request("POST", url, json=payload, headers=headers)
  
   content = response.json()["choices"][0]["message"]["content"]

   return content

text2Image

Этот инструмент генерирует изображения из промпта. Под капотом он использует конечную точку Novita text-to-image. Эта конечная точка асинхронная, поэтому она не возвращает изображение немедленно; вместо этого она возвращает ID задачи.

@mcp.tool()
def text2Image(prompt):
   """
   Generate an image from a text prompt using the Novita API.
   """

   url = base_url + "/async/txt2img"

   payload = {
       "request": {
           "model_name": "sd_xl_base_1.0.safetensors",
           "prompt": prompt,
           "width": 1024,
           "height": 1024,
           "image_num": 1,
           "steps": 20,
           "clip_skip": 1,
           "sampler_name": "Euler a",
           "guidance_scale": 7.5,
       },
       "extra": {
           "response_image_type": "jpeg"
       }
   }

   response = requests.request("POST", url, json=payload, headers=headers)

   return response.json()["task_id"]

task_result

Этот инструмент используется для получения статуса текущей задачи в Novita API. Он принимает только ID задачи. Например, инструмент Image генерирует изображение асинхронно и возвращает хосту ID задачи. Пользователь может затем попросить хост получить результат этой задачи с помощью инструмента Task Result.

@mcp.tool()
def task_result(task_id: str):
   """
   Get the current status of a running task using it's task id
   """

   url = base_url + f'/async/task-result?task_id={task_id}'

   response = requests.request("GET", url, headers=headers)
   return response.json()

generateVideo

Этот инструмент генерирует видео, используя конечную точку Novita API Kling AI V1.6 Text-to-Video. Как и инструмент Image, он генерирует видео асинхронно и возвращает ID задачи.

@mcp.tool()
def generateVideo(prompt: str):
   """
   Generate an image using a prompt
   """

   url = base_url + "/async/kling-v1.6-t2v"

   payload = {
       "mode": "Standard",
       "prompt": prompt,
       "negative_prompt": "low quality",
       "guidance_scale": 0.6
   }

   response = requests.post(url, json=payload, headers=headers)
  
   return response.json()

textToSpeech

Этот инструмент генерирует речь, используя конечную точку Novita API Text-to-Speech. Это также асинхронная конечная точка, поэтому она также возвращает ID задачи.

@mcp.tool()
def textToSpeech(text, voice_id) -> str:
   """
   Generate speech using text and voice id.
   It returns the task id of the generated speech.
  
   The available voice ids are:
   - Emily
   - James
   - Olivia
   - Michael
   - Sarah
   - John
   """

   url = base_url + "/async/txt2speech"

   payload = {
       "request": {
           "voice_id": voice_id,
           "language": "en-US",
           "texts": [text]
       }
   }

   response = requests.post(url, json=payload, headers=headers)
  
   return response.json()["task_id"]

После определения всех инструментов мы можем настроить механизм транспорта. Мы будем использовать stdio.

if __name__ == "__main__":
   # Run using stdio transport
   mcp.run(transport="stdio")

Теперь мы можем собрать весь код вместе:

import os
import sys

from mcp.server.fastmcp import FastMCP

import requests

import uvicorn

from starlette.applications import Starlette
from starlette.routing import Mount

base_url = "https://api.novita.ai/v3"

headers = {
   "Content-Type": "application/json",
   "Authorization": f"Bearer {os.environ['NOVITA_API_KEY']}"
}

mcp = FastMCP("Novita_API")

@mcp.tool()
def list_models() -> str:
   """
   List all available models from the Novita API.
   """

   url = base_url + "/openai/models"

   response = requests.request("GET", url, headers=headers)
   data = response.json()["data"]
  
   text = ""
   for i, model in enumerate(data, start=1):
       text += f"Model id: {model['id']}\
"
       text += f"Model description: {model['description']}\
"
       text += f"Model type: {model['model_type']}\
\
"
  
   return text

@mcp.tool()
def get_model(model_id: str, message) -> str:
   """
   Provide a model ID and a message to get a response from the Novita API.
   """

   url = base_url + "/openai/chat/completions"

   payload = {
       "model": model_id,
       "messages": [
           {
               "content": message,
               "role": "user",
           }
       ],
       "max_tokens": 200,
       "response_format": {
           "type": "text",
       },
   }

   response = requests.request("POST", url, json=payload, headers=headers)
  
   content = response.json()["choices"][0]["message"]["content"]

   return content

@mcp.tool()
def text2Image(prompt: str) -> str:
   """
   Generate an image from a text prompt using the Novita API.
   """

   url = base_url + "/async/txt2img"

   payload = {
       "request": {
           "model_name": "sd_xl_base_1.0.safetensors",
           "prompt": prompt,
           "width": 1024,
           "height": 1024,
           "image_num": 1,
           "steps": 20,
           "clip_skip": 1,
           "sampler_name": "Euler a",
           "guidance_scale": 7.5,
       },
       "extra": {
           "response_image_type": "jpeg"
       }
   }

   response = requests.request("POST", url, json=payload, headers=headers)

   return response.json()["task_id"]

@mcp.tool()
def task_result(task_id: str) -> str:
   """
   Get the current status of a running task using it's task id
   """

   url = base_url + f'/async/task-result?task_id={task_id}'

   response = requests.request("GET", url, headers=headers)
   return response.json()

@mcp.tool()
def generateVideo(prompt: str) -> str:
   """
   Generate an image using a prompt
   """

   url = base_url + "/async/kling-v1.6-t2v"

   payload = {
       "mode": "Standard",
       "prompt": prompt,
       "negative_prompt": "low quality",
       "guidance_scale": 0.6
   }

   response = requests.post(url, json=payload, headers=headers)
  
   return response.json()["task_id"]

@mcp.tool()
def textToSpeech(text, voice_id) -> str:
   """
   Generate speech using text and voice id.
   It returns the task id of the generated speech.
  
   The available voice ids are:
   - Emily
   - James
   - Olivia
   - Michael
   - Sarah
   - John
   """

   url = base_url + "/async/txt2speech"

   payload = {
       "request": {
           "voice_id": voice_id,
           "language": "en-US",
           "texts": [text]
       }
   }

   response = requests.post(url, json=payload, headers=headers)
  
   return response.json()["task_id"]

if __name__ == "__main__":
   # Run using stdio transport
   mcp.run(transport="stdio")

Мы можем протестировать наш MCP-сервер на любом MCP-хосте, таком как Claude Desktop, Cursor или VS Code, используя следующую конфигурацию:

{
     "command": "python",
     "args": [
       "path/to/server.py" 
     ],
     "env": {
       "NOVITA_API_KEY": "sk_...."
     }
   }

Мы также можем использовать разработанный ранее клиентский скрипт для тестирования нашего сервера.

Использование низкоуровневого MCP-сервера

Сервер, который мы создали в предыдущем разделе, использует класс FastMCP, предоставляющий высокоуровневый интерфейс для создания MCP-серверов. Вы также можете создавать MCP-серверы с использованием низкоуровневого сервера, который даёт вам детальный контроль над протоколом MCP. Давайте посмотрим, как можно модифицировать сервер из предыдущего раздела для использования низкоуровневого сервера.

Управление инструментами

Одна из задач FastMCP — управлять определёнными вами инструментами. Когда вы декорируете функцию декоратором tool класса FastMCP, FastMCP добавляет этот инструмент в список. Когда агент запрашивает этот инструмент, FastMCP извлекает его, вызывает и отправляет результат обратно агенту.

С помощью низкоуровневого сервера мы можем управлять этим процессом самостоятельно, используя декоратор call_tool.

@app.call_tool()
async def manage_tool(name: str, arguments: dict ) -> list[types.TextContent]:
   if name == "list_models":
       return await list_models_tool()
  
   if name == "get_model":
       return await get_model_tool(arguments)
  
   else:
       raise ValueError(f"Unknown tool: {name}")

Приведённый выше код показывает функцию, декорированную методом call_tool. Когда агент вызывает инструмент, он передаёт имя инструмента и любые аргументы, которые ожидает инструмент. Используя имя функции, мы можем определить, какой инструмент агент хочет вызвать, и выполнить его.

Мы также управляем выводом списка инструментов с помощью низкоуровневого сервера, в отличие от FastMCP, который делает это автоматически, когда функция декорирована методом tool.

@app.list_tools()
async def list_tools() -> list[types.Tool]:
   return [
       types.Tool(
           name="list_models",
           description="List all available models from the Novita API.",
           inputSchema={"type": "object", "properties": {}},
       ),
       types.Tool(
           name="get_model",
           description="Provide a model ID and a message to get a response from the Novita API.",
           inputSchema={
               "type": "object",
               "required": ["model_id", "message"],
               "properties": {
                   "model_id": {
                       "type": "string",
                       "description": "The ID of the model to use.",
                   },
                   "message": {
                       "type": "string",
                       "description": "The input message to send.",
                   },
               },
           },
       ),
   ]

Вот полный код низкоуровневого сервера. Он содержит два инструмента и может общаться с клиентом через стандартный ввод и вывод.

import os
import asyncio
import requests
from mcp.server.lowlevel import Server
from mcp.server.stdio import stdio_server
import mcp.types as types

base_url = "https://api.novita.ai/v3"

headers = {
   "Content-Type": "application/json",
   "Authorization": f"Bearer {os.environ['NOVITA_API_KEY']}"
}

app = Server("Novita_API")

async def list_models_tool():
   """
   Lists all available models from the Novita API.
   """
   url = base_url + "/openai/models"
   response = requests.get(url, headers=headers)
   data = response.json()["data"]

   text = ""
   for i, model in enumerate(data, start=1):
       text += f"Model id: {model['id']}\
"
       text += f"Model description: {model['description']}\
"
       text += f"Model type: {model['model_type']}\
\
"

   return [types.TextContent(type="text", text=text)]

async def get_model_tool(arguments: dict):
   """
   Given a model ID and a user message, fetch a response from the Novita API.
   """
   model_id = arguments.get("model_id")
   message = arguments.get("message")

   if not model_id or not message:
       raise ValueError("Both 'model_id' and 'message' are required.")

   url = base_url + "/openai/chat/completions"

   payload = {
       "model": model_id,
       "messages": [
           {
               "content": message,
               "role": "user",
           }
       ],
       "max_tokens": 200,
       "response_format": {
           "type": "text",
       },
   }

   response = requests.post(url, json=payload, headers=headers)
   content = response.json()["choices"][0]["message"]["content"]
   return [types.TextContent(type="text", text=content)]

@app.call_tool()
async def manage_tool(name: str, arguments: dict ) -> list[types.TextContent]:
   if name == "list_models":
       return await list_models_tool()
  
   if name == "get_model":
       return await get_model_tool(arguments)
  
   else:
       raise ValueError(f"Unknown tool: {name}")

@app.list_tools()
async def list_tools() -> list[types.Tool]:
   return [
       types.Tool(
           name="list_models",
           description="List all available models from the Novita API.",
           inputSchema={"type": "object", "properties": {}},
       ),
       types.Tool(
           name="get_model",
           description="Provide a model ID and a message to get a response from the Novita API.",
           inputSchema={
               "type": "object",
               "required": ["model_id", "message"],
               "properties": {
                   "model_id": {
                       "type": "string",
                       "description": "The ID of the model to use.",
                   },
                   "message": {
                       "type": "string",
                       "description": "The input message to send.",
                   },
               },
           },
       ),
   ]

async def main():
   async with stdio_server() as streams:
       await app.run(streams[0], streams[1], app.create_initialization_options())

if __name__ == "__main__":
   asyncio.run(main())

Низкоуровневый сервер не только предоставляет детальный контроль над управлением инструментами, но также даёт низкоуровневый контроль над ресурсами, промптами и другими частями протокола MCP, такими как управление жизненным циклом.

Заключение

В этом руководстве мы создали MCP-сервер, который использует Novita API для расширения возможностей любого MCP-хоста. Вы изучили основы того, что необходимо для создания MCP-сервера, включая то, как определять и предоставлять инструменты.

Имея эту основу, вы можете начать изучение более продвинутых тем, таких как аутентификация, развёртывание удалённых MCP-серверов и работа напрямую с низкоуровневой реализацией на Python.

Мы также изучили сам Novita API и увидели его возможности: от разнообразного набора языковых моделей до инструментов генерации видео, аудио и изображений. Посетите Novita LLM Playground, чтобы опробовать другие API, которые мы не успели осветить, такие как конечные точки для редактирования изображений и лиц.

Novita AI — это облачная AI-платформа, которая предоставляет разработчикам простой способ развёртывания AI-моделей с помощью нашего простого API, а также доступное и надёжное облако GPU для создания собственных моделей.