ГлавнаяБлогДва типа памяти AI-агентов: почему ваш агент забывает и тратит токены
AI / Нейросети

Два типа памяти AI-агентов: почему ваш агент забывает и тратит токены

Узнайте, почему AI-агенты забывают диалог или тратят бюджет токенов. Разделяйте память разговора и память контекста. Практический гайд с кодом Python.

Al
Редакция Algolitalgolit.ru
14 мин чтения17 июня 2026 г.

Зачем разделять память AI-агента?

Ваш AI-агент забывает, что вы сказали три хода назад, или тратит весь бюджет токенов на один вызов инструмента? Корень проблемы — смешение двух типов памяти: памяти разговора (что было сказано) и памяти контекста (большие выводы инструментов вроде логов). Они требуют разного хранения и разного поиска. В этой статье вы узнаете, как разделить их с помощью фреймворка Strands, и увидите замеры: до 97% экономии токенов.

Два типа памяти AI-агента

У AI-агента есть два вида памяти:

  • Память разговора — хранит реплики, предпочтения, факты. Поиск по смыслу (семантическая близость).
  • Память контекста — хранит большие выводы инструментов: логи, датасеты, документы. Поиск по точному идентификатору.

Если использовать один тип там, где нужен другой, агент либо забывает, либо переполняет окно контекста.

Память разговораПамять контекста
Реплики, предпочтения, извлечённые фактыБольшие выводы инструментов (логи, датасеты)
Поиск по смыслу (семантическое сходство)Поиск по точному идентификатору (ссылка)
Вопрос: «Что пользователь сказал раньше?»Вопрос: «Дай мне тот 5MB лог-файл, точно»
Не подходит для: 5MB лог-блобНе подходит для: «Как зовут пользователя?»

Почему память контекста переполняется первой

Большие выводы инструментов переполняют окно контекста, потому что они неделимы и отправляются заново при каждом вызове модели. Инструмент, вернувший 200KB логов, стоит не 200KB один раз — эти данные едут во входе каждого последующего шага, пока не вытеснят исходный вопрос.

Исследование IBM Research (Solving Context Window Overflow in AI Agents, 2025) показало: пайплайн материаловедения потреблял 20 822 181 токен и падал; после выноса больших данных из контекста — 1 234 токена и успех.

Решение: не кладите данные в разговор

Раньше мы хранили большие данные вручную: инструмент писал их в agent.state и возвращал короткий указатель; следующий инструмент читал по ключу. Но логика выноса жила внутри каждого инструмента. Теперь Strands поставляет этот паттерн как плагин ContextOffloader — ваши инструменты остаются обычными функциями:

from strands import Agent
from strands.vended_plugins.context_offloader import ContextOffloader, FileStorage

# Обычные инструменты — без логики указателей, без agent.state внутри
agent = Agent(
    model=MODEL,
    tools=[fetch_application_logs, count_errors_by_service],
    plugins=[
        ContextOffloader(
            storage=FileStorage("./artifacts"),
            max_result_tokens=800,
            preview_tokens=200
        )
    ],
)
agent("Fetch 2 hours of logs for 'api-gateway' and tell me the top error service.")

Когда результат инструмента превышает max_result_tokens, плагин перехватывает его, сохраняет каждый блок в хранилище и оставляет в контексте маленький превью + ссылку. Агент получает инструмент retrieve_offloaded_content(reference), чтобы забрать полные данные по точной ссылке, когда они действительно нужны.

Нативный паттерн Memory Pointer в Strands

Нативный паттерн Memory Pointer — это ContextOffloader, плагин, который перехватывает слишком большие результаты инструментов во время выполнения, сохраняет каждый блок в бэкенде и заменяет контекстный результат на превью + ссылку. Большие данные никогда не затапливают окно контекста, а ваши инструменты не касаются логики указателей.

Измеренные результаты

Я выполнил один и тот же запрос тремя стратегиями. Один запрос, gpt-4o-mini, 2 часа логов:

СтратегияТокенов в контексте
Без управления~18 000–20 000
ContextOffloader (FileStorage)~490
context_manager="auto"~1 000

Это примерно 97% меньше токенов для того же ответа. Цифры варьируются, потому что данные логов случайны; test_native_pointer.py воспроизводит их.

