136 lines
5.3 KiB
Markdown
136 lines
5.3 KiB
Markdown
# Диалог DeepSeek ↔ Opus — Decoupling пайплайна
|
||
|
||
Дата: 28.06.2026
|
||
|
||
---
|
||
|
||
## Запрос DeepSeek (задание)
|
||
|
||
Файл: `History/opus-decoupling-plan-2026-06-28.md`
|
||
|
||
5 блоков, интерактивный режим:
|
||
1. Модульность пайплайна — контракты между стадиями
|
||
2. Интеграционное тестирование (fixture-based)
|
||
3. Деплой и синхронизация
|
||
4. Перспектива переезда на managed Flask
|
||
5. Вопросы к заказчику
|
||
|
||
---
|
||
|
||
## Ответ Opus — 5 развилок
|
||
|
||
### Вопрос 1. Граница decoupling
|
||
Варианты:
|
||
- A. Единый интерфейс пайплайна (контракт оркестратора)
|
||
- B. Изолировать только внешние зависимости (LLM, БД)
|
||
- C. И то, и другое
|
||
|
||
**Рекомендация Opus:** C
|
||
|
||
### Вопрос 2. База данных в тестах
|
||
Варианты:
|
||
- A. Абстрагировать репозиторий за интерфейсом → in-memory заглушка
|
||
- B. Реальный Postgres в Docker/testcontainers
|
||
- C. Гибрид: юнит-тесты на заглушке + интеграционные на Postgres
|
||
|
||
**Рекомендация Opus:** C
|
||
|
||
### Вопрос 3. Мокирование LLM
|
||
Варианты:
|
||
- A. DI — LLM-клиент через зависимость
|
||
- B. Мокать на уровне httpx-транспорта
|
||
- C. Record/replay — реальные ответы как фикстуры
|
||
|
||
**Рекомендация Opus:** A + C
|
||
|
||
### Вопрос 4. Тестовый фреймворк
|
||
Варианты:
|
||
- A. pytest + папка tests/ + conftest
|
||
- B. Только smoke-тесты
|
||
- C. Полное покрытие
|
||
|
||
**Рекомендация Opus:** A → C поэтапно
|
||
|
||
### Вопрос 5. Деплой
|
||
Варианты:
|
||
- A. Не трогать, отдельная задача
|
||
- B. Заодно привести sync.sh/systemd
|
||
- C. Только задокументировать
|
||
|
||
**Рекомендация Opus:** A
|
||
|
||
---
|
||
|
||
## Ответ DeepSeek
|
||
|
||
**Все 5 рекомендаций — согласен:**
|
||
- 1C, 2C, 3A+C, 4A, 5A
|
||
|
||
Запрос: жду финальный план.
|
||
|
||
---
|
||
|
||
## Ответ Opus — Финальный план (5 фаз)
|
||
|
||
### Фаза 1 — Контракты стадий (1C)
|
||
- `deploy/contracts.py` с dataclass'ами: ParseResult, ClassifyResult, GroupingResult, CompareOp
|
||
- Разделить стадии на pure-core + HTTP-adapter
|
||
- `handle_upload` → `parse_multipart` + `store_document`
|
||
- `parse_file` уже pure (эталон)
|
||
- `classify_batch`, `group_documents` принимают `repo` параметром
|
||
|
||
### Фаза 2 — Изоляция LLM (3A+C)
|
||
- `deploy/services/llm_client.py`: протокол `LLMClient.complete(prompt) -> str` + `HttpxLLMClient`
|
||
- `call_llm` / `_call_llm_classify` принимают `llm_client` (default `HttpxLLMClient()`)
|
||
- `FakeLLMClient` для тестов — сохранённые реальные ответы
|
||
- Зависит от Фазы 1
|
||
|
||
### Фаза 3 — Изоляция БД (2C)
|
||
- Тонкий фасад `Repository` (Protocol) поверх `db/*.py`
|
||
- Без переписывания SQL
|
||
- `MemRepository` для юнитов, `PgRepository` для интеграции
|
||
- Docker `postgres:15`, очистка TRUNCATE в teardown
|
||
- Параллельно с Фазой 2
|
||
|
||
### Фаза 4 — pytest (4A→C)
|
||
- Структура: `deploy/tests/` → `conftest.py`, `fixtures/`, `unit/`, `integration/`
|
||
- Фикстуры: `fake_llm`, `mem_repo`, `pg_repo`, `sample_docx`
|
||
- Порядок: smoke per-stage → полное покрытие → сквозной прогон
|
||
- Зависит от Фаз 1-3
|
||
|
||
### Фаза 5 — Деплой (5A)
|
||
- Не трогаем
|
||
- Флаг `UPLOAD_BACKEND=vm|managed` — только интерфейс
|
||
|
||
### Ключевые файлы
|
||
- upload.py, classify.py, grouping.py, process.py, llm.py, connection.py — модифицируются
|
||
- Новые: contracts.py, llm_client.py, repository.py, tests/, docker-compose.test.yml
|
||
|
||
### Верификация
|
||
1. `pytest unit/` — зелёные без сети/БД
|
||
2. `docker-compose up postgres` + `pytest integration/` — реальный SQL
|
||
3. Сквозной: sample.docx → пайплайн → ожидаемые ops
|
||
4. convert_server.py без изменения поведения
|
||
5. JS-тесты (131) — PASS
|
||
|
||
### Scope
|
||
Включено: контракты, DI LLM+БД, pytest, фикстуры, флаг UPLOAD_BACKEND
|
||
Исключено: деплой, переписывание SQL, изменения фронтенда, managed-upload
|
||
|
||
---
|
||
|
||
## Ответ DeepSeek — Рецензия
|
||
|
||
Оценка: 5/5
|
||
|
||
### Поправки:
|
||
- `upload.py` уже читает из `BytesIO`, не из сокета
|
||
- Ф2 и Ф3 можно параллельно (независимы)
|
||
|
||
### 3 вопроса к Opus:
|
||
1. Dataclass vs TypedDict? dict из БД vs валидированный dataclass
|
||
2. `complete(prompt) -> str` достаточно? или нужен `complete_structured`?
|
||
3. `conftest.py` на уровне `deploy/tests/` или `deploy/`?
|
||
|
||
### Вердикт: План принимаю. Жду ответ на 3 вопроса.
|