Как 7 ИИ-агентов собирают контекст: я прочитал их код

Raghav Chamadiya13 мин

ИИ-агенты контекст · контекстное окно агента · сжатие контекста · архитектура coding agent · grep или индекс · openclaw архитектура

Содержание

Я прочитал код семи открытых агентов, чтобы ответить на один вопрос: как каждый из них решает, что увидит модель. Короткий ответ: ни один не строит индекс вашего кода по умолчанию. Все ищут код так же, как человек в терминале: через grep, find и read. Различаются они тем, что выбрасывают из контекста и в какой момент.

Меня это слегка удивило, потому что публичные разговоры об агентах крутятся вокруг поиска: эмбеддинги, графы кода, карты репозитория. А в этих семи кодовых базах код, который выбирает, что модель прочитает, совсем небольшой. Зато код, который решает, что ей больше не читать, занимает много места, и именно туда ушли инженерные усилия.

Дальше для каждого репозитория указаны пути к файлам, так что всё можно проверить самостоятельно.

Семь репозиториев в выборке

Это агентские репозитории, которые у нас в repowise уже были проиндексированы. Под вывод я их не подбирал. Устроены они по-разному, поэтому сначала разложу их по группам.

Полноценные обвязки. Обвязкой (по-английски harness) я буду называть программу, которая крутит цикл агента: отправляет сообщения модели, выполняет инструменты, которые та запросила, возвращает ей результаты и так по кругу.

  • pi (earendil-works/pi): CLI для программирования и библиотеки под ним (слой API к LLM, цикл агента, терминальный UI).
  • DeepSeek Harness (deepseek-ai/deepseek-harness): обвязка, в которой любая функция оформлена плагином на фреймворке Cordis.

Универсальные ассистенты, которые заодно пишут код. Это персональные агенты: подключаются к мессенджерам, выполняют задачи по расписанию, ходят в браузер. Программирование для них лишь одна из задач.

Надстройки над чужим агентом.

  • OmO (code-yeongyu/oh-my-openagent): плагины и агенты для OpenCode и Codex, а с версии 5.0 ещё и собственный CLI на «senpi», который README называет форком pi.
  • free-claude-code (alishahryar1/free-claude-code): прокси, который встаёт между агентом (Claude Code, Codex, pi и ещё восемь) и провайдером модели и перенаправляет запросы на другие модели.
  • Публичный репозиторий Claude Code (anthropics/claude-code): ядра агента в нём нет. Есть 13 плагинов, примеры и исходники четырёх встроенных «модов», то есть плагинов, которые подписываются на события движка. Поэтому про Claude Code я могу рассказать только то, что он открывает наружу, а как устроены его собственный поиск и сжатие, отсюда не видно.

Codex CLI, Gemini CLI, OpenCode, Aider, Cline и OpenHands в статью не попали: мы их не индексировали, а писать о коде, который я не читал, не хотелось.

Цифры рядом

РепозиторийЧто этоФайловСтрок кодаHealthЧем ищет кодКак ужимает контекст
piОбвязка для кода2 010379 тыс.6,9read, bash; grep, find, ls опциональноПересказ, когда остаётся меньше 16 384 токенов; хранит последние 20 000
DeepSeek HarnessОбвязка на плагинах12 578899 тыс.6,6read, glob, grep, bash; LSP-инструмент опциональноПересказ на 80 % окна; оставляет 16 %
OpenClawАссистент19 3614,36 млн6,7read, ls, shell (ripgrep, fd)Лимит на вывод инструментов, очистка старых результатов, пересказ
Hermes AgentАссистент8 7582,12 млн5,3read_file, search_files (ripgrep), terminalПересказ более дешёвой моделью: на 50 % окна, если оно от 512 тыс. токенов, иначе на 75 %
OmOНадстройка5 591591 тыс.8,1Инструменты основного агента плюс серверы LSP и ast-grepСжатие основного агента; замороженный блок памяти
free-claude-codeПрокси744168 тыс.5,6Не его задачаЧасть служебных запросов отвечает сам; опциональный фильтр вывода
Claude Code (публичный репозиторий)Плагины и моды1 12426 тыс.7,6Не в этом репозиторииНе в этом репозитории

