28 сентября 2026 г.
BSL Language Server vs граф зависимостей 1С: что реально кормить ИИ-агенту
Две парадигмы: язык и связи
Когда тимлид впервые подключает Claude Code или Cursor к конфигурации 1С, возникает один и тот же вопрос: «У меня же уже стоит BSL Language Server — зачем ещё какой-то граф зависимостей?». Ответ короткий: BSL LS отвечает на вопрос «правильно ли написан код», а граф зависимостей — на вопрос «какой код вообще относится к задаче». Для LLM-агента второе важнее в разы, потому что контекстное окно — это дефицитный ресурс, а не абстракция.
Что умеет BSL Language Server
BSL LS — это LSP-сервер и набор диагностик для языка BSL. Он умеет:
- парсить модули и строить AST;
- выдавать 100+ диагностик (неиспользуемые переменные,
Ссылка.ПолучитьОбъект()в цикле, неправильныеПопытка/Исключение, запросы в цикле); - поддерживать LSP-примитивы:
textDocument/definition,references,hover,documentSymbol,callHierarchy; - форматировать код и работать как quality gate в CI.
Для человека в IDE это отлично. Для агента — почти бесполезно в чистом виде. Причины ниже.
Почему LSP ≠ контекст для LLM
- LSP поточечный, а не пакетный. На запрос
textDocument/definitionвы получите одно определение, а не замыкание вызовов. Агенту же нужны 5–7 уровней:ПриЗаписиНаСервере→РассчитатьСуммуСНДС→ОбщегоНазначения.ЗначениеРеквизитаОбъекта→ подпискаПередЗаписьюв другом общем модуле. - N round-trip вместо одного запроса. Каждый переход — отдельный вызов MCP/IDE-моста, каждый ответ снова улетает в контекст. 20 переходов — это 20 × 2–4 КБ служебных данных.
documentSymbolна общем модуле УТ 11 — это тысячи символов. Агент получает оглавление вместо нужного абзаца.- LSP не знает метаданных. BSL LS видит код, но не видит, что
Документ.РеализацияТоваровУслугвходит в подсистему, что на реквизитСуммаСНДСзавязан отчёт СКД, а на таблицу — регистр накопления. Метаданные и код в LSP живут раздельно. - Нет запросов как сущности. Текст запроса — это строка. Связь «поле запроса → реквизит метаданных → тип» LSP не строит.
Что такое граф зависимостей 1С
Графон индексирует выгрузку конфигурации и строит ориентированный граф, где узлы — это:
- объекты метаданных (
Документ,Справочник,Регистр,ОбщийМодуль,ПодпискаНаСобытие,Форма); - процедуры и функции (
МодульОбъекта.ПриЗаписиНаСервере); - реквизиты и измерения, табличные части, поля форм;
- тексты запросов и их поля;
- подписки на события и их обработчики.
Рёбра — это вызывает, переопределяет, обрабатывает событие, читает поле, пишет реквизит, используется в запросе, обрабатывает заполнение. Всё это лежит локально, обычно в SQLite/embedded-графе, и отдаётся агенту через MCP.
Архитектура Графона
Выгрузка XML (ERP, УТ, ЗУП)
│
▼
Парсер XML + AST модулей BSL
│
▼
Индексатор (граф: узлы + рёбра)
│
▼
MCP-сервер (localhost)
│
├──► Claude Code
├──► Cursor
└──► Windsurf / Roo Code
MCP-запросы: как это выглядит
Агент не «грепает» репозиторий, а делает пакетный запрос:
{
"tool": "grafon_pack_context",
"arguments": {
"entry_point": "Документ.РеализацияТоваровУслуг.МодульОбъекта.ПриЗаписиНаСервере",
"depth": 2,
"include": ["callers", "subscriptions", "queries", "metadata_fields"],
"budget_tokens": 12000
}
}
Ответ — компактный срез: сигнатуры, тела только «горячих» процедур, схемы реквизитов, тексты запросов.
{
"nodes": [
{ "id": "Документ.РеализацияТоваровУслуг.ПриЗаписиНаСервере", "kind": "procedure", "lines": 74 },
{ "id": "ОбщийМодуль.СуммыНДС.РассчитатьСуммуСНДС", "kind": "function", "signature": "РассчитатьСуммуСНДС(Товары)" },
{ "id": "Подписка.ПередЗаписьюРеализации", "kind": "subscription", "handler": "ОбщийМодуль.КонтрольОстатков.ПередЗаписьюРеализации" }
],
"edges": [
"ПриЗаписиНаСервере -> РассчитатьСуммуСНДС",
"ПриЗаписиНаСервере -> ЗарегистрироватьИзменения",
"Подписка.ПередЗаписьюРеализации -> КонтрольОстатков.ПередЗаписьюРеализации"
],
"queries": [
{ "owner": "ПриЗаписиНаСервере", "tables": ["Документ.РеализацияТоваровУслуг.Товары"], "fields": ["Номенклатура", "Сумма"] }
]
}
Другой типовой вызов — анализ влияния перед изменением реквизита:
{
"tool": "grafon_impact_analysis",
"arguments": {
"target": "Справочник.Номенклатура.Реквизит.СтавкаНДС",
"edge_kinds": ["reads", "writes", "query_field", "form_attribute"],
"max_nodes": 200
}
}
BSL-код, который агент получает целиком вместо 3000 строк
Без графа агент читает модуль документа (часто 2500–4000 строк) и общий модуль КонтрольОстатков (иногда 8000+ строк). С графом — только этот фрагмент:
Процедура ПриЗаписиНаСервере(Отказ, РежимЗаписи, РежимПроведения)
СуммаСНДС = РассчитатьСуммуСНДС(Объект.Товары);
Объект.СуммаСНДС = СуммаСНДС;
// Граф подсказал: есть подписка ПередЗаписью, изменяющая Объект
ЗарегистрироватьИзменения(Объект.Ссылка, "Запись");
КонецПроцедуры
Функция РассчитатьСуммуСНДС(Товары)
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Товары.Номенклатура КАК Номенклатура,
| СУММА(Товары.Сумма) КАК Сумма,
| Товары.СтавкаНДС КАК СтавкаНДС
|ИЗ
| Документ.РеализацияТоваровУслуг.Товары КАК Товары
|ГДЕ
| Товары.Ссылка = &Ссылка
|СГРУППИРОВАТЬ ПО
| Товары.Номенклатура,
| Товары.СтавкаНДС";
Запрос.УстановитьПараметр("Ссылка", Ссылка);
Выборка = Запрос.Выполнить().Выбрать();
СуммаСНДС = 0;
Пока Выборка.Следующий() Цикл
СуммаСНДС = СуммаСНДС + Выборка.Сумма * Выборка.СтавкаНДС / 100;
КонецЦикла;
Возврат СуммаСНДС;
КонецФункции
Агент сразу видит, что СтавкаНДС — это реквизит табличной части, и что на итог влияет подписка. Без графа он бы нашёл функцию после 6–8 grep-итераций и, вероятно, выдумал несуществующий метод НДССумма().
Сравнение: с Графоном и без
| Сценарий | Подход | Токены | Время | Галлюцинации |
|---|---|---|---|---|
| Доработать контроль остатков при записи реализации | grep + чтение файлов | ~186 000 | 9–14 мин | 3–5 несуществующих методов |
| То же | Графон через MCP | ~14 500 | 35–50 сек | 0 |
| Рефакторинг общего модуля на 8 000 строк | чтение модуля целиком | ~64 000 | 4–6 мин | путаница одноимённых функций |
| То же | Графон + call hierarchy | ~9 200 | 25 сек | 0 |
| Анализ влияния изменения реквизита | ручной поиск ссылок | не сходится, агент «сдаётся» | 15+ мин | 40 % пропущенных точек |
| То же | grafon_impact_analysis | ~6 000 | 12 сек | 0 |
Итого по бюджету: экономия токенов 8–12×, времени — 6–15×.
Практические сценарии
- Фикс бага в типовой. Агент получает только цепочку
кнопка формы → команда → серверная процедура → запрос → регистр. Остальные 700 модулей не грузятся. - Генерация нового общего модуля. Графон отдаёт список существующих похожих функций, чтобы агент не создал дубль
ОбщегоНазначения.ЗначениеРеквизитаОбъекта. - Миграция на новую версию. Граф показывает все места, где используется изменённый метод БСП.
- Аудит подписок. Один MCP-запрос отдаёт все подписки на
ПередЗаписьюс обработчиками — типичная задача при разборе «почему документ пишется дважды». - Ревью pull request от агента. В контекст подтягиваются вызывающие и вызываемые, а не весь модуль.
Гибридная схема: LSP + граф
Не нужно выбирать одно. Рабочая конфигурация для команды:
- BSL Language Server — pre-commit и CI: диагностики, форматирование, порог по ошибкам.
- Графон (MCP) — рантайм ИИ-агента: сборка контекста, impact analysis, поиск подписок и запросов.
.cursorrules/CLAUDE.md— правило: «перед чтением любого модуля вызовиgrafon_pack_context».
Антипаттерны
- Отдавать агенту
documentSymbolпо общему модулю — это не контекст, а оглавление. - Полагаться на
grepпо XML-выгрузке: структура каталогов у ERP и УТ различается, regex ломается. - Грузить формы целиком:
Form.xmlна 5 МБ съедает окно за один ход. - Игнорировать подписки: в 1С логика часто живёт не в модуле объекта.
Вывод
BSL Language Server — это компилятор совести разработчика: он скажет, что код плохой. Граф зависимостей — это карта местности: он скажет, какой именно код относится к задаче. Для ИИ-кодинга в 1С критичен второй пункт, потому что ограничение — не качество модели, а объём контекста. Графон закрывает эту проблему на уровне MCP: один запрос — точный срез замыкания вызовов, метаданных, подписок и запросов, минус 10× токенов и почти нулевые галлюцинации. BSL LS при этом остаётся на своём месте — в CI, где он и должен быть.