pxpipe: сжатие контекста LLM через рендеринг текста в изображения

· 2 мин чтения
tokens optimization claude-code context-engineering ai-coding
📂 Исходный код на GitHub

Локальный прокси для Claude Code, который рендерит bulky-части запроса в PNG, чтобы снизить число input-токенов на 59–70%.

pxpipe: сжатие контекста LLM через рендеринг текста в изображения

Что это

pxpipe — локальный прокси, который подменяет у Claude Code самые тяжёлые куски входящего запроса PNG-картинками. Системный промпт, описание инструментов и старая история уходят в визуальный канал, а сам ответ модели и последние ходы остаются текстом. На текущей Fable 5 заявлено ~59–70% снижения end-to-end счёта, но цифра зависит от нагрузки — устойчивая величина это сам cut по токенам, который замеряется per-request через бесплатный count_tokens контрфактик и пишется в ~/.pxpipe/events.jsonl.

Ключевая идея

Стоимость изображения зависит от пикселей, а не от количества символов внутри. На реальном трафике Claude Code плотный контент (код, JSON, вывод утилит) даёт ~3.1 символа на image-token против ~1 символа на text-token. В роли читателя выступает тот же vision-канал, на который Anthropic уже опирается в computer use. pxpipe эксплуатирует этот канал: перехватывает /v1/messages, переписывает bulky-блоки в компактные PNG, склеивает обратно cache-friendly (статический префикс сохраняется, prompt caching продолжает работать) и форвардит дальше.

Архитектура

tool_result string ──► wrap at 1928px-wide columns ──► pack ~92,000 chars/page ──► PNG[]

Картинка 1928×1928 стоит ~4 761 vision-токен и вмещает ~92 000 символов. Точка перехода: текст выгоднее картинки только при плотности выше ~19 символов на токен; в реальном трафике Claude Code медиана ~1.91 символа/токен, так что почти всё уходит в изображения. Per-request estimator на каждом запросе решает, что оставить текстом — например, разреженную прозу — а что перевести в PNG. Все события логируются в ~/.pxpipe/events.jsonl.

Что сжимается

Три категории входящих блоков, каждая за profitability gate:

  1. Крупные tool_result (чтения файлов, вывод команд, логи) свыше ~6k символов плотного контента.
  2. Старая свёрнутая история: ходы за живым хвостом рендерятся в image-страницы, последние ходы остаются текстом.
  3. Статический system prompt + slab tool-документации.

Остальное проходит byte-identical: сообщения пользователя, последние ходы, ответ модели (это response, прокси его не трогает), разреженная проза, всё слишком мелкое. Модели вне allowlist проходят полностью — по умолчанию это только Fable 5 и GPT 5.6. Opus 4.8 и GPT 5.5 читают изображения заметно хуже, поэтому они opt-in через дашборд или PXPIPE_MODELS, никогда не подключаются молча. PXPIPE_MODELS=off полностью выключает imaging.

Запуск за 30 секунд

npx pxpipe-proxy                                  # proxy on 127.0.0.1:47821
ANTHROPIC_BASE_URL=http://127.0.0.1:47821 claude  # point Claude Code at it

Дашборд на http://127.0.0.1:47821/ показывает сэкономленные токены, side-by-side сравнение text→image, kill-switch и активные model chips. Ответы стримятся как обычно — pxpipe сжимает только request, никогда output. Последние ходы остаются текстом; system prompt, tool docs и старая bulk-история уходят в изображения.

Бенчмарки

Тесты на свежих случайных числах, которые модель не могла запомнить в обучающих данных.

test N text pxpipe (image) tokens
novel arithmetic, claude-fable-5 100 100% 100% −38%
novel arithmetic, claude-opus-4-8 100 100% 93% −38%
gist recall A/B (решения, значения, пути, имена, отрицания; с дистракторами; сессии 15k–45k символов), Fable 5 98/arm 98/98 98/98 -
state tracking (значение мутировано 3 раза: финальное/первое/count), Fable 5 18/arm 18/18 18/18 -
confabulation на не-заявленных фактах (меньше — лучше), Fable 5 16/arm 0/16 0/16 -
verbatim 12-char hex recall, dense render, Opus 15 15/15 0/15 -
verbatim 12-char hex recall, dense render, Fable 5 15 - 13/15 -

На реальной работе: SWE-bench Lite pilot 10/10 оба рукава при −65% размера запроса; SWE-bench Pro 14/19 ON против 15/19 OFF при −60%, вердикты совпали в 18/19, единственный сплит повторился 3/3 — это run-to-run variance, а не компрессия. Маленькая выборка; чеки в eval/.

