Перейти к основному содержимому

Измерение маршрутизатора инструментов Jev

AT-237 (EP-029, HS-063). Измерение вне продукта: ничто в apps/ не импортирует этот код, ничего не пишется в базу, и никакой выгоды продукта здесь не утверждается — это задача AT-239, которая сравнивает ходы с маршрутизатором и без него. Измеряемый маршрутизатор — тот, что специфицирует AT-235; решения, от которых он зависит, — из AT-236.

Измерено 2026-09-29 против локального экземпляра dev (проект compose brabo-dev), репозиторий на d48f99f8ec. Второй раунд — варианты state, классы эквивалентности, разделение настройка/проверка, top-2 и расстояние по причинам — ниже.

Что существует​

Всё живёт в scripts/jev/ и запускается Node репозитория (type stripping, без шага сборки, без новых зависимостей).

файлроль
catalogo.exsвыгружает из самого кода engine каталог инструментов каждого агента (spec/0 каждого инструмента: имя и описание) и идентичность (Engine.Harness.Agents.identity/1)
catalogo.jsonвыгрузка, версионируемая — перегенерируйте при изменении каталога (команда в заголовке .exs)
passos.tsчистый: event log → шаги и state каждого шага
jev.tsчистый: запрос к Decisions API и чтение ответа
medicao.tsчистый: согласие, интервалы Уилсона, кривая уверенности, задержка, стоимость, отчёт в Markdown
replay.tsCLI первого раунда: три SELECT, один запрос на шаг, JSONL вне checkout
dados.tsвторой раунд: сырые данные (события, строки расхода, задачи, истории, карты модулей, исходы действий) и кеш снимка
equivalencia.tsвторой раунд: классы эквивалентности E1–E3, зафиксированные до запуска, и классификатор терминальных команд
kickoff.tsвторой раунд: первое сообщение цикла dev agents и gates, перенесённое из Elixir engine (spec сверяет фиксированный текст с файлами .ex)
variantes.tsвторой раунд: варианты state и граница исполнения; каждое поле называет свой источник в engine
divisao.tsвторой раунд: разделение настройка/проверка, по исполнению
cliente.ts, medicao2.ts, analise.tsвторой раунд: вызов (сохраняет вероятности), таблицы top-k / каскада / по причинам и CLI jev:analise

Шаг, а не вызов инструмента​

Маршрутизатор опрашивается один раз на вызов чат-модели, перед provider.chat (AT-235). Шаг может нести несколько вызовов инструментов — десять emit_artifact в ответе Criativo, terminal + read_file в ответе dev, — поэтому опрос Jev по разу на tool.call задавал бы вопросы, которых продукт никогда не задаёт, с state, уже содержащим соседние вызовы того же шага.

У event log нет маркера шага (AT-235, пробел 1), поэтому граница берётся из token_usage: api записывает строку на вызов LLM до того, как engine запишет tool.call этого ответа. Каждый tool.call той же сессии и того же актора между двумя последовательными строками — один и тот же шаг. Отсюда три метки:

  • шаг с одним инструментом (один или несколько его вызовов): метка = этот инструмент;
  • разнородный шаг (два разных инструмента): попадание = выбор Jev — один из них, — но ограничение меню одним инструментом отрезало бы остальное;
  • шаг без tool.call после своей строки: модель ответила текстом (или упала). Это единственная метка, которую responder_sem_ferramenta может получить этим методом, — бриф не ожидал ни одной; граница шага даёт семь.

Моменты сравниваются как текст UTC фиксированной ширины с микросекундами: строка расхода и первый tool.call шага иногда попадают в одну и ту же миллисекунду.

Отправляемый state​

Формат AT-235, вырезанный из того, что существовало до шага: agente; pedido — для разговорных агентов последнее chat.message, написанное пользователем; для dev agents и gates задач — заголовок задачи из dev.working; contexto — идентичность агента плюс строка agent_instructions проекта, когда она есть (два слоя системного промпта, а не весь собранный промпт); passos_recentes — последние 6 вызовов этого актора в этой сессии, с аргументами и результатом, обрезанными до 500 символов. Вопрос — choice, чьи criteria — это {name: description} каталога плюс зарезервированный responder_sem_ferramenta.

Запрос идёт в POST https://openrouter.ai/api/alpha/decisions с моделью typesafe/jev-1.13. Исправление к AT-235, измеренное: questions — объект, индексированный по id вопроса, а не список — списочная форма получает 400 expected record, received array. Ответ — answers.<id>.{choice, probabilities, confidence}, usage.{input_tokens, output_tokens, cost}, id (gen-dec-…) и датированный снимок в model (typesafe/jev-1.13-20260917 в каждом ответе этого исполнения).

Выборка​

экземплярлокальный dev (brabo-dev), проект test, 4 сессии с шагами (у пятой сессии, core-api, нет ни одного)
период2026-09-29 06:19:11 → 07:57:22 UTC
прочитано879 событий (502 tool.call), 307 строк token_usage агентов
шаги305 от агентов каталога; 302 опрошено (3 шага Psicólogo имеют каталог из одного инструмента и никогда не маршрутизировались бы — AT-235, условие c)
метки295 шагов с инструментом (36 разнородных), 7 без
подозрительные меткиу 157 из 295 шагов есть вызов, результат которого показывает сбой (ok: false, текст, начинающийся с falhou/erro, exit ≠ 0), или который так и не получил результата, — вызванный инструмент мог быть неправильным

Было сделано два полных исполнения (сообщается второе; между ними в базе появился шаг Anamnese). Между исполнениями, на 301 шаге, общем для обоих, Jev дал один и тот же выбор в 283 (94%); средняя |Δ уверенности| 0,029, максимальная 0,16. Выборка — небольшой проект, один день, одна чат-модель (~deepseek/deepseek-flash-latest); каждая доля ниже несёт свой 95% интервал Уилсона, и большинство интервалов по агентам слишком широки, чтобы упорядочить агентов.

Согласие по агентам​

«Согласие» = выбор Jev — инструмент, который модель вызвала на этом шаге. «Повторить предыдущий» — бесплатная базовая линия: предложить последний инструмент, который тот же актор использовал на предыдущем шаге.

агентвариантовшагов с инструментомразнородныхсогласие (95% ДИ)без подозрениякогда Jev выбрал инструментбазовая линия «повторить предыдущий»шагов без инструмента
anamnese5803/8 = 38% (14–69%)3/83/34/4—
appsec6620/6 = 0% (0–39%)0/60/10/5—
arquiteto9521/5 = 20% (4–62%)1/51/21/43/3
criativo3503/5 = 60% (23–88%)3/53/41/42/2
dev-board-engine924312/24 = 50% (31–69%)1/312/2420/23—
dev-game-session938220/38 = 53% (37–68%)5/1420/3825/37—
dev-input-keyboard925312/25 = 48% (30–67%)5/1012/2518/24—
dev-lead4110/1————
dev-persistence934324/34 = 71% (54–83%)4/1224/3426/33—
dev-piece-catalog937521/37 = 57% (41–71%)4/1121/3731/36—
dev-retro-renderer926013/26 = 50% (32–68%)5/1413/2619/25—
dev-scoring938119/38 = 50% (35–65%)4/1519/3829/37—
infra5210/20/1—1/10/1
infra-workflows3200/20/2—0/1—
po10826/8 = 75% (41–93%)6/86/60/71/1
qa-automacao72054/20 = 20% (8–42%)2/94/2014/19—
qa-estrategia61660/16 = 0% (0–19%)0/15—7/15—
все29536138/295 = 47% (41–52%)43/138 = 31% (24–39%)138/258 = 53% (47–59%)196/275 = 71% (66–76%)6/7 = 86% (49–97%)

Кривая уверенности по принятому правилу​

AT-236 решила (ответы 7 и 12), что маршрутизатор только ограничивает меню и что responder_sem_ferramenta — с любой уверенностью — отправляет весь каталог в v1. Поэтому шаг ограничивается, только когда уверенность на пороге или выше и выбор — инструмент; всё остальное ведёт себя как сегодня. Дорого стоит ошибка ограничения не тем инструментом.

порогменю ограничено до 1падает на весь каталогверных среди ограниченных (95% ДИ)ограничено не тем инструментомразнородных шагов отрезано
0.0025837138/258 = 53% (47–59%)12018
0.30191104110/191 = 58% (51–64%)8113
0.4012616976/126 = 60% (52–68%)5010
0.507322250/73 = 68% (57–78%)235
0.604325229/43 = 67% (53–80%)144
0.701727814/17 = 82% (59–94%)32
0.8072887/7 = 100% (65–100%)00
0.9022932/2 = 100% (34–100%)00

