Files
vector/SERVICES_README.md
T
Sadmin d8723582c9 Полный отказ от LLM: детерминированный rules-анализ
Решение Виктора: ИИ убран из проекта — карточки детей (ПД) не должны
покиать контур. Анализ полностью локальный и детерминированный.

- services/rules_analysis.py: правила вместо Claude (бывший
  analyze_with_fallback + rule_based_urgency из closed_cases):
  urgency по возрасту/профилям, зоны через geo+scoring,
  behavioral_prediction/immediate_actions/key_locations — справочники.
- search_engine: анализатор инъекцией (CaseAnalyzer, Protocol),
  импорт claude_service удалён; рантайм — rules_analyze.
- УДАЛЕНЫ: services/claude_service.py, backend/services/claude_service.py
  (устаревшая копия), test_claude_service.py; ключевые правила-кейсы
  перенесены в test_rules_analysis.py (+тест отсутствия LLM-упоминаний).
- docker-compose/.env.example: ANTHROPIC_API_KEY удалён.
- Фронт: бейдж 'ИИ-анализ' -> 'Локальный расчёт'.
- Доки: DEPLOY/SERVICES_README/ANALYZE_API переписаны, FIXES_REPORT
  помечен историческим, vector_tasks B20: zones/probability — из движка.

pytest: 187 passed (было 214; -27 удалённых LLM-тестов, +тест rules).
Контракт /analyze не изменён (фронт совместим).
2026-09-09 18:30:44 +03:00

3.2 KiB

Сервисы анализа SAR-MCHS

Обзор

Анализ поисково-спасательных операций — полностью локальный и детерминированный (внешний ИИ убран: ПД-данные детей не покидают контур).

Состав

Модуль Назначение
services/search_engine.py Чистый движок: SearchInput → build_search_model → SearchModel (B14)
services/rules_analysis.py Правила: urgency, зоны, прогноз поведения, действия (замена LLM)
services/geo_service.py Зоны через Overpass (8 направлений × 4 дистанции)
services/scoring_service.py WeightedScorer, поведенческие профили (§8)
services/distance_service.py Формула Экстремум: макс. дистанция + коэффициенты
services/psychotype_service.py Детекция психотипа, модификаторы полос
services/recommendation_service.py Стат-рекомендации по истории (B3)

Поток анализа

analyze_case (роутер, тонкая обёртка)
  └─ build_search_model(SearchInput, analyzer=rules_analyze)
       ├─ derive_profiles / derive_time_of_day   (деривации)
       ├─ detect_psychotype                      (если ответы есть)
       ├─ calculate_max_distance                 (формула Экстремум)
       ├─ rules_analyze                          (urgency/зоны/действия по правилам)
       │    └─ build_search_zones + rank_zones   (если есть координаты)
       └─ WeightedScorer                         (веса, профили)

API

POST /api/v1/analyze

Анализ случая (поле case_id опционально — без него анализ «на лету»).

POST /api/v1/analyze/combined

Синоним /analyze (оставлен для совместимости).

GET /api/v1/analyze/{case_id}

Последний сохранённый результат анализа кейса.

Ответ /analyze (сокращённо):

{
  "max_distance_km": 5.4,
  "coefficients": {"base_speed": 1.2, "terrain": 0.5, "urgency": 5.0, ...},
  "urgency": "высокая",
  "primary_zones": [{"priority": 1, "name": "Зона N 0.5км", ...}],
  "search_radius_km": 5.0,
  "key_locations": ["водоёмы", ...],
  "behavioral_prediction": "...",
  "immediate_actions": ["..."],
  "active_profiles": [{"name": "велосипед", ...}],
  "fallback_used": true
}

fallback_used: true означает «локальный расчёт» (единственный режим).

Тестирование

curl -X POST http://192.168.0.99:8000/api/v1/analyze \
  -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{"age": 8, "gender": "м", "terrain": ["лес"], "elapsed_hours": 2.0,
       "has_transport": "bike", "season": "лето"}'
# max_distance_km == 5.4 (регресс B14)