Thumbnail for null by null

44m 35s5,153 words~26 min read
Auto-Generated

[0:00]3 доллара - столько стоит одна задача и я агент, если отправлять каждый запрос на фронтир модель с полным контекстом. 3 доллара, кажется, мелочь. Агент делает 10 вызовов за задачу. 1000 задач в день. 90.000 в месяц. И мы с вами платим за каждый токен. За каждый кусок текста, который запихнули в контекстное окно, за каждую итерацию цикла, где это контекстное окно пересчитывается заново. А значит, нам критически важно понимать, что именно помещать в это окно. Какую модель вызывать, дорогую или дешёвую? Что достать из памяти, всё или только нужное? Как не раздуть контекст до потолка, и когда агенту стоит думать глубоко, а когда хватит быстрого ответа? Всем привет. Меня зовут Дмитрий Бережницкий, и это вторая часть серии Анатомия агентов. В первой мы вскрыли скелет: пайплайн, контекст, циклы, инструменты. Сегодня мозг. Ну что, поехали? Ключевой тезис этой части: интеллект агента не в модели, а в инфраструктуре вокруг модели. Правильный роутинг, точечный ретривол и управление контекстом, и это важнее, чем фронтир модель. Сейчас же разберёмся почему и начнём мы с вами с роутинга. Сколько моделей доступно на рынке? Десятки, сотни, и каждый месяц появляются новые. А цены отличаются не на проценты, в разы. Дешёвая модель и дорогая, разница может быть в 30, 50, 100 раз за один и тот же запрос. И какой же выбрать? Кажется, что ответ подороже, чтобы она точно работала и хорошо отвечала. И шлём мы туда все запросы подряд. Сколько сахара добавить в кофе? Отправляем дорогую модель. Рефакторинг архитектуры? Тоже отправляем дорогую модель. Вернёмся к нашему примеру бариста, который у нас проходит через серию всех наших видео. Сколько стоит латте? Это обычный лукап и дешёвая модель ответит быстро и качественно. А вот проанализируй предпочтения команды за 3 месяца, составь заказ на ретро с учётом аллергии, бюджета и погоды. Вот это уже сложный запрос, и, возможно, его стоит отправить в фронтир модели. Зачем же за них платить одинаково? Идея простая: маленький классификатор смотрит на запрос и решает отправить на дорогую модель или на дешёвую. Это как сортировщик на почте: взвесил, посмотрел адрес и отправил уже в нужное окно. Исследователи из Беркли формализовали это в роутер LM. Это OpenSource Framework. Результат - снижение стоимости более чем вдвое при сохранении 95% качества. И здесь можно задуматься, ну ладно, роутинг - это понятно. Но дешёвая же модель, она глупее, и качество у нас очень сильно упадёт, и эти 5% для нас важны. Но здесь нам надо уже понимать, что для нас важно: дать вот это максимальное качество или, возможно, всё-таки попасть в нужный бюджет и сэкономить деньги. И казалось бы, что такого сложного в роутинге? Давайте разбираться, как его реализовать для нашего с вами агента. Итак, у нас есть с вами наш запрос. Какие же дальше у нас с ним будут происходить шаги? Давайте посмотрим, что нам надо сделать первым. На этом этапе мы смотрим на тип входящих данных. Что же к нам приходит: картинки, аудио или просто текст, и на основе этого мы сразу же можем отсеять часть моделей, либо включить те, которые смогут работать с этим типом контента. Дальше, шаг второй. Шаг второй - модель классификатор. Здесь у нас может быть с вами небольшая модель или модель подороже, или вообще мы можем с вами оттюнить модель на наших данных. Всё зависит от того, что мы можем туда поставить. Основная её цель - это возвращать ту, какую модель дальше вызвать. Ну и шаг третий. Это будет фоллбек. Если что-то не так произошло на втором шаге, у нас модель не уложилась по времени или вернула какой-то непонятный ответ или не смогла определиться, то здесь мы можем с вами сделать простые правила по ключевым словам. Это как запасной генератор, не очень красиво, шумно, но свет есть. Также мы можем сюда поставить просто выбор модели по умолчанию. И как мы видим, у нас есть две детерминированные части, и одна - недетерминированная - наш классифаер. И для него мы как раз-таки должны дать описание всех тех моделей, на которые он будет смотреть и выбирать. Поэтому на основе входящего запроса наш классифаер должен определить, какая же модель для него подходит. И качество описания этих моделей, оно напрямую влияет на качество нашего с вами роутинга. И казалось бы, этот роутинг нужен для того, чтобы экономить, выбирать дорогую или более дешёвую модель. Но если мы с вами приходим к каким-то сложным агентам, у нас могут быть специализированные модели под определённые задачи. Может, мы сделали файн-тюнинг или определили, что разные модели по-разному работают с определёнными запросами.