Ограничения и честная часть

  • Сжатие с потерями. Точные 12-символьные hex-строки в плотном imaged-контенте: 13/15 на Fable 5, 0/15 на Opus — и промахи тихие конфабуляции, а не ошибки. Байт-точные значения (ID, хэши, секреты) должны оставаться текстом; последние ходы остаются. Специализированный verbatim-risk guard пока не построен.
  • Escape hatch: subagents на не-allowlisted моделях проходят как текст — направляйте байт-точную работу туда (CLAUDE_CODE_SUBAGENT_MODEL=claude-sonnet-4-6 или model: sonnet в frontmatter агента).
  • Workload-dependent. Выигрыш на плотном контенте (~1 символ/токен), проигрыш на разреженной прозе (~3.5 символа/токен); profitability gate (калиброван на N=391 production row) превращает в картинку только там, где математика сходится.
  • Real-world провал. За недели ежедневного использования один раз модель вспомнила имя человека из imaged истории чата и уверенно ошиблась. Никакой ошибки, просто правдоподобно неправильное имя. Это задокументированный failure mode: точные строки в imaged-контенте не byte-safe. Кодинг-сессии это переносят, потому что агент перечитывает файл перед редактированием; чистый chat recall такой проверки лишён.
  • Почему промахи — тихие конфабуляции, а не ошибки чтения. Потому что vision модели — это не OCR: изображение становится patch-эмбеддингами, не дискретными символами, и показывать per-glyph confidence нечего. Когда пиксели недоопределяют глиф, языковая априорная заполняет пробел правдоподобным значением. Механизм и рецепты — в docs/NOT-OCR.md.
  • Latency. PNG-кодирование добавляет задержку к большим запросам до их отправки.
  • ASCII/Latin-1 хорошо протестирован; CJK работает, но консервативно.

Как измеряется экономия

Обе стороны одного запроса в один момент. На каждый POST /v1/messages прокси параллельно с реальным форвардом шлёт бесплатный count_tokens к оригинальному uncompressed body (контрфактик) и читает из ответа фактически билинговый usage block Anthropic. Оба попадают в одну строку ~/.pxpipe/events.jsonl, без turn-count или run-to-run confound. Перевод в доллары по Fable 5 list ratios: input ×1.0, cache write ×1.25, cache read ×0.1, output ×5. Кэш-тарификация применяется одинаково к обеим сторонам, так что скидка кэширования сокращается и не может задвоиться как «savings». Пере-выведите самостоятельно из лога событий: формула и имена полей в src/core/baseline.ts.

Headline — это end-to-end?

Да. Большинство инструментов компрессии рапортуют экономию только по input-срезу, который сами трогали, что делает цифру приятнее. End-to-end знаменатель — это каждый production request: мелкие, которые pxpipe корректно не трогал, все cache write и read, и все output-токены (прокси их никогда не сжимает). На снимке в 13 709 запросов это 59% ($100 → ~$41); позже на 8 904 compressed-request трейсе — ~70%. Compressed-only показывает выше (~72–74%) и квотируется отдельно, никогда не как headline. Точная цифра workload-dependent — воспроизведите на своём логе.

Library use без прокси

import { renderTextToImages, transformAnthropicMessages } from "pxpipe-proxy";

const { pages } = await renderTextToImages(toolResultText);     // pages[i].png: Uint8Array
const { body, applied, info } = await transformAnthropicMessages({
  body: requestBytes,
  model: "claude-fable-5",
});

options.keepSharp(block) фиксирует блоки как текст; options.emitRecoverable возвращает оригиналы imaged-блоков. Pure-JS runtime (Node и edge/Workers); @napi-rs/canvas нужен только на этапе сборки. Полный API — в src/core/index.ts.

Development

pnpm install && pnpm test
pnpm run build                # regenerates dist/

Roadmap

Rendering research припаркован с 2026-07-05: verbatim misreads ограничены ёмкостью канала, а не трюками, и никакие изменения шрифта/цвета/раскладки не починят exact-string recall на прибыльной плотности. Почему — в docs/NOT-OCR.md; датированный анализ и три задокументированных follow-up треда (glyph-style A/B с banked-страницами, runtime canary + re-fetch, surrogate-reader pre-flight) — в FINDINGS.md, запись 2026-07-05. Watch condition: пересобирать resolution sweep на каждый релиз модели; readable density сдвинулся ~4x в glyph area от Opus 4.8 к Fable 5, и модель, читающая production cells около 100%, автоматически поднимет экономию.

Всё ещё открыто, без изменений: тянет ли imaged bulk эффективный контекст (~2x реального контента в том же 1M окне), и улучшает ли меньший активный контекст точность на длинных задачах. Гипотезы, не утверждения — они выходят как числа с n или вырезаются.

Лицензия

MIT. Исходный репозиторий: https://github.com/teamchong/pxpipe.

Источник: https://github.com/teamchong/pxpipe