Кеш промпта
Ломает ли rtok кеш промпта?
Нет — это измерено, а не обещано. rtok stats на этой машине (2026-09-18) показывает
hit=97.5% — 5 620 803 600 токенов чтения из кеша против 145 402 240 токенов создания кеша и
667 038 некешированных входных токенов за 910 сессий, — а раздел Cache в rtok report на
ту же дату не содержит строк о сбросах во всём журнале: ноль зафиксированных сбросов кеша промпта.
Причина структурная, по каждому интерфейсу ниже: побайтно стабильное внедрение, переписывания вне
рабочей кромки разговора и хуки, которые касаются каждого результата один раз. Воспроизведите оба числа:
rtok stats 2>/dev/null | head -4
rtok report 2>/dev/null | sed -n '/[Cc]ache/,+6p'
Хуки — фильтрация один раз, дальше байтами владеет хост
cmd и read работают на PreToolUse, до вызова: вывод сокращается один раз, и
хост сохраняет этот текст в своём транскрипте. Каждый следующий ход воспроизводит собственные сохранённые байты
хоста — rtok в этом цикле больше не участвует, поэтому ничто из того, что он затронул, между ходами не меняется.
Та же логика, что и в аргументе rtk о кеше, плюс архив: всё вырезанное можно получить обратно, а
оставшиеся байты зафиксированы на всё время жизни сессии.
inject — побайтно стабилен на каждом ходу
Внедрение SessionStart пересчитывается на каждом ходу, поэтому оно остаётся внутри закешированного префикса,
только если байты никогда не сдвигаются. Они и не сдвигаются: два запуска с неизменным состоянием дают идентичный
вывод, что закреплено тестом three_500_budget_800_drops_one_and_is_byte_stable
(src/plugins/inject/mod.rs), а session_start_has_nudges_once_and_stable покрывает
путь с подсказками. Всё, что в inject зависит от времени или счётчиков, — ошибка по собственному
инварианту плагина, а не компромисс.
archive / proxy — переписывание только вне keep_turns, побайтно идентичные указатели
Фильтр archive на стороне прокси переписывает результат инструмента в указатель на архив, только когда
ход старше archive.keep_turns; system, tools и самые новые ходы
никогда не трогаются, поэтому рабочая кромка — та часть, которую провайдер ещё записывает в
кеш, — остаётся нетронутой. Стабильность закрепляют два теста в src/plugins/archive/mod.rs:
six_turn_fixtures_archive_only_turns_1_and_2_on_every_wire (из шести ходов переписываются только 1–2,
в каждом формате протокола) и live_blobs_shrink_stably_outside_the_working_edge
(указатель переписанного блока побайтно идентичен при повторном переписывании).
Измерено на этой машине, 2026-09-18 — mise exec -- cargo run --quiet -- stats 2>/dev/null | head -4:
sessions 910 lines 433211 malformed 0
usage input=667038 cache_create=145402240 cache_read=5620803600 output=27472613 hit=97.5% median_context=63829
api input cache_create cache_read output hit
codex 12370533 0 243051392 671350 95.2%
и mise exec -- cargo run --quiet -- report 2>/dev/null | sed -n '/[Cc]ache/,+6p':
## Cache
Prompt-cache busts by cause, from the proxy's `usage` rows (whole ledger).
No rows in window.
Это весь журнал, записанный прокси: при том что archive переписывает старые результаты инструментов
в протоколе, ни одного сброса не зафиксировано, а доля попаданий — 97.5% (95.2% для api codex,
который сообщает 0 токенов создания кеша).
По полосам — доля попаданий и replay-тест
Когда прокси обслужил трафик вне полосы agent (bulk, internal, …), rtok stats добавляет рядом с
api таблицу lane с теми же счётчиками и долей попаданий в кеш промпта для каждой полосы
(lanes в --json). Хранилище только с ходами агента такой таблицы не печатает. Стабильность
полосы agent закреплена тестом tests/proxy_cache_replay.rs: он проигрывает один растущий диалог
через прокси со всеми включёнными переписываниями и проверяет, что tools, system и каждое
сообщение до живого края предыдущего хода доходят до upstream побайтно одинаковыми.
guard — отказы не добавляют байтов
Отказ guard — это решение PreToolUse, а не содержимое: он подавляет повторный вызов
с фиксированной однострочной причиной duplicate; rtok expand <id> и не добавляет байтов
результатов инструментов ни в один ход. За результат, в котором он отказывает, уже заплатили один раз, и его можно получить через этот
id, поэтому модель никогда не платит за вторую копию — а воспроизводимый транскрипт
не меняется, что и есть благоприятный для кеша исход.
Отсутствие потерь не стоит кеша
Всё описанное выше сокращает байты; ничто их не теряет. Все сокращённые данные архивируются
до обрезки, и expand <id> восстанавливает оригинал (--lines, --grep). Указатель
в транскрипте побайтно стабилен, поэтому возможность восстановления никогда не переписывает префикс: кеш
сохраняет свои попадания, а вы сохраняете полный текст.
Sticky-маршрутизация и Batch / Flex
Попаданиям в кеш промпта у провайдера нужен стабильный байтовый префикс и, на upstream из нескольких подов,
привязка к одному и тому же бэкенду, на котором лежит кеш (I-84 / sticky-маршрутизация). Это ортогонально
Batch (асинхронный pass-through; нет живого KV сессии, общего с интерактивным агентом) и
Flex (service_tier в том же синхронном протоколе — правила кеша по-прежнему действуют, скидка даётся за
уровень). rtok не будет превращать синхронный ход агента в задание Batch только ради экономии; делайте это
лишь с явным клиентом Batch. Подробности: batch-flex.md.
# Запланированный флаг sticky в [proxy.routing] (сегодня не загружается) — закрепить upstream ради привязки к кешу.
# Flex — это [proxy.flex]; наблюдение за Batch — [proxy.batch]. Ни один из них не переписывает закешированные
# байты system/tools/живой кромки так, как это сделало бы небрежное сжатие.
[proxy.routing]
sticky = true