# Проверка тома в несколько этапов и несколько моделей

Что реально даёт выигрыш, а что является декорацией. Проверено на полном томе ИОС1.1
(78 стр., 11,8 МБ, текстовый слой есть).

## Итоговая схема

| Этап | Чем делать | Что даёт |
|---|---|---|
| 1. Извлечение | `pypdf` постранично в JSON (`{page, chars, text}`) | полный корпус; проверить, что нет страниц с `chars < 50` (скан без слоя) |
| 2. Сверка кодом | `Decimal` + `re`, на своей машине | вся арифметика, балансы, нумерация, обозначения НТД, повторы |
| 3. Независимый аудитор | модель ДРУГОГО семейства по первоисточнику | находки, которые пропустил из-за невнимательности к тому же тексту |

## Когда использовать

Том объёмнее ~20 страниц, или когда отчёт будет разбираться с подрядчиком, или когда одну и
ту же методику надо применить без пропусков и с проверяемым следом. Для быстрой прикидки по
одному листу достаточно этапов 1 и 2.

## Что НЕ работает

- **Стадия «сформируй алгоритм» отдельной моделью.** Алгоритм уже есть — чек-лист этого
  скилла. Модель, изобретающая план заново, добавляет галлюцинаций, а не пользы.
- **Аудитор, который видит только текст чужого заключения.** Он не может проверить числа,
  не имея исходника: начинает соглашаться или придираться к формулировкам, а номера
  пунктов НТД выдумывает. Аудитору давать ВЫДЕРЖКИ ИЗ ТОМА, а не пересказ.
- **Mixture-of-Agents в роли проверяющего.** В Hermes reference-модели MoA инструментов не
  имеют («you cannot call tools, run commands, browse, or access files») и работают
  параллельно ДО действия. Это веер советчиков, а не последовательная проверка работы.
- **Доверять модели арифметику.** Суммы, `√(P²+Q²)`, `tgφ`, годовой расход — только кодом.

## Как готовить аудитора

- Дать: выдержки первоисточника (20–30 страниц по делу, ~46 тыс. символов работают) плюс
  список ПРОВЕРЯЕМЫХ УТВЕРЖДЕНИЙ с ожидаемым вердиктом `СОВПАДАЕТ / НЕ СОВПАДАЕТ /
  НЕ ПРОВЕРИТЬ`.
- Прямо запретить: выдумывать номера пунктов и значения; при отсутствии основания в выдержке
  писать «не проверить по выдержке».
- Просить отдельный блок «ЧТО ПРОПУЩЕНО» — там и появляются главные находки.
- Температура 0, `max_tokens` с большим запасом.
- **ЛОВУШКА: reasoning-модель съедает весь бюджет на рассуждения и возвращает пустой
  `content`.** Ответ приходит `completion_tokens == max_tokens`, `reasoning_tokens == max_tokens`,
  а `content` пустой. Признак: нулевая длина ответа при списанной стоимости. Лечение — поднять
  `max_tokens` до 16000 и требовать «отвечай сразу, без длинных рассуждений».
- **Проверено на polza.ai с `anthropic/claude-sonnet-5.5`:** при промпте ~87 тыс. символов
  модель ушла в `reasoning`, вернула `finish_reason=length` и **пустой `content`**. Рабочая
  схема: `max_tokens` ≥ 24000 (лучше 32000) и **дробление ПЗ на части по ~25 тыс. символов**
  (том 78 стр. → 4 части, 45–97 с на часть). Обязательно проверять оба поля — `content`
  И `finish_reason`; пустой `content` записывать как ошибку прогона, а не как
  «нового не найдено». Эндпоинт: `POST https://api.polza.ai/v1/chat/completions`,
  заголовок `Authorization: Bearer <HERMES_CUSTOM_POLZA_AI_API_KEY>`.
- **В промпт аудитора обязательно включать список уже известных замечаний** с припиской
  «не повторять» — иначе аудитор отдаёт 50+ строк, из которых половина дублирует шаги 1–2,
  и сводить их приходится вручную. С ним — 4 из 4 частей дали реально новые находки.
- Стоимость такого прогона невелика (порядка 25 тыс. токенов промпта у аудитора) — это не
  довод против, это довод за постоянное использование.

## Как сводить два заключения

Не складывать списки, а разделить находки по источнику:

- совпало у обоих → в отчёт;
- только у аудитора → **проверить кодом самому**, прежде чем включать: он мог ошибиться в
  разборе строки (частая ошибка — принять количество за Ру, потерять перенос строки);
- только у меня → перепроверить по первоисточнику; если аудитор не подтвердил, это аргумент
  против, а не за.

Отдельно фиксировать в отчёте, что дал третий этап — это честная оценка метода и
единственный способ понять, когда его стоит повторять.

## Разбор таблиц нагрузок из PDF

Текстовый слой таблицы — плоский текст, колонки разделены пробелами, поэтому разбор идёт
регулярками по префиксу номера строки, а не по позициям колонок:

```python
m = re.match(rf"^(\d{{1,2}})\s+(\S.*)$", line)     # номер строки + остаток
rest = re.sub(r"\d+\s*кВт", "", rest)              # убрать «22кВт» из названия
# строки-продолжения (перенос номера с прошлой страницы) отбрасывать по «Изм. Кол.уч.»
```

Признак правильного разбора: сумма Ру по строкам сходится с «Итого ВРУ с КРМ» с точностью до
округления. Если не сходится на десятки кВт — разбор врёт, а не документ.