[4:42]И как раз-таки в этом случае наш классифаер даст нам не только экономию, но и, возможно, увеличение качества за счёт выбора правильной модели под конкретный запрос. Но есть один нюанс, который часто не рассматривают, когда думают о том, что будут использовать роутер. И это самый настоящий подводный камень: когда наш роутер переключает наши модели, то нам надо с вами понимать, а есть ли у нас с вами сейчас кэш? Может быть, у нас идёт довольно-таки длинный диалог с пользователем, и сейчас мы кэш очень эффективно используем, и наши запросы уже экономически эффективны. Так вот, у разных провайдеров это может работать по-разному. Где-то этот кэш автоматически, где-то его надо включать через API и платить за это. И время жизни при этом у кэша разное. Но принцип здесь один: если вы переключили модель посреди диалога, кэш предыдущий может быть потерян. А может, переключение на более дешёвую модель с учётом кэша дорогой теперь стоит дороже. И это значит, не делать роутер, это значит, что вам надо считать и смотреть, как и когда вы можете переключать. И здесь есть пересечение с первой частью. Помните, мы закончили на наблюдаемости. Без неё наш роутинг слепой. И вы не знаете, правильно ли наш классификатор выбрал модель? Сколько стоит средний запрос на каждую модель? Сколько мы теряем на переключениях кэша? Роутинг без метрик - это надежда, но не инженерия. Поэтому наблюдайте за каждым выбором: какая модель, почему, сколько стоило, попали ли в кэш. Без этого будет тяжело добиться хорошего качества. Роутинг выбирает модель, но модель без знаний - это как у нас врач без карты пациента. Он, скорее всего, умный, очень хочется в это верить, но каждый раз, когда вы с ним общаетесь, он не знает, что же у вас там было. Так вот откуда наш агент берёт знания? Давайте вспомним, что наши языковые модели, они заморожены во времени. Они знают всё о мире до даты обучения и ничего о том, что произошло недавно. Ничего в ваших внутренних документах, вашей кодовой базе, ваших клиентов. И если вы хотите, чтобы агент знал что-то конкретное, вам нужно эти знания до него достать. И здесь вопрос: как? Здесь у нас есть с вами несколько интересных мнений, и первое - это RAG. Retrieval-Augmented Generation.

[7:05]Это инженерный подход, когда мы нарезаем документы на фрагменты, превращаем в векторы, складываем в базу. И когда пользователь спрашивает, ищем релевантные фрагменты и подставляем в контекст. Модель видит не всё, только то, что мы с вами нашли.

