Из отчёта по хвостам обогащения — в ранжированный портфель проверяемых гипотез.
С деньгами, трассировкой до ячейки исходного xlsx и воспроизводимым хешем.
Система читает реальный отчёт фабрики (xlsx), ставит диагноз потерь металла, достаёт механизмы из корпуса литературы и детерминированно собирает портфель гипотез: что изменить, сколько это даст в долларах за год, откуда это следует и как это проверить экспериментом.
Это не чат с ИИ. Диагноз ставит детерминированный парсер. Гипотезы находит детерминированный алгоритм на графе знаний. LLM работает только на чтении литературы — и может быть выключен целиком, демо от этого не сломается.
xlsx хвостов ──► диагноз потерь ──┐
PDF корпус ──► claims + граф ──┼──► discovery engine ──► портфель гипотез
YAML pack ──► доменная логика ──┘ (Rust, 5 операторов) $/год + trace + DOE
| Воспроизводимость | те же данные + KPI + pack → байт-в-байт тот же результат, подтверждённый snapshot-хешем |
| Объяснимость | каждое число кликается до ячейки исходного отчёта (cell_ref) или страницы учебника |
| LLM не решает | диагноз, гипотезы, ранжирование и экономика — детерминированный код, не генерация |
| Смена домена = смена YAML | движок не знает слов «флотация» и «гидроциклон»; есть flotation-v1 и metallurgy-v1 |
| Встроенная валидация | 27 гипотез реальных экспертных мозговых штурмов по 4 фабрикам используются как ground truth |
docker compose up --build # или: make up| Сервис | Адрес |
|---|---|
| Frontend | http://localhost |
| Backend API | http://localhost:8080 |
| Sidecar API | http://localhost:8766 |
Стек поднимается без .env, без LLM-ключей и без Postgres — ровно для того,
чтобы проверяющий не тратил время на конфигурацию. Live-режим включается отдельно:
скопируйте agent-system/.env.example → agent-system/.env, задайте OPENAI_API_KEY
или Yandex-credentials и SIDECAR_LLM_ENABLED=true. RAG на Postgres/pgvector —
опциональный профиль rag в compose.yaml.
make up поднять стек в фоне (с пересборкой)
make smoke smoke-проверка API: прогон КГМК, benchmark, экспорт
make front только UI в фикстурном режиме (:5173, без бэкенда)
make rag-up стек вместе с Postgres/pgvector
make logs хвост логов всех сервисов
make down остановить, make clean — снести с volume'ами
make help полный список
# полный прогон по конфигу фабрики
curl -sS -XPOST http://localhost:8080/run \
-H 'content-type: application/json' \
-d '{"factory_id":"kgmk","pack_id":"flotation-v1"}'
# «скрытая» фабрика — система её не видела, подан только файл
curl -sS -XPOST http://localhost:8080/run \
-H 'content-type: application/json' \
-d '{"factory_id":"hidden_nof_med","pack_id":"flotation-v1","source_file":"norn-hack/Пример 3/Хвосты НОФ мед.xlsx"}'1. Диагноз потерь — якорный парсер xlsx (Python, без LLM). Устойчив к плавающей
структуре, битым ячейкам #REF! и секциям породных/пирротиновых хвостов; проверен
на всех 4 фабриках кейса. Для каждой ячейки: тонны, извлекаемость и причина по
правилам из pack — закрытые сростки в крупных классах → недоизмельчение, раскрытый
минерал в −10 мкм → переизмельчение, силикаты → неизвлекаемо. Проблемы данных не
прячутся, а выносятся в панель Data Readiness.
2. Извлечение знаний — корпус PDF режется на чанки с номерами страниц, LLM под
строгим Pydantic-валидатором достаёт claims вида рычаг → механизм → эффект с
полярностью и постраничной ссылкой. Entity Resolver сводит синонимы
(гидроциклон = циклон = ГЦ-660) через словарь pack и fuzzy matching.
3. Граф знаний (Rust) — из claims строится рычаг → механизм → диагноз → KPI;
диагноз-узлы получают тоннаж из шага 1, рычаги — признак доступности из конфига
фабрики. Граф фиксируется снапшотом с хешем: это и есть граница воспроизводимости.
4. Discovery Engine (Rust, детерминированный) — пять операторов, не знающих о флотации: работают с типами рёбер и тегами.
| Оператор | Что ищет | Пример гипотезы |
|---|---|---|
mechanism_path |
путь от KPI через диагноз с тоннажом до доступного рычага | «замени насадки ГЦ 12→8» |
substitution |
альтернативный рычаг с тем же механизмом | «грохот вместо гидроциклона» |
gap |
диагноз с тоннажом, но без доступного рычага | «нужна магнитная сепарация» |
contradiction |
claims с противоположным эффектом | «найди граничное условие» |
analogy_transfer |
механизм из смежного передела без переноса | «примени приём из Cu-цикла» |
5. Оценка в деньгах, а не в баллах — адресуемые тонны × консервативный диапазон прироста извлечения (из литературы, с trace) × цена металла = $/год диапазоном,
с раскрытыми допущениями. Поверх — скоринг по 6 осям (kpi_impact, evidence,
plausibility, cost, risk, novelty), хард-фильтры по capex и доступности
оборудования, skeptic-rules на слабые места.
6. Benchmark — сколько экспертных гипотез система воспроизвела и что нашла сверх них. Плюс live-прогон на фабрике, которой не было в конфигах: меняется один YAML.
7. Управление портфелем — структурированные действия (exclude_factor,
change_weight, add_constraint, relax_constraint, change_price): исключить
рычаг, поменять цену металла — пересчёт за секунды с подсветкой изменений,
snapshot-hash при этом не плывёт.
| Каталог | Что внутри |
|---|---|
frontend/ |
React + Vite + TypeScript UI за nginx. Heatmap диагноза, портфель, карточка гипотезы, trace-view, benchmark. README |
backend/ |
Rust: contracts (общие структуры), engine (discovery + scoring), platform (axum API). README |
agent-system/ |
Python FastAPI-сайдкар: диагностика xlsx, извлечение, эмбеддинги, constraints. README |
docs/ |
Контракты, фикстуры, packs, factories, демо-документы, презентация |
norn-hack/ |
Кейс-файлы (xlsx/docx) четырёх фабрик для /diagnose |
Источник правды по правилам разработки — docs/AGENTS.md, описание решения целиком — docs/SOLUTION.md, архитектура — docs/ARCHITECTURE.md.
Backend — :8080, Rust/axum
| Метод | Путь | Назначение |
|---|---|---|
POST |
/run |
полный прогон: диагноз → граф → портфель |
POST |
/rerun |
пересчёт портфеля без повторного extraction |
GET |
/board |
текущий портфель гипотез |
GET |
/hypothesis/:id |
карточка гипотезы целиком |
GET |
/trace/:id |
цепочка происхождения до источника |
GET |
/benchmark |
сравнение с экспертными гипотезами |
GET |
/data_readiness |
качество входных данных |
GET |
/expert_hypotheses |
ground truth мозговых штурмов |
GET |
/factories, /library, /roadmap |
конфиги фабрик, корпус, план |
POST |
/constraints/parse, /skeptic, /narrate, /novelty |
вспомогательные операции |
GET |
/export/board.csv, /export/board.json |
выгрузка портфеля |
Sidecar — :8766, Python/FastAPI
| Метод | Путь | Назначение |
|---|---|---|
POST |
/diagnose |
якорный парсер xlsx → loss_cells с тоннажом и cell_ref |
POST |
/extract |
claims по Pydantic-схеме (LLM или mock-фикстуры) |
POST |
/embed, /retrieve |
эмбеддинги и поиск по корпусу |
POST |
/parse_constraints |
естественный язык → структурные ограничения |
POST |
/skeptic, /narrate, /novelty |
разбор рисков, нарратив, оценка новизны |
GET |
/health |
статус и текущий режим (mock/live) |
Rust (axum, petgraph) · Python 3 (FastAPI, Pydantic, openpyxl) · TypeScript (React, Vite,
TanStack Query) · Docker Compose · опционально Postgres + pgvector и LLM-провайдер
(OpenAI-совместимый или Yandex).
Сделано на хакатоне «Норникель». Большие PDF и лишние локальные данные намеренно вынесены из репозитория — закоммиченных фикстур и малых xlsx/docx хватает на полный демо-путь.