Честное предостережение: оффлоадер — это страховочная сетка, а не всё решение. Основная экономия достигается в паре с селективным инструментом. Мой count_errors_by_service вычисляет ответ на сервере и возвращает краткую сводку, так что агент отвечает из сводки, а логи остаются выгруженными. Без селективного инструмента агент, которому нужны все данные, просто вызовет retrieve_offloaded_content и вернёт всё обратно. Оффлоадер гарантирует, что вы не переполнитесь; селективные инструменты удерживают низкое количество токенов.

Одна строка для большинства агентов

Для типичного многошагового агента не нужно настраивать выгрузку и суммаризацию отдельно:

agent = Agent(
    model=MODEL,
    tools=[...],
    context_manager="auto"
)

Это объединяет SummarizingConversationManager (суммаризирует старую историю с упреждающим сжатием) и ContextOffloader (в памяти) с проверенными на бенчмарках настройками. Всё, что вы передаёте явно, имеет приоритет.

То же самое, но на реальном Amazon S3

FileStorage пишет на локальный диск. Поменяйте одну строку — и большие выводы инструментов попадают в настоящий S3-бакет, вызываются по точной ссылке, никогда не в окне:

from strands.vended_plugins.context_offloader import ContextOffloader, S3Storage

agent = Agent(
    model=MODEL,
    tools=[fetch_application_logs, count_errors_by_service],
    plugins=[
        ContextOffloader(
            S3Storage(bucket=CONTEXT_BUCKET, prefix="log-artifacts/")
        )
    ],
)

Датасет логов размером 83KB был сохранён в S3, в контексте осталось ~486 токенов, данные вернулись байт-в-байт по точной ссылке:

📊 Tokens left in LLM context:  486
📦 Objects offloaded to S3:     1
   pointer in context:  s3://…/log-artifacts/1781569100199_1_call_…_0
   storage.retrieve()  → 77,050 bytes  (text/plain)
   verified: 200 log events recovered verbatim — exact data, no loss

Это вторая строка таблицы в производственной форме: поиск по точному идентификатору. Вам не нужны «логи, наиболее похожие на мой запрос». Вам нужны те логи, точно. Это объектное хранилище, а не семантический поиск.

Продакшн: две памяти, целенаправленно

В продакшне разделение становится архитектурой. Агент на Amazon Bedrock AgentCore держит каждую память на своём месте:

  • Разговор → AgentCore Memory. Реплики, предпочтения, извлечённые факты. Поиск по семантической близости (RetrieveMemoryRecords: эмбеддинги, top_k, оценка релевантности). Ограничено пользователем через actor_id. Подключается через Strands AgentCoreMemorySessionManager.
  • Память контекста → Amazon S3. Тот же ContextOffloader с S3Storage вместо FileStorage. Поиск по точной ссылке.

Почему не класть логи тоже в AgentCore Memory? Потому что AgentCore Memory возвращает семантически наиболее похожую память, а это неправильно для задачи «верни этот датасет по идентификатору». Разговору нужен смысл; данным — точный ключ. Один агент, две памяти, каждая делает то, что умеет лучше всего.

agent = Agent(
    model=BedrockModel(region_name=REGION),
    tools=[fetch_application_logs, count_errors_by_service],
    session_manager=AgentCoreMemorySessionManager(memory_config, REGION),  # разговор
    plugins=[
        ContextOffloader(S3Storage(bucket=CONTEXT_BUCKET, prefix="…")),  # данные
    ],
)

Наблюдаемость и оценка бесплатно

На AgentCore полная наблюдаемость встроена. Вы добавляете библиотеку инструментирования и получаете трейсы, метрики и логи для каждого вызова без написания кода мониторинга. Развёртывание уже включает это: агент отправляет OpenTelemetry (OTEL) трейсы и метрики в пространстве имён bedrock-agentcore, а дашборд CloudWatch GenAI Observability показывает представления агента, сессии и трейсов (латентность, частота ошибок, использование токенов, вызовы инструментов) прямо из коробки.

Так я диагностировал ошибку разрешения ListEvents за секунды: неудачный трейс был прямо в CloudWatch, без дополнительной настройки. См. View observability data for AgentCore agents.

Та же инструментировка питает AgentCore Evaluations: автоматизированное, LLM-as-a-Judge оценивание выполнения задач и точности вызовов инструментов на основе тех же трейсов. Вы можете измерять качество агента непрерывно, а не только при запуске.