[7:25]И второй подход - это длинные контексты. Берём документы и запихиваем целиком в контекстное окно. Без базы, без эмбедингов, без поисков, просто модель сама разбирается, у неё же миллионы токенов, она же справится. И это тот выбор, перед которым мы часто с вами стоим. Давайте разберёмся, нужен ли нам с вами RAG или всё-таки длинный контекст сейчас решает все проблемы? С чего же начались все эти обсуждения? А с того, что сейчас контекстные окна стали огромными. Мы можем с вами засовывать туда миллион токенов, это 700.000 слов. То есть туда влезает вся серия томов Властелин колец, и ещё Хоббит к ней в придачу и останется место. И зачем же тогда нам нужен весь этот RAG-стек, все эти чанки, эмбединги, векторные базы, различные подходы, технологии, для того, чтобы всё это качественно выбирать, тестировать, смотреть, это невероятно сложно. Если же мы можем просто запихнуть всё в контекстное окно, и это очень интересный вопрос, над которым стоит задуматься. И давайте подойдём к этому инженерно, рассмотрим плюсы, минусы разных подходов, поймём, какие у нас есть трейдофы и там, и там, и что же мы можем с вами использовать. Первое, почему мы будем оценивать - это простота. Итак, RAG, с точки зрения простоты, он невероятно сложен, потому что нам надо с вами развернуть специализированные базы данных. Выбрать стратегии того, как же мы будем нарезать эти данные, понять, какие модели для эмбедингов подходят, может быть, нам надо их тюнить. Потом сделать ранжирование, делать синхронизации, потом мы должны разобраться, как же нам получать максимально эффективно нужные данные из RAG. И это очень много различных движущихся частей. Много мест, где что-то может сломаться. А с точки зрения контекста, наш длинный контекст взял документ, положил в промт, и всё. Нету ни стека, ни поломок, нам не надо всё это разворачивать, мы просто работаем с контекстом.

[9:43]И второе - это полнота предоставляемых данных. RAG у нас ищет по математическим представлениям текста. Иногда он может не находить. Ответ у нас с вами был в данных, но модель его не увидела, потому что поиск наш промахнулся. И здесь мы с вами даже не узнаем о том, что мы не поместили в контекст то, что у нас есть. С длинным же контекстом всё наоборот: модель видит всё, и ей негде промахнуться.