Scroll the table sideways to see every column.

Health в repowise оценивает здоровье кода по шкале от 1 до 10: насколько вероятно, что файл принесёт баги, и насколько трудно его менять. Она считается по статическим проверкам и истории git, а оценка репозитория равна среднему по файлам, взвешенному по числу строк кода. В таблице она показана с одним знаком после запятой, как на странице репозитория. Файлы и строки взяты из последнего индекса каждого проекта, снятого между 26 июня и 30 сентября (точные даты в разделе «Как считали»). Строками кода считаются непустые строки без комментариев.

Сразу бросается в глаза разброс размеров. OpenClaw примерно в 167 раз больше публичного репозитория Claude Code. Сравнивать по этой цифре сами агенты нечестно: движка Claude Code в его репозитории нет. Зато хорошо видно, во что вырастает открытый агент, когда ему приходится общаться с мессенджерами, телефонами, браузерами, планировщиками и десятками провайдеров моделей. Часть OpenClaw, которая пишет код, занимает в нём небольшой угол.

Как ищут код: grep, read и по кругу

Все репозитории, где крутится собственный цикл агента, а вместе с ними OmO, дают модели один и тот же базовый набор: прочитать файл, посмотреть каталог, поискать по содержимому, выполнить команду в шелле.

  • pi по умолчанию включает четыре инструмента: read, bash, edit и write. grep, find и ls лежат в packages/coding-agent/src/core/tools/ и включаются отдельно. Системный промпт по умолчанию в system-prompt.ts перечисляет [read, bash, edit, write]. Искать модель должна через шелл.
  • DeepSeek Harness держит read, write и edit в пакете tool-fs, а glob и grep в tool-fs-search. Есть и пакет tool-lsp: через языковой сервер модель может перейти к определению или найти ссылки (тот же механизм, что у «go to definition» в редакторе). README прямо расставляет приоритеты: использовать его, «когда текстовый поиск неоднозначен», а «обычная навигация по-прежнему идёт через search и read». В стандартный набор этот пакет не входит.
  • OpenClaw собирает файловые инструменты в src/agents/core-coding-tools.ts: read, ls, edit, write, apply_patch и шелл. Отдельного grep-инструмента в основном раннере я не нашёл. src/agents/utils/tools-manager.ts скачивает зафиксированные версии ripgrep и fd, так что поиск идёт через шелл этими бинарниками.
  • Hermes Agent даёт search_files на ripgrep в tools/file_operations_search.py рядом с read_file и terminal.
  • OmO надстраивает структуру над агентом, внутри которого работает: общий демон языкового сервера (packages/lsp-daemon), инструменты LSP и ast-grep в виде MCP-серверов и правки «hashline», где модель указывает на строку коротким хешем её содержимого вместо номера строки. Когда мы индексировали OmO в июле, его плагин для Codex ещё запускал фоновый индекс CodeGraph при старте сессии (packages/omo-codex/plugin/components/codegraph). Сейчас этого компонента нет, а текущая миграция конфига удаляет старую настройку codegraph как устаревшую.

Получается, единственную функцию, похожую на индекс, убрали, а инструменты на языковом сервере опциональны. По-моему, команды сделали осознанную ставку: модели научились хорошо работать с grep, результат grep всегда свежий, а индекс может устареть или сломаться на машине пользователя. Для поиска функции эта ставка, на мой взгляд, верная. Для вопросов вроде «что сломается, если я это поменяю» я в ней уверен меньше, потому что ответ размазан по файлам, которые друг друга по имени не упоминают.

Как собирается системный промпт

Второй источник контекста включает всё, что попадает в модель ещё до первого сообщения пользователя.

