Search
Write a publication
Pull to refresh

Как строить умных AI-агентов: уроки Context Engineering от Manus

Reading time9 min
Views470
Original author: Yichao Peak Ji

В самом начале проекта Manus перед нашей командой встал ключевой вопрос: обучать ли end-to-end агентную модель, используя open-source foundation-модели, или же строить агента поверх возможностей in-context learning у frontier models?

В моё первое десятилетие в NLP у нас и выбора-то такого не было. В далёкие времена BERT (да, прошло уже семь лет) модели приходилось fine-tune'ить и тестировать, прежде чем они могли переноситься на новую задачу. Этот процесс часто занимал недели на одну итерацию, даже при том, что тогдашние модели были крошечными по сравнению с сегодняшними LLM. Для быстроразвивающихся приложений, особенно на этапе до PMF, такие медленные циклы обратной связи — смертный приговор. Это был горький урок из моего прошлого стартапа, где я обучал модели с нуля для open information extraction и семантического поиска. А потом появились GPT-3 и Flan-T5, и мои внутренние модели стали не актуальны буквально за ночь. Ирония в том, что именно эти модели положили начало in-context learning — и открыли совершенно новый путь развития.

Из этого болезненного опыта выбор был очевиден: Manus делает ставку на context engineering. Это позволяет выпускать улучшения за часы, а не за недели, и держит наш продукт ортогональным по отношению к базовым моделям: если прогресс моделей — это прилив, то мы хотим, чтобы Manus был лодкой, а не сваей, вбитой в морское дно.

Тем не менее context engineering оказался далеко не тривиальным делом. Это экспериментальная наука — и мы перестраивали наш агентный фреймворк четыре раза, каждый раз находя более удачный способ формировать контекст. Мы с любовью называем этот ручной процесс перебора архитектур, подбора промптов и эмпирических догадок «Stochastic Graduate Descent». Это не изящно, но работает.

В этом посте я делюсь локальными оптимумами, к которым мы пришли через собственный «SGD». Если вы создаете своего AI-агента, надеюсь, эти принципы помогут вам сойтись к решению быстрее.

Проектирование вокруг KV-cache

Если бы мне пришлось выбрать всего одну метрику, я бы сказал, что KV-cache hit rate — это самый важный показатель для AI-агента на продакшн-стадии. Он напрямую влияет и на латентность, и на стоимость. Чтобы понять почему, давайте посмотрим, как обычно работает агент.

После получения пользовательского ввода агент проходит через цепочку использования инструментов для выполнения задачи. На каждой итерации модель выбирает действие из предопределенного action space на основе текущего контекста. Затем это действие исполняется в среде (например, в виртуальной машине-песочнице Manus), что дает наблюдение (observation). Действие и наблюдение добавляются в контекст, формируя вход для следующей итерации. Этот цикл продолжается, пока задача не будет завершена.

Как можно догадаться, контекст растёт с каждым шагом, а вывод — обычно структурированный вызов функции — остается относительно коротким. Это делает соотношение между prefilling и decoding сильно перекошенным у агентов по сравнению с чат-ботами. Например, в Manus среднее соотношение количества входных и выходных токенов составляет примерно 100:1.

К счастью, контексты с одинаковыми префиксами могут использовать KV-cache, что значительно снижает time-to-first-token (TTFT) и стоимость инференса — будь то на self-hosted модели или при вызове inference API. И речь идёт не о мелкой экономии: например, с Claude Sonnet кэшированные входные токены стоят 0,30 USD/MTok, а не кэшированные — 3 USD/MTok, то есть в 10 раз дороже.

С точки зрения context engineering, повышение KV-cache hit rate сводится к нескольким ключевым практикам:

  1. Держите префикс промпта стабильным. Из-за авторегрессионной природы LLM даже одно различие в токене может инвалидировать кэш начиная с этого места. Частая ошибка — включение временной метки, особенно с точностью до секунды, в начале system prompt. Да, это позволяет модели сообщить вам текущее время, но полностью убивает cache hit rate.

  2. Делайте контекст только с добавлением (append-only). Избегайте модификации предыдущих действий или наблюдений (actions/observations). Убедитесь, что сериализация детерминирована. Многие языки программирования и библиотеки не гарантируют стабильный порядок ключей при сериализации JSON-объектов, что может незаметно сломать кэш.

  3. Явно помечайте точки разрыва кэша, когда это необходимо. Некоторые провайдеры моделей или inference-фреймворки не поддерживают автоматическое инкрементальное кэширование префикса, а требуют ручной вставки точек разрыва (cache breakpoints) в контекст. Назначая такие точки, учитывайте возможное истечение кэша и, как минимум, убедитесь, что точка разрыва включает конец system prompt.

Кроме того, если вы self-host'ите модели с использованием фреймворков вроде vLLM, убедитесь, что prefix/prompt caching включено, и что вы используете такие техники, как session IDs, для консистентной маршрутизации запросов между распределенными воркерами.

