main
3 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
bb5e3f5eb3 |
feat(sprint8b): регрессия ответов веток · general_info + фикс PRAGMA foreign_keys
Параллель к 8a, но проверяем не код intent от роутера, а содержимое ответа
конкретной ветки на одиночную реплику. Старт — general_info, 46 кейсов.
Логика pass/fail (для одного кейса):
- A — RAG-секция: среди retrieved-чанков есть кусок с
section == expected_doc_section (точное совпадение). Если поле не задано —
пропускаем.
- B — keywords: обязательные expected_keywords встречаются в predicted_answer
(case-insensitive). По умолчанию все; поддерживаются keywords_min: N
и keywords_any: true. Запрещённые expected_must_not — ни одного.
- Pass = A ∧ B. Незаданные поля не проверяются.
- Кэш: (text_hash, branch_config_id) → {answer_text, retrieved_sections}.
Привязан к версии промпта ветки. Смена версии = пустой кэш = свежий прогон.
Правка JSONL без изменения text → pass/fail пересчитывается без LLM.
Backend:
- Таблицы eval_branch_runs / eval_branch_run_cases / eval_branch_predictions.
Миграция m9g1f7e89j56.
- services/eval_branch_run_service.py: загрузка JSONL, фоновый прогон через
asyncio.create_task, кэш, оценка A+B с поддержкой keywords_min/keywords_any.
- chat_service.run_branch_single_turn — изолированный single-turn без
роутера и треда (использует существующий config_service + vectorstore + llm).
- API: POST /eval/branch-runs, GET /eval/branch-runs?intent_code=,
GET /eval/branch-runs/{id}, GET /eval/branch-cases-with-status?intent_code=.
UI (static/regression.html):
- Селектор режима «Роутер / Ветка · general_info». Логика пикера переиспользуется
(фильтры, диапазон, массовый выбор, счётчик «новые / в кэше»).
- Для режима «Ветка»: фильтр по coverage, колонки секция/coverage, keywords,
частота, кэш. Drill-down прогона: ожидание, retrieved-секции, причины fail,
полный ответ ветки.
База кейсов (eval/branch_cases_general_info.jsonl) — от пользователя, 46 кейсов
по схеме {text, intent, coverage, expected_doc_section?, expected_keywords?,
expected_must_not?, keywords_min?, keywords_any?, count?, note?}.
Связанная правка SQLite (нашли при удалении документа в этом спринте):
- db/session.py: connect-listener PRAGMA foreign_keys=ON на каждое подключение.
Без этого ondelete=CASCADE в SQLite не enforced, и удаление документа
оставляло подписки в intent_documents висячими (что давало пустой RAG
и fail регрессии).
- Миграция n0h2g8f9a0k67 — одноразовая чистка существующих висячих подписок.
docs/SPRINTS.md: Спринт 8b → ✅ Закрыт. Diff vs предыдущий прогон для веток
и кнопка «Сбросить кэш регрессии» вынесены в docs/BACKLOG.md.
Также включены обновлённые data/datasets/general_info.md и price_question.md
(рабочий материал оператора), и черновик eval/branch_cases_price_question.jsonl
для следующего захода (8b на price_question).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
a8f7e68795 |
feat(sprint8a): регрессия роутера в UI с выбором кейсов и кэшем
Оператор-настройщик после правки промпта _router нажимает «Прогнать выбранное»
на странице «Регрессия» и видит, что сломалось. Не CLI, не в обход
интерфейса — встроено в верхнюю навигацию рядом с Настройками.
Backend:
- Таблицы eval_runs / eval_run_cases (с is_pass) / eval_router_predictions
(кэш text_hash + router_config_id → predicted_intent). Миграции
k7e9d5c67h34 и l8f0e6d78i45.
- services/eval_run_service.py: start_router_run(text_hashes) запускает
фоновую корутину через asyncio.create_task, фиксирует активную версию
_router. Кэш привязан к версии: повторный прогон на той же версии —
мгновенный, на новой — пересчитывается. compute_diff_vs_previous
сравнивает с предыдущим прогоном на той же версии (новые fail / pass).
- API: POST /eval/runs (фон, body text_hashes), GET /eval/runs,
GET /eval/runs/{id}, GET /eval/router-cases-with-status (все 1573 кейса
+ кэш на активной версии).
Frontend (static/regression.html — новая страница, ссылка добавлена в
шапки index/sandbox/settings/docs):
- Сворачиваемый блок «Выбор кейсов»: фильтр по intent, ввод диапазона
(1-50, 200-300), кнопки «Все видимые», «Снять все», «Только без кэша»,
«Только FAIL в кэше», «Снять кэшированные». Чекбокс в шапке.
- Таблица 1573 кейсов отсортирована по count desc: #, чекбокс, запрос,
intent, частота, кэш (PASS / FAIL → predicted / —). Цветной фон строки
по статусу кэша.
- Счётчик «выбрано N (новых: X, в кэше: Y)»; кнопка
«Прогнать выбранное (X новых + Y из кэша)» — сразу видно реальный
объём LLM-работы.
- Polling /eval/runs/{id} раз в 2 секунды, прогресс-бар, drill-down:
все кейсы прогона + фильтр pass/fail + поиск + diff vs предыдущий
(новые fail / новые pass).
docs/SPRINTS.md: Спринт 8 разбит на 8a (✅ закрыт), 8b (регрессия ответов
веток, ждёт базу кейсов от пользователя), 8c (handoff/resumable/loop/
guard/rag — позже).
docs/BACKLOG.md: новый файл для идей на потом. Записаны: просмотр
архивного графа без активации (из 7.7), варианты C (LLM-judge) и D
(эталон + embeddings) для регрессии веток в 8b.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
74befa484d |
feat(sprint7.5): обновление промптов 4 веток + eval-каркас и тест-кейсы в UI Настроек
Промпты веток (по docs/BRANCH_MAP_AND_PROMPTS_v1.md):
- reschedule.md — полная замена. Одношаговый сценарий из 6 пунктов:
action (cancel/reschedule), patient_name, patient_phone, original_time,
preferred_new_time. Слоты хранит вызывающая система, STATE_JSON не используется.
- price_question.md — добавлены 3 пункта: эндоскопия 1000₽ при первичном
ЛОР-приёме, лечебные процедуры доплачиваются, ОМС только сурдолог
(последний пункт работает только при подтверждении в базе).
- medical_question.md — расширена карта жалоб → специалист (ЛОР / сурдолог /
аллерголог / иммунолог / пульмонолог); добавлен пункт про беременность,
онкологию, психиатрию — мягко сказать «специализированная клиника»,
не предлагать запись.
- general_info.md — добавлены разделы «Отзывы и социальное доказательство»,
«Преимущества клиники», «Сокращения». Условия выхода расширены до 5 интентов.
escalate_human и new_booking не трогаем (escalate — карта говорит «не менять»;
new_booking — отдельный Спринт 7.6 по docs/OPTIMIZATION_CONVERSION_v1.md).
Применение в БД — вручную через UI «Настройки» (вариант A): оператор копирует
текст из .md, сохраняет как новую версию + активирует. Файлы — только seed.
Eval-каркас (заготовка под Спринт 8):
- eval/router_cases_booking.jsonl (875 кейсов new_booking) и
eval/router_cases_other.jsonl (698 кейсов: general_info 295, price 165,
escalate 139, medical 59, reschedule 40). CSV-исходники рядом.
- eval/README.md — формат, глоссарий, что это и зачем.
- routers/eval.py: GET /eval/router-cases?intent_code=...&limit=...
Lazy-кэш, сортировка по count desc, фильтр по expected_intent.
UI Настроек — выбор готового кейса в тест-блоке:
- Полоса «Готовый кейс:» с datalist (поиск по началу строки) + кнопка
«🎲 Случайный» + счётчик кейсов для активной ветки.
- При выборе — текст подставляется в textarea вопроса.
- Загружается при выборе ветки. Если кейсов 0 (для _router, _debug) — скрыто.
- Полная подсистема прогона (run.py, отчёты, baseline) — Спринт 8.
SPRINTS.md:
- Спринт 7 (мульти-RAG, часть A) → ✅ Закрыт (коммит
|