docs(tasks): add B11 (Anthropic -> local Ollama) and B12 (ISRID priors)

Both are Section B (needs-context): B11 touches the AnalysisResult
contract and the question of where an LLM is needed at all; B12 touches
scoring coefficients and the DB schema, which project rules keep off
limits to automated edits.

B11 records the key finding that the LLM does not compute priorities --
the math already lives in geo_service/scoring_service/psychotype_service
and analyze_with_fallback already returns a full AnalysisResult with no
API. The only unique in-hot-path LLM role is parsing free-text reports,
so a strict intake form and a local provider are independent levers.

B12 notes ISRID supplies empirical priors for the currently hand-tuned
zone weights, with the legal status of the database flagged as a
blocking question to resolve before any data enters the repo.

Summary table updated to B1-B12.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
root
2026-07-25 13:31:04 +00:00
parent b30ce86fa9
commit 83e75e7c24
+35 -1
View File
@@ -627,6 +627,40 @@ sed -i 's/sar_mchs/vector_mchs/g; s#/root/sar-mchs#/root/vector#g' DEPLOY.md
## B10 — Секреты и деплой (`.env`)
**Тип:** security/deploy, исключено из делегирования. `.env` содержит плейсхолдеры `ANTHROPIC_API_KEY=your_...` и слабый `JWT_SECRET=your_jwt_secret_here_change_in_production`. Установка реального ключа Claude (для выхода из fallback) и генерация стойкого `JWT_SECRET` — ручная операция с секретами.
## B11 — Переход с Anthropic API на локальный Ollama
**Тип:** архитектура / приватность, needs-context. Исключено из делегирования: затрагивает контракт `AnalysisResult` и границу «где вообще нужна LLM».
**Мотив:** данные о пропавших без вести (особенно о детях) не должны покидать контур. Сейчас `backend/services/claude_service.py` ходит во внешний Anthropic API. Целевой провайдер — локальная Ollama (lxc200 на pve-node2, 192.168.0.17, уже поднята под OpenHands).
**Ключевой факт для решения:** LLM НЕ считает приоритеты. Вся математика уже в `geo_service.build_search_zones` + `scoring_service.WeightedScorer` (7 взвешенных факторов + множители по возрасту/сезону/профилю) + `psychotype_service`. Метод `analyze_with_fallback` уже отдаёт полноценный `AnalysisResult` вообще без API. Единственная уникальная роль модели в hot-path — разбор неструктурированного текста донесения в поля `profiles`/`circumstances`; остальное (`behavioral_prediction`, `immediate_actions`, `summary`) — переупаковка уже отранжированного топ-5.
**Отсюда два независимых рычага (не взаимоисключающие):**
1. Строгая категоризованная форма ввода (чипы/дропдауны/числа) — убирает саму НЕОБХОДИМОСТЬ в LLM, скоринг становится чистой математикой. Свободнотекстовое поле `circumstances` оставить для чтения человеком.
2. Локальная модель — сохраняет LLM, но переносит провайдера внутрь контура. Недетерминизм и риск галлюцинаций при этом НЕ исчезают.
**Рекомендуемая слоёная схема:** скоринг ВСЕГДА детерминированный (то есть инвертировать текущую логику — сегодняшний fallback становится основным путём, а не аварийным); форма — способ ввода по умолчанию; Ollama — опциональный ЧЕРНОВОЙ парсер, который предзаполняет форму для подтверждения оператором, никогда не имеет решающего слова и никогда не считает приоритеты.
**Объём работ:** абстрагировать провайдера за интерфейсом (сейчас класс жёстко завязан на пакет `anthropic`), вынести выбор в конфиг (`LLM_PROVIDER`, `OLLAMA_BASE_URL`, имя модели), учесть отсутствие у Ollama нативного tool-use и более слабое следование формату JSON (из-за этого B2 — устойчивое извлечение JSON — становится критичным), покрыть тестами оба провайдера. Отдельно решить судьбу `ANTHROPIC_API_KEY` в `.env` (см. B10).
**Зависимости:** пересекается с B2 (парсинг JSON) и B10 (секреты). Делать после решения по B4 (мёртвая мобильная форма) — иначе неясно, какая форма ввода целевая.
## B12 — Внесение данных из ISRID (международная база инцидентов ПСР)
**Тип:** данные / доменная модель, needs-context. Исключено из делегирования: напрямую затрагивает коэффициенты скоринга и схему БД.
**Что это:** ISRID (International Search & Rescue Incident Database, Robert Koester, «Lost Person Behavior») — международная база инцидентов поисково-спасательных операций со статистикой поведения потерявшихся по категориям субъекта: кольцевые модели и модели рассеивания (дистанции по процентилям от точки потери), типовые места обнаружения, зависимость от рельефа и категории субъекта.
**Зачем именно нам:** сейчас веса зонального скоринга (`forest 0.25`, `water 0.20`, …) и радиусы зон заданы вручную, экспертно. ISRID даёт внешние ЭМПИРИЧЕСКИЕ априорные значения для тех же величин по международной выборке — это позволяет заменить часть догадок статистикой и резко снижает объём собственных данных, нужный для калибровки.
**Как стыкуется с планом по 14-летнему архиву спецдонесений:** ISRID — источник априорных значений, собственный архив — источник локальной калибровки (местная специфика: рельеф, климат, структура вызовов). Правильный порядок — сначала ISRID как базовая линия, затем поправки по своим данным. Именно эта комбинация делает переход к чисто статистической модели реалистичным.
**Что нужно решить до начала:**
- **Правовой статус — блокирующий вопрос.** ISRID не является свободно распространяемой базой: доступ к данным и производным моделям регулируется автором/правообладателем. Условия использования (в частности, допустимость зашивать производные коэффициенты в наш продукт) нужно выяснить ДО внесения каких-либо данных в репозиторий. Вопрос не технический.
- **Единицы и категории.** Категории субъекта в ISRID (hiker, dementia, child по возрастным группам, autism, …) не совпадают один-к-одному с нашими профилями; дистанции даны в своих единицах и привязаны к типу местности. Нужны явные словари соответствия и решение, что делать с профилями без аналога.
- **Редкие профили.** По РАС и эпилепсии выборки малы даже в ISRID — там сохранить экспертные коэффициенты и помечать их как «не выведенные из данных».
- **Куда кладём.** Отдельный версионированный справочник априорных значений с указанием источника на каждую величину, а не правка констант в коде: нужно всегда понимать, какое число откуда взялось (ISRID / свой архив / эксперт).
**Жёсткое правило:** ни ISRID, ни архив не дают права автоматически перезаписывать формулу весов — изменение коэффициентов проходит через ревью человека (см. B1 и «Жёсткие исключения» в начале файла).
---
# Сводка
@@ -635,6 +669,6 @@ sed -i 's/sar_mchs/vector_mchs/g; s#/root/sar-mchs#/root/vector#g' DEPLOY.md
|---|---|---|
| Atomic (backend) | A1–A9 | локальной LLM |
| Atomic (frontend) | A10–A16 | локальной LLM |
| Needs-context | B1–B10 | сильной модели / человеку |
| Needs-context | B1–B12 | сильной модели / человеку |
**Рекомендуемый порядок для локальной модели:** A8 и A7 первыми (чистка мёртвого кода и зелёный CI дают чистую базу для проверки остальных), затем backend A1–A6, затем docs A9, затем frontend A10–A16. После каждой backend-задачи прогонять `PYTHONPATH=/root/vector python -m pytest backend/tests -q`.