СКД и дерево элементов обычной формы 1С: два некритичных шага в агентном пайплайне

30.06.26

Разработка - Инструментарий разработчика

После распаковки Form.bin у обычной формы 1С остаются два соседних источника контекста, которые LLM-агент по умолчанию не видит: настройки СКД во внешних отчетах и дерево элементов формы в elem.json. В статье разобрано, как извлечь оба в компактные JSON-индексы пакетным режимом, не запуская платформу 1С, и где проходит честная граница достоверности разбора. Материал для разработчиков и архитекторов, строящих агентные инструменты поверх кодовой базы 1С.

Статья продолжает разбор подготовки обычных форм 1С для агентного пайплайна и описывает два некритичных шага одного релиза. Первый: пакетное извлечение запросов СКД (Система компоновки данных - встроенный в 1С механизм построения отчётов) из Template.bin внешних отчетов через extract_all_skd_queries, с записью отдельного skd_queries.json по каждому отчету и обработкой ошибок в режиме best-effort. Второй, основной: разбор сериализованного дерева элементов формы из elem.json и построение компактного form_elements_index, который сжимает исходный файл более чем в 10 раз, отбрасывая визуальные свойства и оставляя структуру. Подробно разобраны два прохода парсера, восстановление иерархии из путей-ключей, коллизии одноименных страниц через parent_path и граница достоверности: почему вложенность групп намеренно не реконструируется. Все примеры синтетические, на demo-конфигурации, код - Python.

Предыдущая статья закрыла первый вопрос: как сделать Form.bin читаемым. Казалось, дальше всё просто - агент видит Form.obj.bsl, живёт и радуется.

Не тут-то было!

Когда я полез подключать агента к отчётам - и вскрылся первый незакрытый хвост: пообъектный extract_skd_queries при передаче корня с несколькими .erf просто брал первый найденный Template.bin и уходил. Остальные отчёты - как будто их нет. Молча, без ошибки. Это я поймал только когда начал проверять выдачу агента по конкретным отчётам и удивился, почему у половины нет СКД.

Второй хвост оказался крупнее. Form.obj.bsl - это только обработчики. Рядом в директории формы лежит CatalogForm.elem.json - сериализованное дерево элементов: кнопки, поля, группы, привязки к реквизитам. Без него агент видит процедуры, но не видит структуру: на какой вкладке кнопка, к какому реквизиту привязано поле, что вообще на этой форме есть. Слепое пятно номер два.

Эта статья закрывает обе темы. Сначала быстро разберём доработку СКД - это прямое продолжение прошлой статьи. Потом основная часть: elem.json и form_elements_index.

 

Коротко: что делать

  • Для пакета отчётов вызывать extract_all_skd_queries, а не пообъектную функцию: один корень над несколькими Template.bin иначе даст только первый отчёт.

  • Проверить, что skd_queries.json пишется внутрь директории каждого отчёта, а не на уровень выше.

  • Трактовать СКД-шаг как best-effort: skd_extracted=False при extraction_ok=True - это сигнал о неполноте контекста, а не авария пайплайна.

  • Строить form_elements_index из elem.json, а не подавать elem.json в RAG (Retrieval-Augmented Generation - метод дополнения LLM контекстом из индекса) целиком: визуальные свойства раздувают файл в десятки раз и агенту не нужны.

  • Использовать path как канонический адрес элемента, parent_path - для разрешения коллизий одноименных страниц.

  • Не доверять реконструкции вложенности групп: смотреть warnings в индексе.

 

Доработка СКД: от скрипта к модулю пакета

Template.bin внутри .erf содержит запросы СКД - для агента это контекст выборки данных: какие источники участвуют в отчёте, что выбирается, какие условия. Без этого слоя агент видит только BSL (Built-in Script Language - встроенный язык 1С)-обработчики отчёта, но не понимает, что он вообще считает.

Пообъектный extract_skd_queries я написал первым. Работает нормально, когда передаёшь ему корень одного отчёта. Но как только выгрузка содержит несколько .erf под одним корнем - он брал первый найденный Template.bin и останавливался. Я потратил немного времени, пока не дошло, что проблема именно здесь: в памяти возвращался один SkdResult, и это не выглядело как ошибка.

Пакетный режим решает это в лоб:

Функция Режим Поведение
extract_skd_queries(unpacked_root) пообъектный один отчёт → SkdResult; берёт первый Template.bin
extract_all_skd_queries(unpacked_root) пакетный обходит все Template.bin SkdBatchResult
from pathlib import Path
from v8unpack_agent import extract_all_skd_queries, SkdBatchResult

