11 KiB
Рецензия DeepSeek V4 Pro на отчёт Opus
Дата: 27.06.2026
Общая оценка: ⭐⭐⭐⭐⭐ (5/5)
Opus сделал ТО, ЧТО НУЖНО: прочитал код, нашёл расхождения с документацией, не писал код, не рисовал графы. Это эталонный анализ.
Что Opus нашёл такого, чего я НЕ заметил
🔴 КРИТИЧЕСКОЕ: PyPDF2 теряет структуру таблиц
Я читал parse.py, видел PyPDF2, но не осознал что он извлекает текст построчно и не сохраняет колонки. Для спецификаций — это катастрофа. Таблица «наименование | цена | кол-во | сумма | дата» после PyPDF2 станет плоским текстом, и LLM придётся угадывать где какая колонка.
Opus прав на 100%. Это вероятно главный риск точности прямо сейчас.
Надо: pdfplumber (для цифровых PDF) или camelot.
🔴 КРИТИЧЕСКОЕ: Кода сверки CRM↔фискальная НЕТ
Я знал это из ответов заказчика, но Opus проверил grep'ом (crm|фискал|fiscal|сверк|PAYG|reconcil) — нашёл только «акт сверки» как тип мусора. Это greenfield. Меняет планирование: не «эволюция», а «новый модуль».
🟡 ВАЖНОЕ: service-description.md устарел
Я дал Opus читать service-description.md как «актуальный». Opus обнаружил что он описывает парсинг через Lucee (Java POI/PDFBox), а реальный код (upload.py → parse.py) парсит на ВМ через PyPDF2/python-docx. Без Java. Без Lucee.
Моя ошибка: я не перепроверил service-description.md на соответствие коду. Надо поправить доку.
🟡 ВАЖНОЕ: llm_prompt.py зависит от Lucee
build_prompt() (основной пайплайн) ходит HTTP в Lucee за активным промптом. А build_classify_prompt() берёт из БД напрямую. Непоследовательно + точка отказа.
🟡 ВАЖНОЕ: chat.cfm содержит захардкоженный API-ключ
Плюс ссылается на spec_rows вместо spec_current — сломан вдвойне.
🟢 Безопасность: verify=False в llm.py
TLS-проверка отключена. Надо включить.
Где Opus прав, а где нет
| Тезис Opus | Моё мнение |
|---|---|
| Гипотеза 1 (гибрид): ⚠ частично — «текущий код — чистый pipeline, и это правильно» | ✅ Согласен. 131 тест на детерминированные функции — сильный аргумент против агентов. |
| Гипотеза 2 (фильтр мусора): ⚠ частично — «этап 1 по имени файла ненадёжен» | ⚠ Частично. Для имён типа «счет-фактура №123 от 01.01.2025.docx» regex надёжен. Но для «scan001.pdf» — да, бесполезен. Вывод: этап 1 — приоритизация, не жёсткий дроп. |
| Гипотеза 3 (парсинг на ВМ): ❌ отвергнута | ✅ Полностью согласен. Моя гипотеза была основана на устаревшей документации. Парсинг уже на ВМ. |
| Гипотеза 4 (трёхуровневый matching): ⚠ частично — «difflib опасен на коротких токенах» | ✅ Согласен. Примеры «IPv4↔IPv6», «10 кВт↔15 кВт» убедительны. Матчить по структурным атрибутам, не по сырой строке. |
| Гипотеза 5 (MVP): ⚠ частично — «нужен CRM-прогон уже в v1» | ✅ Согласен. Иначе v1 будет «готов», а к цели не приблизимся. |
| Гипотеза 6 (PG-очередь): ✅ подтверждена | ✅ Согласен. Плюс Opus добавил: сейчас очереди нет вообще, in-process ThreadPool. |
| «LLM бесплатный ≠ быстрый» — не наращивать проходы | ✅ Согласен. 5-30s × 100+ файлов = узкое место. |
| «Не отказываться от детерминированного matching» | ✅ Согласен. Воспроизводимость и аудит важнее «бесплатности». |
Единственное где я НЕ согласен:
Opus говорит «не использовать имя файла для фильтрации».
Я считаю: regex (сч[её]т|акт|плат[её]ж|УПД|сверк|инвойс|invoice) по имени файла — ДОСТАТОЧНО надёжен для пред-фильтрации. «Счет-фактура №123.docx» — это всегда мусор. Да, «scan001.pdf» не отфильтруется — но он уйдёт на этап 2 (первые 2KB текста). Риск ложного срабатывания на договоре с именем «счет-фактура» — ноль.
Что Opus упустил
-
testgen/ — в репо есть
testgen/generate.py,testgen/pools.py,testgen/templates.py. Это генератор синтетических тестовых данных. Opus предлагает «тестировать матчинг на синтетике», но не знает что инструмент уже есть. -
convert_server.py роутинг — Opus не проверил ВСЕ эндпоинты. Например,
/api/batch-progress,/api/apply-groups,/api/cleanup,/api/sync— они есть, но не проанализированы. -
services/llm.py — расхождение ВМ↔репо — Opus заметил
verify=False, но не предложил КАК выяснить какая версия каноническая (репо или ВМ). Я поднимал этот вопрос вopus-plan-review-2026-06-27.md. -
LibreOffice — узкое место для .doc —
/convert-docзапускает LibreOffice subprocess последовательно с таймаутом 30с. На пачке старых .doc файлов это потенциально медленнее даже LLM. Но на практике .doc — редкость (заказчик говорил про docx/pdf). -
OCR не нужен — заказчик уточнил: «только текст, сканов не будет». Значит риск «потребуется внешний OCR-сервис» снимается.
Дополнения из второго анализа (подтверждения)
Второй анализ полностью подтвердил выводы Opus. Дополнительно акцентировано:
- Дрейф документации — не только
service-description.md, но и другие .md могут устареть. Правило: код > документация. Всегда проверять. - base64 в БД —
upload.pyкладёт файлы как base64 вdocuments. На 100+ многомегабайтных файлах это раздует БД. Риск масштабирования. - Нет устойчивой очереди —
classify.py=ThreadPoolExecutorв одном процессе. Падение процесса = потеря прогресса. PG-очередь добавит durability.
Итог: что я беру в работу
Немедленно (следующий чат, по команде «делай»):
- Заменить PyPDF2 на pdfplumber в
services/parse.py— критично для точности - Починить chat.cfm — убрать ключ,
spec_rows→spec_current - Включить verify=True в
services/llm.py - Отвязать llm_prompt.py от Lucee —
build_prompt→db.prompts.get_active() - Поправить service-description.md — парсинг на ВМ, не через Lucee
Вторая очередь:
- Детерминированная проверка
sum == price*qty— бесплатный сигнал ошибок - Золотой набор — 30-50 реальных документов с ручной разметкой
- Метрики — логировать
_safe_json_parseсрабатывания, UNRESOLVED, латентность
Третья очередь (после золотого набора):
- Спроектировать нейтральную CanonicalRow для CRM↔фискальная
- Прототип матчинга на синтетике из testgen/
Вывод
Opus дал отличный анализ. Главная ценность — нашёл расхождения кода и документации, которые я пропустил. PyPDF2 — критическая находка. То что кода CRM-сверки нет — меняет приоритеты: не «эволюция», а «новый модуль».
Что отсеялось после двух анализов:
- OCR не нужен (только текст, без сканов)
- LLM не использовать агрессивнее (бесплатный ≠ быстрый, 5-30s/вызов)
- Агенты не нужны (131 тест на pipeline, детерминизм > гибкость)
- RabbitMQ не нужен (PG-очередь достаточна)
Что осталось в работе (5 немедленных + 3 второй очереди):
- pdfplumber вместо PyPDF2
- chat.cfm: ключ + таблица
- llm.py: verify=True
- llm_prompt.py: отвязать от Lucee
- service-description.md: поправить
- Проверка sum==price*qty
- Золотой набор 30-50 документов
- Метрики (_safe_json_parse, UNRESOLVED, латентность)
Следующий шаг: команда «делай» → правлю пункты 1-5.