Все они читают файл инструкций проекта. resource-loader.ts в pi ищет AGENTS.override.md, AGENTS.md и CLAUDE.md. В DeepSeek Harness есть плагин agent-instructions, который загружает AGENTS.md или CLAUDE.md и перечитывает их после того, как агент правит файл. У OmO для вложенных файлов инструкций есть agents-md-core и пакет rules-engine. В публичном репозитории Claude Code лежит исходник мода agents-md: он передаёт движку файлы AGENTS.md как файлы инструкций проекта, в том же месте и в том же обрамлении, что и CLAUDE.md, включая вложенные, когда модель читает файл в этой папке. Выходит, все агенты из списка, которые вообще загружают файлы инструкций, читают AGENTS.md, и Claude Code не исключение: его встроенный мод agents-md подхватывает AGENTS.md, если в проекте нет своего CLAUDE.md (или, по отдельной настройке, вместе с ним).

Две детали показались мне хорошо продуманными.

DeepSeek Harness кладёт инструкции в историю сессии. README пакета context говорит, что подмешанные инструкции и ссылки «попадают в историю сессии как сообщения с ролью user, поэтому сохраняются, воспроизводятся и сжимаются как обычная переписка». Выигрыш в том, что правка AGENTS.md посреди сессии не переписывает системный промпт.

Hermes Agent и OmO замораживают память на старте сессии. Hermes ведёт два файла памяти: MEMORY.md (заметки агента) и USER.md (профиль пользователя). Докстринг в tools/memory_tool.py говорит, что оба попадают в системный промпт «как ЗАМОРОЖЕННЫЙ снимок на старте сессии; записи во время сессии уходят на диск, но промпт не меняют». В changelog OmO описано то же исправление: коммит памяти во время сессии больше не переписывает её системный промпт.

Обе команды защищают одно и то же: кэш промпта. Провайдеры берут меньше денег и отвечают быстрее, если начало промпта им уже встречалось. Стоит поменять один байт в начале, и кэш теряется целиком. Удивительно много кода, который отвечает за контекст, существует только ради того, чтобы начало промпта не менялось ни на байт.

Как обрезают: на это уходит основная часть кода

Здесь семь проектов расходятся сильнее всего, и здесь же сосредоточена большая часть кода.

Объём контекста держат в рамках двумя способами. Каждый результат инструмента ограничивают сразу при поступлении, а когда разговор подбирается к пределу модели, включается сжатие контекста (compaction): старые ходы заменяются пересказом, который пишет модель.

РепозиторийЛимит на один результатКогда сжимаетЧто оставляет
pi2 000 строк или 50 КБ; строки grep режутся на 500 символахОсталось меньше 16 384 токеновПоследние ~20 000 токенов
OpenClawПо умолчанию 16 000 символов, 32 000 для окон больше 100 тыс. токенов, 64 000 больше 200 тыс.; вывод инструментов не больше 30 % окнаРезерв не больше 25 % окна; до 3 повторов при переполненииУмолчания ядра агента: резерв 16 384, последние 20 000 токенов
Hermes Agentread_file 100 000 символов50 % окна, если оно от 512 тыс. токенов; иначе 75 %Первые 3 и последние 20 сообщений; середина пересказывается
DeepSeek HarnessСначала вычищаются слишком большие результаты; опционально «сброс» на диск80 % окнаОколо 16 % окна

Scroll the table sideways to see every column.

