СКД и дерево элементов обычной формы 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С:ERP Управление предприятием 2 1С:Бухгалтерия 3.0 1С:Управление торговлей 11 1С:Комплексная автоматизация 2.х 1С:Управление нашей фирмой 3.0 Россия Платные (руб)

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

24900 руб.

20.08.2024    75108    379    170    

325

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

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

10000 руб.

02.09.2020    268404    1494    421    

1179

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

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

22570 руб.

06.10.2023    40170    113    54    

126

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

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

15250 руб.

25.08.2025    63783    130    36    

137

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

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

14000 руб.

17.04.2026    8917    38    46    

51

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

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

17000 руб.

10.11.2023    26429    98    46    

104

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

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

6000 руб.

15.04.2026    2625    6    0    

21

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

Инструмент для написания и отладки кода в режиме «1С:Предприятие». Представляет собой консоль кода с возможностью пошаговой отладки, просмотра значений переменных любых типов, использования процедур и функций, просмотра стека вызовов, вычисления произвольных выражений на встроенном языке в контексте точки останова, синтаксического контроля и остановки по ошибке. В консоли используется удобный редактор кода с подсветкой, контекстной подсказкой, возможностью вызова конструкторов запроса и форматной строки. 1.3.11 Доработан механизм контекстной подсказки по метаданным

9500 руб.

17.05.2024    54772    187    63    

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