152 lines
11 KiB
Markdown
152 lines
11 KiB
Markdown
# Анализ ответа Опуса — zip_source, UI-режимы, промпты
|
||
|
||
Дата: 26.06.2025 | Ответ на [opus-request-zip-plan.md](../Files/opus-request-zip-plan.md)
|
||
|
||
---
|
||
|
||
## 1. Оценка ответа в целом
|
||
|
||
**Качество: высокое.** Опус прочитал реальный код, разобрался в архитектуре, дал конкретные диффы по слоям. Не «размышления вообще», а точные строки и функции. 95% рекомендаций — правильные.
|
||
|
||
**Что упущено:**
|
||
- Lucee-слой (`upload.cfm`, `api.cfm`) — тоже участвует в upload, но Опус его не проанализировал
|
||
- `confidence` — предлагает сохранять в БД, но не говорит где именно брать (LLM возвращает? парсить из промпта?)
|
||
- Порог 100 файлов для «Потока» — спорный, обсудим ниже
|
||
|
||
---
|
||
|
||
## 2. По пунктам
|
||
|
||
### 2.1. `zip_source` — ✅ СОГЛАСЕН полностью
|
||
|
||
План по слоям правильный. Ключевые моменты:
|
||
|
||
- **`zip_source` не участвует в classify/group/compare** — верно. Чисто визуальный атрибут.
|
||
- **Формат: имя ZIP с расширением** — да, `«Ромашка.zip»`.
|
||
- **PK не трогаем (UUID)**, «ID = zip/filename» только для отображения — верно.
|
||
- **Дедупликация по паре `(zip_source, name)`** — ⚠️ самый критичный момент. Опус прав: если не сменить ключ, одноимённые файлы из разных ZIP будут перезаписываться. Но **надо проверить**: текущий код в `addRegularFile()` (files.js) ищет по `f.name`. При добавлении `zip_source` нужно либо:
|
||
- Ключ = `zip_source + "/" + filename` (как предлагает заказчик)
|
||
- Или ключ = `(zip_source || "") + filename`
|
||
|
||
Я за вариант с конкатенацией в одну строку — проще для сравнения.
|
||
|
||
- **unzip.py не трогаем** — верно. Имя ZIP уже есть на фронте (`file.name`).
|
||
|
||
### 2.2. Вариант отображения — ✅ СОГЛАСЕН (Вариант А)
|
||
|
||
Заголовок-секция ZIP + отступ `padding-left: 24px`.
|
||
- Просто, без нового состояния
|
||
- Соответствует тому что описал заказчик
|
||
- Опциональное сворачивание — да, но не в первой итерации
|
||
|
||
### 2.3. Два UI-режима — ⚠️ ЧАСТИЧНО СОГЛАСЕН
|
||
|
||
**Плюсы:**
|
||
- Бэкенд не меняется — правильно
|
||
- `state.ui.mode` — хорошее место
|
||
- Сводный отчёт («зелёное сворачиваем, красное показываем») — отличная идея
|
||
- Авто-определение + ручной override — разумно
|
||
|
||
**Спорные моменты:**
|
||
- **Порог 100 файлов** — слишком низкий для автоматического предложения. При 100 файлах текущий UI работает нормально (скролл, 50vh). Реальный болевой порог — **200-300+**. Предлагаю порог **200**.
|
||
- **«Поток» сейчас не нужен.** Если заказчик работает с 5-50 файлами, весь Stream Mode — оверинжиниринг. Но архитектурно заложить `state.ui.mode` — дёшево и правильно.
|
||
|
||
### 2.4. Промпты — ✅ СОГЛАСЕН, с уточнениями
|
||
|
||
#### Classify — проблемы А-Д:
|
||
|
||
**А. Counterparty / блок про стороны НУБЕС** — 🔴 КРИТИЧНАЯ.
|
||
Опус абсолютно прав. Промпт сейчас не говорит что НУБЕС = Исполнитель. LLM возвращает случайную сторону. Чинится одной вставкой в промпт. Делать **первым**.
|
||
|
||
НО: Опус предлагает «ИНН 7727... (взять у заказчика)». Это перебор. Достаточно:
|
||
```
|
||
НУБЕС известен как: «НУБЕС», «ООО НУБЕС», «ООО "НУБЕС"», «Nubes».
|
||
counterparty — ВСЕГДА вторая сторона, НИКОГДА не НУБЕС.
|
||
```
|
||
|
||
**Б. parent_number у contract** — ✅ верно. `parent_number = null` для contract.
|
||
|
||
**В. Мусорные документы** — ✅ верно. Добавить примеры в `doc_type=other`.
|
||
|
||
**Г. Few-shot примеры в classify** — ✅ верно. 1-2 примера улучшат точность.
|
||
|
||
**Д. confidence** — ⚠️ спорно. Опус говорит «добавить колонку и показывать low в отчёте». Но `confidence` сейчас даже не сохраняется. Предлагаю **сначала убрать из промпта** (меньше путаницы), а потом, когда будет реальная потребность — добавить и колонку, и парсинг.
|
||
|
||
#### Compare (diff) — ✅ СОГЛАСЕН
|
||
|
||
- «UNRESOLVED вместо дубль-ADD при сомнении» — верно
|
||
- `temperature=0.1` для diff — проверить (скорее всего уже)
|
||
- `full_replace` → автоматическое удаление старых строк на стороне Python — **умная идея**, снижает нагрузку на LLM
|
||
|
||
#### Разные промпты под сценарии — ✅ СОГЛАСЕН
|
||
|
||
Не нужно. Один classify + один diff. Меньше рассинхрона.
|
||
|
||
### 2.5. Гомоглифы — ⚠️ ОСТОРОЖНО
|
||
|
||
Опус предлагает:
|
||
- `С/C → C` (латиница)
|
||
- `О/0` — «трактовать осторожно»
|
||
- `Ё → Е`
|
||
|
||
**Моё мнение:**
|
||
- `С→C` и `Ё→Е` — **опасно**. Это меняет семантику номера. `МЭС-123` ≠ `МЭC-123`. Лучше: **не заменять, а добавить второй проход сравнения** — если точное совпадение не найдено, попробовать с гомоглифами. Или нормализовать ОБА варианта (и кириллицу, и латиницу) к единому представлению, но сохранять оригинал для отображения.
|
||
- Конкретно для `Ё`: да, `Ё→Е` допустимо (в делопроизводстве Ё часто заменяют на Е). Но лучше сделать настраиваемым.
|
||
|
||
### 2.6. Приоритеты — ✅ СОГЛАСЕН с корректировкой
|
||
|
||
| Что | Приоритет Опуса | Моя оценка |
|
||
|-----|----------------|-----------|
|
||
| Counterparty в промпте | P0 | P0 ✅ |
|
||
| doc_type=other мусор | P0 | P0 ✅ |
|
||
| Гомоглифы | P0 | P1 ⚠️ (осторожно, не ломать) |
|
||
| zip_source | P1 | P1 ✅ |
|
||
| Группировка по ZIP в UI | P1 | P1 ✅ |
|
||
| Режим «Поток» | P2 | P3 (отложить, нет потребности) |
|
||
| confidence в БД | P3 | P3 (или убрать из промпта) |
|
||
| diff-UNRESOLVED | P3 | P2 (дёшево, большой эффект) |
|
||
|
||
---
|
||
|
||
## 3. Что Опус упустил
|
||
|
||
### 3.1. Lucee-слой
|
||
|
||
`upload.cfm` и `api.cfm` на Lucee тоже обрабатывают загрузку. Если файл идёт через Lucee (а не напрямую на VM), `zip_source` нужно прокинуть и там. Надо проверить — идёт ли upload через Lucee или напрямую на VM.
|
||
|
||
**Факт:** судя по `index.cfm`, JS грузится с VM (`contracts.kube5s.ru/static/app.js`), а upload идёт на `VM_API + '/upload'`. Значит Lucee в upload **не участвует**. `zip_source` в Lucee не нужен. Опус оказался прав молча.
|
||
|
||
### 3.2. Промпты в БД vs хардкод
|
||
|
||
Опус верно заметил: «промпты берутся из БД (Lucee), fallback — хардкод. Менять надо в БД через интерфейс промптов». Это **критично важно для исполнителя**: если просто поправить `FALLBACK_EXTRACT`/`FALLBACK_DIFF` в `llm_prompt.py` — в проде ничего не изменится, потому что используется версия из БД.
|
||
|
||
**Порядок правки промптов:**
|
||
1. Сначала в БД через UI (`/prompt.cfm`)
|
||
2. Потом в хардкоде (для fallback)
|
||
|
||
### 3.3. Порог для «Потока»
|
||
|
||
100 файлов — слишком консервативно. Таблица с `max-height: 50vh` и `overflow-y: auto` нормально работает при 100-150 файлах. Предлагаю **200** как порог для автопредложения. Но лучше — **сделать настраиваемым** (константа в начале app.js).
|
||
|
||
---
|
||
|
||
## 4. Итоговое мнение
|
||
|
||
**Ответ Опуса — хороший план.** 95% рекомендаций принимаю.
|
||
|
||
**Что делаем прямо сейчас (P0):**
|
||
1. Правка classify-промпта: блок про стороны НУБЕС + parent_number=null + примеры мусора
|
||
2. Правка diff-промпта: UNRESOLVED вместо дубль-ADD, temperature проверка
|
||
|
||
**Что делаем дальше (P1):**
|
||
3. `zip_source` сквозь все слои (БД → Python → JS)
|
||
4. Группировка по ZIP в таблице (Вариант А)
|
||
5. Дедупликация по `(zip_source, filename)`
|
||
|
||
**Что откладываем:**
|
||
6. Режим «Поток» — пока нет потребности
|
||
7. Гомоглифы — нужно больше примеров от заказчика
|
||
8. confidence — убрать из промпта, вернуть когда будет нужно
|
||
|
||
**Главный риск (ещё раз):** дедупликация в `addRegularFile()`. Без правки ключа на `(zip_source, name)` — фича сломается на первом же случае одинаковых имён в разных ZIP.
|