Files
scud_ai/docs/SCUD Orion AI — Полная энциклопедическая хроника, архитектурный паспорт и технический контекст (v4.0).md
T

223 lines
32 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# **SCUD Orion AI — Полная энциклопедическая хроника, архитектурный паспорт, разбор всех инцидентов и технический контекст проекта**
**Версия документа:** 4.0 (Исчерпывающий монолитный контекстный паспорт для новой сессии)
**Стек технологий и инфраструктура:** Python 3.11+, FastAPI (Uvicorn), SQLite (WAL mode, PRAGMA synchronous=NORMAL, внешние ключи ON), Ollama REST API (Qwen 2.5:14b — основной текстовый агент и классификатор, Qwen 2.5-VL:7b-q8\_0 / Qwen 3-VL:8b — OCR и зрение), MS SQL Server 2019/2022 (СКУД «Орион Pro» ЗАО НВП «Болид», 1С:ЗУП 3.1 через pyodbc / ODBC Driver 18), сетевая Samba-шара (/mnt/scud\_share), Git/Gitea, HTML5 / Vanilla JS / Tailwind CSS.
## ---
**1\. Исходный бизнес-контекст, роли систем и фундаментальные задачи**
Проект решает комплексную проблему контроллинга трудовой дисциплины, автоматического сопоставления кадровых фактов и защиты от рассинхронизации мастер-данных на предприятии со штатом \~270–276 сотрудников.
### **Источники первичных данных:**
> * **СКУД «Орион Pro» (Болид):** База данных MS SQL Server (SERVER: 172.16.31.221\\SQL, DB: Orion-14.01.21-1). Основные таблицы:
* pLogData — журнал всех сырых физических транзакций турникетов, калиток и внутренних дверей. Ключевые поля: TimeVal (время сервера), DeviceTime (время контроллера), HozOrgan / Hrk (ID сотрудника), Event (код события: 26, 28, 32 — вход; 27, 29, 33 — выход; 54, 55, 64, 65 — внутренние считыватели), Mode (направление: 1 — IN, 2 — OUT), ReaderIndex, DoorIndex.
* pList — реестр физических лиц и пропусков (ФИО, табельный номер, статус архива).
* PDivision, PPost — справочники подразделений и должностей СКУД.
> * **1С:ЗУП 3.1 (Кадры):** База данных MS SQL Server (SERVER: ACCOUNT-01, DB: ZUP30).
* dbo.\_Reference299 — эталонный справочник сотрудников.
* dbo.\_InfoRg16921 — периодический регистр сведений состояний сотрудников (отпуска основные, больничные, командировки, декретные отпуска, отпуска без сохранения оплаты).
* Файловые выгрузки с сетевой шары /mnt/scud\_share: файлы Штат\_ДД\_ММ\_ГГГГ.xlsx (шапка 7–8 строк) и Отсутствия\_ДД\_ММ\_ГГГГ.xlsx (шапка 3–4 строки).
> * **Реестры статических исключений:** static\_reason\_workers.csv (реестр удаленщиков и постоянных разъездных сотрудников), exceptions.json (декларативный фильтр обслуживающего персонала и спец-отделов).
## ---
**2\. Подробнейшая пошаговая хронология разработки, эволюция идей и разбор ошибок**
### **Фаза 1: Первые эксперименты с LLM, выявление галлюцинаций и гибридная парадигма**
> * **Попытка передачи сырых списков в чат:** Первоначальная попытка скормить модели Qwen 2.5:14b список из сотен ФИО с инструкцией *«запомни список 1С»* показала, что у LLM нет постоянной памяти между сессиями. Модель теряла контекст, путала фамилии и выдавала ответы с троеточиями ('Васильев Л.И.', ...) или придумывала несуществующие строки (*«ЛЕНМОРНИИПРОЕКТ ОЭС Варламова Мария»*).
> * **Ошибки openpyxl vs pandas:** Первая генерация кода моделью использовала библиотеку openpyxl с построчным перебором ячеек, жестко зашитыми опечатками (поиск слова 'фиио') и падением по FileNotFoundError.
> * **Переход к детерминированному пайплайну:** Принято ключевое архитектурное решение — **LLM не считает математику и не фильтрует 300 строк текста**. Всю механическую работу (ETL, слияние, фильтрацию) выполняет быстрый детерминированный Python (pandas, SQL), а локальная LLM выступает исключительно в роли «умного ревизора» на этапе сопоставления сомнительного несовпавшего остатка (Diff).
### **Фаза 2: Нормализация ФИО, кодировки и коллизия совместителей (Кейс Балаевой О.Г.)**
> * **Символьные ловушки:**
* Латинские буквы-двойники (омоглифы a, c, e, o, p, x, y, случайно набранные в английской раскладке).
* Служебные суффиксы в скобках, добавляемые 1С ((осн.), (совм.), (внешн.)).
* Буквы ё/е, двойные пробелы, неразрывные пробелы \\xa0 и случайный ввод цифры 0 вместо буквы О.
> * **Функция normalize\_fio():** Разработан строгий конвейер очистки:
> `def normalize_fio(fio):`
> `if not fio or not isinstance(fio, str): return ""`
> `fio_clean = re.sub(r'\(.*?\)', '', fio) # Удаление скобок`
> `fio_clean = fio_clean.replace('\xa0', ' ')`
> `trans = str.maketrans('aceopxyABCEHKMOPTX', 'асеорхуАВСЕНКМОРТХ')`
> `fio_clean = fio_clean.translate(trans)`
> `fio_clean = fio_clean.replace('ё', 'е').replace('Ё', 'Е')`
> `return " ".join(fio_clean.strip().split()).title()`
> * **Коллизия 270 vs 271:** В СКУД числилось 270 уникальных человек, а в 1С — 271 строка. Ручной разбор показал, что **Балаева Ольга Геннадьевна** занимает две ставки в 1С (*Руководитель управления персоналом* и *Руководитель режимно-секретного отдела*) при одном физическом пропуске в СКУД.
> * **Решение:** Внедрена обязательная группировка штата 1С по fio\_clean с объединением должностей и подразделений через " / ".
### **Фаза 3: Защита Entity Resolution от однофамильцев (Инцидент с Семеновыми)**
> * **Сбой модели:** При передаче несовпавших ФИО в Qwen 2.5 модель ошибочно сопоставила *«Семенову Юлию Борисовну»* (которая была на работе) с *«Семеновой Диной Дмитриевной»* (находившейся в отпуске), посчитав это опечаткой в имени из\-за одинаковой фамилии. В результате Юлия Борисовна получила статус нарушителя («в отпуске, но пришла»).
> * **Двухконтурная защита:**
1. В системный промпт ИИ зашито категорическое правило: однофамильцы с разными именами/отчествами — строго разные люди, объединение запрещено.
2. В Python встроен дублирующий барьер: если фамилии совпадают, но инициалы/первые буквы имен различаются, связь ИИ принудительно аннулируется с логированием ⚠️ \[Блокировка фейка\].
### **Фаза 4: Декларативные исключения и синонимы отделов**
> * **Переход к exceptions.json:** Исключение клининга, дворников, гардеробщиков и хозяйственного персонала отдела «ЭТО» вынесено из кода в конфигурационный файл exceptions.json (поддержка списков departments, positions, fio, position\_keywords).
> * **База синонимов отделов (department\_synonyms):** Для сопоставления сокращений СКУД с длинными названиями 1С (например, *«ОВК» ⟷ «Отдел внутреннего контроля»*) создана таблица SQLite, автоматически обучаемая при подтверждениях оператора.
### **Фаза 5: Аппаратный сбой СКУД 04.08.2026, разгадка «исчезающих неизвестных» и Первая активность**
> * **Анатомия сбоя:** Утром 04.08.2026 зависли регистраторы входа на главном КПП. У 119 сотрудников не записалось событие входа (time\_in \= 'Нет входа'). Из них 57 человек были официально закрыты документами 1С (отпуска, командировки). Оставшиеся \~74 человека реально пришли на работу, но утренней отметки не имели. Однако вечером сводка выдала всего 4–7 «неизвестных».
> * **Вскрытие механизма ошибки:** Было обнаружено, что скрипт агрегации видел дневные перемещения сотрудников (выходы на обед, считыватели туалетов, внутренние двери) и автоматически выставлял Статус \= 'Присутствовал' и is\_present \= 1\. Из-за этого люди попадали в категорию «Итого на работе», а массовый аппаратный сбой скрывался.
> * **Внедрение «Первой активности»:**
1. В базу данных и выгрузки Excel добавлена колонка **first\_activity («Первая активность»)** — минимальное время любого события дня в здании (MIN(TimeVal) AS FirstRawEvent без учета направления двери).
2. Если time\_in \== 'Нет входа', но first\_activity \!= '—', записи присваивается anomaly\_flag \= 'ANOMALY\_NO\_IN\_HAS\_ACTIVITY', а is\_present принудительно сбрасывается в 0\.
3. Внедрен модуль analyze\_scud\_mass\_failure\_ai(): при превышении порога в 5% смены (\>10 человек) ИИ поднимает тревогу о массовом сбое контроллеров КПП.
> * **Кейс Равина В.Э.:** Сотрудник находился в официальном отпуске, утреннего входа не имел, но пришел после обеда (первая активность 14:11:06, выход 17:18:38). Система корректно зафиксировала истинную кадровую аномалию (физическое присутствие при официальном отпуске).
### **Фаза 6: Архитектурная миграция под Gitea и система срезов (снапшотов)**
> * **Безопасный рефакторинг:** Монолит разделен на слои (core/, services/, scripts/, modules/web\_api/) через git mv с сохранением истории коммитов в ветке refactor/modular-structure.
> * **Формат ID снапшота:** Введена схема \[Y\]YYYYMMDD-NNN (например, Y20260804-001 для вчерашнего зафиксированного вечернего среза на 22:00 и 20260805-002 для дневного).
> * **Оптимизация экспорта:** Если в SQLite уже зафиксирован вчерашний срез с префиксом Y, повторный тяжелый SQL-запрос к СКУД Орион не выполняется (функция has\_yesterday\_final\_snapshot).
> * **Инспекция и CLI:** Написан инструмент scripts/db\_cli.py с командами stats, snapshots, scud, absences, anomalies, rules, prompts, tools, sessions, dump, snapshot del.
### **Фаза 7: Web API, Generative UI, управление памятью LLM и Topic Drift Guard**
> * **FastAPI & Безопасность:** Развернут Web API с JWT-авторизацией (bcrypt), изолированными задачами пользователей (tasks с привязкой к user\_id), гостевым режимом и ролевой моделью.
> * **Проблема деградации контекста LLM:** Вывод объемных списков задач, текстов системных промптов и таблиц снапшотов засорял контекстное окно чата, приводя к галлюцинациям и «залипанию» модели на старых правилах.
> * **Решение проблемы памяти (Topic Drift & Ephemeral Context):**
* В таблицу chat\_messages добавлен флаг is\_ephemeral \= 1 для временных сообщений.
* Введены двухфазные сессии (PROMPT\_PREVIEW → PROMPT\_FOLLOWUP) и детерминированный счетчик отвлечений idle\_turns.
* **Context Guard:** На 3-м шаге отвлечения оператора на сторонние темы система отвечает на вопрос и выводит интерактивное напоминание с кнопками \[Завершить настройку\] / \[Показать промпт\]. При idle\_turns \> 3 происходит автоочистка сессии вызовом db\_purge\_ephemeral\_messages().
* **Fast-Path:** Прямой перехват команд подтверждения («да», «подтверждаю», «сохранить») и выхода («нет, спасибо», «закончить настройку») без обращения к LLM (ответ за 0.05 сек).
* **Декларативный реестр действий (tool\_action\_registry):** Хранение шаблонов ответов, типов кнопок и признаков эфемерности в SQLite.
> * **Generative UI (Интерактивные карточки задач):** Инструмент db\_get\_tasks возвращает полезную нагрузку TASK\_INTERACTIVE\_CARD. Фронтенд рендерит живой виджет с табами (Все / В работе / В планах / Завершенные), чекбоксами и inline-созданием задач через REST API без вызова LLM.
## ---
**3\. Полная схема базы данных SQLite (data/scud\_orion\_ai.db)**
| Таблица | Назначение и бизнес-логика | Полная структура колонок |
| :---- | :---- | :---- |
| **scud\_logs** | Хранение логов проходов СКУД, расчетного времени и снапшотов. | id (PK), log\_date, fio, fio\_clean, department, position, time\_in, first\_activity, time\_out, time\_in\_building, is\_present, anomaly\_flag, snapshot\_time, snapshot\_id, created\_at |
| **zup\_staff** | Штатное расписание 1С:ЗУП на даты срезов. | id (PK), snapshot\_date, fio, fio\_clean, department, position, created\_at |
| **zup\_absences** | Официальные кадровые отклонения 1С (отпуска, больничные, командировки, декреты). | id (PK), absence\_date, fio, fio\_clean, absence\_type, created\_at |
| **anomalies\_history** | Журнал выявленных кадровых и аппаратных аномалий. | id (PK), anomaly\_date, fio, anomaly\_type, details, human\_status, created\_at |
| **ai\_knowledge\_base** | Глобальные правила арбитража и приоритеты компании для ИИ. | id (PK), rule\_text, added\_by, created\_at |
| **system\_prompts** | Версионные системные промпты агента (активный промпт по is\_active=1). | id (PK), name, prompt\_text, is\_active, updated\_at |
| **tool\_action\_registry** | Декларативный реестр шаблонов, кнопок и настроек эфемерности инструментов. | id (PK), tool\_name, category, bypass\_llm, success\_template, follow\_up\_question, action\_type, buttons\_json, is\_active, is\_ephemeral, updated\_at |
| **session\_states** | Активные состояния сессий, черновики и счетчик idle\_turns. | session\_id (PK), state\_type, pending\_data, updated\_at |
| **chat\_messages** | История диалогов с поддержкой разделения на постоянные и эфемерные сообщения. | id (PK), session\_id, role, content, is\_ephemeral, created\_at |
| **tasks** | Реестр задач пользователей с привязкой к user\_id. | id (PK), task\_id, module, title, priority, status, due\_date, user\_id, created\_at |
| **users** | Учетные записи операторов (хэши паролей bcrypt, права администратора). | id (PK), username, password\_hash, is\_admin, full\_name, created\_at |
| **department\_synonyms** | База знаний соответствия аббревиатур СКУД полным названиям отделов 1С. | id (PK), short\_name, full\_name, created\_at |
| **system\_reference** | Справочник команд и примеров промптов для операторов. | id (PK), category, title, example\_prompt, description |
## ---
**4\. Актуальная архитектура каталогов и назначение файлов**
`scud_ai/`
`├── config.py # Конфигурация: пути, расчет дат, URL Ollama, параметры MS SQL`
`├── exceptions.json # Декларативные фильтры исключений (ОВК, уборщики, подрядчики)`
`├── main_etl.py # Оркестратор ETL: экспорт СКУД/1С -> SQLite -> Excel/MD отчеты`
`├── project_code_snapshot.md # Полный исходный код всех файлов репозитория`
`├── core/`
`│ └── database.py # Драйвер SQLite (WAL), функции сохранения/загрузки срезов`
`├── services/`
`│ ├── scud_export.py # Прямой SQL-экспорт из MS SQL «Орион Pro»`
`│ ├── zup_extractor.py # Прямой SQL-экспорт из MS SQL 1С:ЗУП 3.1`
`│ ├── data_loader.py # Загрузка данных, нормализация ФИО, расчет первой активности`
`│ ├── data_validator.py # Проверка свежести и наличия файлов за Вчера и Сегодня`
`│ ├── excel_exporter.py # Генерация сводки и детального отчета в Excel (openpyxl)`
`│ ├── text_reporter.py # Построение итогового Markdown-отчета через Qwen 2.5`
`│ ├── ai_verifier.py # Модули ИИ-аудита, Fuzzy Matching и детекции сбоев СКУД`
`│ ├── feedback_loop.py # Интерактивный консольный модуль Human-in-the-Loop`
`│ ├── knowledge_base.py # Интерфейс работы с базой знаний правил`
`│ └── share_copier.py # Резервное скачивание файлов 1С с шары /mnt/scud_share`
`├── scripts/`
`│ ├── db_cli.py # CLI-утилита управления БД, снапшотами, дампами и сессиями`
`│ ├── fix_snapshots.py # Скрипт переиндексации и нормализации снапшотов`
`│ ├── init_tool_registry.py # Инициализация декларативного реестра инструментов`
`│ └── diagnostics/`
`│ ├── inspect_db.py # Диагностика структуры таблиц и количества записей`
`│ ├── inspect_ephemeral.py # Анализ распределения постоянных и эфемерных сообщений`
`│ ├── inspect_files.py # Аудит файлов и размеров на диске`
`│ └── show_tree.py # Вывод дерева каталогов`
`├── modules/web_api/`
`│ ├── main.py # Точка входа FastAPI приложения, роутеры и раздача статики`
`│ ├── routers/`
`│ │ ├── admin.py # Управление пользователями`
`│ │ ├── auth.py # JWT аутентификация и смена паролей`
`│ │ ├── chat.py # Эндпоинты диалогов (авторизованный и гостевой)`
`│ │ └── tasks.py # REST API управления задачами`
`│ ├── llm/`
`│ │ ├── agent.py # Координатор диалога, Tool Calls и Topic Drift Guard`
`│ │ ├── schemas.py # Описание JSON-схем инструментов для Ollama`
`│ │ ├── file_parser.py # Мультимодальный парсер файлов (PDF, PNG, XLSX, TXT)`
`│ │ ├── db_tools.py # Фасадные вызовы функций БД для агента`
`│ │ ├── core/`
`│ │ │ ├── calendar_utils.py # Формирование системного контекста дат и дней недели`
`│ │ │ ├── fast_path.py # Быстрый перехват команд подтверждения/отмены (0.05 с)`
`│ │ │ ├── ollama_client.py # HTTP-клиент взаимодействия с Ollama API`
`│ │ │ ├── prompt_merger.py # Парсинг и слияние правок системного промпта`
`│ │ │ └── tool_injector.py # Очистка сырых тегов и артефактов Tool Calls`
`│ │ └── db/`
`│ │ ├── connection.py # Подключение к scud_orion_ai.db`
`│ │ ├── db_chat.py # Сохранение истории и очистка эфемерных сообщений`
`│ │ ├── db_prompts.py # Системные промпты, стейты и реестр действий`
`│ │ ├── db_snapshots.py # Выборка и удаление снапшотов`
`│ │ └── db_tasks.py # CRUD операции с задачами пользователей`
`│ └── static/`
`│ ├── index.html # SPA разметка (модалки, чат, боковая панель задач)`
`│ ├── css/styles.css # Стили и мобильные оптимизации`
`│ └── js/`
`│ ├── app.js # Инициализация приложения`
`│ ├── auth.js # Логика входа, смены паролей и администрирования`
`│ ├── chat.js # Обработка сообщений, Drag&Drop, виджет задач и кнопки`
`│ └── tasks.js # Управление боковой панелью задач (Drawer)`
`└── docs/`
`└── development_roadmap.md # Стратегическая дорожная карта и архитектурный бэклог`
## ---
**5\. Справочник команд командной строки (CLI Reference)**
### **Главный конвейер контроллинга (main\_etl.py)**
> * python main\_etl.py — стандартный дневной запуск: экспорт свежих данных СКУД и 1С, сохранение снапшота в SQLite, генерация Excel и Markdown отчетов.
> * python main\_etl.py \--skip-export — построение отчетов по последнему имеющемуся снапшоту из SQLite без повторного запроса к MS SQL.
> * python main\_etl.py \--snapshot 20260805-001 — точный расчет отчетов по указанному составному ID снапшота.
> * python main\_etl.py \-d — запуск в режиме расширенной отладки (DEBUG).
### **CLI-утилита управления SQLite базой данных (scripts/db\_cli.py)**
> * python scripts/db\_cli.py stats — общая статистика количества записей по всем таблицам БД.
> * python scripts/db\_cli.py snapshots \[ДД.ММ.ГГГГ\] — просмотр реестра снапшотов с сортировкой по времени создания (самые свежие сверху).
> * python scripts/db\_cli.py scud \[ДД.ММ.ГГГГ\] \[--snapshot ID\] \[--export-xlsx NAME\] — просмотр логов СКУД и опциональный экспорт в Excel.
> * python scripts/db\_cli.py absences \[ДД.ММ.ГГГГ\] — список кадровых отклонений из 1С:ЗУП.
> * python scripts/db\_cli.py anomalies — история выявленных аномалий.
> * python scripts/db\_cli.py rules — правила базы знаний компании.
> * python scripts/db\_cli.py prompts — просмотр системных промптов из таблицы system\_prompts.
> * python scripts/db\_cli.py tools — вывод декларативного реестра действий инструментов и шаблонов кнопок.
> * python scripts/db\_cli.py sessions — просмотр активных сессионных стейтов и висящих черновиков.
> * python scripts/db\_cli.py snapshot del \[ID\] — удаление конкретного снапшота по ID.
> * python scripts/db\_cli.py snapshot del \--day \[ДД.ММ.ГГГГ\] — удаление всех снапшотов за выбранный день.
> * python scripts/db\_cli.py dump \[backup.xlsx\] — полный дамп всех таблиц базы данных в многостраничный Excel-файл.
## ---
**6\. Стратегическая дорожная карта развития (Roadmap & Backlog)**
> 1. **Масштабирование механизма эфемерного контекста на все инструменты (Rollout Roadmap):**
* **Снапшоты (snapshots):** Перевод вывода объемных таблиц срезов в эфемерный режим (is\_ephemeral \= 1), внедрение интерактивного подтверждения при удалении снапшотов по ID/дате через состояния SNAPSHOTS\_PREVIEW / SNAPSHOTS\_FOLLOWUP.
* **База знаний и аномалии (kb & anomalies):** Вывод справочников команд, правил арбитража и списков аномалий исключительно во временный слой для исключения «залипания» модели на устаревших правилах из истории сообщений.
* **Декларативная унификация в tool\_action\_registry:** Расширение схемы таблицы полями followup\_state\_type, auto\_purge\_on\_exit, guard\_question\_template для устранения хардкода имен функций в agent.py.
> 2. **Модуль анализа внутридневных перемещений («Контроль перекуров»):**
* Анализ интервалов между событиями OUT (выход) и IN (возврат) по журналу pLogData.
* Подсчет суммарного времени нахождения вне рабочего места в течение смены с отсечением технологической нормы (30–40 минут).
* Вывод аналитического блока и злостных нарушителей в отдельный лист Excel-отчета и итоговую Markdown-сводку.
> 3. **Интерактивный Task Planner & Roadmap Engine:**
* Специализированный инструмент для ведения динамических проектных планов и чек-листов с чекбоксами (\[ \] / \[x\]) прямо в диалоге с синхронизацией в таблицу tasks.
> 4. **Изолированная среда исполнения кода (Code Execution Sandbox):**
* Безопасный изолированный Docker/gVisor контейнер для динамического выполнения генерируемого моделью Python/Pandas кода на лету с возвратом stdout/stderr и графиков в контекст.
> 5. **Автоматизация расписания срезов и Telegram-алерты:**
* Автозапуск выгрузок в 12:00, 17:00 и 19:00 через systemd-таймеры с фиксацией snapshot\_time.
* Отправка мгновенных алертов о массовых сбоях турникетов (\>5%) и критических кадровых конфликтах дежурному системному администратору в Telegram.