Mask, Don't Remove

По мере того как ваш агент осваивает больше возможностей, его action space естественным образом становится всё сложнее — проще говоря, количество инструментов растет взрывными темпами. Недавняя популярность MCP только подливает масла в огонь. Если вы допускаете пользовательские настраиваемые инструменты, поверьте: рано или поздно кто-то подключит сотни загадочных тулов к вашему тщательно отобранному action space. В результате модель с большей вероятностью выберет неправильное действие или пойдет неэффективным путем. Иными словами, ваш агент начинает тупеть.

Естественная реакция — спроектировать динамический action space, например подгружая инструменты по мере необходимости через что-то вроде RAG. Мы пробовали этот подход и в Manus. Но наши эксперименты показали, что если нет крайней необходимости, не добавляйте и не удаляйте инструменты динамически в середине итерации. Основные причины:

  1. В большинстве LLM определения инструментов находятся в начале контекста после сериализации — обычно до или сразу после system prompt. Любое изменение в этой части полностью инвалидирует KV-cache для всех последующих actions и observations.

  2. Когда предыдущие actions и observations все еще ссылаются на инструменты, которые больше не определены в текущем контексте, модель путается. Без constrained decoding это часто приводит к нарушению схемы или галлюцинированию действий.

Чтобы решить эту проблему и при этом улучшить выбор действий, Manus использует context-aware state machine для управления доступностью инструментов. Вместо удаления инструментов мы маскируем token logits во время decoding, чтобы предотвратить (или, наоборот, принудить) выбор определенных действий в зависимости от текущего контекста.