batch: SkdBatchResult = extract_all_skd_queries(unpacked_root=Path("src/Report"))
# batch.skd_extracted: bool - True если хотя бы один отчёт извлёкся
# batch.results: list[SkdResult]
# batch.warnings: list[str] - предупреждения по неудачным отчётам

Ошибка одного отчёта не прерывает обработку остальных - принцип тот же, что и в extraction_ok у форм.

Отдельная история с путём записи файла. В исходной реализации skd_queries.json писался на уровень выше корня отчёта. При пакетном обходе это означало: каждый следующий отчёт тихо перезаписывал файл предыдущего. В памяти batch.results собирал все SkdResult корректно, а на диске оставался только последний. Я это поймал только когда стал проверять файлы руками - в коде всё выглядело правильно. После небольшой правки каждый файл теперь пишется внутрь директории каждого отчёта.

Практическое правило: skd_extracted=False при extraction_ok=True - это не авария. Это сигнал агенту: BSL-слой доступен, но контекст отчёта неполный. То же самое справедливо для elem_index_ok у форм.

 

Дерево элементов обычной формы

Вот тут я потратил больше всего времени. Казалось бы - elem.json это просто JSON. Открыл, прочитал. Всё хорошо, но нет.

 

Что такое elem.json

После распаковки Form.bin через v8unpack в директории формы появляется несколько файлов. Form.obj.bsl - модуль формы: процедуры и обработчики. Его агент читает нормально.

CatalogForm.elem.json (имя варьируется по типу объекта) - сериализованное дерево элементов формы. Здесь хранится:

  • иерархия элементов: Group, Panel, Button, Field, Label, CommandPanel;

  • вложенность: страницы Panel, Group внутри страницы;

  • имена элементов - программные идентификаторы, которые используются в BSL через ЭтотОбъект.Элементы.<Имя>;

  • привязки реквизитов: Field ссылка на реквизит объекта;

  • описание обработчиков: имя элемента имя процедуры в Form.obj.bsl;

  • визуальные свойства: координаты, размеры, цвета.

 

Что агент видит без elem.json

Смотришь на Form.obj.bsl после распаковки - там что-то вроде:

// Form.obj.bsl
Процедура КнопкаВоВложеннойГруппеНажатие(Команда)
    // ... тело обработчика ...
КонецПроцедуры

Код есть. Имя процедуры есть. Но агент не знает, что КнопкаВоВложеннойГруппе - это именно кнопка, где она расположена в дереве, на какой странице, внутри какой панели. Не знает, какие реквизиты вообще отображаются на форме. Он видит процедуры без контекста.

Спросить агента «что делает эта форма» - ответит что-то вроде «содержит обработчик нажатия кнопки». Технически верно. Практически бесполезно.

 

Почему elem.json - не готовое дерево

Я рассчитывал просто распарсить JSON и получить дерево. Не вышло.

elem.json - это сериализованный формат платформы. Иерархия элементов там не кодируется структурой JSON-объектов - она кодируется в путях-ключах секции data. Ключ вида Страница1/ПанельВерхняя/Страница1/ПанельВложенная/Страница11/Код - это и есть адрес элемента Код в дереве формы. Чтобы восстановить иерархию, нужно разобрать пути.

Плюс несколько неочевидных вещей:

  • страницы Panel могут быть одноименными на разных уровнях - без parent_path они неотличимы;

  • пустые страницы без элементов-потомков хранятся в ключах -pages-, а не как отдельные объекты;

  • вложенность групп в путях-ключах не отражается вообще - она в бинарном слое;

  • реквизиты формы из секции props - не визуальные элементы, у них нет места в дереве;

  • GUID реквизитов резолвятся через Catalog.json / Catalog-3.json, то есть через отдельный файл метаданных.

Это не «просто прочитать JSON». Это «восстановить дерево из путей, зная, что формат сериализует иерархию нестандартно».

 

Два прохода парсера

Алгоритм работает в два прохода.

Проход 1 - секция data. Ключи разбираются как пути: из каждого пути извлекаются name (последний сегмент), parent (предпоследний), parent_path (всё до последнего сегмента), path (полный ключ). Ключи -pages- дают пустые страницы, которые иначе потеряются. Типы элементов берутся из секции tree по имени.

Проход 2 - секция props. Реквизиты формы добавляются отдельной группой с source: "props", без path и parent - они не входят в визуальное дерево.

Если секция data отсутствует - парсер переключается на резервный разбор секции tree и помечает результат предупреждением.

 

