- BrainTools - https://www.braintools.ru -

vue-llm: AI SDK для Vue и Nuxt — стриминговый чат, Generative UI и модели прямо в браузере

Если вы делали AI-фичу на Vue, то, скорее всего, сталкивались с одним и тем же: большинство готовых инструментов для LLM-интерфейсов написаны с прицелом на React, а во Vue их приходится адаптировать или писать стриминг, tool calling и состояние чата вручную. Я сделал vue-llm — open-source библиотеку, которая закрывает это для Vue 3, Nuxt и даже Vue 2.7.

Сразу ссылки, чтобы можно было пощупать:

– Песочница без API-ключа (модель скачивается и работает прямо в браузере на WebGPU): https://vue-llm.js.org/ru/playground [1]

– Документация на русском: https://vue-llm.js.org/ru/ [2]

– GitHub: https://github.com/dadashi44/vue-llm [3]

– npm: npm i vue-llm

Ниже — что умеет библиотека и как это выглядит в коде.

Чат за десять строк

Основа — композабл useChat. Он стримит ответ модели токен за токеном в реактивное состояние: сообщения, статус, ошибка [4], отмена, перегенерация.

<script setup lang="ts">

import { useChat } from 'vue-llm'

import { createProxyProvider } from 'vue-llm/server'




const { messages, input, handleSubmit, status, stop } = useChat({

  provider: createProxyProvider('/api/chat'),

  model: 'gpt-4o',

})

</script>




<template>

  <div v-for="m in messages" :key="m.id">

    <b>{{ m.role }}:</b>

    <template v-for="(part, i) in m.parts" :key="i">

      <span v-if="part.type === 'text'">{{ part.text }}</span>

    </template>

  </div>

  <form @submit.prevent="handleSubmit">

    <input v-model="input">

    <button v-if="status === 'streaming'" type="button" @click="stop">Стоп</button>

  </form>

</template>

Сообщения состоят из «частей» (parts): текст, рассуждения модели, вызовы инструментов, файлы, источники. Поэтому один и тот же шаблон показывает и обычный ответ, и reasoning у Claude или Qwen3, и вызов tool.

API-ключ при этом остаётся на сервере. Серверная часть — обычный Web-стандартный обработчик Request → Response, который работает в Nuxt/Nitro, Node, Bun, Deno и edge-рантаймах:

// server/api/chat.post.ts (Nuxt)

import { createLLMHandler } from 'vue-llm/server'

import { createAnthropic } from 'vue-llm/providers'




const handler = createLLMHandler({

  provider: createAnthropic({ apiKey: process.env.ANTHROPIC_API_KEY! }),

  model: 'claude-sonnet-4-5',

  rateLimit: { maxRequests: 30, interval: 60_000 },

})




export default defineEventHandler(event => handler(toWebRequest(event)))

Провайдеры из коробки: OpenAI (и любой OpenAI-совместимый API), Anthropic, Google Gemini, Ollama. Если у вас уже есть свой бэкенд со стримингом, createSSEProvider подключает useChat к нему: вы описываете, как ваши SSE-события превращаются в куски ответа, и всё остальное работает как есть.

Generative UI: модель отвечает компонентами

Самая интересная для меня часть. Когда модель вызывает инструмент, вместо текста можно показать ваш Vue-компонент. Аргументы стримятся в компонент по мере генерации, то есть карточка начинает заполняться ещё до того, как модель дописала вызов.

import { defineTool } from 'vue-llm'




export const getWeather = defineTool<{ city: string }, Weather>({

  name: 'get_weather',

  description: 'Погода в городе',

  parameters: { type: 'object', properties: { city: { type: 'string' } }, required: ['city'] },

  execute: ({ city }) => fetch(/api/weather?city=${city}).then(r => r.json()),

})

<MessageParts

  v-for="m in messages"

  :key="m.id"

  :message="m"

  :components="{ get_weather: WeatherCard }"

  @tool-result="addToolResult"

/>

Инструмент с execute выполняется сам. Инструмент без execute ставит чат на паузу и ждёт ответа из интерфейса — так делается human-in-the-loop: модель предлагает забронировать столик, пользователь жмёт «Подтвердить» в карточке, addToolResult передаёт ответ, и разговор продолжается. Живое демо (работает без сети): https://vue-llm.js.org/ru/guide/generative-ui [5]

