|
Автономность мелких моделей: OUTPUT DISCIPLINE, milestone-todo, перехват финала хода
Два последовательных захода над одной проблемой — мелкие модели (12–30B) в navi_code теряют автономность на трудных шагах: «остановился поболтать» вместо действия и слишком большое расстояние между пунктами плана. Заход 1 (З1–З3): - З1: OUTPUT DISCIPLINE в системном промпте navi_code — «act, don't announce», без few-shot антипримеров. Контракт хода: ответ без tool_calls = конец хода, поэтому объявление намерения текстом убивает автономность; правила заставляют вызывать инструмент в том же ходе. - З2: плоский todo + метка группы milestone + декомпозиция. _parse_plan_steps возвращает list[tuple[milestone, text]]; milestone — метка группировки (не сущность, без статуса), «done» вычисляется при рендеринге; подшаги = больше плоских шагов (без вложенности). TUI side-panel группирует по milestone (плоский фолбэк при пустом milestone). Plan depth: max 15→20 + правило декомпозиции. - З3: adaptive re-plan «длинный шаг» — nudge «разбей шаг» при in_progress ≥ порога итераций без смены todo (порог 4, раньше общего anti-stall warning на 8). Заход 2 (шаги 1–3, после cloud-теста 31b vs 12b): Корневая структурная причина: весь спасательный механизм (anti-stall warning с явным предложением reflect, adaptive re-plan) живёт только внутри tool-цикла — nudge инжектируется в pre_turn *следующей* итерации, которой при «остановился поболтать» нет (ход закрылся по return до post_turn). 31b застревала через «продолжаю tool-итерации» → дожала до warning → спаслась; 12b — через «замолчала текстом» → мимо всех nudge. - Шаг 1: перехват финала хода. Если модель выдала bare-text, но в todo есть открытые шаги (pending/in_progress) и лимит не исчерпан — НЕ эмитить StreamEnd, а сохранить ассистентский текст в session.context, поставить системный nudge и continue (без StreamEnd, без workers — консистентно с multi-iteration tool-турами). Счётчик final_interceptions на AgentTurnContext, лимит final_intercept_limit (default 2), эскалация жёсткости (мягкий → «second stop»). has_open_steps в todo.py: пустой todo → False (защита casual-сообщений), failed/skipped терминальны. Профильные флаги final_intercept_enabled/limit в base.py + loader + admin. - Шаг 2: жёсткий reflect-триггер в промпте — «~3 tool attempts on the same step without progress → call reflect IN THIS TURN (tool call, not reasoning aloud)». - Шаг 3: открыть replan для застревания — «call replan when reflect showed the whole approach is dead (not one failed step, but the approach itself)». Тесты: 874 passed, 1 skipped. Новые — has_open_steps (5), final intercept (5), milestone-группировка, adaptive long-step nudge, парсер шагов с milestone-маркером. cloud: navi_code model → gemma4:31b-cloud для тестирования догадки (31b признала застревание, 12b — нет); .env cloud-host уже gitignored. Co-Authored-By: Claude <noreply@anthropic.com> |
|---|
|
|
| clients/terminal/tui/widgets/todo_list.py |
|---|
| navi/api/routes/admin.py |
|---|
| navi/core/agent.py |
|---|
| navi/core/agent_run_context.py |
|---|
| navi/core/anti_stall.py |
|---|
| navi/core/events.py |
|---|
| navi/core/planning.py |
|---|
| navi/profiles/base.py |
|---|
| navi/profiles/loader.py |
|---|
| navi/profiles/navi_code/config.json |
|---|
| navi/profiles/navi_code/system_prompt.txt |
|---|
| navi/tools/todo.py |
|---|
| tests/clients/test_todo_list.py |
|---|
| tests/integration/test_api_routes.py |
|---|
| tests/unit/core/test_agent.py |
|---|
| tests/unit/core/test_anti_stall.py |
|---|
| tests/unit/core/test_planning.py |
|---|
| tests/unit/profiles/test_base.py |
|---|
| tests/unit/tools/test_todo.py |
|---|