see-smc-autotest/GUIDE.md

304 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Как создать автотесты для другого проекта
Этот гайд описывает полный цикл создания автотестов для SEE и SMC на любом проекте — от первого запуска до полного набора asserts.
## Архитектура тестов
Тесты **универсальные**: не содержат хардкода имён моделей. Всё привязывается динамически:
| Компонент | Где | Что делает |
|-----------|-----|-----------|
| `TEXT_RULES` | В начале каждого теста | По ключевым словам в имени модели подбирает текст для запроса |
| `DEFAULT_HOST` / `DEFAULT_PORT` | В начале каждого теста | Куда стучаться (меняешь под свой проект) |
| `asserts.json` | Отдельный файл | Опциональные проверки — какой ответ ожидается от каждой модели |
## Шаг 1: Подготовка тестов к новому проекту
Скопируй `test_see_models.py` и/или `test_smc_models.py` в репозиторий нового проекта.
### 1.1 Укажи адрес сервера
В начале каждого тестового файла поменяй `DEFAULT_HOST` и `DEFAULT_PORT`:
```python
DEFAULT_HOST = "10.101.60.27" # IP вашего SEE/SMC
DEFAULT_PORT = 6184 # порт SEE: 6184, SMC: 6181
```
### 1.2 Настрой TEXT_RULES для своих моделей
`TEXT_RULES` — список `(keyword, text)`. **Первое совпадение побеждает**, поэтому специфичные правила должны идти раньше общих.
**Принцип**: для каждой модели нужен текст, который гарантированно вернёт непустой ответ.
Пример для SEE (`test_see_models.py`):
```python
TEXT_RULES = [
# специфичные — раньше
("fio", "Иванов Иван Иванович"), # модель ФИО → имя
("date", "на завтра"), # модель даты → фраза с датой
("phone", "8 913 456 78 90"), # модель телефона → номер
("number", "пятьсот двадцать три"), # модель числа → число прописью
("weekday", "в пятницу"), # модель дня недели → день
("mobilizac", "оператор"), # конкретная модель
("trud", "зарегистрироваться в цзн"), # конкретная модель
# общие — позже
("mfc", "записаться в мфц"), # fallback для всего MFC
("test", "test message"), # fallback для тестовых
]
```
**Как подобрать правила для нового проекта:**
1. Посмотри список моделей: `curl http://HOST:PORT/SEE_OR_SMC/models`
2. Для каждой модели подбери текст, который точно вернёт ответ
3. Сгруппируй по ключевым словам (одно правило может покрыть несколько моделей)
4. Расположи специфичные правила **выше**, общие — **ниже**
Пример для SMC (`test_smc_models.py`):
```python
TEXT_RULES = [
("филиал", "родники"), # филиалы → название филиала
("offices", "родники"),
("мфц", "записаться в мфц"), # модели МФЦ
("mfc", "записаться в мфц"),
("ekc", "записаться в екц"), # модели ЕКЦ
("екц", "записаться в екц"),
("minsoc", "какие выплаты"), # минсоц
("техническая", "подключите оператора"), # техподдержка
("тест", "тестовый запрос"),
]
```
## Шаг 2: Первый запуск без asserts
Запусти тест с `-v` (verbose), чтобы увидеть каждую модель и её ответ:
```bash
python3 test_see_models.py --host 10.101.60.25 --port 6184 -v
```
Вывод будет примерно таким:
```
── PRETRAINED ──────────────────────────────────────────────
✓ date → 2026-06-24
✓ number → 523
✓ fio → Ф:"Иванов" И:"Иван" О:"Иванович"
─── 6 passed, 0 empty
── CUSTOM ──────────────────────────────────────────────
✓ zags → отдел_центрального_оовосибирска
✓ weekday → пятница
✗ fio2 → empty
✗ Начало диалога → empty
─── 200 passed, 9 empty
```
Из вывода ты видишь:
- Какие модели работают (`✓ модель → результат`)
- Какие всегда пустые (`✗ модель → empty`)
- Какие есть хеш-варианты и бэкапы (у них тот же префикс, но с `~hash` или `-backup`)
## Шаг 3: Создание asserts
### 3.1 Правило `min_found`
| Тип модели | `min_found` | Почему |
|------------|-------------|--------|
| Базовая (без суффикса) | `1` | Должна всегда отвечать |
| Хеш-вариант (`~4f2d37c9...`) | `0` | Копия базы для тестирования, может не работать |
| `-backup` | `0` | Бэкап, может не работать |
| `-planned` | `0` | Запланированная, ещё не готова |
| `-new` | `0` | Экспериментальная, может не работать |
### 3.2 Формат для SEE (entity-модели)
SEE возвращает сущности с полями `text`, `calculated`, `confidence`:
```json
{
"asserts": [
{
"model": "fio",
"text": "Иванов Иван Иванович",
"checks": {
"min_found": 1,
"text_contains": "иван",
"calculated_contains": "Ф:",
"confidence_min": 0.3
}
}
]
}
```
| Поле checks | Что проверяет | Пример |
|-------------|--------------|--------|
| `min_found` | Минимум сущностей в ответе | `1` |
| `text_contains` | Подстрока в `text` первой сущности | `"иван"` |
| `calculated_contains` | Подстрока в `calculated` первой сущности | `"Ф:"` |
| `confidence_min` | Минимальный confidence первой сущности | `0.3` |
**Где брать значения**: из вывода `-v`. Например:
```
✓ fio → Ф:"Иванов" И:"Иван" О:"Иванович"
↑ берём отсюда подстроки для text_contains и calculated_contains
```
### 3.3 Формат для SMC (classifier-модели)
SMC возвращает классы с полями `class` и `confidence`:
```json
{
"asserts": [
{
"model": "МФЦ НСК",
"text": "записаться в мфц",
"checks": {
"min_found": 1,
"text_contains": "Запись",
"confidence_min": 0.5
}
}
]
}
```
| Поле checks | Что проверяет | Пример |
|-------------|--------------|--------|
| `min_found` | Минимум классов в ответе | `1` |
| `text_contains` | Подстрока в `class` первого класса | `"Запись"` |
| `confidence_min` | Минимальный confidence первого класса | `0.5` |
**Где брать значения**: из вывода `-v`:
```
✓ МФЦ НСК → Предварительная запись (1.000)
└── text_contains: "Запись"
└── confidence_min: 0.5
```
### 3.4 Полный assert для каждой строки `-v`
Проходишь вывод `-v` и для каждой строки создаёшь запись:
| Вывод `-v` | Запись в asserts |
|-------------|-----------------|
| `✓ fio → Ф:"Иванов" И:"Иван" О:"Иванович"` | `{"model": "fio", "text": "Иванов Иван Иванович", "checks": {"min_found": 1, "calculated_contains": "Ф:", "confidence_min": 0.3}}` |
| `✓ weekday → пятница` | `{"model": "weekday", "checks": {"min_found": 1, "text_contains": "пятница"}}` |
| `✓ zags~ffb403 → ...` (хеш) | `{"model": "zags~ffb403", "checks": {"min_found": 0}}` |
| `✗ fio2 → empty` | `{"model": "fio2", "checks": {"min_found": 0}}` |
### 3.5 Поле `text` в assert
Поле `text` в assert — опционально. Если оно есть, оно **переопределяет** `pick_text()`.
**Когда указывать `text`:**
- Модель работает с конкретным текстом, отличным от того что подбирает `pick_text`
- Например: модель `service_mfc` возвращает услуги, но `pick_text` даёт "записаться в мфц" — лучше явно указать "хочу получить водительское удостоверение"
**Когда НЕ указывать `text`:**
- `pick_text()` уже подбирает правильный текст
- Для хеш-вариантов и бэкапов — используй тот же текст что у базовой модели (укажи явно, чтобы не зависеть от порядка `pick_text`)
**Важно**: если указываешь `text` для хеш-варианта или бэкапа, используй тот же текст, что для базовой модели. Разные тексты могут не работать для копий.
Пример:
```json
// Базовая модель
{"model": "zags", "text": "загс центрального района", "checks": {"min_found": 1}}
// Хеш-вариант — тот же текст!
{"model": "zags~ffb403fff9f5802d53aac8a5c844af26", "text": "загс центрального района", "checks": {"min_found": 0}}
```
## Шаг 4: Запуск с asserts
```bash
python3 test_see_models.py --host 10.101.60.25 --port 6184 --asserts see_asserts.json -v
```
Теперь для каждой модели:
- `✓` — ответ непустой, проверки asserts пройдены
- `✗ → empty` — ответ пустой (но `min_found: 0`, тест проходит)
- `✗ → assert fail` — ответ есть, но не прошёл проверки (тест падает)
## Шаг 5: Исправление проблем
### Модель возвращает пустой ответ, а должна работать
1. Проверь текст в assert — попробуй другой текст напрямую через curl:
```bash
curl "http://HOST:PORT/see/entities/MODEL?text=ТЕКСТ&similarity=70"
```
2. Если другой текст работает — обнови `text` в assert
3. Если никакой текст не работает — модель действительно пустая, оставь `min_found: 0`
### Модель проходит без asserts, но падает с asserts
Проверь значения в `checks`:
- `text_contains` — проверь, что подстрока действительно есть в ответе
- `calculated_contains` — только для SEE entity-моделей
- `confidence_min` — возможно завышен, поставь 0.1 для ненадёжных моделей
### Хеш-вариант работает без asserts, но с asserts — пустой
Это значит assert для хеш-варианта переопределяет `text` на неправильный. Убедись, что `text` совпадает с базовой моделью.
## Полный пример: с нуля до готового набора
Допустим, у тебя новый проект с SEE на `10.10.10.10:6184`.
```bash
# 1. Первый запуск — смотрим что есть
python3 test_see_models.py --host 10.10.10.10 --port 6184 -v
# 2. Вывод показывает 50 моделей. Создаём see_asserts.json:
# - Для каждой базовой модели → min_found: 1 + проверки из ответа
# - Для хеш-вариантов и бэкапов → min_found: 0
# - Для пустых → min_found: 0
# 3. Запускаем с asserts
python3 test_see_models.py --host 10.10.10.10 --port 6184 --asserts see_asserts.json
# 4. Если есть ✗ assert fail — правим checks в asserts
# 5. Повторяем 3-4 пока все не пройдут
```
## Структура репозитория после настройки
```
мой-проект/
├── test_see_models.py # тест SEE (скопирован, изменён DEFAULT_HOST/PORT и TEXT_RULES)
├── test_smc_models.py # тест SMC (опционально)
├── see_asserts.json # проверки для SEE
├── smc_asserts.json # проверки для SMC (опционально)
└── README.md # краткое описание
```
## Важные замечания
1. **Порядок правил в TEXT_RULES важен** — специфичные ключевые слова (`"fio"`, `"phone"`) должны быть выше общих (`"mfc"`, `"test"`).
2. **Не указывай `text` в assert без необходимости** — если `pick_text()` уже подбирает правильный текст, не переопределяй. Каждый лишний `text` в assert — потенциальный источник расхождений.
3. **Хеш-варианты и бэкапы** — всегда `min_found: 0`. Они могут не работать, и это нормально.
4. **confidence_min для ненадёжных моделей** — ставь `0.1`, не `0.5`. Даже минимальный confidence лучше чем пустой ответ.
5. **`_find_assert` ищет сначала точное совпадение** — модель `ekc_smc-backup` не перепутается с `ekc_smc`. Порядок записей в asserts не критичен.
6. **Проверяй на всех серверах** — если у тебя несколько инсталляций (dev/stage/prod), гоняй тесты на каждой:
```bash
for host in 10.101.60.25 10.101.60.26 10.101.60.27; do
python3 test_see_models.py --host $host --port 6184 --asserts see_asserts.json
done
```