[10:14]Третий, который вытекает отсюда же - это у нас есть с вами иногда задачи, где нам нужна полная картина. Допустим, у нас есть документ с требованиями и документ с релизными заметками. И был вопрос: какие требования по безопасности пропущены в релизе? RAG может найти фрагменты по безопасности в документах, но при этом он может что-то пропустить. Для того, чтобы модель увидела всё, ей надо два документа целиком. Поэтому в RAG у нас возможен пропуск. А контекст у нас с вами видит всё, и это у нас довольно сильные аргументы в пользу контекста. Если на этом остановиться, то можно вообще выкинуть RAG и больше никогда его не использовать. Но давайте посмотрим на экономику. У нас есть с вами плата за перечитывание, и это деньги. Длинный контекст означает, что модель будет перечитывать все наши документы при каждом запросе. И нам придётся платить за этот документ много раз сегодня, завтра, послезавтра. Всегда, когда мы будем использовать этот документ и помещать его в контекст, нам придётся платить за то, что модель будет его читать. При этом RAG платит за обработку документа один раз в момент, когда мы его загрузили. Да, вы скажете, кэширование документов снимает эту проблему, но это только для одной конкретной сессии. Ведь эти документы мы будем использовать не один раз, а множество сессий, множество запросов. А значит, и кэш нам здесь с вами не помогает. Следующий пункт - это качество на длинных контекстах. Помните про Lost in the middle из Стэнфорда? Когда контекст растёт до сотен тысяч токенов, внимание модели размывается. А это значит, что какой-то конкретный параграф в середине 2.000 страничный документ, модель может его даже не заметить или начать галлюцинировать детали из окружающего текста. RAG в этом плане убирает сток сена и даёт модели только иголки. А это значит, что здесь будет намного меньше шума и точнее ответ. Да, новые модели значительно снизили выраженность этого эффекта, но его полностью пока не устранили, а это значит, что нам надо с вами об этом продолжать думать. И последнее, что мы с вами разберём - это масштаб. Миллион токенов звучит впечатляюще. Но если ваша база знаний гигантская, это может быть терабайты, гигабайты, то попробуйте запихнуть её в это контекстное окно. И это у нас с вами может не получиться. Поэтому нам с вами нужен какой-то поисковый слой, который отфильтрует ненужное и оставит только то, что нам надо для конкретного запроса. А это именно то, что делает наш с вами RAG. А это значит, для RAG подходит, что мы можем сюда запихнуть любой объём нашей базы знаний. При этом, когда у нас длинное контекстное окно, мы не можем сюда добавить всю нашу базу знаний. Так что же нам с вами выбрать? RAG или длинное контекстное окно? Если у нас с вами ограниченный выбор документов и задача на глобальное рассуждение, то это будет длинный контекст. Если же у нас гигантская корпоративная база знаний, у нас тысячи документов, у нас динамические данные, и у нас есть способность развернуть и поддерживать RAG качественно, то однозначно мы с вами выберем RAG. Но в реальности сейчас чаще всего мы объединяем и RAG, и длинное контекстное окно. RAG у нас с вами находит релевантное, длинное контекстное окно позволяет положить достаточно для рассуждений. Поэтому в зависимости от ситуации, в которой мы находимся, мы можем выбирать одно, другое или и то, и другое. Мы можем взять лучшее из обоих миров. И на этот счёт уже есть исследования, когда в контекстное окно запихивается всё, что только возможно, или добавляет туда нужные кусочки при помощи RAG. Тем самым контекстное окно уменьшается в этих исследованиях в 4 раза с RAG. И как результат, 90% снижение задержки с 70 секунд с полным контекстным окном до полутора. Но что же с качеством? Авторы нам пишут: полный контекст даёт небольшое преимущество в точности. Но при этом RAG даёт нам конкурентное качество при меньших затратах и большей скорости. Поэтому нам с вами надо будет взвешивать, что же для нас с вами важнее из тех инструментов, которые мы можем использовать. По поводу того, как устроен RAG-пайплайн: нарезка документов, эмбединги, векторные базы, поиск, я уже подробно разбирал в отдельном видео. Ссылка будет в описании. Здесь мы не будем повторяться и смотреть уже на конкретные техники. Но есть и моменты, которые мы разбирали немного в прошлом видео, и те, которые часто забываются, когда мы используем с вами RAG. И первое - это обогащение запроса пользователя. Если пользователь напишет нашему с вами баристе: а покрепче, это всего лишь два слова и никакого контекста. Если мы с вами отправим этот запрос в наш RAG, то, скорее всего, мы получим какой-то мусор. Но если перед фазой RAG мы поставим обогащение нашего запроса и посмотрим контекст предыдущего сообщения или о чём вообще наш пользователь до этого общался, то мы можем получить запрос. Пользователь хочет более крепкий кофе, предыдущий заказ был капучино. И теперь наш RAG найдёт всё правильно. И второй, не менее важный - это Feedback Loop. Это то, что делает RAG живым. То есть RAG даёт нам с вами ответ. Мы смотрим за реакцией пользователя. И на основе реакции обновляем наши базы. И это нам помогает давать более точный ответ в следующий раз. Как на примере нашего бариста: если пользователь одобрил заказ, то вес предпочтения растёт. Если же пользователь отклонил, то вес падает. А если пользователь написал: я теперь предпочитаю чай, то это у нас будет новая запись. Но как же это реализовать? И вот эта реакция пользователя, она у нас может идти как фоновый процесс, который обновляет наши базы. Здесь главное - не блокировать нашего пользователя при работе с основным потоком. Поэтому помните, что RAG без обратной связи - это отличная база. RAG с обратной связью - это уже обучающая система. Но здесь возникает вопрос: RAG даёт нам знания. Но знания - это очень общее слово. Какие именно, когда нам надо работать с этой реакцией? Что вообще мы можем здесь сделать? Потому что предпочтения пользователей - это одно. Уроки из прошлых ошибок - это другое. Текущий контекст задачи - это третье. У агента не одна память, их четыре. Почему и какие они? Давайте продолжать.