На практике большинство провайдеров моделей и inference-фреймворков поддерживают ту или иную форму response prefill, которая позволяет ограничивать action space, не изменяя определения инструментов. Обычно встречаются три режима function calling (возьмём формат Hermes от NousResearch как пример):

  • Auto – модель может вызвать функцию или не вызывать ее. Реализуется префиллом только префикса ответа:<|im_start|>assistant

  • Required – модель должна вызвать функцию, но выбор не ограничен. Реализуется префиллом до токена вызова инструмента: <|im_start|>assistant<tool_call>

  • Specified – модель должна вызвать функцию из определённого подмножества. Реализуется префиллом до начала имени функции: <|im_start|>assistant<tool_call>{"name": "browser_

Используя этот подход, мы ограничиваем выбор действия, маскируя token logits напрямую. Например, когда пользователь присылает новый ввод, Manus должен немедленно ответить, а не выполнять действие. Мы также намеренно спроектировали имена действий с согласованными префиксами — например, все инструменты, связанные с браузером, начинаются с browser_, а командные — с shell_. Это позволяет нам легко обеспечить выбор агентом только из определённой группы инструментов в текущем состоянии без использования stateful logits processors.

Такие решения помогают поддерживать стабильность agent loop в Manus — даже в архитектуре, управляемой модель.

Используйте файловую систему как контекст

Современные frontier LLM уже предлагают context window на 128K токенов и более. Но в реальных агентных сценариях этого часто недостаточно — а иногда это даже становится обузой. Есть три типичных проблемы:

  1. Observations могут быть огромными, особенно когда агенты работают с неструктурированными данными вроде веб-страниц или PDF. Очень легко превысить лимит контекста.

  2. Производительность модели обычно начинает деградировать за пределами определённой длины контекста, даже если модель технически поддерживает такой размер окна.

  3. Длинные входы дороги даже при prefix caching: вы всё равно платите за передачу и префилл каждого токена.

Чтобы справиться с этим, многие агентные системы внедряют стратегии усечения (context truncation) или сжатия (compression). Но слишком агрессивное сжатие неизбежно ведёт к потере информации. Проблема фундаментальна: агент по своей природе должен предсказывать следующее действие, исходя из всего предыдущего состояния, и вы не можете надежно предсказать, какое наблюдение окажется критически важным через десять шагов. Логически любая необратимая компрессия несет риск.

Поэтому в Manus мы рассматриваем файловую систему как ultimate context: она не ограничена по размеру, по своей природе является персистентной и может напрямую использоваться самим агентом. Модель учится записывать и читать файлы по запросу — используя файловую систему не только как хранилище, но и как структурированную, вынесенную наружу память (externalized memory).

Наши стратегии сжатия всегда проектируются так, чтобы их можно было восстановить. Например, содержимое веб-страницы можно убрать из контекста, если сохранён её URL, а содержимое документа можно опустить, если в песочнице (sandbox) остаётся его путь. Это позволяет Manus сокращать длину контекста без безвозвратной потери информации.

Разрабатывая эту функцию, я задумался, что потребуется, чтобы State Space Model (SSM) могла эффективно работать в агентной среде. В отличие от Transformers, SSM не обладают полноценным механизмом внимания (full attention) и испытывают трудности с долгосрочными обратными зависимостями. Но если бы они смогли освоить файловую память (file-based memory) — вынося долгосрочное состояние во внешний стор, вместо того чтобы держать его в контексте, — их скорость и эффективность могли бы открыть путь к новому классу агентов. Агентные SSM могли бы стать настоящими наследниками Neural Turing Machines.

Manipulate Attention Through Recitation (Управление вниманием через рецитацию)

Если вы работали с Manus, то, вероятно, замечали любопытную деталь: при работе со сложными задачами он склонен создавать файл todo.md — и обновлять его пошагово по мере выполнения, отмечая завершенные пункты.

Это не просто «милое» поведение — это осознанный механизм управления вниманием (attention manipulation).

В Manus типичная задача в среднем требует около 50 вызовов инструментов (tool calls). Это длинный цикл — и поскольку Manus полагается на LLM для принятия решений, он уязвим к уходу от темы или потере из виду изначальных целей, особенно в длинных контекстах или при сложных задачах.

Постоянно переписывая todo list, Manus фактически "проговаривает" свои цели в конце контекста. Это перемещает глобальный план в недавний диапазон внимания модели (recent attention span), избегая проблемы «lost-in-the-middle» и снижая риск goal misalignment. По сути, он использует естественный язык, чтобы сместить собственный фокус в сторону целевой задачи — без необходимости в специальных архитектурных изменениях.

Оставляйте ошибки в системе

Агенты ошибаются. Это не баг — это реальность. Language models галлюцинируют, окружение возвращает ошибки, внешние инструменты ведут себя некорректно, а неожиданные крайние случаи появляются постоянно. В многошаговых задачах сбои — это не исключение, а часть цикла.

И всё же у многих возникает естественное желание спрятать эти ошибки: подчистить trace, повторить действие или сбросить состояние модели, полагаясь на магический "temperature". Это кажется более безопасным, более управляемым. Но у такого подхода есть цена: стирая сбой, вы убираете доказательства. А без доказательств модель не может адаптироваться.

По нашему опыту, один из самых эффективных способов улучшить поведение агента обманчиво прост: оставляйте неверные ходы в контексте. Когда модель видит неудачное действие, и полученное в результате наблюдения (observation) или stack trace, она неявно обновляет свои внутренние представления (internal beliefs). Это смещает её априорные ожидания от подобных действий, снижая вероятность повторения ошибки.

Мы вообще считаем, что способность к восстановлению после ошибки (error recovery) — один из самых четких индикаторов по-настоящему агентного поведения. Тем не менее, эта тема всё ещё не представлена в академических работах и публичных бенчмарках, которые чаще всего фокусируются на успехе выполнения задачи в идеальных условиях.

Остерегайтесь few-shot подхода

Few-shot prompting — распространённая техника улучшения выходов LLM. Но в агентных системах она может иметь тонкие побочные эффекты.

Языковые модели — отличные имитаторы: они воспроизводят шаблон поведения, представленный в контексте. Если контекст полон похожих пар «действие–наблюдение» (action–observation), модель будет склонна следовать этому паттерну, даже когда он уже не оптимален.

Это может быть опасно в задачах, связанных с повторяющимися решениями или действиями. Например, при использовании Manus для помощи в разборе пачки из 20 резюме агент часто впадает в ритм, повторяя схожие действия просто потому, что видит их в контексте. Это приводит к drift, чрезмерным обобщениям (overgeneralization) или даже к галлюцинациям.

Решение — повысить разнообразие. Manus вносит небольшое количество структурных вариаций в actions и observations, разные шаблоны сериализации, альтернативные формулировки, лёгкий шум в порядке или форматировании. Эта контролируемая случайность помогает разрушить шаблон и слегка перенастраивает внимание модели.

Иными словами, не загоняйте себя в few-shot-колею. Чем более однообразен ваш контекст, тем чаще ошибается агент.

Заключение

Context engineering всё ещё остаётся формирующейся дисциплиной, но для агентных систем он уже критически важен. Модели становятся мощнее, быстрее и дешевле, но никакая «сырая» вычислительная способность не заменяет необходимости в памяти, окружении и обратной связи. То, как вы формируете контекст, в конечном итоге определяет, как ведёт себя ваш агент: насколько быстро он работает, как хорошо восстанавливается и как масштабируется.

В Manus мы пришли к этим выводам через многократные переработки, тупики и реальное тестирование на миллионах пользователей. Ничто из сказанного здесь не является универсальной истиной, это те паттерны, которые сработали у нас. Если они помогут вам избежать хотя бы одной болезненной итерации, значит, этот пост выполнил свою задачу.

Будущее агентов строится благодаря контекстам. Проектируйте их грамотно.

Tags:
Hubs:
0
Comments0

Articles