Hermes Agent сжимает раньше большинства. По умолчанию он пересказывает историю на 50 % окна, если у модели окно от 512 тыс. токенов, и на 75 %, если окно меньше. Комментарий в коде объясняет, откуда взялась эта нижняя граница: на маленьком окне сжатие на 50 % освобождает так мало места, что оно срабатывало бы заново каждые один-два хода. На большом окне это намного раньше, чем у DeepSeek Harness (80 %) или pi (он ждёт, пока свободными останутся 16 384 токена, то есть пока окно в 512 тыс. заполнится примерно на 97 %). Пересказ Hermes делает отдельной, более дешёвой «вспомогательной» моделью, а перед этим вычищает большие выводы инструментов (agent/context_compressor.py). За раннее сжатие приходится платить более частыми вызовами пересказа. Взамен модель редко работает с почти полным окном, а на нём ответы обычно портятся. Для персонального ассистента, у которого сессии тянутся днями, такой размен мне кажется разумным.

DeepSeek Harness ждёт, а потом сбрасывает. Он сжимает на 80 % и оставляет около 16 %. Пакеты spill умеют и вовсе вынести большой результат инструмента из контекста: полный текст уходит в файл, а модель получает короткую ссылку и инструкцию, как дочитать. Так же поступает человек, который сохраняет длинный лог в файл вместо того, чтобы вставлять его в чат.

OpenClaw очищает старые результаты инструментов. Кроме лимита на каждый результат, src/agents/embedded-agent-runner/tool-result-truncation.ts заменяет вывод, который пережил окно кэша промпта, на [Old tool result content cleared], а старые картинки на [image removed during context pruning]. Модель помнит, что вызывала инструмент, но самих данных уже не видит.

У pi всё коротко. Вся логика сжатия pi лежит в packages/coding-agent/src/core/compaction/compaction.ts: сжимать, когда до предела меньше 16 384 токенов, оставлять последние ~20 000 токенов, всё до них пересказывать. Из четырёх реализаций эту проще всего прочитать за один присест.

free-claude-code сокращает число запросов к модели. Это прокси, и репозитория он вообще не видит. Зато src/free_claude_code/api/optimization_handlers.py локально, без вызова модели, отвечает на пять видов служебных запросов Claude Code: проверку квоты, определение префикса команды, генерацию заголовка, подсказки и извлечение путей к файлам. Ещё README описывает опциональный фильтр, который укорачивает вывод терминала до того, как его увидит модель.

pi оказался внутри трёх других проектов

Этого я не ожидал: pi, один из самых небольших репозиториев в наборе (379 тыс. строк), обнаруживается внутри трёх других.

  • OpenClaw зависит от @earendil-works/pi-tui в package.json. В его packages/agent-core те же имена файлов сжатия, что у pi (compaction.ts, branch-summarization.ts), и те же умолчания: резерв 16 384 токена и 20 000 последних токенов. В его truncate.ts точные лимиты pi: 2 000 строк, 50 КБ, 500 символов на строку grep. Ещё OpenClaw резервирует имена инструментов bash, edit, find, grep, ls, read, write, а это список инструментов pi. Какая история за этим стоит, я не знаю и гадать не буду. По коду видно одно: ядро агента OpenClaw повторяет устройство и числа pi.
  • OmO пишет в README, что версия 5 «работает на senpi, нашем форке pi».
  • У DeepSeek Harness есть пакет dsh-llm-pi-ai, адаптер к библиотеке pi для API моделей. В описании пакета он назван «двойником для проверки дизайна» основного адаптера DeepSeek, так что по умолчанию он не используется.

Поэтому, если хочется разобраться по исходникам, как устроен цикл агента, я бы начинал с pi. Он достаточно маленький, чтобы прочитать его целиком, а многие проекты покрупнее взяли его решения.

Гигантские функции и что с ними стало

Когда мы индексировали эти репозитории, в двух из них жили две самые длинные функции всего набора. run_conversation в agent/conversation_loop.py у Hermes Agent занимала 6 591 строку (индекс от 19 августа). runEmbeddedAttempt в src/agents/embedded-agent-runner/run/attempt.ts у OpenClaw занимала 4 972 строки (индекс от 26 июня). Обычно такая функция и есть цикл агента: каждое правило повтора, каждая причуда провайдера и каждый путь восстановления становятся ещё одной веткой в единственном месте, которое видит всё.