[18:13]У нашего с вами агента есть память. Отлично, но какая? Ну, memory. Но какая конкретная? Это как сказать: у компьютера есть хранилище. Регистры процессора, оперативная память, SSD, облачный архив. Четыре абсолютно разных типа с разным временем жизни и назначением. У агента тоже четыре. Эту классификацию формализовали исследователи из Принстона в фреймворке CoALA (Cognitive Architectures for Language Agent). Сегодня её используют все основные фреймворки, и каждый тип решает свою задачу. Давайте разберём их. И первое у нас будет процедурная. Процедурная память - это то, как делать. Здесь будет наш системный промт плюс описание инструментов. Это не база знаний, это инструкция, как должностная инструкция у нас с вами на работе. И её обновляют осознанно между сессиями, не на лету. Внутри сессий она стабильна. Итак, инструкция у нас с вами есть. Но откуда агент знает факт, кто что любит, что написано в документации, какая у клиента политика возврата? И это будет семантическая. И это то, что знает наш агент. Здесь как раз-таки и будет наш RAG. Это долгосрочные знания, которые обновляются по мере поступления новых. Поэтому для нашего агента-бариста: то, что кто-то любит капучино, кто-то любит на овсяном молоке, а кто-то пьёт чай. Или для нашей разработки у нас может быть прописано, что микросервис платежей у нас написан на чистой архитектуре, на стеке Go с использованием определённых баз данных. Как аналог - это справочник, и он не статичный, он живой, который постоянно пополняется и корректируется. Факты у нас теперь с вами есть. Давайте вернёмся к нашему агенту-бариста и подумаем, а кто же учит нашего агента на ошибках? Справочник нам говорит, что Костя любит латте. А кто помнит, что в прошлый вторник забыли его аллергию на орехи, и у нас был с вами инцидент? И в этом нам с вами поможет эпизодическая память. Это то, что было, это конкретные эпизоды с результатами. И это самый недооценённый тип. В индустрии очень часто его игнорируют. Как, например, LangChain. Они именно так и пишут: Единственный тип памяти из KoALA, который у нас отсутствует - это эпизодик. И поэтому большинство продакшн систем, особенно, которые работают на LangChain, они его не реализуют. А зря. Как наш пример. Наш бариста забыл про аллергию, у нас произошёл инцидент, была жалоба, может быть, мы потеряли репутацию или деньги. А может быть, ваш кодинг-агент, который проводил рефакторинг всего модуля, всё сделал неправильно, откатил, что-то сломал. И после этого вы ему сказали: блин, ну ты же должен был всё делать через интерфейсы. И этот подход сработал. Так вот, чтобы в следующий раз он тоже сработал, у него должно быть знание об этом. Поэтому это у нас как дневник с уроками. Как мы с вами это можем реализовать? У нас есть с вами различные записи. В них есть действие, контекст, результат и урок. И перед действием, которое хочет совершить агент, он спрашивает наше хранилище. Были ли проблемы с похожими действиями раньше? И если мы нашли негативный эпизод, то мы добавляем его в контекст, как предупреждение. Ну и, соответственно, после следующего действия мы опять записываем результат. То есть у нас с вами появляется два дополнительных действия: каждый раз чтение перед действием и запись после. Понятно, что здесь у нас будет с вами накапливаться знания, и нам надо будет реализовать забывание. Здесь ровно так же, как проблема работы с кэшом, когда же нам его инваидировать. И здесь мы можем проставлять веса нашим знаниям или придумывать другие алгоритмы вытеснения. Поэтому, чтобы каждый день у нас не было одних и тех же ошибок, чтобы мы не начинали с чистого листа, мы используем этот тип памяти. А это значит, что теперь все уроки у нас будут запомнены. Но что агент знает прямо сейчас в конкретной задаче, в конкретном диалоге? И для этого нам с вами поможет рабочая память. И это то, что прямо сейчас контекст текущей задачи. Возвращаемся к нашему баристе. Пять человек, ретро через час, стресс после хотфикса, температура -15 у нас на улице. И эта память живёт пока задача активна. Потом она нам не нужна, она уничтожается. То есть это у нас будет как оперативная память, и она у нас с вами временная.