Какую память когда использовать

  • Просто проблема с данными, локально? ContextOffloader(FileStorage(...)). Обычные инструменты, никакого кода указателей.
  • Типичный многошаговый агент? context_manager="auto". Суммаризация + выгрузка в одной строке.
  • Продакшн? AgentCore Memory для разговора, ContextOffloader(S3Storage(...)) для данных. Держите их раздельно.

В любом случае: сочетайте оффлоадер с селективными инструментами, которые возвращают сводки, а не сырые блобы. Оффлоадер предотвращает переполнение; селективные инструменты удерживают низкое количество токенов.

Попробуйте сами

Вам понадобится Python 3.11+, uv и OPENAI_API_KEY (или замените модель на BedrockModel). Для шагов с S3 и AgentCore также нужны AWS-учётные данные.

git clone https://github.com/aws-samples/sample-why-agents-fail
cd sample-why-agents-fail/stop-ai-agents-wasting-tokens/01-context-overflow-demo
uv venv && uv pip install -r requirements.txt

uv run python test_native_pointer.py  # локальное сравнение токенов
AWS_PROFILE=you uv run python test_s3_offload_local.py
# Продакшн-развёртывание + пошаговое руководство по двум памятям: setup_agentcore_s3.ipynb

Ноутбуки: test_native_pointer.ipynb (локально) и setup_agentcore_s3.ipynb (провижн + деплой + вызов на AWS).

Ключевые выводы

  • У агента две памяти. Разговор (семантическая) и данные (точная ссылка). Большинство проблем с контекстом — это когда одна используется вместо другой.
  • Сторону данных больше не нужно строить вручную. ContextOffloader — это паттерн Memory Pointer как плагин; инструменты остаются обычными функциями.
  • Измерено ~97% меньше токенов в этом демо; датасет 83KB выгружен в реальный S3 и восстановлен байт-в-байт по ссылке.
  • В продакшне держите две памяти раздельно. AgentCore Memory для разговора, S3 для данных. Поиск логов по смыслу — неправильный дизайн.
  • Оффлоадер — страховочная сетка; селективные инструменты — выигрыш. Возвращайте сводки, а не блобы.
  • На AgentCore наблюдаемость и оценка бесплатны. Добавьте библиотеку — получите трейсы, метрики и LLM-as-a-Judge оценку без кода мониторинга.

FAQ

Нужен ли ContextOffloader'у AWS? Нет. С FileStorage или InMemoryStorage он работает полностью локально. AWS нужен только при выборе S3Storage или развёртывании на AgentCore.

Можно ли хранить большие файлы в AgentCore Memory вместо S3? Можно, но не стоит. AgentCore Memory ищет по семантическому сходству, поэтому возвращает наиболее похожую память, а не точный файл. Большим выводам инструментов нужен поиск по точному идентификатору — это даёт S3 (через ContextOffloader).

Нужен ли Docker для развёртывания на AgentCore? Нет. Стартовый набор собирает образ в облаке с AWS CodeBuild по умолчанию. Docker нужен только для локальной сборки.

В чём разница между agent.state и ContextOffloader? agent.state — это ручной паттерн Memory Pointer: вы пишете и читаете указатели внутри инструментов. ContextOffloader — та же идея как плагин: инструменты остаются обычными, а фреймворк выгружает большие результаты за вас.

Какая из моих двух памятей тратит токены? Память данных. Память разговора — это маленький текст; взрыв токенов происходит из-за больших выводов инструментов, которые едут в контексте. Эту память и исправляет ContextOffloader.

Какая из двух памятей вашего агента тратит токены? Напишите в комментариях.

Ссылки

Исследования

  • Solving Context Window Overflow in AI Agents — IBM Research, 2025
  • Towards Effective GenAI Multi-Agent Collaboration — Amazon, 2024 (передача ссылок между агентами)

Реализация

  • Strands · Context Management
  • Strands · Conversation Management
#память AI-агента#контекстное окно#токены#Strands#ContextOffloader
Al
Редакция Algolit

Пишем про алгоритмы, подготовку к собеседованиям и карьеру в IT — так, чтобы было понятно и полезно.

Хочешь закрепить знания на практике?

Решай задачи на Algolit — интерактивная платформа для обучения

Начать бесплатно →