С тех пор обе команды их разбили. На 6 октября conversation_loop.py у Hermes занимает 1 835 строк против 8 298 в нашем индексе, а run_conversation стала короткой обёрткой над _run_conversation_turn. attempt.ts у OpenClaw сократился с 5 808 строк до 567. Соседняя папка run/ выросла с 65 нетестовых файлов до 173, с именами вроде attempt-prompt-build.ts, attempt-history-prepare.ts и attempt-tool-search-executor.ts.

По-моему, это хорошо показывает, как растёт агентский код. Цикл пишут первым, и в него же попадает каждое исправление, поэтому он быстро распухает. Наши индексы обоих репозиториев сделаны до разбиения, так что оценки health в таблице выше описывают код до него.

Ограничения этих цифр

  • Health не измеряет качество агента. Оценка здоровья показывает, насколько безопасно менять код. О том, насколько хорошо агент решает задачи, она ничего не говорит. Самая низкая оценка в этом наборе у Hermes Agent, одного из двух ассистентов, которые держат в одном репозитории интеграции с мессенджерами, десктопные приложения и тесты. Вторая снизу у free-claude-code, небольшого прокси, так что размер и широта проекта объясняют не каждую низкую оценку.
  • Claude Code здесь почти не виден. Его оценка описывает только 26 тыс. строк плагинов и модов, кода самого агента в ней нет. Считайте эту строку таблицы «публичной поверхностью расширений».
  • У снимков есть даты. Индекс OpenClaw от 26 июня, OmO от 17 июля. Код я цитирую из основной ветки каждого репозитория на 6 октября, поэтому некоторые числа в тексте новее таблицы.
  • В реальной работе настройки могут отличаться. Я привёл значения по умолчанию, а пользователи их меняют, и некоторые проекты подбирают значения под конкретную модель или интерфейс.
  • Я только читал код. Что работает лучше, раннее сжатие или позднее, можно измерить, но бенчмарков для этой статьи я не запускал.

При чём тут repowise

Сразу оговорюсь: я делаю repowise, слой контекста для агентов. Он индексирует граф зависимостей, историю git и документацию репозитория и отдаёт их по MCP (стандартному протоколу, через который агенты вызывают внешние инструменты). После всего увиденного я бы описал его как дополнение к grep. grep отвечает на вопрос «где это имя». Индекс помогает с вопросами «что от этого зависит» и «почему это так устроено», на которые grep за один вызов не ответит. Все страницы репозиториев, на которые ведут ссылки в статье, построены этим индексом, и любой из этих репозиториев можно подключить к своему агенту.

Как считали

  • Репозитории: семь агентских репозиториев, которые уже были проиндексированы в repowise и получили оценку health. Специально для статьи мы ничего не индексировали.
  • Цифры: файлы, строки кода, health и самые длинные функции взяты из последнего готового снимка каждого репозитория в нашей базе, прочитаны 6 октября 2026 года. Даты снимков: pi 30 сентября, DeepSeek Harness 28 сентября, Claude Code 27 сентября, free-claude-code 19 сентября, Hermes Agent 19 августа, OmO 17 июля, OpenClaw 26 июня. Health показан с одним знаком после запятой, как на страницах репозиториев.
  • Чтение кода: неглубокие клоны основной ветки каждого репозитория на 6 октября 2026 года плюс файлы на проиндексированных коммитах для сравнения «до и после». Все пути к файлам в статье взяты из этих клонов.
  • Оценка health: определение дано выше, в разделе «Цифры рядом». Методика описана на странице здоровья кода каждого репозитория.

Если вы поддерживаете один из этих проектов и я где-то ошибся, напишите мне, я исправлю.

Попробовать: подключите любой из этих репозиториев к Claude или ChatGPT и спросите у своего агента, как он обращается с контекстом: так вы заодно проверите мой разбор.

Проиндексируйте свой репозиторий бесплатно