Отчёт печатает ту же кривую по группам (dev agents, разговорные агенты, gates и прочие агенты ToolLoop). Dev agents следуют таблице выше (0.70: 11/14; 0.80: 6/6). Разговорные агенты, когда Jev выбирал инструмент с любой уверенностью, были правы в 10/12 шагах; он выбирал responder_sem_ferramenta в 9 из их 21 шага с инструментом, что по ответу 12 безвредно.

Порог. Ни у одного порога сетки нижняя граница интервала не достигает 90% или выше — ни в целом, ни в какой-либо группе. Единственная точка без неверного ограничения — 0.80, и там маршрутизатор действует на 7 из 295 шагов (2%) — с нижней границей 65%. Эта выборка не поддерживает порог; если он будет зафиксирован по ней, 0.80 — значение, на которое она указывает, с таким покрытием. Ответ 4 AT-236 просит стоимость каждого типа ошибки, которую этот повтор оценить не может.

Задержка и стоимость​

задержка (302 запроса, последовательно, с машины сопровождающего)p50 306 мс, p95 410 мс, макс 550 мс; 0 выше 2 000 мс (первое исполнение: 286 / 409 / 512)
входных токенов на запросот 538 до 3 220, медиана 1 710
стоимость по usage.costUS$ 0,021964 за 302 шага — US$ 0,0000727 за шаг
списанная стоимостьGET /api/v1/generation для каждого из 302 id: total_cost даёт в сумме те же US$ 0,021964 (отношение 1,000)

Дельта GET /api/v1/key вокруг каждого исполнения не совпала: +US$ 0,0349 против заявленных 0,0219 в первом исполнении, +0,0185 против 0,0220 во втором. Ключ общий, и его счётчик запаздывает: за всю сессию AT-237 его usage вырос с US$ 1,830 до US$ 2,052 (+0,222), тогда как генерации этого повтора были списаны на US$ 0,044, значит, другая работа тратила на том же ключе в то же время. Дельта — не измерение одного исполнения; запись по генерации — да. Всего потрачено AT-237, два исполнения и пробы формата: около US$ 0,044, против потолка US$ 2,00.

Чего повтор не видит​

  • Первое сообщение цикла. Агент ToolLoop (dev agents, gates, Anamnese, Infra-Workflows) начинает с пользовательского сообщения, собранного в коде, — задача, история, карта модулей, — которое никогда не доходит до event log. У повтора есть лишь заголовок задачи для dev agents и gates задач и ничего для qa-estrategia, appsec, anamnese и infra-workflows. state продукта нёс бы это сообщение. 0/16 у qa-estrategia (Jev каждый раз отвечал responder_sem_ferramenta) измеряет слепоту повтора так же, как и Jev; эти строки — нижняя граница и ничего не должны решать.
  • Остальной системный промпт. contexto — это идентичность и строка инструкции проекта, а не собранный промпт (бизнес-правила, состояние задачи, файлы).
  • Верна ли метка. Модель, выбравшая инструмент, — не эталон; 157 шагов помечены как подозрительные и сообщаются отдельно («без подозрения»). Согласие ниже на чистых шагах (31%), чем в целом (47%): подозрительные шаги — в основном падающие вызовы terminal от dev agents, которые Jev тоже склонен выбирать, — поэтому плохо размеченные шаги не объясняют несогласия.
  • Эффект. Ограниченное меню меняет то, что модель делает дальше; повтор лишь сравнивает выбор с записанным. Становятся ли ходы короче, быстрее или дешевле — это AT-239.

Две находки вне чисел​

  • Разнородные шаги часты: 36 из 295 (12%). Ограничение меню одним инструментом превращает каждый из них как минимум в два шага — пробел 1 AT-235, теперь подсчитанный.
  • Риск синхронизации каталога из AT-235 (пробел 3) реален, под другим именем: GET /api/v1/models не перечисляет typesafe/jev-1.13, но перечисляет typesafe/jev-router — чат-маршрутизатор с ценой -1. Синхронизация моделей импортировала бы его как чат-модель (неактивную). Записано здесь, не изменено.

Второй раунд (2026-09-29): где расстояние​

Запрошен владельцем после первого раунда: повторить измерение, попытаться дойти хотя бы до 90% и сказать, где именно расстояние. Не достигнуто. На шагах проверки top-1 Jev — 73% по эквивалентности (95% ДИ 66–79%, n = 160) и 66% строго (58–73%); его top-2 доходит до 90% (84–94%). Остальная часть раздела — протокол, числа и ручное прочтение 43 оставшихся ошибок top-1. Тот же экземпляр, та же оговорка, что и в первом раунде: небольшой проект, один день, одна чат-модель; никакой выгоды продукта не утверждается (это AT-239). Репозиторий на bc7f4c0738, ветка test/replay-do-jev-v2.

Протокол (записан до любого исполнения)​

  • Только то, что продукт может произвести во время выполнения, до шага. Ничто от целевого шага не попадает в state: ни инструмент, который он вызвал, ни аргументы, ни результат, ни текст, который модель написала на том же шаге (Passo.texto читается только из предыдущих шагов; variantes.spec.ts утверждает для каждого варианта, что вызов, аргумент, результат и текст целевого шага отсутствуют). Каждое новое поле имеет источник в engine, процитированный в заголовке scripts/jev/variantes.ts.
  • Классы эквивалентности зафиксированы в scripts/jev/equivalencia.ts до запуска, исходя из семантики инструментов, и сообщаются рядом со строгим правилом (правилом первого раунда, чтобы 47% оставались сопоставимыми). Три накопительных слоя: E1 terminal, чья команда лишь читает/перечисляет/ищет (ls, find, cat, pwd, grep, head, git status/log/diff… — составная команда считается по самому сильному сегменту, исполнение > запись > чтение) ≡ read_file/search_workspace; E2 read_file ≡ search_workspace; E3 terminal, пишущий файл (перенаправление, heredoc, tee, sed -i, cp, mv, touch) ≡ write_file. Асимметричны намеренно: выбор Jev terminal подходит только к вызову terminal, а команда, которая исполняет (npm, node, rm, mkdir, git commit…), не эквивалентна ничему, кроме terminal. Заголовок — полное правило (E1+E2+E3), строгое правило рядом. Ничего не переклассифицировалось после просмотра результата; 3 ошибки, которые классы всё ещё допускают, посчитаны как таковые ниже.
  • Настройка × проверка по исполнению, а не по шагу. Группа — это исполнение ToolLoop (задача dev agent, раунд gate) или, для разговорных агентов, вся сессия агента. Группы упорядочиваются по хешу имени, и каждая идёт в ту половину, где к этому моменту меньше шагов, — детерминированно и слепо к любому результату. 328 пригодных шагов: 167 настройки, 161 проверки (n ниже считает шаги с инструментом: 161 и 160). Варианты итерировались только на настройке; проверка опрашивалась потом, по разу на вариант. Один инцидент, заявленный: после первых исполнений настройки я обнаружил, что skip_proficiency / emit_proficiency Anamnese тоже завершают цикл, и добавил их в список границ исполнения, используемый для сборки state. Использование исправленного списка для разделения также переместило бы 154 из 167 шагов настройки в проверку, поэтому разделение сохраняет список, который был до первого запроса (FERRAMENTAS_DE_FIM_DA_DIVISAO), и только state использует исправленный. Четыре варианта state, зависящие от границы, были опрошены на настройке заново (US$ 0,075, сохранены как .descartado в журнале расходов).
  • Замороженный снимок. База dev продолжала получать шаги от другой работы во время сессии (335 строк расхода в конце против 333 в начале); анализ выполняется по снимку из 333 строк и событиям до тех же порядковых номеров (--dados-cache). 26 новых шагов с первого раунда (302 отвеченных → 328 пригодных) — все шаги Anamnese из половины настройки.
  • Потолок расходов US$ 1,00 по сумме usage.cost, проверяемый перед каждым запросом против накопленного итога каталога вывода (.jsonl и .descartado). Потрачено: US$ 0,414 на 4 604 запроса (см. «Задержка и стоимость»).

Выборка​

