Files
contracts/History/llm-analysis/opus-zip-plan-analysis.md

152 lines
11 KiB
Markdown
Raw Permalink 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.
# Анализ ответа Опуса — 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.