[23:54]Итак, у нас с вами есть четыре типа, это четыре жизненных цикла. Процедурная - она у нас меняется редко между сессиями. Семантическая обновляется по мере поступления новых данных. Эпизодическая содержит инсайты из того, что мы с вами делали. И рабочая - она у нас живёт пока жива наша задача, которую мы выполняем. Выглядит как очень красивая модель. Но строит ли кто-то так в реальности? Или это просто академическая классификация из научных работ? И это всё очень избыточно для нашего продакшена, для наших агентов. Так вот, ответ на этот вопрос пришёл буквально вчера. 31 марта этого года Anthropic выпускает очередную версию Claude Code. И это был их рутинный релиз. Кто-то забыл добавить одну строчку в конфигурации сборки, одну. И весь исходный код стал доступен: 500.000 строчек кода. И там было всё: система инструментов, оркестрация, промты. И самый для нас интересный в разрезе нашего сегодняшнего диалога - полная архитектура памяти. Да, Anthropic через час нашёл эту проблему. Через 3 на GitHub зеркала с этой утечкой уже набирали десятки тысяч звёзд. При этом Anthropic подтвердил, что это ошибка упаковки, не взлом. Я подробно изучил их архитектуру, чтобы понять, как устроены продакшн-системы лидеров рынка. Конечно, мы не будем показывать код, потому что это интеллектуальная собственность Anthropic. Но архитектурные решения, давайте разберём. Потому что это продукт с выручкой 2,5 миллиарда долларов в год. Это не прототип, не демо, это система, которой пользуются миллионы разработчиков. Многие издания написали, что это трёхслойная архитектура памяти. В реальности, когда я посмотрел на код, я обнаружил, что там 11 подсистем, 11. И они идеально ложатся на нашу модель из четырёх типов. Давайте посмотрим на карту целиком. Проведём через него запрос пользователя и посмотрим, что происходит в памяти.

[26:34]А для этого нам надо посмотреть, что попадает в контекстное окно, что увидит модель. И наша с вами задача будет понять, как память попадает внутрь. И здесь у нас контекстное окно разделено на две зоны. Статическая, в ней у нас будет правила поведения, стиль, инструкции по инструментам. Она будет одинакова для всех наших запросов, и она кэшируется глобально. И вторая часть - динамическая. И здесь у нас будет память, окружение, язык, и у каждого это будет своя. Зачем так надо, сейчас мы с вами разберём. Но мы можем запомнить, что memory.md живёт именно здесь, в динамической части. Следующая часть динамической памяти, всем нам с вами знакомый файл, Cloud MD. И здесь у нас с вами будут инструкции нашего проекта. И метасообщения перед историей.

[27:51]Дальше, если наш контекст раздулся и произошёл compaction, то здесь будет compact summary.

[28:01]Который будет заменять собой все наши старые сообщения. Это сжатие нашего контекста. Дальше у нас с вами пойдёт история разговора и результаты работы инструментов. И в самом низу у нас будет Memory Attachments. Это файлы, которые дешёвая модель выбрала в фоне для того, чтобы наполнить наш контекст дополнительной информацией. Заметьте порядок: статическая инструкция самого верха, динамическая память внизу. Помните Lost in the middle? Самое важное в начале и в конце. Середина - это история и результаты инструментов. Это не случается. Это попытка максимально эффективно использовать те модели, которые доступны прямо сейчас. Теперь давайте посмотрим, что происходит, когда пользователь отправляет запрос Claude. И три вещи происходят параллельно. Первые две - это memory.md и Cloud MD. Они уже загружены при старте нашей сессии. И тут мы с вами ничего не ждём. Но есть ещё третье, о которой мы сказали вот здесь вот, когда говорили про memory prefetch.

[29:30]И что же происходит интересного в этой фазе? А тут у нас с вами дешёвая модель, для Клода это будет Sonnet. Она в фоне выбирает до пяти релевантных файлов. При этом это не блокирующая операция. Если вдруг он не успел их подобрать, значит, ответ произойдёт без него. Если успел, то информация помещается в контекст.

[30:08]И вот мы отправили всё это в нашу модель, и она дала нам ответ. И после ответа Claude в фоне запускает три процесса. Первый - это агент записывает уроки.

[30:26]Второй - это Session Memory. Он обновляет заметки текущей сессии. И последнее - это Team Memory - синхронизация с нашей командой, если мы работаем как команда с Claude Code.

[30:44]И всё это происходит в фоне. Поэтому пользователь уже видит ответ, но Claude Code делает что-то интересное с памятью. И если посмотреть на всю архитектуру внимательно, то память никогда не стоит на пути ответа. И сейчас мы с вами пройдёмся по каждому блоку по отдельности. Итак, что же есть в нашей процедурной памяти?

[31:18]Здесь у нас есть с вами наш Cloud MD.