Два кейса из demo-конфигурации

Я прогнал парсер на двух справочниках: «Номенклатура» с вложенными панелями и «Склады» с вложенными группами.

 

Кейс 1: вложенные Panel и страницы

Форма с ПанельВерхняя на корневой странице и ПанельВложенная внутри первой страницы внешней панели. Дерево из прогона:

 

 

Panel "ПанельВерхняя"
    Page "Страница1"
        Panel "ПанельВложенная"
            Page "Страница11"
                Field "Код", Field "Наименование", Field "Родитель", Field "Артикул"
                Label "НадписьКод", ...
            Page "Страница12" # пустая - из ключей -pages-
            Page "Страница13" # пустая - из ключей -pages-
    Page "Страница2"
        Panel "ПанельВложенная2"
            Page "Страница1" # одноимённый узел - коллизия!
                Label "Надпись1"

В form_elements_index элемент Код выглядит так:

{
    "name": "Код",
    "type": "Field",
    "parent": "Страница11",
    "parent_path": "Страница1/ПанельВерхняя/Страница1/ПанельВложенная/Страница11",
    "path": "Страница1/ПанельВерхняя/Страница1/ПанельВложенная/Страница11/Код",
    "page": "Страница11",
    "source": "data"
}

Страница1 в этой форме встречается на трёх уровнях. Без parent_path они неотличимы по имени:

path: "Страница1"
path: "Страница1/ПанельВерхняя/Страница1"
path: "Страница1/ПанельВерхняя/Страница2/ПанельВложенная2/Страница1"

path разрешает коллизию однозначно. Это, кстати, не экзотика - в реальных конфигурациях одноимённые страницы на разных уровнях встречаются регулярно.

 

Кейс 2: Group внутри страницы - и первый честный warning

 

Форма «Склады» с вложенными группами:

 

 

data-ключи:
    Страница1/РамкаГруппыОбщая
    Страница1/РамкаГруппыСлужебная # вложенная группа, но ключ плоский
    Страница1/НадписьКод
    Страница1/Код
    Страница1/НадписьНаименование
    Страница1/Наименование

Все элементы получают parent = "Страница1". Вложенность РамкаГруппыСлужебная внутри РамкаГруппыОбщая - в путях-ключах data не отражена. Она есть в raw/info-векторах каждого элемента: позиционные списки дочерних числовых id. Но raw - это недокументированный внутренний формат платформы 1С. Я посмотрел на эти векторы, подумал - и решил не трогать.

Не потому что лень, просто декодирование недокументированного формата - это и нестабильная зависимость и нарушение лицензионного соглашения 1С. Платформа обновится, формат сдвинется, парсер начнёт врать. Честный warning в индексе лучше нестабильной догадки.

Практическое правило: если агент спрашивает о вложенности групп - смотреть warnings. Если warnings содержит предупреждение о группах, иерархию групп использовать нельзя - только плоский список элементов страницы.

Граница достоверности

Узел формы Источник иерархии Результат Статус
Панели, страницы, включая пустые пути-ключи секции data полная цепочка, parent_path снимает коллизии достоверно
Группы и их вложенность только raw/info-векторы вложенность не реконструируется, parent указывает на страницу best-effort + warning

Это честная граница между тем, что можно получить из публичных артефактов распаковки, и тем, что требует декодирования недокументированного формата. Я рад, что обозначил её явно, а не «дореконструировал» и получил парсер, который ломается на следующем релизе платформы.

 

Сколько весит elem.json и почему это важно

На двух формах цифры такие:

Форма elem.json form_elements_index.json Сжатие Элементов
Номенклатура (панели) ~124 КБ ~10 КБ ~12x 24
Склады (группы) ~55 КБ ~3 КБ ~18x 10

Большую часть исходного файла занимают координаты, цвета, шрифты и GUID метаданных. Агенту это не нужно - он не рисует интерфейс.

Подавать elem.json в RAG целиком нецелесообразно: 124 КБ мусора съедают контекстное окно и ничего полезного не дают.

 

Что оставляет form_elements_index

Что нужно Зачем агенту
Имя элемента + тип понять, что есть на форме
path канонический адрес элемента внутри формы
parent, parent_path понять родителя, сгруппировать дочерние элементы
Привязка реквизита для Field к каким данным привязано поле
Имя обработчика для Button/Field связать элемент с кодом в Form.obj.bsl
page на какой вкладке находится элемент
source отличить элемент формы (data) от реквизита (props)

Формат индекса:

{
    "form": "Форма",
    "elements": [
        {
            "name": "Страница1",
            "type": "Page",
            "parent": null,
            "parent_path": null,
            "path": "Страница1",
            "page": null,
            "source": "data"
        },
        {
            "name": "КнопкаНаСтранице11",
            "type": "Button",
            "parent": "Страница11",
            "parent_path": "Страница1/ПанельВерхняя/Страница1/ПанельВложенная/Страница11",
            "path": "Страница1/ПанельВерхняя/Страница1/ПанельВложенная/Страница11/КнопкаНаСтранице11",
            "page": "Страница11",
            "source": "data",
            "handler": "КнопкаНаСтранице11Нажатие"
        },
        {
            "name": "ОбработкаОбъект",
            "type": "Unknown",
            "parent": null,
            "parent_path": null,
            "path": null,
            "page": null,
            "source": "props"
        }
    ]
}

Это третий артефакт формы после Form.obj.bsl и Form.json.

 

Что бы я сделал иначе

  • Сразу проверял бы наличие нескольких Template.bin под одним корнем. Пообъектный режим брал только первый - всплыло не сразу, потому что в памяти всё выглядело корректно. Пакетный режим стоило заложить с самого начала, не откладывать.

  • Путь записи skd_queries.json зафиксировал бы относительно корня отчёта сразу. Запись на уровень выше при пакетном обходе тихо перезаписывала результат предыдущего - обнаружил только при ручной проверке файлов. Это классическая ошибка, которую сложно заметить в логах.

  • Границу достоверности по группам обозначил бы явно с первого дня. Соблазн «дореконструировать» вложенность из raw велик - выглядит как простая задача. Но это декодирование недокументированного формата платформы. Честный warning лучше нестабильной догадки, которая ломается при обновлении.

  • Разделение data и props через поле source ввёл бы сразу. Без него реквизиты формы и визуальные элементы смешивались в одном списке, и агент не отличал одно от другого. Пришлось переделывать индекс.

 

Чек-лист для применения

  1. Для пакета отчётов вызывать extract_all_skd_queries, а не пообъектную функцию: один корень над несколькими Template.bin иначе даст только первый отчёт.

  2. Проверить, что skd_queries.json пишется внутрь директории каждого отчёта, а не на уровень выше.

  3. Трактовать СКД-шаг как best-effort: skd_extracted=False при extraction_ok=True - это сигнал о неполноте, а не авария.

  4. Строить form_elements_index из elem.json, а не подавать elem.json в RAG целиком: визуальные свойства раздувают файл в десятки раз и забивают контекстное окно.

  5. Использовать path как канонический адрес элемента; parent_path - для разрешения коллизий одноимённых страниц.

  6. Не доверять реконструкции вложенности групп: при отсутствии иерархии групп проверять warnings в индексе.

  7. Отличать элементы формы (source: "data") от реквизитов формы (source: "props") при индексации.

 

Что дальше

Два артефакта формы - Form.obj.bsl и form_elements_index - дают агенту и код, и структуру. Следующий шаг: связать имена обработчиков из индекса с процедурами в модуле и резолвить привязки реквизитов через Catalog.json.

 

Ссылки

Вступайте в нашу телеграмм-группу Инфостарт

LLM агент RAG v8unpack Form.bin Template.bin обычные формы агентный пайплайн СКД

Вы можете заказать платную адаптацию этой статьи под ваши задачи на «Бирже заказов».

  • 0% комиссии — оплата напрямую исполнителю;
  • Исполнители любого масштаба — от отдельных специалистов до команд под проект;
  • Прямой обмен контактами между заказчиком и исполнителем;
  • Безопасная сделка — при необходимости;
  • Рейтинги, кейсы и прозрачная система откликов.

См. также

Инструментарий разработчика Роли и права Запросы СКД Программист Руководитель проекта 1С:Предприятие 8 Платные (руб)

Инструменты для разработчиков 1С 8.3: Infostart Toolkit. Автоматизация и ускорение разработки на управляемых формах. Легкость работы с 1С.

16500 руб.

02.09.2020    264911    1477    421    

1175

Инструментарий разработчика Чистка данных Свертка базы Инструменты администратора БД Системный администратор Программист Руководитель проекта 1С:Предприятие 8 1С:ERP Управление предприятием 2 1С:Бухгалтерия 3.0 1С:Управление торговлей 11 1С:Комплексная автоматизация 2.х 1С:Управление нашей фирмой 3.0 Россия Платные (руб)

