Глава 18: Чему мы научились
Пять архитектурных ставок
Claude Code — не единственная agentic system. Это не первый случай. Но он сделал пять архитектурных ставок, которые отличают его от среды agentic frameworks, и после почти двух тысяч файлов и семнадцати глав эти ставки заслуживают рассмотрения.
Ставка 1: цикл генератора с обратными вызовами
Большинство agentic platforms предоставляют вам конвейер: определите tools, зарегистрируйте обработчики, позвольте платформе оркестровать. Разработчик пишет callbacks. Платформа решает, когда их вызывать.
Claude Code делает обратное. Функция query() — это асинхронный генератор — цикл принадлежит разработчику. Модель передает ответ, генератор выдает tool calls, вызывающая сторона выполняет их, добавляет результаты и генератор зацикливается. Существует одна функция, один поток данных, одно место, через которое проходит каждое взаимодействие. 10 State терминала и 7 State продолжения типа возвращаемого значения генератора кодируют все возможные результаты. Петля — это система.
Ставка заключалась в том, что одна функция-генератор, даже если она выросла до 1700 строк, будет более понятной, чем распределенный граф callbacks. После изучения первоисточника ставка окупилась. Если вы хотите понять, почему завершился сеанс, вы смотрите на одну функцию. Когда вы хотите добавить новое State терминала, вы добавляете один вариант к одному дискриминируемому объединению. Система типов обеспечивает исчерпывающую обработку. В архитектуре обратного вызова эта логика будет разбросана по десяткам файлов, а взаимодействие между обратными вызовами будет неявным, а не видимым в потоке управления.
Ставка 2: файловая memory важнее баз данных
В главе 11 это подробно описано, но архитектурное значение выходит за рамки memory. Решение использовать простые Markdown files вместо SQLite, векторной базы данных или облачного сервиса было ставкой на прозрачность, а не на возможности. База данных будет поддерживать более сложные запросы, более быстрый поиск и гарантии транзакций. Файлы ничего этого не предоставляют. Файлы обеспечивают доверие.
Пользователь, который открывает ~/.claude/projects/myapp/memory/MEMORY.md в vim и видит, что именно о нем помнит agent, имеет принципиально иные отношения с системой, чем пользователь, который должен спрашивать agent «что ты помнишь?» и надеюсь, что ответ полный. Благодаря файловому дизайну State знаний agent можно наблюдать извне, а не просто сообщать самостоятельно. Это важнее, чем производительность запросов. Система отзыва на базе LLM компенсирует простоту хранения интеллектуальным поиском: побочный запрос Sonnet, выбирающий пять соответствующих воспоминаний из манифеста, является более точным, чем встраивание сходства, и не требует никакой инфраструктуры.
Ставка 3: tools с самоописанием вместо центральных оркестраторов
Платформы agents обычно предоставляют реестр tools: вы описываете свои tools в центральной конфигурации, а платформа представляет их модели. Tools Claude Code описывают себя. Каждый объект Tool имеет собственное имя, описание, входную схему, prompt, флаг безопасности параллелизма и логику выполнения. Task Tool System заключается не в описании tools для модели, а в том, чтобы позволить tools описывать себя.
Эта ставка окупается расширяемостью. Tools MCP (глава 15) становятся первоклассными благодаря реализации одного и того же интерфейса. Tool от сервера MCP и встроенный tool для модели неотличимы. Системе не нужен отдельный слой «Адаптер tool MCP» — оболочка создает стандартный объект Tool, и с этого момента его обрабатывает существующий конвейер tools: проверка разрешений, параллельное выполнение, бюджетирование результатов, hook hook.
Ставка 4: agents форка для совместного использования кэша
В главе 9 был рассмотрен механизм разветвления: sub-agent, который начинается с полного разговора parent agent в своем контекстном окне и совместно использует Prompt Cache parent agent. Это не оптимизация для удобства — это архитектурная ставка на то, что модель совместного использования кэша стоит сложности управления жизненным циклом вилки.
Альтернатива — создание нового agent с кратким изложением разговора — проще, но дороже. Каждый новый agent оплачивает полную стоимость обработки своего контекста с нуля. Разветвленный agent бесплатно получает cached префикс родителя (скидка 90 % на входные токены), что делает экономичным создание agents для небольших Task: извлечение memory, проверка кода, проходы проверки. Agent фонового извлечения memory (глава 11) запускается после каждого поворота Query Loop, и его стоимость незначительна именно потому, что он использует общий кэш родительского объекта. Без совместного использования кэша на основе разветвлений этот agent был бы непомерно дорогим.
Ставка 5: hook над плагинами
Большинство систем расширяемости используют плагины — код, который регистрирует возможности и выполняется внутри хост-процесса. Claude Code использует hooks — внешние процессы, которые запускаются в точках жизненного цикла и взаимодействуют через коды завершения, а также JSON на stdin/stdout.
Ставка на то, что изоляция процессов оправдает затраты. Плагин может привести к сбою хоста. Hook приводит к сбою собственного процесса. Плагин может привести к утечке memory в кучу хоста. Memory hook умирает вместе с его процессом. Для плагина требуется поверхность API, для которой необходимо управлять версиями и поддерживать ее. Для hook требуются stdin, stdout и код выхода — протокол, который стабилен с 1971 года.
Накладные расходы реальны: порождение процесса на каждый вызов hook стоит миллисекунд, чего не потребовал бы обратный вызов внутри процесса. Быстрый путь -70% для внутренних callbacks (глава 12) показывает, что система понимает, что эти затраты имеют значение. Но для внешних hooks — пользовательских сценариев, командных линтеров, серверов политики предприятия — гарантия изоляции делает расширение системы более безопасным. Предприятие может применять политику на основе hooks, не беспокоясь о том, что неверный сценарий hook приведет к сбою сеансов разработчиков.
Что переносится, что нет
Не каждый шаблон в Claude Code обобщает. Некоторые из них являются последствиями масштаба, ресурсов или конкретных ограничений, которые могут не разделяться другими разработчиками agents.
Шаблоны, которые передаются любому agent
Шаблон цикла генератора. Любой agent, которому необходимо передавать ответы в streaming, обрабатывать tool calls и управлять несколькими состояниями терминала, получает выгоду от явного выполнения цикла, а не от его сокрытия за обратными вызовами. Тип возвращаемого значения дискриминируемого объединения, точно определяющий причину остановки цикла, представляет собой шаблон, исключающий целый класс вопросов «почему agent остановился?» сеансы отладки.
Файловая memory с вызовом LLM. Конкретные детали реализации описаны в Claude Code, но принцип — простое хранение в сочетании с интеллектуальным извлечением — применим к любому agent, которому необходимо сохранять знания между сеансами. Таксономия четырех типов (пользователь, обратная связь, проект, ссылка) и тест на выводимость («можно ли это получить повторно из текущего State проекта?») представляют собой многоразовые эвристики проектирования.
Асимметричные каналы чтения/записи для удаленного выполнения. Если чтение представляет собой высокочастотные потоки, а запись — низкочастотные RPC, их разделение корректно независимо от конкретного транспортного протокола.
Предварительные фильтры растровых изображений для поиска. Любой agent, выполняющий поиск по индексу больших файлов, использует 26-битное растровое изображение в качестве предварительного фильтра. Четыре байта на запись, одно целочисленное сравнение на кандидата — соотношение затрат и выгод просто поразительное.
Стабильность Prompt Cache как архитектурная проблема. Если ваш agent использует API с кэшированием prompts, структурирование prompt со стабильным содержимым в первую очередь, а затем с изменчивым содержимым не является оптимизацией — это архитектурное решение, определяющее структуру затрат.
Паттерны, характерные для масштаба Claude Code
Разветвленный модуль рендеринга терминала. Claude Code развил Ink и переопределил конвейер рендеринга с упакованными типизированными массивами, интернированием на основе пула и сравнением на уровне ячеек, поскольку для этого требовалась streaming в терминале со скоростью 60 кадров в секунду. Большинство agents отображают веб-интерфейс или простой вывод журнала. Вложения в разработку имеют смысл только в том случае, если рендеринг терминала является вашим основным UI и вы транслируете видео с высокой частотой.
Более 50 контрольных точек для профилирования стартапов. Это полезно, если у вас сотни тысяч пользователей и выборка 0,5 % дает статистически значимые данные. Для меньшего agent достаточно более простой системы синхронизации.
Восемь типов транспорта MCP. Claude Code поддерживает stdio, SSE, HTTP, WebSocket, SDK, два варианта IDE и прокси-сервер Claude.ai, поскольку он должен интегрироваться с каждой топологией развертывания. Большинству agents необходимы stdio и HTTP.
Модель безопасности снимка hooks. Замораживание конфигурации hooks при запуске и никогда не перечитывание ее неявно является защитой от конкретной угрозы: вредоносный код репозитория изменяет hooks после того, как пользователь принимает диалог доверия. Это имеет значение, когда ваш agent работает в произвольных репозиториях с ненадежными конфигурациями .claude/. Agent, который работает только в доверенных средах, может использовать более простое управление hooks.
Цена сложности
Почти две тысячи файлов. Что это дает и сколько это стоит?
Количество файлов вводит в заблуждение как показатель сложности. По большей части это тестовая инфраструктура, определения типов, схемы конфигурации и разветвленный модуль визуализации Ink. Фактическая поведенческая сложность концентрируется в небольшом количестве файлов с высокой плотностью: query.ts (1700 строк, agent loop), hooks.ts (4900 строк, система hook жизненного цикла), REPL.tsx (5000 строк, интерактивный оркестратор) и функциях быстрого построения системы memory.
Сложность возникает из трех источников, каждый из которых имеет разный характер:
Разнообразие протоколов. Поддержка пяти протоколов терминальной клавиатуры, восьми типов транспорта MCP, четырех топологий удаленного выполнения и семи областей настройки по своей сути сложна. Каждый дополнительный протокол представляет собой линейное дополнение к базе кода, а не экспоненциальное, но сумма велика. Эта сложность случайна в смысле Брукса: она исходит из окружающей среды (фрагментация терминалов, эволюция транспорта MCP, топологии удаленного развертывания), а не из решаемой проблемы.
Оптимизация производительности. Рендеринг на основе пула, предварительные фильтры поиска растровых изображений, фиксированные блокировки кэша и спекулятивное выполнение tools — все это усложняет работу в обмен на измеримый прирост производительности. Эта сложность оправдана измерениями: каждой оптимизации предшествовало профилирование данных, которые выявили узкое место. Риск заключается в том, что оптимизации накапливаются и взаимодействуют таким образом, что «горячие пути» становится сложнее модифицировать.
Поведенческая настройка. Оперативные инструкции системы memory, предупреждения об устаревании, протокол проверки, инструкция по борьбе с шаблонами «игнорировать memory» — это не сложность кода. Они быстро усложняются и несут различную нагрузку по обслуживанию. Когда поведение модели меняется в зависимости от версии, инструкции prompt, которые были тщательно настроены посредством оценок, могут нуждаться в повторной настройке. Инфраструктура оценки (обозначаемая в кодовой базе как номера дел и оценки оценки) является защитой от регресса, но требует постоянных инвестиций.
Бремя обслуживания этой системы является значительным. Новый инженер, читающий кодовую базу, должен понимать не только пути выполнения кода, но и результаты оценки, которые мотивировали конкретные формулировки prompts, производственные инциденты, которые мотивировали конкретные проверки безопасности, и профили производительности, которые мотивировали конкретные оптимизации. Комментарии к коду являются подробными — многие из них включают номера случаев оценки и измерения до/после — но подробные комментарии почти в двух тысячах файлов сами по себе утомительны для чтения.
Куда движутся agentic systems
Из фигур Claude Code видны четыре тенденции, и они указывают на то, куда движется поле.
MCP как универсальный протокол
В главе 15 Claude Code описывался как один из наиболее полных клиентов MCP. Значение не в реализации Claude Code, а в том, что MCP вообще существует. Стандартизированный протокол обнаружения и вызова tools означает, что tools, созданные для одного agent, работают с любым agent. Экосистемный эффект очевиден: однажды созданный сервер MCP для Postgres обслуживает каждого agent, говорящего на языке MCP. Инвестиции разработчика в интеграцию tools переносимы.
Вывод для разработчиков agents: если вы определяете собственный протокол tool, вы, вероятно, совершаете ошибку. MCP достаточно хорош, он становится лучше, и со временем экосистемные преимущества стандартного протокола увеличиваются. Создайте клиент MCP, внесите свой вклад в спецификацию и позвольте протоколу развиваться благодаря отзывам сообщества.
Multi-agent coordination
Система sub-agents Claude Code (глава 8), координация Task (глава 10) и механизм разветвления (глава 9) являются ранними реализациями multi-agent шаблонов. Они решают конкретные проблемы — совместное использование кэша, параллельное исследование, структурированную проверку — но они также выявляют фундаментальную проблему: накладные расходы на координацию.
Каждое сообщение между agentsи потребляет токены. Каждый форк использует общий кеш, но добавляет ветку диалога, которую родительский элемент должен в конечном итоге согласовать. Конечный автомат системы Task (в очереди, в работе, завершен, сбой, отменен) представляет собой координационный механизм, который усложняет работу, не добавляя при этом возможностей. По мере того, как agents становятся более способными, давление сместится с вопроса «как нам координировать действия нескольких agents?» на «как нам сделать одного agent достаточно способным, чтобы координация была ненужной?»
Имеющиеся данные свидетельствуют о том, что оба подхода будут сосуществовать. В простых tasks будут использоваться отдельные agents. Для сложных tasks будут использоваться скоординированные multi-agent системы. Инженерная task состоит в том, чтобы сделать накладные расходы на координацию достаточно низкими, чтобы точка пересечения отдавала предпочтение multi-agent systems для действительно параллельной работы, а не только для сложных Task.
Постоянная memory
Система memory Claude Code представляет собой постоянную memory agent версии 1. Файловый дизайн, четырехтипная таксономия, отзыв на основе LLM, система устаревания и режим KAIROS для длительных сеансов — все это решения первого поколения для проблемы, которая будет значительно развиваться.
Будущие системы memory, вероятно, добавят структурированный поиск (нынешняя система извлекает целые файлы; будущие системы могут извлекать конкретные факты), межпроектное обучение (предпочтения пользователя, которые применяются повсюду, соглашения проекта, которые не применяются) и совместную memory (групповая memory главы 11 — это первый шаг, но синхронизация, разрешение конфликтов и контроль доступа минимальны).
Открытым остается вопрос, масштабируется ли файловый подход. При 200 воспоминаниях на проект это работает. При 2000 memory на проект манифест дополнительного запроса Sonnet становится слишком большим, консолидация становится слишком дорогой, а индекс превышает свои ограничения. Архитектурная ставка на файловую базу данных столкнется с самым трудным испытанием по мере роста использования.
Автономная работа
Режим KAIROS, agent фонового извлечения memory, автоматическая консолидация снов, спекулятивное выполнение tools — все это шаги к автономной работе. Agent выполняет полезную работу без просьбы: он запоминает то, что вы забыли ему сказать, он консолидирует свои знания, пока вы спите, он начинает выполнять следующий tool до того, как будет завершен текущий ответ.
Траектория ясна. Будущие agents будут менее реактивными и более активными. Они будут замечать закономерности, которые пользователь не описал, предлагать исправления, которые пользователь не запрашивал, и сохранять свои знания без явных команд /remember. Система memory Claude Code с ее системой безопасности фонового извлечения и оперативно разработанной эвристикой «что сохранить» является прототипом этого будущего.
Ограничение – доверие. Автономная работа требует от пользователя уверенности в том, что agent в отсутствие присмотра поступит правильно. Файловая memory, наблюдаемая система hooks, предупреждения об устаревании, диалоговые окна разрешений — все это существует, потому что доверие нужно заслужить, а не предполагать. Путь к более автономным agents лежит через более прозрачные agents.
Закрытие
Семнадцать глав. Шесть основных абстракций. Цикл генератора в центре, tools, выходящие наружу, memory, перемещающаяся назад во времени, hooks, охраняющие периметр, механизм рендеринга, переводящий все это в символы на экране, и MCP, соединяющий его с миром за пределами кодовой базы.
Самый глубокий паттерн в Claude Code – это не какая-то одна техника. Это повторяющееся решение довести сложность до предела. Система рендеринга увеличивает сложность пулов и различий — внутри конвейера все представляет собой целочисленные сравнения. Система ввода усложняет токенизатор и преобразователь привязки клавиш — внутри обработчиков все представляет собой типизированные действия. Система memory усложняет протокол записи и селектор вызова — внутри разговора все является контекстом. Цикл agent усложняет State терминала и Tool System — внутри цикла это просто: поток, сбор, выполнение, добавление, повтор.
Каждая граница поглощает хаос и экспортирует порядок. Необработанные байты преобразуются в ParsedKey. Файлы Markdown становятся вызванными воспоминаниями. MCP JSON-RPC становится объектом Tool. Коды выхода из hook становятся решениями о разрешении. По одну сторону каждой границы мир беспорядочен — пять клавиатурных протоколов, хрупкие серверы OAuth, устаревшие воспоминания, ненадежные hooks репозитория. С другой стороны, мир типизирован, ограничен и исчерпывающе обрабатывается.
Если вы строите agentic system, это урок, который можно перенести. Не конкретные методы — вам может не понадобиться рендеринг на основе пула, режим KAIROS или восемь транспортов MCP. Но принцип: определите свои границы, поглотите там сложность и держите все между ними в чистоте. Границы — это то место, где инженерия трудна. В интерьере приятная инженерия. Создавайте приятные интерьеры и вкладывайте свой бюджет сложности в края.
Исходный код открыт. Краб держит карту в клешне. Иди прочти.