[31:23]И это инструкция нашего проекта. Но это не один файл, это четыре разных уровня: глобальный, пользовательский, проектный и локальный. И ближе к рабочей директории выше приоритет. То есть проектный файл загружается последним, значит, он ближе к концу нашего сообщения, значит, модель уделяет ему больше внимания. И получается, что здесь приоритет реализован не через условия в коде, а через позицию в контекстном окне. И это всё загружается один раз за сессию, и результат кэшируется. И у него есть лимит: 40.000 символов, 25 КБ. При этом также он содержит директивы и может ссылаться на другие файлы, собирая инструкции модульно. А значит, мы с вами получаем модульный системный промт. И он у нас версионируется в Git. Это именно то, о чём мы с вами говорили в первой части. Промт, которым вы владеете, даёт вам силу.

[32:53]Так вот, системный промт в Claude разделён на статику и на динамику. 20 секций в сумме, семь статических: правила поведения, стиль, инструкции по инструментам. Они одинаковые для всех, они кэшируются глобально. И 13 динамических: память, окружение, язык, они у каждого свои. Статика попадает в кэш один раз. Memory MD в динамической части, потому что память у каждого своя. Хорошо, агент знает, как работать, но откуда он знает, что он знает? Откуда берутся факты о проекте, о пользователях, о предметной области? И здесь будет наша семантическая часть. Каждая единица памяти - это будет отдельный Markdown файл с темой и заголовком. И у нас с вами будет четыре подтипа. Первое - это user.

[34:00]Здесь у нас будет роль, цели, предпочтения. Следующий - feedback. В нём содержатся ошибки и подтверждённые подходы. Дальше содержится project - текущая работа. И последний - reference.

[34:22]Там у нас будут указатели на внешние системы. Обратите внимание на feedback. Это, по сути, эпизодик, который записан в наш Semantic Storage. Это урок из прошлого, который записан как знание.

[34:41]Индексируется через Memory MD, и на нём есть ограничения: 200 строк максимум, 25 КБ. Каждая строка - это ссылка на топик-файл с описанием в одну фразу. То есть здесь содержатся не данные, здесь содержатся адреса данных. Так вот теперь, как же агент выбирает, какие файлы памяти нужны прямо сейчас? При каждом сообщении пользователя в фоне запускается отдельный вызов. Не основной модели, а дешёвой. И для Claude это у нас Sonnet. Даже если пользователь работает с Opus, зачем тратить дорогую модель для того, чтобы просмотреть наш манифест? Так вот, эта модель получает текст запроса, манифест всех файлов памяти и одна строка на файл, только метаданные и список инструментов, которые агент уже использует. Содержимое файлов он не видит и принимает решение только по описаниям. И тут промт оптимизирован на точность, а не на полноту. И там есть инструкции: только если уверен, если сомневаешься - не включай, можешь вернуть пустой список. Философия простая: лучше не вспомнить, чем засорить контекст. И эта выборка точечная: не все там 200 файлов мы засунем в контекст, а только те, которые нужны, и выбираем их по описаниям того, что здесь есть. И опять же, как я говорил ранее, этот префетч не блокирует ответ. Если вдруг он не успел или что-то пошло не так, то у нас запрос идёт без дополнительной памяти. Итак, наш семантик: данные, которые у нас уже существуют, и префетч их находит и подставляет. Но кто-то же должен создать эти данные, кто-то должен положить их туда для того, чтобы мы их могли проанализировать. И кто решает, что вот этот кусок разговора стоит запомнить, а вот это мусор, он нам не нужен? Так вот, помните, эпизодик memory, о котором мы сказали, что это самый недооценённый тип. Вот код это подтверждает. Они построили отдельного агента только для этого. После каждого финального ответа, когда модель закончила и нет никаких ожидающих вызовов, инструмент запускает фоновый агент. Отдельный процесс с ограниченными правилами. Он видит весь разговор, полный контекст, включая системный промт, инструкции, историю. Но промт говорит ему: обрати внимание на последние N сообщений, только те, что появились после прошлого извлечения. Зачем нам весь контекст, если мы смотрим только новое? Потому что, чтобы решить, стоит ли запомнить, что кто-то у нас аллергик или что-то произошло, нам надо знать информацию по всему диалогу, по контексту. Но здесь есть ограничение: максимум пять итераций, чтобы фоновый агент не ушёл в бесконечный цикл. Также ограниченные права: может читать код, но писать может только в директорию памяти. И последнее, если основной агент уже записал что-то в память на этом ходу, фоновый не запускается. Также есть интересный момент - курсор. Каждая успешная экстракция сдвигает курсор - идентификатор последнего обработанного сообщения. Следующая экстракция начинается именно с этого места. И если вдруг что-то не получилось, то курсор у нас не двигается, и эти сообщения будут рассмотрены снова, и ничего не потеряется. Это тот же принцип At least once, что в любой очереди сообщений. И Anthropic перенесли его в архитектуру памяти агента. Помните нашу схему: действие, контекст, результат, урок? Это именно она уже в продакшене. Только вместо простой структуры, фоновый агент с ограниченными правами, жёсткими лимитами, итерациями и курсорами, который не пропускает неудачи. Принципы абсолютно те же. Следующая подсистема - это Session Memory - отдельный файл заметок на каждую сессию: решения, изменённые файлы, замеченные паттерны. И это не логирование, это как рефлексия: данные собираются, данные извлекаются, и данные записываются в фоне. И кажется, что Claude собирает столько всего. Как же он сделает так, чтобы наше контекстное окно с вами не лопнуло? Кто же следит за тем, чтобы вся память не съела весь бюджет?