Под капотом для этого пришлось написать парсер «недописанного» JSON: {"city":"Мос превращается в { city: 'Мос' }, а незаконченные ключи отбрасываются до тех пор, пока не допишутся.

Модели прямо в браузере

createWebLLM запускает открытые модели (Llama 3.2, Qwen, SmolLM, Phi) на WebGPU через WebLLM. Никакого сервера и ключа, данные не покидают устройство.

import { CreateMLCEngine } from '@mlc-ai/web-llm'

import { createWebLLM } from 'vue-llm/providers'




const ai = createWebLLM({

  createEngine: CreateMLCEngine,

  onProgress: ({ progress }) => console.log(${Math.round(progress * 100)}%),

})




useChat({ provider: ai, model: 'Llama-3.2-1B-Instruct-q4f16_1-MLC' })

Это тот же useChat, что и с OpenAI, — меняется только провайдер. Можно, например, давать пользователям без WebGPU серверную модель, а остальным — локальную. Первая загрузка модели занимает от 400 МБ, дальше она берётся из кеша браузера за секунду-две.

Готовый интерфейс чата в стиле shadcn

Писать окно чата с нуля утомительно: автоскролл, который не дёргает пользователя, листающего вверх; Enter для отправки, который не срабатывает при наборе на китайском или японском; вставка картинок из буфера; drag-and-drop файлов. Поэтому библиотека устроена гибридно:

– в npm лежит headless-логика: usePromptInput и useAutoScroll;

– готовые компоненты копируются в ваш проект как в shadcn — одной командой, после чего код ваш:

npx shadcn-vue@latest add https://vue-llm.js.org/r/chat.json

Компоненты используют токены темы shadcn, поэтому сразу выглядят как остальной ваш интерфейс, включая тёмную тему.

Отладка в Vue DevTools

vue-llm/devtools добавляет в Vue DevTools вкладку LLM: список всех useChat, токены, время до первого токена, скорость генерации, вызовы инструментов и таймлайн каждого запроса. Без плагина библиотека ничего не трассирует и не тратит на это ресурсы.

Nuxt

Модуль подключается одной командой:

npx nuxi module add vue-llm

Он делает auto-import композаблов и провайдеров, регистрирует компоненты и в dev-режиме сам подключает вкладку в DevTools. Проверено на Nuxt 3 и 4.

Почему не взять готовый AI SDK

Хороший вопрос, и я сам с него начинал. vue-llm сделан Vue-first: Nuxt-модуль, Vue-компоненты для Generative UI, интеграция с Vue DevTools, провайдер для моделей в браузере, адаптер под существующий SSE-бэкенд и поддержка Vue 2.7 для композаблов (у многих легаси-админок до сих пор Vue 2). Зависимостей в рантайме нет, кроме самого Vue.

Что дальше

Библиотека под MIT, версия 1.3, покрыта тестами на Vue 3 и Vue 2.7. В планах — MCP-клиент (подключать MCP-серверы как инструменты), ответы с цитатами для RAG и голосовой ввод.

Буду рад обратной связи: что неудобно, чего не хватает, где документация непонятна. Issues и PR приветствуются, а если проект пригодится — поставьте звёздочку на GitHub, это правда помогает его продвигать.

– Песочница: https://vue-llm.js.org/ru/playground [1]

– Документация: https://vue-llm.js.org/ru/ [2]

– GitHub: https://github.com/dadashi44/vue-llm [3]

Автор: dadash_i

Источник [6]


Сайт-источник BrainTools: https://www.braintools.ru

Путь до страницы источника: https://www.braintools.ru/article/37753

URLs in this post:

[1] https://vue-llm.js.org/ru/playground: https://vue-llm.js.org/ru/playground

[2] https://vue-llm.js.org/ru/: https://vue-llm.js.org/ru/

[3] https://github.com/dadashi44/vue-llm: https://github.com/dadashi44/vue-llm

[4] ошибка: http://www.braintools.ru/article/4192

[5] https://vue-llm.js.org/ru/guide/generative-ui: https://vue-llm.js.org/ru/guide/generative-ui

[6] Источник: https://habr.com/ru/articles/1101308/?utm_source=habrahabr&utm_medium=rss&utm_campaign=1101308

www.BrainTools.ru

Rambler's Top100