Инструмент представляет собой обработку для проведения свёртки или обрезки баз данных. Работает на ЛЮБЫХ конфигурациях (УТ, БП, ERP, УНФ, КА и т.д.). Поддерживаются серверные и файловые базы, управляемые и обычные формы, интерфейс 8.5. Может выполнять свертку одновременно в несколько потоков, а также без непосредственного участия пользователя. Решение в Реестре отечественного ПО.

24900 руб.

20.08.2024    73032    370    170    

320

Пакетная печать Печатные формы Инструментарий разработчика Программист 1С:Предприятие 8 Платные (руб)

Расширение для создания и редактирования печатных форм в системе 1С:Предприятие 8.3. Благодаря конструктору можно значительно снизить затраты времени на разработку печатных форм, повысить качество и прозрачность разработки, а также навести порядок в многообразии корпоративных печатных форм. Обновление версии от 21.04.26

22570 руб.

06.10.2023    39412    111    48    

125

Инструментарий разработчика Нейросети Платные (руб)

Первые попытки разработки на 1С с использованием больших языковых моделей (LLM) могут разочаровать. LLMки сильно галлюцинируют, потому что не знают устройства конфигураций 1С, не знают нюансов синтаксиса. Но если дать им подсказки с помощью MCP, то результат получается кардинально лучше. Далее в публикации: MCP для поиска по метаданным 1С, справке синтакс-помощника и проверки синтаксиса.

15250 руб.

25.08.2025    60244    124    36    

134

Инструментарий разработчика Разработка Администрирование веб-серверов Системный администратор Программист Бизнес-аналитик Руководитель проекта 1С 8.3 Платные (руб)

Analyzer 1C сводит выгрузку 1С — основную конфигурацию и все расширения — в единый граф знаний. Любой запрос по связям за доли секунды, с пометками «Доб.» / «Заимств.» / «Переопределено». Новое в 2.0 — обновление поставки: сравнение и объединение версий деревом «как в Конфигураторе» с выгрузкой плана решений; поиск конфликтов из-за перехватов расширений и висячих ссылок; загрузка из бинарных .cf/.cfe; циклические зависимости. Плюс анализ влияния, запросы BSL, роли и RLS, граф вызовов. Минута на развёртывание через Docker без необходимости подключения к Интернет. Любая 1С:Предприятие 8.3+.

14000 руб.

17.04.2026    7403    31    42    

45

Инструменты администратора БД Инструментарий разработчика Роли и права Программист 1С:Предприятие 8 1C:Бухгалтерия Россия Платные (руб)

Расширение позволяет без изменения кода конфигурации выполнять проверки при вводе данных, скрывать от пользователя недоступные ему данные, выполнять код в обработчиках. Не изменяет данные конфигурации, легко устанавливается практически на любую конфигурацию на управляемых формах.

17000 руб.

10.11.2023    26034    97    46    

104

Мастера заполнения Поиск данных Инструментарий разработчика Подбор и обработка объектов 1С 8.3 1С 8.5 Платные (руб)

Infostart MagicInput улучшает подбор в полях ввода 1С: ищет по любой части названия и по нескольким ключевым фрагментам, распознаёт ввод в другой раскладке и показывает иконки/статусы объектов прямо в списке. Поддерживает вставку навигационной ссылки/представления документа для автоподбора; для разработчиков доступны поиск по GUID и полному имени предопределённого. Работает в управляемых формах и подключается в большинстве конфигураций 1С 8.3/8.5.

6000 руб.

25.02.2026    4391    16    1    

20

Информационная безопасность Инструменты администратора БД Инструментарий разработчика Учет документов Системный администратор Программист Бизнес-аналитик Бухгалтер Пользователь Руководитель проекта 1С 8.3 1С 8.5 Розничная и сетевая торговля (FMCG) Платные (руб)

Контроль ввода данных в 1С: проверка заполнения реквизитов, обязательные поля, контроль перед записью и проведением, запрет проведения документа. Позволяет настраивать любые проверки данных в 1С 8.3/8.5 от обязательных полей до сложных условий – без открытия конфигуратора и написания кода. Готовое расширение, которое подключается и работает сразу.

6000 руб.

15.04.2026    2296    6    0    

21
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. ТочкаScarab 30.06.26 12:27 Сейчас в теме
@MRDK80 Вот спасибочки огромаднешее - продолжение подъехало! На гитхабе звёздочку поставил
2. MRDK80 4 30.06.26 18:29 Сейчас в теме
Спасибо!
ТочкаScarab; +1 Ответить
Для отправки сообщения требуется регистрация/авторизация