[40:24]И тут нам надо посмотреть, как устроена рабочая память, то, что мы используем здесь сейчас. И у Claude реализовано пять уровней сжатия контекста. И на первом уровне сжатия нашего контекста мы пропускаем уже саморизированные сообщения. А это значит, что нам здесь делать ничего не надо. Второй - это бюджет на результаты инструментов. И он установлен в 200.000 символов на сообщение. Если вдруг превысили, то самые крупные результаты уходят на диск. Модель видит первые 2 КБ плюс путь к полному файлу.

[41:20]И вот дальше решение заменить или вставить замораживается навсегда. Потому что мутировать уже отправленное, значит, убить наш KV-кэш. Помните из первой части: каждая мутация середины - это потерянные деньги. Вот тут вот у нас есть реализация. Третья часть - это удалить самый старый сообщения. Четвёртый - это микрокомтакт.

[41:53]И тут у нас есть два пути, и они зависят от состояния кэша. Если кэш протух, то можно мутировать прямо: заменяем старые результаты на заглушку. Ни одного вызова модели не происходит. Если же кэш живой, то мутировать нельзя. Вместо этого через API отправляем инструкцию удалить содержимое вот этих результатов из кэша. И сервер удаляет данные, не инваидируя весь кэш. И у обоих этих путей одна цель - защитить KV-кэш, и это как сквозной принцип. И пятое - это автокомпакт. Это очень тяжёлая операция. Здесь фоновый агент суммиризирует всё. В нём есть предохранитель: три неудачных сжатия подряд, и система останавливается. И это ограничители в коде, а не в промте. Также есть резерв на суммаризацию: 20.000 токенов. Если мы посмотрим на эти типы сжатия, то это очень похоже на наш пайплайн. Сначала у нас идут дешёвые операции, и каждая последующая операция дороже.

[43:21]То есть мы с вами максимально оптимизируемся по деньгам. Что же мы с вами видим на примере Claude? И здесь интеллект агента - не в модели, а в инфраструктуре вокруг модели. RAG, retrieval, четыре типа памяти, бюджет контекста, стратегия мышления. Пять компонентов, которые перемножаются. И мы видели, как всё это устроено в продакшн-системе Anthropic. И на её основе можно понять, что правильная архитектура важнее стека. Но также красивая архитектура без защиты может быть дырявой, без отказоустойчивости. Один сбой API, и всё мертво. Без наблюдаемости мы летим вслепую и не знаем, куда деваются наши деньги и что вообще происходит с агентом. В третьей части будет продакшн: безопасность, отказоустойчивость и многое другое. Ссылка на первую часть в описании. До встречи в финале.

Need another transcript?

Paste any YouTube URL to get a clean transcript in seconds.

Get a Transcript