настройкапроверка
шаги (с инструментом / без)167 (161 / 6)161 (160 / 1)
dev agents (ToolLoop)dev-piece-catalog 37, dev-retro-renderer 26, dev-input-keyboard 25dev-game-session 38, dev-scoring 38, dev-persistence 34, dev-board-engine 24
gates и прочие ToolLoopanamnese 32, qa-automacao 20, appsec 3qa-estrategia 16, appsec 3, infra-workflows 2, anamnese 2
разговорныеpo 8, criativo 5, arquiteto 5infra 2, dev-lead 1

В проверке доминируют dev agents (134 из 160 шагов с инструментом) и один gate (qa-estrategia, 16). Половина настройки несёт 32 шага Anamnese, на которые Jev отвечает responder_sem_ferramenta, когда агент использовал skip_proficiency (30 из 32): без них настройка даёт 94/129 = 73% по эквивалентности, как и проверка.

Опробованные варианты (все)​

tokens — медианный размер входа; задержка в мс (p50 / макс), последовательные запросы с машины сопровождающего. Только шаги с инструментом.

вариантчто добавляет к предыдущемунастройка строго → эквивалентность (top-2)проверка строго → эквивалентность (top-2)токенызадержка
originalничего — state первого раунда39% → 48% (83%)49% → 58% (82%)1 687322 / 780
kickoffpedido = первое сообщение цикла, восстановленное из кода engine55% → 58% (89%)65% → 73% (91%)1 867318 / 612
escopoнедавние шаги только текущего исполнения (ctx.messages начинается заново при каждом ToolLoop.run)57% → 59% (89%)66% → 73% (90%)1 867312 / 814
resultadosрезультаты/аргументы до 2 000 символов53% → 55% (91%)62% → 69% (88%)2 011314 / 699
textoтекст модели из предыдущих шагов53% → 55% (91%)64% → 73% (93%)2 090315 / 685
progressoвыведенные счётчики (шагов к этому моменту, вызовов по инструменту, последний инструмент, запущенные тесты…)55% → 57% (91%)65% → 70% (93%)2 224309 / 817
trilhaescopo + вся последовательность инструментов исполнения (только имена)53% → 57% (91%)64% → 71% (89%)1 936310 / 614
fluxotrilha + вопрос, говорящий, что агенты работают рывками49% → 55% (92%)64% → 75% (93%)2 014309 / 586
enxutotrilha только с 2 последними вызовами50% → 54% (89%)63% → 74% (91%)1 429307 / 920
so_trilhatrilha без единого недавнего вызова39% → 44% (80%)33% → 56% (83%)1 168307 / 480
acoesescopo + результат команд, ожидавших одобрения (восстановленный из исхода действия)50% → 53% (91%)53% → 61% (89%)2 333348 / 1 352
acoes_completoacoes + 2 000 символов + текст + прогресс47% → 51% (92%)51% → 58% (92%)3 360326 / 845

Шесть строк от original до progresso (каскад ниже) были написаны до первого запроса. Остальные шесть написаны позже, в ответ на то, что показала настройка, и представляют собой обычный поиск на половине настройки: trilha, fluxo, enxuto и so_trilha пытаются дать Jev шаблон исполнения в более лёгкой для чтения форме; acoes и acoes_completo появились после того, как стало видно, что многие недавние шаги читали (sem resultado gravado) (команды, ожидавшие одобрения).

Победитель — escopo, выбранный на настройке (лучший top-1, строго и по эквивалентности); проверка для выбора не использовалась. Две вещи, которые стоит прочесть в таблице: различия между kickoff … progresso лежат в пределах доверительных интервалов (±7 пунктов), поэтому не показано, что «больше входа» мешает или помогает после первого шага; а у fluxo лучшее число проверки (75%), но он ниже победителя на настройке (55% против 59%), и именно поэтому он не стал победителем — выбрать его сейчас значило бы выбирать по проверке.

Откуда берётся каждое новое поле в engine (apps/engine/lib/engine/…):

полеисточник
pedido (dev)initial_message/2, dev/dev_agent_server.ex:484; заголовки задачи и истории из tasks/stories
pedido (qa-automacao)initial_message/2, gates/qa_automacao_agent.ex:108; задача из последнего dev.awaiting_gate, требования истории
pedido (qa-estrategia, appsec)gates/qa_estrategia_agent.ex:93, gates/appsec_agent.ex:79; история не восстанавливается из лога, поэтому сообщение говорит об этом и несёт карту модулей
недавние шаги по исполнениюToolLoop.Default.init/1 и loop/1 (harness/tool_loop.ex): messages собирается run
полные результаты, textoсообщения tool и assistant, которые добавляет loop/1 (concluir_despacho/5, append(ctx, message)); лог обрезает результаты до 2 000
результаты одобренных команд (acoes)texto_do_desfecho/1, dev/dev_agent_server.ex:460; в логе для них нет tool.result, только proposed_actions.execution_result
progresso, trilhaсчётчики по предыдущим вызовам исполнения в тех же messages

Не перенесены, и это сказано в kickoff.ts: Anamnese (её сообщение собирается из окна лога и списка членов, которых лог не хранит), infra-workflows (карта контекста) и разговорные агенты (их pedido по-прежнему последнее сообщение пользователя).

Каскад (проверка, шаги с инструментом)​

Каждая строка — предыдущая плюс одна деталь, на тех же 160 шагах.

шагntop-1 (95% ДИ)top-2 (95% ДИ)
вход первого раунда, строгое правило16078/160 = 49% (41–56%)118/160 = 74% (66–80%)
+ E1 терминал-чтение ≡ чтение16092/160 = 57% (50–65%)125/160 = 78% (71–84%)
+ E2 read_file ≡ search_workspace16093/160 = 58% (50–65%)131/160 = 82% (75–87%)
+ E3 терминал, который пишет ≡ write_file16093/160 = 58% (50–65%)131/160 = 82% (75–87%)
+ pedido = первое сообщение цикла160116/160 = 73% (65–79%)145/160 = 91% (85–94%)
+ недавние шаги только текущего исполнения160117/160 = 73% (66–79%)144/160 = 90% (84–94%)
+ результаты до 2 000 символов160110/160 = 69% (61–75%)141/160 = 88% (82–92%)
+ текст модели из предыдущих шагов160116/160 = 73% (65–79%)149/160 = 93% (88–96%)
+ выведенные счётчики160112/160 = 70% (62–77%)148/160 = 93% (87–96%)

Всё движение несут две строки: эквивалентности (+9 пунктов) и первое сообщение цикла (+15). После escopo ничто не выводит top-1 за пределы интервала, а восстановленные результаты одобренных команд (acoes) его понижают. 47% первого раунда на том же входе — это 58% при объявленных эквивалентностях.

Заголовок​

Вариант escopo, проверка, 160 шагов с инструментом (плюс 1 без, на котором Jev ошибся):

top-1, правило эквивалентности117/160 = 73% (66–79%)
top-1, строгое правило (сопоставимо с 47%)105/160 = 66% (58–73%)
top-2 (меню ограничено до 2), эквивалентность / строго144/160 = 90% (84–94%) / 134/160 = 84% (77–89%)
top-3, эквивалентность148/160 = 93% (87–96%)
базовая линия «повторить предыдущий инструмент» (бесплатная), эквивалентность / строго122/149 = 82% (75–87%) / 108/149 = 72% (65–79%)
меню из 2 без второго вызова, {выбор Jev, предыдущий инструмент}, эквивалентность / строго140/160 = 88% (81–92%) / 125/160 = 78% (71–84%)
без Anamnese (kickoff не восстановлен; приостановлена в продукте)115/158 = 73% (65–79%)

Jev не обыгрывает бесплатную базовую линию. На тех же шагах проверки «повторить предыдущий инструмент» даёт 82% (72% строго), выше 73% (66%) Jev. Его единственное преимущество проявляется в объединении: предложение выбора Jev и предыдущего инструмента доходит до 88% (78% строго), на 15 пунктов выше одного Jev, без лишнего вызова. Ни одна конфигурация не доходит до 90% в top-1, и ни у одной нижняя граница не 90%.

По агентам (проверка, эквивалентность): dev-board-engine 23/24 = 96% (80–99%), dev-persistence 28/34 = 82% (66–92%), dev-scoring 31/38 = 82% (67–91%), dev-game-session 28/38 = 74% (58–85%), qa-estrategia 4/16 = 25% (10–49%), appsec 1/3, infra 0/2, infra-workflows 0/2, dev-lead 0/1 (у qa-estrategia и appsec первое сообщение восстановлено, но без истории; у остальных трёх оно вообще не восстановлено).

Уверенность по-прежнему не отделяет верное от неверного:

порогменю ограничено до 1верных среди ограниченных (95% ДИ)
0.00155/160117/155 = 75% (68–82%)
0.40123/16095/123 = 77% (69–84%)
0.6055/16044/55 = 80% (68–88%)
0.7032/16023/32 = 72% (55–84%)
0.8016/1608/16 = 50% (28–72%)
0.9010/1604/10 = 40% (17–69%)

Выше 0,7 точность падает: уверенные ошибки — те, что описаны ниже (Jev уверен, что после написания тестов идёт их запуск).

Расстояние по причинам​

82 ошибки проверки по правилу первого раунда и то, что с ними сделала каждая деталь каскада (шаги с инструментом, n = 160):

причинашаговпунктовдоля расстояния
мерка — выбор Jev был эквивалентным (E1–E3, объявленные заранее)159.4
мерка — остаток: классы всё ещё упускают случай (3 шага, ниже)31.922% (18 шагов)
вход — первое сообщение цикла (kickoff)2314.4
вход — escopo10.6
вход — остаток: невосстановленные первые сообщения или результат вне лога (7)74.438% (31 шаг)
темп агента, а не поле state (ниже)2918.1
Jev расходится без того, чтобы state это оправдывал (4)42.540% (33 шага)
итого8251.3

43 ошибки, оставшиеся после последней восстановленной детали, прочитаны по одной (не выборка): отправленный state, вызванные инструменты, собственный текст модели на этом шаге (который Jev никогда не видит), а также выбор и уверенность Jev. Результат:

  • Мерка, 3. dev-board-engine terminal→search_workspace: команда агента была find … | sort; ls; for f in docs/*; do …cat — только чтение, но цикла for нет в списке «только чтение», поэтому он оценивается как исполнение. Плюс два read_file→terminal, где агент всё время читал через terminal: эквивалентны при любом прочтении, но классы асимметричны намеренно, и это не переоценивалось.
  • Вход, 7. Все ошибки infra (2 шага), infra-workflows (2) и dev-lead (1) — пять шагов, первое сообщение которых перенос не восстанавливает, — плюс два report_done→terminal, где результата последней команды («exit 0, a suíte passou») нет в логе. Вариант acoes восстанавливает эти результаты и в целом сделал Jev хуже (61%): перед падающей песочницей он говорит report_blocked там, где агент продолжал пытаться.
  • Темп агента, 29. Jev называет следующий этап потока, а агент остаётся ещё на шаг в текущем: 14 × write_file→terminal (Jev: «тесты написаны, запустите их», 8 из них с уверенностью ≥ 0,6, до 0,98; агент написал ещё два-три файла до этого), 12 × qa-estrategia read/search→emit_plano_de_teste (Jev перескакивает к финальному инструменту kickoff с уверенностью 0,25–0,56; агент исследовал ~15 шагов, прежде чем выпустить), 2 × appsec то же самое, 1 × terminal→report_blocked после отклонённого действия. Во всех них выбор Jev — то, что читатель лога назвал бы естественным следующим шагом. То, что решает «сколько ещё файлов, сколько ещё чтений», — это план модели, которого нет ни в одном поле, которое продукт мог бы передать маршрутизатору, — он существует, один раз, в самом тексте предсказываемого шага.
  • Jev расходится, 4. write_file→search_workspace дважды с уверенностью 0,25–0,26, rag_search→terminal дважды (0,24, 0,59). Это единственные шаги, где state не объясняет выбор: 2,5% шагов.

Итак: из расстояния в 51 пункт между 49% первого раунда и 100% примерно пятая часть была меркой, около двух пятых — входом, которого не хватало повтору (а восстановимая его часть восстановлена), и две пятых — темп агента, причём 5% шагов — чистая ошибка Jev. От входа остаётся максимум 4 пункта, и это не то, что отделяет 73% от 90%.

Что понадобилось бы для 90% и сколько стоит каждая деталь​

Шаги проверки, 43 ошибки; 90% — это 144/160, то есть на 27 попаданий больше.

детальшагов максимумпримечание
завершить перенос входа (Anamnese, infra-workflows, первые сообщения разговорных; история qa-estrategia)до +7 → 79%верхняя граница: с полным входом Jev здесь лучше не стал, а восстановление результатов его ухудшило
ужесточить классы (циклы for, терминал-как-чтение в обратном направлении)+3 → 75%это мерка, а не точность; решать это после просмотра ошибок — именно то, что запрещает протокол, поэтому этого нет в заголовке
темп агентадо +29это не поле state; единственные входные двери — меню из 2, включающее предыдущий инструмент (измерено: 88%, 81–92%), или top-2 (90%, 84–94%)

Если читать как продуктовое решение, а это дело AT-239: маршрутизатор, которому нужно выбрать один инструмент, остаётся около трёх четвертей и ниже бесплатной базовой линии; маршрутизатор, который ограничивает меню до двух, доходит до девяти из десяти, а предыдущий инструмент — второе имя не хуже второго варианта самого Jev. Этот раздел не утверждает ни одной из двух выгод.

Задержка и стоимость (вариант escopo)​

входных токенов на запросp50 1 866, p95 2 557, макс 3 220 (первый раунд: медиана 1 710, макс 3 220)
задержка (328 запросов, последовательно)p50 317 мс, p95 449 мс, макс 814 мс; 0 выше 2 000 мс
стоимостьUS$ 0,0000769 за шаг (US$ 0,025233 за 328), и GET /api/v1/generation для каждого из 328 id даёт в сумме те же US$ 0,025233 (отношение 1,000)
весь этот раундUS$ 0,414 по usage.cost — 12 вариантов, 3 из них дважды на части половины настройки — против потолка US$ 1,00

Более богатые варианты стоят больше входа (acoes_completo: медиана 3 360 токенов, около US$ 0,00014 за шаг против 0,00008) и ничего не покупают; побеждающий state — ещё и дешёвый. У потолка 2 000 мс из AT-236 запас в два раза.

Чего этот раунд всё ещё не видит​

  • Историю двух gates, которые работают до любого кода (qa-estrategia, appsec): запрос, запускающий их, внутренний и не идёт в лог.
  • Первое сообщение Anamnese, infra-workflows и разговорных агентов; и системный промпт за contexto.
  • Эталон. Метка по-прежнему — инструмент, который вызвала чат-модель, и большинство из 29 ошибок темпа — выборы, которые человек-читатель назвал бы разумными, и именно поэтому top-2 и объединение говорят больше, чем top-1.
  • Эффект. Ограниченное меню меняет то, что модель делает дальше; AT-239.

Запрошено владельцем после второго раунда, где top-1 Jev (73%) остался ниже 90%, но меню из двух ({выбор Jev, предыдущий инструмент}) и top-2 Jev выглядели хорошо: проверить меню из 2 вариантов. Только результат, у которого нижняя граница 95% интервала не ниже 90%, — ясное «да». Не так: ни одна политика туда не доходит. Лучшая политика из 2 вариантов, P3, покрывает 91% (85–94%) шагов проверки, то есть правильный инструмент находится внутри меню; нижняя граница — 85%, на пять пунктов ниже линии. И это покрытие, потолок для сквозной точности (см. «Потолок»), а не сама точность. Тот же экземпляр, те же оговорки, что в предыдущих раундах; ничего здесь не меняет продукт (это AT-239). Воспроизведите через pnpm --filter @brabo/scripts jev:menu.

Политики (записаны до запуска, в scripts/jev/menu.ts)​

Политика превращает ответ Jev в ограниченное меню. Решения владельца действуют везде: Jev только ограничивает меню, а когда он отвечает responder_sem_ferramenta, остаётся весь каталог (AT-236); потолок 2 000 мс (во втором раунде его не превысил ни один из 328 запросов). Ничего не переклассифицировалось после просмотра результата; menu.spec.ts фиксирует, что возвращает каждая политика.

политикаменю
P0весь каталог (якорь: 100% покрытия, ничего не ограничивает)
P1два самых вероятных инструмента Jev
P2{выбор Jev, предыдущий инструмент того же исполнения}
P3P2, но если Jev говорит responder_sem_ferramenta (или предыдущего инструмента нет), меню — весь каталог
P4{выбор, предыдущий инструмент, второй вариант Jev} (до 3; только для справки)

Правила, общие для всех: упавший ответ (таймаут, ошибка, выбор вне вариантов) оставляет весь каталог; предыдущий инструмент, которого нет в каталоге агента, игнорируется; меню, которое вышло бы пустым, — весь каталог.

Покрытие = доля шагов с инструментом, на которых инструмент, который агент действительно вызвал, находится внутри меню, — строго (то же имя) и по эквивалентности (классы E1–E3 второго раунда, так что меню с read_file покрывает terminal, который лишь читает). Доля ограничения = доля шагов, на которых меню меньше каталога агента: политика, которая почти никогда не ограничивает, тривиально «100%» и бесполезна, поэтому покрытие даётся также среди ограниченных шагов. Вариант escopo (победитель второго раунда), половина проверки, 160 шагов с инструментом (плюс 1 без).

Числа (проверка)​

политикапокрытие, эквивалентность (95% ДИ)строгоограничиваетпокрытие среди ограниченныхоткрытые инструменты, до → послетокены определений на вызов, до → после
P0160/160 = 100% (98–100%)100%0/160 = 0%—7.4 → 7.4746 → 746
P1144/160 = 90% (84–94%)134/160 = 84% (77–89%)158/160 = 99%142/158 = 90% (84–94%)7.4 → 2.0746 → 150
P2143/160 = 89% (84–93%)128/160 = 80% (73–85%)157/160 = 98%140/157 = 89% (83–93%)7.4 → 1.3746 → 102
P3145/160 = 91% (85–94%)132/160 = 83% (76–88%)147/160 = 92% (87–95%)132/147 = 90% (84–94%)7.4 → 1.6746 → 138
P4149/160 = 93% (88–96%)142/160 = 89% (83–93%)158/160 = 99%147/158 = 93% (88–96%)7.4 → 2.2746 → 166

Какая лучшая. Важна P3: наибольшее покрытие среди политик из 2 вариантов, она соблюдает правило владельца и ограничивает 92% шагов. Её нижняя граница — 85,1%; у P1 — 84,4%, у P2 — 83,6%, у P4 — 88,1%. P4 ближе всех к линии, но меню до 3 — не тот вопрос, который был задан. Все политики остаются без «ясного да»; P1 и P3 попадают в 90% по точечной оценке, те же «90% (84–94%)», что второй раунд уже имел для top-2, — предыдущий инструмент ничего не добавляет к покрытию сверх второй догадки самого Jev, он лишь делает меню меньше (1,6 инструмента против 2,0).

Две вещи, которые таблица скрывает.

  • P3 предлагает лишь один инструмент в 98 из 160 шагов. Когда выбор Jev является предыдущим инструментом, в меню одно имя (P2: 108 из 160). Эти меню покрывают 89 из 98 (91%). Остальные 49 ограниченных шагов имеют меню из двух и покрывают 43 (88%). «Меню из 2» большую часть времени — это меню из 1 без выбора, оставленного агенту: он вынужден.
  • Интервал оптимистичен. Уилсон считает 160 шагов независимыми, а они таковыми не являются: проверка — это 10 исполнений (задачи четырёх dev agents, gates qa-estrategia, appsec и infra-workflows, а также Anamnese, Infra и Dev Lead), и последовательные шаги одного исполнения делят запрос, файлы и результаты. При так малом числе кластеров честный интервал шире напечатанных. Это не меняет ответа («нет» не улучшается), но и «да» не было бы заработано 160 шагами.

Настройка и новые шаги​

политиканастройка (161 шаг) покрытие, эквивалентностьограничиваетновые шаги (36) покрытие
P1144/161 = 89% (84–93%)156/161 = 97%36/36
P2143/161 = 89% (83–93%)127/161 = 79%36/36 (ограничивает 0)
P3147/161 = 91% (86–95%)115/161 = 71%36/36 (ограничивает 0)
P4148/161 = 92% (87–95%)156/161 = 97%36/36

Настройка говорит то же, что и проверка (P3 91%, нижняя граница 86%), как и ожидалось, поскольку ни одна из политик не настраивалась. Она несёт 32 шага Anamnese, для которых Jev говорит responder_sem_ferramenta, и P3 поэтому оставляет весь каталог: 71% ограничения вместо 92%. 36 новых шагов (база dev выросла с 333 до 369 строк расхода после снимка) — все от Anamnese, агента, приостановленного в продукте: Jev отвечает «никакого инструмента», и P2/P3 открывают весь каталог, поэтому «36/36» тривиально верно и ничего не говорит о меню. Все шаги вместе и без Anamnese (287 с инструментом; половина настройки уже выбрала вариант, так что это не чистая проверка): P1 89% (84–92%), P2 88% (84–91%), P3 90% (86–93%), P4 92% (88–94%). Больше шагов сужают интервал, но нижняя граница остаётся на 86%; при истинном покрытии около 91% нужно около трёх тысяч шагов, чтобы нижняя граница перешла 90%, а помог бы лучший маршрутизатор, а не большая выборка.

Чувствительность, а не выбор: с любым из двенадцати вариантов state P2 покрывает 88–91%, а P3 — 89–92% шагов проверки, поэтому результат не зависит от escopo (P1 зависит: 82% с исходным входом, 93% с texto или fluxo). Ни у одного варианта нижняя граница тоже не 90% — самые высокие у P1 с texto (88%) и P3 с enxuto (87%), — а выбрать один после того, как это увидено, — ровно то, что запрещает протокол.

Где покрытие проваливается​

P3, проверка, 15 шагов вне меню: write_file использован, когда меню было terminal (4), read_file, когда terminal (2), report_done, когда terminal (2), write_file, когда {search_workspace, terminal} (2), и пять единичных случаев среди gates и разговорных агентов (emit_plano_de_teste предложен вместо rag_search или search_workspace, и наоборот). Это расстояние темпа второго раунда, увиденное с другой стороны: Jev называет следующий этап, агент делает ещё шаг в текущем — а агент, чьё меню — terminal, не может записать файл инструментом, сделанным для этого. По агентам (P3, эквивалентность): dev-board-engine 23/24 = 96% (80–99%), dev-scoring 35/38 = 92% (79–97%), dev-persistence 31/34 = 91% (77–97%), qa-estrategia 14/16 = 88% (64–97%), dev-game-session 32/38 = 84% (70–93%); у остальных меньше четырёх шагов.

Потолок: чего не говорит покрытие​

Покрытие — это потолок сквозной точности, а не точность. Меню содержит правильный инструмент; модели агента ещё нужно выбрать его среди вариантов. Метка («инструмент, который вызвала чат-модель») — выбор, сделанный агентом из всего каталога, поэтому полное меню — 100% по построению, а ограниченное может только терять. Что можно сказать без продукта, для P3 на проверке, разделив 160 шагов:

  • 99 (62%, 54–69%): каждый инструмент меню верен, поэтому любой выбор агента верен — пол.
  • 46 «спорных»: ровно один из вариантов верен, и агент решает сам — 28 только предыдущий инструмент, 18 только выбор Jev. Агент, всегда берущий предыдущий инструмент, заканчивает на 127/160 = 79%; всегда берущий выбор Jev — на 117/160 = 73% (снова базовые линии второго раунда); бросающий монетку — на 76%. Агент, выбирающий лучше обоих, а на этом и строится вся ставка, попадает между 79% и потолком 91%.
  • Остальные 15 вне меню: потеряны, что бы ни делал агент.

Итак, сквозной диапазон — от 62% до 91%, и где он окажется, зависит от того, насколько хорошо модель агента читает ситуацию, которую повтор не видит. Ответить на это может только живой тест (AT-239).

Экономия на определениях инструментов​

Каталог содержал описание каждого инструмента (catalogo.json), а теперь ещё и definicoes: размер в байтах полного spec/0 каждого инструмента (имя, описание и схема параметров), сериализованного engine (catalogo.exs, запущен заново; остальная часть файла не изменилась). Токены — это байты, делённые на 4, приближение, которое использует весь повтор. На проверке P3 уходит с 746 до 138 токенов определений на вызов — 608 токенов, на 81% меньше: восемь инструментов dev agent весят 3 068 байт, а меню из двух — около 500. P1 экономит 596, P2 — 644 (средние по шагам половины; половина настройки экономит меньше, потому что Anamnese сохраняет весь каталог).

Сколько это стоит — другой вопрос. Сам вызов Jev читает ~1 870 токенов (US$ 0,0000769) на модели гораздо дешевле модели агента; экономия на определениях — 608 токенов модели агента на вызов. Точка безубыточности — входная цена US$ 0,126 за миллион токенов (0,0000769 / 608): выше неё экономия окупает вызов Jev, без учёта кеша. Кеш — подвох: провайдеры кешируют префикс запроса, определения инструментов идут первыми, а меню, меняющееся от шага к шагу, меняет префикс — экономия может быть возвращена промахами кеша. Это живое измерение, и причина, по которой тест ниже записывает долю кешированных токенов.

Живой тест (не выполнен): схема​

  • Вопрос. С P3 перед агентом ухудшается ли работа агента, и насколько она дешевеет? Не «есть ли инструмент в меню» (это этот раздел).
  • Этап 1, тень (дёшево, до того как пользователь увидит меню). Для каждого шага зарезервированной выборки спросить саму модель агента дважды об одном state, с полным каталогом и с меню P3, и сравнить инструмент, который она выбирает, по правилу эквивалентности. Метрика: согласие между двумя, с нижней границей 95% интервала. Чтобы показать истинное согласие 94% с нижней границей 90% (мощность 80%): около 390 шагов, взятых из не менее чем 40 разных исполнений и более чем одного проекта (в этой выборке 21 исполнение в одном проекте), интервал по кластеру (исполнению), а не по шагу.
  • Этап 2, живой A/B, только если этап 1 пройден. Ветви: контроль (полный каталог) и P3, разыгрываемые по исполнению, никогда по шагу (меню одного шага формирует следующий). Основная метрика: исполнение доходит до gate без переделки, допуск не меньшей эффективности 5 пунктов; при 80% завершения, 5% одностороннем и мощности 80% — около 790 исполнений на ветвь (допуску 10 пунктов нужно около 200). При объёме этого проекта (7 исполнений dev во всей выборке) это требует многих проектов или недель. Вторичные: шаги на исполнение, входные токены включая долю кешированных токенов, стоимость исполнения, задержка, добавленная Jev (p50/p95, потолок 2 000 мс), и доля шагов, на которых Jev оставляет весь каталог.
  • Стражи. Флаг отключения на проект; откат на весь каталог при любом сбое Jev или выше потолка задержки (уже в каждой политике); способ для агента запросить полный каталог, когда в меню нет нужного (меню из одного вынуждает инструмент, 61% шагов здесь); промежуточный просмотр каждые 100 исполнений с остановкой, если основная метрика падает больше допуска; Anamnese вне выборки (приостановлена); меню и выбор записываются на каждом шаге, чтобы анализ был запросом, а не воспоминанием.

Чего этот раздел всё ещё не видит​

  • Выбор агента внутри меню: причина, по которой это потолок.
  • Зависимость между шагами: 10 кластеров в проверке; интервалы — по шагам.
  • Кеш промпта и задержка в цикле агента: не измерены (вызов Jev измерен, p50 317 мс; его эффект в цикле — нет).
  • Метка: по-прежнему инструмент, который вызвала чат-модель, а ограниченное меню меняет то, что она делает дальше.

Стоимость этого теста​

Один вызов, для 36 новых шагов: US$ 0,001275 по usage.cost (потолок задачи US$ 0,30). Политики работают офлайн по ответам, уже лежащим на диске. Накопленный расход каталога вывода вырос с US$ 0,4136 до US$ 0,4149.

Живое сравнение (AT-239, 2026-10-01): ограничивать, включено для Haiku и выключено для DeepSeek​

AT-239 (EP-029, HS-063) задаёт вопрос, который оставлял открытым каждый предыдущий раздел: с включённым маршрутизатором становятся ли ходы короче, быстрее или дешевле, и выходит ли работа по-прежнему? Те же задачи, на той же модели OpenRouter, с маршрутизацией ADR 0179, включённой и выключенной, на двух чат-моделях разной скорости.

Ситуация на 2026-10-01: измерено с третьей попытки (ниже). Первая попытка: не измерено. У сессии, построившей инструмент (ветка test/jev-com-e-sem, от dev на d070b000d7), был платный ключ и потолок US$ 5,00, но её исходящий прокси отказал в CONNECT к openrouter.ai:443 по политике организации, а также к repo.hex.pm и builds.hex.pm, поэтому даже engine нельзя было скомпилировать. Ни один вызов чата и ни один вызов Jev не покинул машину: потрачено US$ 0,00. Далее — инструмент, протокол и правило решения, всё записанное до любого исполнения, числа, которые удалось измерить без сети, а затем живая таблица третьей попытки.

Вторая попытка, в тот же день: всё ещё не измерено, по другой причине. Владелец открыл openrouter.ai на выходе сессии (GET ответил 200), и обе модели протокола значились с поддержкой инструментов (deepseek/deepseek-v4.1-flash по US$ 0,03/0,50 за миллион входа/выхода, anthropic/claude-haiku-4.5 по US$ 1,00/5,00). Первый вызов чата вернул HTTP 403 Key limit exceeded (total limit): у тестового ключа лимит US$ 10,00, US$ 10,05 уже использовано и никакого сброса (GET /api/v1/key). Smoke одной задачи, вне протокола и в собственной папке, потратил US$ 0,00; ни одно исполнение протокола не было записано. Его запуск требует, чтобы владелец поднял лимит ключа (или выдал другой ключ) — около US$ 1,28 по оценке ниже, меньше по текущей цене DeepSeek. Smoke также нашёл две вещи, которые фальшивая сеть никогда бы не нашла, обе исправлены или задокументированы в инструменте:

  • Сбой учётной записи или сети записывался как измеренное исполнение. Оба исполнения smoke закончились erro на шаге 0 с HTTP 403, были записаны в вывод как «задача не вышла», и возобновление никогда бы их не повторило: с мёртвым ключом все 40 исполнений попали бы в таблицу. falhaDeInfra (resumo.ts) теперь классифицирует ошибку чата HTTP 401/402/403/407/429 или транспорта как несостоявшееся измерение; vivo.ts не записывает такое исполнение, останавливает исполнение с причиной, а возобновление его повторяет. Ошибка провайдера в теле 200, 5xx и падение Jev остаются исходами ветви, как в engine.
  • fetch в Node игнорирует HTTPS_PROXY. За прокси запускайте с NODE_USE_ENV_PROXY=1 (Node ≥ 22.21); без этого вызовы шли напрямую, и выход отвечал 403 с телом, которое не было JSON.

Третья попытка, в тот же день: измерено. Владелец поднял лимит ключа до US$ 20,00 (US$ 9,95 оставалось перед исполнением) и разрешил потолок US$ 4,50. Протокол ниже прошёл ровно так, как написан, — две модели, пять задач, два раунда, 40 исполнений, значения по умолчанию jev:vivo, — на коммите 0eab0cb0e9, без единого сбоя учётной записи или сети и без прерванных исполнений. Потрачено: US$ 0,5195 по сумме usage.cost в выводе (US$ 0,0424 DeepSeek, US$ 0,4771 Haiku); usage ключа сдвинулся на те же US$ 0,5195 (US$ 10,0545 → US$ 10,5739, прочитано примерно через десять минут после исполнения — чтение сразу после него ещё показывало US$ 0,4597, списание запаздывает относительно ответов). Таблица и вердикт — в «Живой таблице» и «Рекомендации» ниже; протокол, правило и оценку не трогали после прихода чисел.

Что запускает инструмент и что является переносом​

pnpm --filter @brabo/scripts jev:vivo (файлы в scripts/jev/vivo/) запускает цикл dev agent на пяти маленьких задачах, один раз с включённым маршрутизатором и один раз с выключенным, и вызывает OpenRouter напрямую — api, engine и база не участвуют, как в платной проверке языка AT-167.

файлрольпродукт или перенос
roteador.tsrecortarEstado, montarPedidoAoJev, lerRespostaDoJev, menuP3, потолок stateкод продукта, реэкспортированный из apps/api/src/domain/llm/tool-router.ts
laco.tsцикл: потолок итераций, восстановление вызовов инструментов, написанных текстом, остановка на принятом report_done/report_blocked, единственная повторная попытка с полным каталогом, когда ограниченное меню получило ответ без инструментаперенос ToolLoop, EngineApiClient.llm_turn/5 и DecidirFerramentaDoPassoUseCase
recuperacao.tsкакие шаги прошли через tool_call_recovery.exперенос; его spec прогоняет случаи tool_call_recovery_test.exs и фиксирует строки-якоря .ex
rede.tsвызов чата (сообщения на проводе, как их пишет api) и вызов Jev (потолок 2 000 мс, те же именованные падения)перенос toWireMessage/toWireTool и JevToolRouter; строки-якоря зафиксированы
ferramentas-dev.exs → ferramentas-dev.jsonполный spec/0 девяти инструментов Engine.Dev.Tools.registry/0 (имя, описание, схема параметров)прочитан из исходников engine чистым elixir, без скомпилированного engine; spec падает, когда реестр или описание дрейфует
tarefas.tsпять задач над проектом Node без зависимостей, у каждой проверка, запускаемая после цикла (исходные тесты восстановлены, скрытые тесты добавлены): «задача вышла»собственный инструмента
executor.tsинструменты в временной песочнице, возвращающие тексты engine там, где они зашиты в кодсобственный инструмента
resumo.ts, vivo.tsтаблица, правило решения, оценка стоимости, CLIсобственный инструмента

Вне инструмента, одинаково в обеих ветвях и заявлено: конвейер одобрения (terminal и write_file выполняются напрямую, как в автоматическом режиме), сжатие контекста, языковая ориентация и профиль автора, добавляемые в конце каждого вызова, RAG (пустой индекс), контракты модулей (ни одного не объявлено) и остальная часть настоящего системного промпта (файлы инструкций, бизнес-правила, состояние задачи). Системный промпт — это идентичность dev из engine плюс две строки контекста проекта; первое пользовательское сообщение — собственный kickoff engine (scripts/jev/kickoff.ts). Стоимость каждого вызова — usage.cost ответа, число, которое RN-665 (ADR 0188) кладёт в metering; token_usage продукта не участвует.

Протокол (записан до любого исполнения)​

  • Модели: deepseek/deepseek-v4.1-flash (медленнее, рассуждающая) и anthropic/claude-haiku-4.5 (быстрее), две, до которых проверка AT-167 уже дотягивалась с определениями инструментов на этом ключе.
  • Задачи: T1-media (реализовать функцию), T2-moeda (исправить баг форматирования), T3-limite (причина в другом файле: config/), T4-slug (создать модуль и его тесты; скрытые тесты его проверяют), T5-renomear (переименовать в двух файлах; в src/ не должно остаться следа старого имени). Начальное состояние каждой задачи проваливает проверку, а эталонное решение её проходит (spec).
  • Выборка: 2 раунда → 10 исполнений на ветвь на модель, всего 40. Порядок ветвей чередуется по задаче и раунду, чтобы ни одна ветвь не получала всегда самую медленную минуту провайдера. Потолок итераций 30 (потолок dev в продукте — 60; здесь он ограничивает расход).
  • На исполнение: шаги; шаги, чьи вызовы пришли текстом и прошли через восстановление; шаги, на которых маршрутизатор был опрошен, применил меньшее меню, оставил весь каталог без падения (нет предыдущего инструмента, или Jev сказал responder_sem_ferramenta) или упал (с причиной и источником RN-059); повторные попытки с полным каталогом; вызовы вне меню шага; настенная задержка всего исполнения (Jev + чат + инструменты) и части LLM; стоимость чата и Jev; как закончилось; вышла ли задача.
  • Правило решения (comparar в resumo.ts), по модели, включено против выключено: качество — доля «задача вышла» у включённого не более чем на 10 пунктов ниже выключенного; стоимость — средняя стоимость на вышедшую задачу (чат + Jev) у включённого не выше выключенного; задержка — медианное исполнение включённого не выше 1,2× выключенного. Оставить включённым по умолчанию, если все три выполняются на каждой модели; выключить, если качество проваливается на каждой модели или ни одна модель не проходит все три; ограничить моделями, которые проходят, — в противном случае. Меньше 10 исполнений на ветвь — это amostra_insuficiente, но никогда не вердикт.

Оценка стоимости (без сети)​

--estimar с ценами, которые можно было измерить по прежним записям: вход DeepSeek по US$ 0,30 за миллион и Haiku по US$ 1,00 (оба выведены из парной входной стоимости, сообщённой в Измерении эвристики языка); выход US$ 1,20 для DeepSeek — предположение (нигде не записанное), а US$ 5,00 для Haiku — прейскурантная цена. Предполагаются 12 шагов на исполнение, 400 токенов истории, добавляемых на шаг, 150 выходных токенов, без кеша:

модельна исполнениеобе ветви, 2 раунда
deepseek/deepseek-v4.1-flash~US$ 0,015~US$ 0,29
anthropic/claude-haiku-4.5~US$ 0,049~US$ 0,99
итого~US$ 1,28

Исполнение останавливается перед любым вызовом, как только накопленный usage.cost папки вывода достигает --teto-usd (по умолчанию 4.50), и не начинает исполнение, если осталось меньше --reserva-usd (0.10).

Что удалось измерить офлайн (2026-10-01)​

Каталог dev вырос со времени повтора: listar_contratos_de_modulos (RN-684) — девятый инструмент, и catalogo.json (восемь) для него устарел — 746 → 138 токенов повтора уже не описывают текущий каталог. На проводе (форма toWireTool, ferramentas-dev.json):

символов≈ токенов (÷ 4)
весь каталог dev, 9 инструментов3 816954
меню из 2 инструментов, медиана по всем парам (мин 501, макс 1 464)850213
экономия на вызов там, где P3 ограничивает меню≈ 741

Jev стоит US$ 0,0000727 за шаг (AT-237), поэтому экономия на определениях окупает его на чат-модели, вход которой стоит больше US$ 0,098 за миллион токенов (0,0000727 ÷ 741) — обе модели протокола, по прейскуранту. Подвох — тот же, что записан в «Экономии на определениях инструментов»: определения инструментов — начало кешированного префикса, меню, меняющееся от шага к шагу, ломает кеш, а DeepSeek отдал большую часть входа из кеша в AT-167. Переживёт ли экономия это и сколько дополнительный последовательный вызов стоит в задержке внутри цикла (p50 306 мс на шаг, измерено вне его), — ровно то, на что ответила бы живая таблица.

Живая таблица (2026-10-01, коммит 0eab0cb0e9)​

Сгенерирована jev:vivo --relatorio по 40 исполнениям прогона протокола (все датированы 2026-10-01, все на 0eab0cb0e9). В скобках — 95% интервал доли «задача вышла».

модельJevисполненийзадача вышлашаги (медиана · среднее)шаги через tool_call_recoveryисполнение p50 · p95LLM (чат + Jev) p50стоимость/исполнение (чат + Jev)из них Jevстоимость на вышедшую задачуJev: применён · без ограничения · падениеповторы с полным каталогомвне меню
deepseek/deepseek-v4.1-flashвкл1010/10 = 100% (72%–100%)5 · 6.50/654.8 s · 16.3 s4.4 sUS$ 0.0029US$ 0.0004US$ 0.002955/65 · 10 · 003
deepseek/deepseek-v4.1-flashвыкл1010/10 = 100% (72%–100%)6 · 6.10/613.3 s · 25.4 s2.9 sUS$ 0.0013—US$ 0.0013———
anthropic/claude-haiku-4.5вкл1010/10 = 100% (72%–100%)6 · 6.40/6412.7 s · 20.2 s12.2 sUS$ 0.0194US$ 0.0004US$ 0.019454/64 · 10 · 004
anthropic/claude-haiku-4.5выкл109/10 = 90% (60%–98%)7 · 7.10/7113.3 s · 21.6 s12.9 sUS$ 0.0283—US$ 0.0314———

Каждое исполнение закончилось принятым report_done; единственная задача, которая не вышла (Haiku, выкл, T4-slug раунд 0), сообщила о завершении после 12 шагов с падающими скрытыми тестами. Ни одному шагу ни одной ветви не понадобился tool_call_recovery, Jev ни разу не упал (ни таймаута, ни HTTP-ошибки, ни недопустимого ответа на 129 вызовах), и ни одно ограниченное меню не получило ответа без инструмента. 10 шагов «без ограничения» на ветвь — это первый шаг каждого исполнения, где нет предыдущего инструмента.

Правило (comparar), по модели, включено против выключено:

моделькачество: Δ «вышла»стоимость на вышедшую задачу, вкл ÷ выклмедианное исполнение, вкл ÷ выклпроходит
deepseek/deepseek-v4.1-flash0 пунктов (в пределах 10)×2.21 (выше 1)×1.45 (выше 1.2)нет
anthropic/claude-haiku-4.510 пунктов в пользу включённого (в пределах 10)×0.62×0.95да

Вердикт правила: ограничить — Haiku проходит все три условия, DeepSeek проваливает стоимость и задержку. Качество не провалилось ни на одной модели.

Почему две модели расходятся, по пошаговым записям того же вывода (токены промпта и кешированные токены, о которых сообщил провайдер):

модельJevтокены промпта (все шаги)из них из кешастоимость чатастоимость Jev
deepseek/deepseek-v4.1-flashвыкл131 983111 104 (84%)US$ 0.0132—
deepseek/deepseek-v4.1-flashвкл97 07043 520 (45%)US$ 0.0248US$ 0.0044
anthropic/claude-haiku-4.5выкл228 8860US$ 0.2827—
anthropic/claude-haiku-4.5вкл137 0590US$ 0.1901US$ 0.0043
  • Оговорка о кеше, записанная до исполнения, — то, что случилось с DeepSeek. Меню урезает промпт (−26% токенов), но меняется от шага к шагу, поэтому кешированный префикс ломается: доля из кеша упала с 84% до 45%, а счёт за чат вырос ×1,9 при меньшем числе отправленных токенов. Сверх того Jev (US$ 0,0004 на исполнение) — треть стоимости целого исполнения с выключенным маршрутизатором.
  • На Haiku кеша не было ни в одной ветви (инструмент не отправляет cache_control, и форма провода продукта, которую он переносит, тоже), поэтому −40% токенов промпта пошли прямо в счёт: −31% на исполнение, а Jev — 2% от него.
  • Задержка следует скорости чата, как и ожидала AT-239. Вызов Jev последовательный (p50 232 мс / p95 358 мс на вызов в исполнениях DeepSeek, 217 / 319 мс в исполнениях Haiku): в исполнении Haiku на 13 с он поглощается на шаг меньшим числом шагов; в исполнении DeepSeek на 3 с он добавляет 1,5 с к медиане.
  • Качество: разница в одно исполнение на Haiku, интервалы пересекаются (60%–98% против 72%–100%) — нет свидетельств, что маршрутизатор помогает качеству, и нет — что вредит, на этих пяти маленьких задачах.

Рекомендация (измерено — решает владелец)​

Ограничить, по правилу, записанному до исполнения: оставлять маршрутизатор включённым там, где у чат-модели нет действующего кеша промпта и она достаточно медленна, чтобы дополнительный последовательный вызов был мал (класс Haiku, US$ 1,00/5,00 за миллион), и выключенным там, где провайдер отдаёт большую часть входа из кеша, а чат быстр (класс DeepSeek). Числа, которые это оправдывают, — строки правила выше: Haiku ×0,62 по стоимости и ×0,95 по задержке без потери качества; DeepSeek ×2,21 по стоимости и ×1,45 по задержке без выигрыша в качестве.

Чего это не покрывает и чего потребовало бы ограничение:

  • Измерены только dev agents (ToolLoop). Прежнее прочтение — никаких свидетельств для семи разговорных агентов — остаётся в силе; ничто здесь на них не распространяется.
  • Разделение — по модели, а переключатель продукта — по workspace (PUT workspaces/:workspaceId/tool-router). Ограничения по модели (или по «действующему кешу») не существует; его создание — новое решение и новое изменение, здесь не сделанное. До тех пор измеренный выбор по workspace таков: включено, если его агенты работают на модели класса Haiku без кеша, выключено, если на модели класса DeepSeek с кешем.
  • Выборка и задачи малы (10 исполнений на ветвь, пять задач от 4 до 16 шагов). Отношения стоимости и задержки достаточно широки, чтобы их читать; разница качества в одно исполнение — нет.
  • Эффект кеша зависит от кеша провайдера, а не только от скорости: workspace на Haiku с включённым кешем промпта, вероятно, сдвинулся бы к линии DeepSeek. Не измерено.

Предварительная рекомендация, которая была здесь до исполнения (ограничить: включено для dev agents, выключено для разговорных агентов), заменена вердиктом правила выше, как и говорил тот абзац.

Как воспроизвести​

# the catalog, when a tool or an identity changed (inside the dev engine container)
docker cp scripts/jev/catalogo.exs brabo-dev-engine-1:/tmp/catalogo.exs
docker exec brabo-dev-engine-1 mix run --no-start --no-compile --no-deps-check /tmp/catalogo.exs \
> scripts/jev/catalogo.json

# count the steps and estimate the cost, without calling the network
pnpm --filter @brabo/scripts jev:replay -- --container brabo-dev-postgres-1 --estimar

# the run (resumes: a step already answered in the output is not asked again)
pnpm --filter @brabo/scripts jev:replay -- --container brabo-dev-postgres-1 \
--arquivo-de-chave ~/.config/brabo/openrouter-test.env --teto-usd 2

# the report again, and the billed cost per generation
pnpm --filter @brabo/scripts jev:replay -- --so-relatorio
pnpm --filter @brabo/scripts jev:replay -- --conferir-custo --arquivo-de-chave ~/.config/brabo/openrouter-test.env

Вывод ($XDG_CACHE_HOME/brabo/replay-jev/respostas.jsonl, иначе ~/.cache/…, права 600) несёт id сессий и остаётся вне checkout — скрипт отвергает назначение внутри него. Печатаемый отчёт содержит лишь счётчики и id агентов. Ключ читается из окружения (OPENROUTER_TEST_KEY) или из указанного файла и никогда не печатается и не записывается.

У второго раунда собственная команда, которая читает замороженный снимок базы (--dados-cache, вне checkout) и пишет файл на вариант:

# the snapshot, once (the dev database keeps moving; every later run reads this file)
pnpm --filter @brabo/scripts jev:analise -- --container brabo-dev-postgres-1 \
--dados-cache ~/.cache/brabo/replay-jev/dados.json --variante original --estimar

# one variant, tuning half first; validation only when the choice is made
pnpm --filter @brabo/scripts jev:analise -- --dados-cache ~/.cache/brabo/replay-jev/dados.json \
--variante escopo --metade tuning --arquivo-de-chave ~/.config/brabo/openrouter-test.env
pnpm --filter @brabo/scripts jev:analise -- --dados-cache ~/.cache/brabo/replay-jev/dados.json \
--variante escopo --metade validacao --arquivo-de-chave ~/.config/brabo/openrouter-test.env

# the tables of this section, and the wrong steps for reading by hand
pnpm --filter @brabo/scripts jev:analise -- --dados-cache ~/.cache/brabo/replay-jev/dados.json --relatorio --final escopo
pnpm --filter @brabo/scripts jev:analise -- --dados-cache ~/.cache/brabo/replay-jev/dados.json \
--variante escopo --metade validacao --dump-erros ~/.cache/brabo/replay-jev/v2/erros.txt

Снимок этого раунда снят с базы в том виде, в каком она была 2026-09-29 14:27 UTC, плюс события proposed_action.created и исходы proposed_actions тех же сессий; у нового снимка больше шагов и другое разделение. Потолок касается накопленного расхода каталога вывода (--teto-usd, по умолчанию US$ 1,00), а не одного вызова.

Тест меню работает офлайн по этим ответам; сеть вызывают только 36 шагов, родившихся после снимка:

pnpm --filter @brabo/scripts jev:analise -- --dados-cache ~/.cache/brabo/replay-jev/dados-d.json \
--variante escopo --metade ambas --arquivo-de-chave ~/.config/brabo/openrouter-test.env

# --dados-base is the snapshot that fixed the split; what it did not know is "new"
pnpm --filter @brabo/scripts jev:menu -- --dados-cache ~/.cache/brabo/replay-jev/dados-d.json \
--dados-base ~/.cache/brabo/replay-jev/dados-c.json --sensibilidade

Живое сравнение AT-239 (нужен доступный openrouter.ai; папка вывода, $XDG_CACHE_HOME/brabo/jev-vivo/ по умолчанию, остаётся вне checkout, и скрипт отвергает папку внутри него):

# the dev tool definitions, when a dev tool changed (plain elixir, no compiled engine)
elixir scripts/jev/vivo/ferramentas-dev.exs > scripts/jev/vivo/ferramentas-dev.json

# the estimate, without the network
pnpm --filter @brabo/scripts jev:vivo -- --estimar \
--preco deepseek/deepseek-v4.1-flash=0.3/1.2 --preco anthropic/claude-haiku-4.5=1/5

# the run (resumes; stops before any call at the ceiling, and on an account or
# network failure without recording it), then the table and the verdict;
# behind a proxy, prefix NODE_USE_ENV_PROXY=1 (Node's fetch ignores HTTPS_PROXY)
pnpm --filter @brabo/scripts jev:vivo -- --rodadas 2 --teto-usd 4.5 \
--arquivo-de-chave ~/.config/brabo/openrouter-test.env
pnpm --filter @brabo/scripts jev:vivo -- --relatorio