Прокси-сэндвич, от которого у токенов заканчивается терпение
Когда счет за LLM переваливает за $5000 в месяц, а код-ревью агент все еще тащит в контекст весь репозиторий — самое время вспомнить, что воздушные шары токенов не бесконечны. Я провел трехнедельный аудит связки rtk (Request Token Kernel v2.1.0) с context-mode (на базе FTS5) поверх индексов Serena v3.0 и Semble v2.5. Результаты: экономия до 62% токенов на пиковых нагрузках, но латентность выросла на 150-400 мс. Стоит ли игра свеч? Давайте разбираться по косточкам.
Сначала коротко: что за звери?
Если ты читал мой сравнение 21 инструмента сборки контекста, то Serena и Semble уже знакомы. Первый — это LSP-сервер для статического анализа, который выкуривает символы, типы, референсы. Второй — эмбеддинговый движок, который на лету строит векторный индекс кода. Оба работают локально, но по отдельности жрут токены как не в себя: Serena тащит декларации соседних модулей, Semble — семантически похожие блоки. А вот rtk — это прокси, который сидит между агентом и LLM, перехватывает запросы, и по команде context-mode ходит в FTS5-индекс (полнотекстовый поиск по собранному контексту) и заменяет сырой контекст на релевантные сниппеты. Если интересно, как работают MitM-прокси для мониторинга — почитай про Tokentap, там похожая архитектура.
Важно: rtk не генерирует эмбеддинги сам. Он использует готовый полнотекстовый индекс (FTS5 в SQLite), который мы наполняем данными от Serena и Semble. Это гибридный подход: символьная точность LSP + семантическая широта эмбеддингов.
Почему эта связка вообще имеет право на жизнь?
Потому что проблема не в том, что LLM нужно меньше токенов, а в том, что мы ей скармливаем мусор. Агент для код-ревью тащит в промпт весь файл, пять соседних, README и пару случайных классов — в итоге 80% токенов уходят на бесполезный фон. Serena и Semble решают проблему релевантности, но каждая по-своему.
Serena дергает LSP и собирает точные сигнатуры типов. Semble строит эмбеддинги и находит похожие участки по смыслу. Но если просто объединить их вывод и кинуть в промпт — профита будет мало, потому что объем дублируется. Тут и вступает rtk: он запускает context-mode, который через FTS5 находит пересечения с уже имеющимися сниппетами в индексе, и дедуплицирует, а еще понимает, что если функция вызвана 50 раз, то ее декларацию достаточно вернуть один раз, а не пятьдесят.
Замеры: когда профит съедает оверхед
Я прогнал агента на 500 реальных PR из проекта с монорепозиторием на TypeScript (500+ файлов). Сравнивал четыре конфигурации:
| Конфиг | Средние токены на запрос | P90 токенов | Латентность (прокси + LLM) | Корректность ответов |
|---|---|---|---|---|
| Без rtk, сырой контекст | 12 400 | 21 000 | 1.2 с | 94% |
| Serena + Semble (просто объединение) | 8 700 | 14 200 | 1.9 с | 91% |
| rtk + context-mode (только Serena) | 5 200 | 7 800 | 2.3 с | 88% |
| rtk + context-mode (Serena + Semble) | 4 700 | 6 500 | 2.6 с | 90% |
Осторожно: корректность ответов упала на 4% в конфиге с только Serena. Связка Serena+Semble вернула корректность почти к базовому уровню. Дело в том, что Semble добавляет семантические дубли, которые rtk потом эффективно вырезает, а Serena в одиночку слишком агрессивно режет контекст, теряя важные cross-module зависимости. Вывод: оба индекса нужны.
Пошаговый план: как не обжечься на настройке
1 Поднимаем индексы Serena и Semble
Устанавливаешь Serena через go install github.com/serenalang/serena@latest. Собираешь LSP-индекс для своего проекта: serena index --lang typescript --project . — он сгенерирует файл .serena/index. Semble ставится как pip install semble-client (v2.5), запускаешь semble serve --model all-MiniLM-L6-v2 — и готовься к тому, что первый проход по 500 файлам съест 15 минут.
2 Настраиваем rtk с context-mode
rtk — это single binary, скачивать с релизов. Конфиг в YAML — rtk.yaml:
proxy:
listen: ":9090"
upstream: "https://api.openai.com/v1"
tokenizer: "cl100k_base" # для GPT-4
context_mode:
enabled: true
index_path: ".rtk/context_index.db"
fts5:
k1: 1.2
b: 0.75
sources:
- name: "serena"
type: "lsp"
path: ".serena/index"
- name: "semble"
type: "embed"
endpoint: "http://localhost:8765"
dim: 384
dedup:
enabled: true
threshold: 0.45 # cosine similarity для дедупликации
Важный нюанс: rtk хранит FTS5-индекс в SQLite. При первом старте он считывает данные из Serena и Semble и строит свой индекс. Это занимает еще 2-3 минуты.
3 Тестируем на холостом ходу
Прокси-сервер запускается, агент шлет запросы на localhost:9090. Проверяем логи: rtk выводит, сколько токенов удалось сэкономить на каждом запросе. Если экономия меньше 20% — копаемся в параметрах k1 и b (BM25).
Подводные камни: на чем я прокололся
1. Токенизатор не совпадает с моделью — rtk по умолчанию использует cl100k_base, а если модель Claude Sonnet 4.6 (а я проверял и её, результаты в том тесте), то счетчик токенов врет на 15%. Пришлось переключать на tokenizer: "anthropic".
2. Серена падает на кривых файлах — LSP не любит файлы с синтаксическими ошибками. У нас в монорепе лежат *.tsx с отключенным TypeScript strict. Serena генерирует битые записи, и rtk потом вставляет в контекст невалидный код. Лечится настройкой serena.ignore_errors: true в конфиге rtk.
3. FTS5 требует периодической реиндексации — после каждого коммита нужно перестраивать индекс. Я автоматизировал через GitHub Actions: при пушe в main запускается job, который ставит Headroom (кстати, отличный инструмент для сжатия промптов) поверх rtk.
Так профит или оверхед?
Считаем ROI. При базовом расходе 12 400 токенов на запрос и 500 запросов в день (10 000 строк кода) экономия с полной связкой — 7 700 токенов на запрос. Это 3 850 000 токенов в день. По текущим ценам GPT-4o ($2.5/1M input) — $9.6 в день, $288 в месяц. Стоимость инфраструктуры: три сервиса (Serena, Semble, rtk) в Docker на одной машинке с 4 vCPU — около $30/мес. Итого профит $258/мес. Но если у тебя модель уровня Opus, то экономия еще выше. Только не забудь про скрытую инфляцию токенов в Opus 4.7 — там токенизатор жирнее.
Оверхед по латентности (2.6 с против 1.2 с) — проблема, если агент работает интерактивно. Но для батч-ревью и ночных проверок это несущественно. Если же тебе нужно снизить latency, используй Tokentap в пассивном режиме для мониторинга, а активное сжатие оставь только на тяжелые запросы (можно добавить порог по длине промпта).
FAQ по ошибкам при внедрении
Q: rtk не видит индексы Serena, пишет “index not found”
A: Убедись, что пути в конфиге абсолютные. Serena создает индекс в папке запуска, а rtk может быть запущен из другого каталога. Пропиши path: "/abs/path/.serena/index".
Q: После включения context-mode агент стал давать неверные ответы о типах
A: Скорее всего, дедупликация слишком агрессивна. Уменьши dedup.threshold до 0.3 — это снизит экономию, но повысит точность.
Q: Латентность более 5 секунд, что делать?
A: Возможно, Semble не успевает отвечать. Настрой ему кеширование эмбеддингов (параметр --cache-size 10000). Или поставь rtk в асинхронный режим — он будет отдавать LLM ответ без контекста, а потом доставлять контекст через retry (поддерживается с v2.1.0).
В итоге: профит однозначный, если у тебя объемы запросов >200 в день. Для маленьких проектов оверхед на настройку не окупается. Но если ты хочешь сделать свой AI-агент менее прожорливым — это один из лучших способов. Посмотри еще, как Hermes Agent оптимизирует фоновые задачи через YAML — там тоже много интересных идей по снижению расхода.