Microsoft Flint: агент описывает график в пять строк, а компилятор собирает его в Vega-Lite, Plotly и Excel
Попроси агента построить график — и получишь сто строк конфига Vega-Lite, в котором он на глаз выставил ширину бинов, интервал тиков, диапазон цветовой шкалы и положение легенды. В следующий раз на тех же данных он выставит их иначе. Проблема не в том, что модель не умеет рисовать. Проблема в том, что 90% спецификации графика — это тюнинг, не имеющий отношения к тому, что ты хотел показать.
Microsoft Research выкатила под MIT решение, которое мне кажется правильным по постановке задачи: перенести весь тюнинг в компилятор, а агенту оставить смысл.
TL;DR: Flint — промежуточный язык визуализации. Ты (или агент) описываешь компактный спек с семантическими типами полей, а компилятор сам выводит масштабы, оси, отступы, подписи и раскладку. Один и тот же вход собирается в Vega-Lite, ECharts, Chart.js, Plotly и нативные графики Excel. В комплекте MCP-сервер:
npx -y flint-chart-mcp, и агент рисует прямо из чата.
Что делает Flint и чем он отличается от Vega-Lite
Он не заменяет Vega-Lite, а компилируется в него. Flint — это уровень выше: ты сообщаешь, что означают данные, а не как их чертить.
Минимальный пример из репозитория выглядит так:
import { assembleVegaLite } from 'flint-chart';
const spec = assembleVegaLite({
data: { values: myData },
semantic_types: { weight: 'Quantity', mpg: 'Quantity', origin: 'Country' },
chart_spec: {
chartType: 'Scatter Plot',
encodings: { x: { field: 'weight' }, y: { field: 'mpg' }, color: { field: 'origin' } },
baseSize: { width: 400, height: 300 },
},
});
// → готовый Vega-Lite spec
Ключевая строчка здесь semantic_types. Ты говоришь не «это число», а «это Quantity» и «это Country». Таких типов больше 70: Rank, Temperature, Price, Currency, Percentage, Latitude, Longitude и так далее. Компилятор на основе типа, вида графика и кардинальности данных сам решает, как масштабировать оси, какие подписи поставить, где разместить легенду и как разнести марки, чтобы они не слиплись.
Смена бэкенда не меняет вход:
import { assembleECharts, assembleChartjs, assemblePlotly, assembleExcel } from 'flint-chart';
const echartsOption = assembleECharts(input);
const chartjsConfig = assembleChartjs(input);
const plotlyFigure = assemblePlotly(input);
const excelArtifact = assembleExcel(input);
Один ChartAssemblyInput, пять нативных выходов. Excel — не картинка, а настоящий редактируемый график через Office.js, что для отчётности часто решает вопрос целиком.
Зачем это агенту, а не просто разработчику
Потому что короткий спек — это то, что LLM генерирует надёжно, а длинный конфиг — то, что она генерирует каждый раз по-разному.
Разница практическая. Полный Vega-Lite конфиг даёт модели десятки мест, где можно поставить плохое значение и не заметить: слишком мелкий шрифт при 40 категориях, перекрывающиеся подписи, легенда поверх данных, цветовая шкала, где последовательное выдано за категориальное. Каждое из этих решений требует знания предметной области визуализации, которого у модели нет — есть только статистика похожих конфигов из обучения.
Flint эти решения забирает себе. Модели остаётся выбрать тип графика, назначить поля и расставить семантические типы — то есть ровно ту часть, где она и должна быть полезна.
Второй аргумент — валидация. MCP-сервер даёт агенту не только «нарисовать», но и «проверить»: спек можно провалидировать до рендера, и агент получает внятную ошибку вместо кривой картинки. Плюс он умеет открывать интерактивный просмотр графика в клиентах, которые это поддерживают, или отдавать статичный PNG/SVG.
Ставится в одну строку:
npx -y flint-chart-mcp
После этого в Claude Code, Cursor или любом MCP-клиенте можно просто попросить: «построй heatmap корреляций по этому CSV, цену помечь как Price, регион как Country» — и получить график, а не диалог про настройку осей. В репозитории лежит папка agent-skills/ с резервной копией того самого скилла, который сервер отдаёт агенту, так что видно, какими инструкциями он руководствуется.
Что уже готово, а что нет
Библиотека на JS/TS готова и активно развивается, Python — нет.
По changelog проекта за последний месяц:
- 0.4.0 (24 июля) — 38 типов графиков Plotly и 18 нативных редактируемых шаблонов Excel. Самый содержательный релиз: именно он превратил Flint из «ещё одной обёртки над Vega-Lite» в мультибэкендовый инструмент.
- 0.3.0 (19 июля) — динамические виджеты: график меняет тип и свойства на месте, без перегенерации спека.
- 0.2.2 (15 июля) — компактные режимы dodge и группированные violin-раскладки.
- 0.2.1 (13 июля) — валидация свойств графика и согласованность между бэкендами.
Python-порт в репозитории есть, но это preview в исходниках, пакет не опубликован. Для проекта про визуализацию данных это существенный пробел: половина аудитории живёт в pandas и Jupyter, и им пока предложить нечего. За теорией — статья на arXiv, за примерами и живым редактором — сайт проекта.
Подводные камни
- Python не готов. Пакета нет, только исходники в репозитории. Если твой пайплайн данных на Python, Flint сегодня работает только через отдельный Node-шаг.
- Версия 0.4.0. До 1.0 API может двигаться, и уже двигался: 0.2.1 занимался согласованностью бэкендов, то есть до него один вход давал заметно разные результаты в разных рендерерах. Пинуй версию.
- Появился ещё один слой для отладки. Когда ось выглядит неправильно, теперь надо понять, что решил компилятор Flint, а что сделал бэкенд. Вместо одного конфига перед тобой цепочка, и для нетривиальных случаев это медленнее, чем правка Vega-Lite напрямую.
- Неверный семантический тип портит вывод молча. Если агент помечает
RankкакQuantity, компилятор добросовестно применит раскладку для количественной величины и не пожалуется. Это худший класс ошибок: результат выглядит аккуратно и при этом неверен. Именно то место, где нужен человеческий взгляд. - Excel только через Office.js. Это не «записать xlsx с диска», а работа внутри контекста Office. Для серверной генерации отчётов схема не подходит.
- MCP-сервер, который рендерит твои данные, — это поверхность атаки. Сервер локальный и наружу ничего не отправляет, но заявление «известных CVE нет» для версии 0.x само по себе не гарантия. Данные в график попадают из внешних источников, а рендер — это исполнение кода бэкенда.
Альтернативы
- Чистый Vega-Lite — агент умеет генерировать его без единой зависимости, и это по-прежнему нормальный дефолт для простых графиков. Проигрывает на многословности и стабильности результата между запусками, зато отлаживается в одном месте.
- Mermaid — для схем и диаграмм, а не для данных, зато рендерится прямо в куче мест без сервера. Другая задача, часто путают.
- matplotlib или Plotly через исполнение кода — максимальная гибкость, агент пишет код и видит результат. Минус в том, что на выходе получается картинка, а не спек: перерисовать её другим бэкендом или отдать во фронтенд нельзя.
- Observable Plot — лаконичная грамматика с хорошими дефолтами, во многом та же идея «умных значений по умолчанию». Один бэкенд и нет MCP-интеграции, зато зрелее и без промежуточного слоя.
Вердикт
Стоит подключить сегодня, если твой агент регулярно строит графики и стек у тебя на JS/TS: npx -y flint-chart-mcp занимает минуту, а разница в качестве вывода на данных с большим числом категорий видна сразу. Мультибэкендовость плюс редактируемый Excel — то, чего у альтернатив нет ни у кого.
Не трогай, если ты в Python: пакета нет, а тянуть Node-прослойку ради графиков — плохая сделка. И не считай Flint защитой от бессмысленных графиков: он гарантирует, что диаграмма будет опрятной, но выбор типа графика и семантических типов остаётся за агентом, а вот именно там ошибки самые дорогие и самые незаметные. Проверять, что Rank не назвали Quantity, придётся глазами.
Как попробовать
- Поставь библиотеку в проект:
npm install flint-chart. Или сразу подними MCP-сервер:npx -y flint-chart-mcpи добавь его в конфиг своего клиента. - Собери один и тот же вход в два бэкенда (
assembleVegaLiteиassembleECharts) и сравни результат — так быстрее всего понять, что именно берёт на себя компилятор. - Проверь эффект семантических типов на своих данных: прогони одно и то же поле как
Quantityи как положенный ему тип (Price,Rank,Percentage) и посмотри на разницу в раскладке. Если разницы нет, тебе Flint не нужен. - Попроси агента в Claude Code или Cursor построить график по твоему CSV с явным указанием семантики полей и посмотри, что он сгенерирует: смысл интеграции виден именно на этом шаге.
- Пощупай без установки в живом редакторе, а настройку MCP сверь по официальному гайду.