[!NOTE] Автоматический перевод Эта статья была автоматически переведена с оригинальной английской версии.

ИИ-агент Архитектура памяти в 2026 году: Чекпоинты, векторные хранилища и память на основе файлов

Часть 2 серии «Инженерия стека Агентный»

цикл ризонинга может существовать лишь в течение одного запроса, если его состояние не сохраняется вне процесса обработки. Без агентской памяти агент не может возобновить приостановленный план, восстановиться после сбоя или воспроизвести предпочтение, заданное ранее в сессия. Часть 1 В данной статье рассматривается контрольный поток. Здесь указывается, какое состояние требуется на каждом последующем шаге и где оно должно храниться.

Я расскажу о архитектуре памяти данного устройства. Агент аналитика рынка, Покажу, как чекпоинты, векторные хранилища с низкой задержкой и память для документов на основе файлов взаимодействуют друг с другом в рамках агентов с длительным временем работы. Затем рассмотрю случаи, когда целесообразно использовать PostgreSQL, Redis, Qdrant, хранилища типа «ключ-значение» и обычные файлы в формате Markdown.

Кратко: Разделяйте память в зависимости от способа доступа. Горячая память представляет собой состояние на уровне потока чекпоинт, необходимое для приостановки и возобновления работы. Холодная память используется для хранения межпоточных сессия данных в структурах типа ключ-значение или векторных хранилищах. Документированная память служит для сохранения проектной информации в удобных для анализа файлах. Начните с проблемы, которую необходимо решить, а затем выберите подходящее хранилище. Не сохраняйте точные данные в системах с фазированным поиском retrieval, а также не используйте чекпоинт в качестве журнала аудита.


Что такое память ИИ-агент?

ИИ-агент память представляет собой слой состояния, который позволяет агенту сохранять прогресс выполнения задачи, восстанавливать ранее полученные знания и обновлять свои данные между разными запусками. В продакшене это не одна векторная база данных; это комбинация активных чекпоинты хранилищ, холодных семантических или структурированных хранилищ, а также памяти в виде документов, читаемых человеком.

НужноЛучший стандартный вариантПочему?
Пауза и возобновление одной запускахранилище PostgreSQL чекпоинтНадёжные данные приложения, поддающиеся поиску и удобные в работе
Низкоуровневое кратковременное состояние латентностьхранилище Redis чекпоинтБыстрое восстановление состояния и его кратковременная жизненность при необходимости компромисса между сохранением данных и производительностью
Кросс-сессия семантическое воспроизведениеQdrant или pgvectorВосстанавливает воспоминания на основе смысла, а не только точных ключей
Структурированные сведения о пользователяхPostgreSQL или хранилище типа «ключ-значение»Детерминистические обновления превосходят нечёткие retrieval методы при работе с предпочтениями и идентификаторами.
Проектные конвенции и устоявшиеся процедуры работыMarkdown-файлы или файлы JSONЧитаемый человеком формат, поддерживающий сравнение изменений, и удобный для обновления агентами
Память отношений между несколькими сущностямиграф знанийПолезно в ситуациях, когда взаимосвязи имеют большее значение, чем отдельные факты.

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

Сбои, требующие использования памяти

Безсостоянийный агент способен ответить на изолированный вопрос, но забывает о запросе сразу после завершения вызова. Такая архитектура теряет эффективность, когда продукту требуются любые из следующих функциональных особенностей:

В рамках Агент аналитика рынка из Часть 1, При запросе «Проанализировать NVDA» генерируется план, пять tool calls, собранные данные и черновик отчета. Когда пользователь отвечает «всё нормально, но добавьте анализ конкурентов», хранилище чекпоинт позволяет агенту загрузить состояние с предыдущего узла и включить этап анализа конкурентов. В отсутствие сохраненных состояний агент не может определить, на что именно указывает оценка «всё нормально», и вынужден начинать работу заново.

Долгосрочная память решает схожую задачу в другом контексте. Если пользователь вернётся через неделю и попросит «Обновить анализ NVDA», агенту, возможно, потребуется вспомнить предпочтение к консервативной оценке рисков и интерес к акциям полупроводниковой отрасли. Хранилище памяти на основе векторов позволяет извлекать такие данные через сессии без необходимости повторного запроса.

LangGraph разделяет данные внутри графа по уровням области применения. Каждая итерация обработки графа выполняется в рамках отдельной thread, то есть для одного конкретного диалога или задачи. Состояние, сохраняемое внутри такой thread, называется краткосрочная память. Состояние, доступное между разными thread, обозначается как долгосрочная память. Текущий контекст и переменные, находящиеся в процессе выполнения, модель, формируют слой рабочей памяти, расположенный над обоими вышеупомянутыми хранилищами данных.

Таксономия памяти


Таксономия памяти ИИ-агент

Прежде чем переходить к реализации, целесообразно классифицировать те данные, которые агентам необходимо запоминать. CoALA фреймворк (Sumers, Yao et al., 2023) представляет собой стандартную таксономию, основанную на принципах когнитивной науки. Я ввёл понятие ограничения области действия памяти в своей работе контекст-инжиниринг публикация; Здесь я разделяю его на шесть категорий:

Тип памятиОбласть примененияВремя существованияПримерШаблон хранения данных
РабочийТекущий шагмиллисекундыаргументы Tool call, текущий ответ LLMВнутрипроцессный словарь (Python)
КраткосрочныйТекущая веткаМинуты–часыИстория диалога, ход выполнения плана, собранные данныеЧекпоинт хранение
Эпизодическиймежпоточная коммуникацияДни–месяцыНа прошлой неделе пользователь спрашивал о результатах деятельности NVDA.хранилище векторов / хранилище типа KV
Семантическиймежпоточная коммуникацияМесяцы — постоянные«Пользователь отдаёт предпочтение консервативным инвестициям»хранилище векторов / хранилище KV
Документациямежпоточная коммуникацияДни — постоянныеЗаметки по проекту, краткие обзоры исследований, выявленные закономерностиХранилище файлов (Markdown/JSON)
Процедурныйпо всей системеПостоянныйПри анализе акций обязательно проверяйте документы, подаваемые в SEC.Config / системный промпт

Рабочая память — это то, с чем в данный момент активно взаимодействует ризонинг через LLM: переменные Python в текущей функции, содержимое контекстное окно, аргументы tool call во время выполнения. Это самый быстрый и кратковременный уровень хранения данных. Ничто не сохраняется после завершения текущего шага. Объём рабочей памяти ограничен контекстное окно модель, что делает её фактическим боттлнек. Все данные, которые агент «знает» в момент принятия решения, должны помещаться именно здесь, независимо от того, поступили ли они из хранилища чекпоинт, в результате векторного поиска или при чтении файла. Остальные уровни предназначены для подачи нужной информации в рабочую память в подходящее время.

Краткосрочная память — это данные, которые чекпоинт LangGraph записывает после каждого узла. Эпизодическая и семантическая память сохраняются в рамках всех потоков выполнения. Документная память хранит проектные заметки, краткие отчеты о исследованиях и выработанные стандарты в файлах, доступных как для людей, так и для агентов. Процедурная память заключена в системных инструкциях и определениях инструментов, поэтому она не изменяется под каждого пользователя.

В процессе реализации эти категории сводятся к трём уровням. В памяти типа «горячая» хранится текущий сессия. Память типа «холодная» обеспечивает возможность восстановления данных в рамках сессии. Память документов сохраняет накопленные знания проекта в состоянии читаемости и позволяет осуществлять прямую редактирование.

Класс CoALA классифицирует память как рабочую, эпизодическую, семантическую и процедурную. The Память в эпоху исследования ИИ-агенты В документации особый акцент делается на векторных хранилищах и графах знаний; кроме того, описываются чекпоинты и его интерфейс Store. Знания проектов, сохраняемые в файлах, не входят в рамки этих таксономий, несмотря на то что Claude Code, Cursor, Windsurf и Devin все поддерживают загрузку постоянных файлов проектов.

Аналогичная схема хранения применяется и в других областях. В проекте Voyager переиспользуемые игровые навыки сохраняются в виде библиотек кода, команды ECR3 работали над процедурными документами промпт, а механизм Agent Workflow Memory позволяет генерировать повторно используемые веб-работы на основе успешных примеров. Благодаря файлам такие знания становятся доступными к анализу и версионированию без необходимости в отдельном сервисе эмбеддинг.

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

Этот Статья «Генеративные агенты» (Park et al., 2023) показали, до каких пределов это может быть доведено: симулированные агенты хранили, анализировали и восстанавливали собственные воспоминания. Их memory stream ранжировал кандидаты по принципам свежести, значимости и релевантности, что до сих пор служит полезной отправной точкой для моделирования памяти агентов retrieval.


Краткосрочная память агента: хранилище чекпоинт

Каждый раз при выполнении узла LangGraph компонент фреймворк сериализует полное состояние графа и сохраняет его в чекпоинт хранилище. Именно это обеспечивает возможность паузы/возобновления работы, отладку с использованием механизма «путешествия во времени», а также поддержку рабочих процессов типа HITL.

Поток горячей памяти Чекпоинт

A чекпоинт содержит состояние графа, необходимое для возобновления работы: AgentState из Часть 1 (сообщения, идентичность, профиль пользователя, шаги плана, исследовательские данные, режим выполнения), а также метаданные LangGraph, включая узел, который его сгенерировал, и его ID чекпоинт. После прерывания типа HITL или перезапуска процесса граф загружает последние зарегистрированные границы и переходит к следующему узлу. Он не продолжает работу с какой-либо произвольной строки кода на Python. чекпоинт также отличается от лога событий с возможностью только добавления данных или трейс. Часть 5 явно разделяет эти рантайм observability поверхности.

Как работает сохранение состояния модели LangGraph

LangGraph’s BaseCheckpointSaver это простой интерфейс: put() пишет чекпоинт, get_tuple() читает самый свежий элемент для данной нити. list() возвращает историю. Каждый чекпоинт имеет свой ключ (thread_id, checkpoint_ns, checkpoint_id), где thread_id определяет разговор checkpoint_ns обеспечивает управление пространствами имён субграфов, и checkpoint_id это уникальная версия.

Ключевым фактором выбора является то, какой бэкенд следует использовать в качестве основы. PostgreSQL и Redis — это два наиболее распространённых варианта для производственной среды.

PostgreSQL против Redis

Redis против PostgreSQL

РазмерностьPostgreSQL (langgraph-checkpoint-postgres)Redis (langgraph-checkpoint-redis)
Прочность модельТранзакции ACID, WAL и механизмы репликацииВозможность настройки сохранения данных в форматах AOF или RDB
Чекпоинт историяНадёжная история операций для анализа логов и отладкиУровень сохранения зависит от настроек сохранения и вытеснения.
Основное ограничениеЗапись в базу данных латентность и рост размера таблицыИспользование ОЗУ, процедура вытеснения данных и настройки сохранения состояния
Соответствие операционным требованиямКоманды, уже использующие реляционные базы данныхКоманды, которые уже используют Redis в высоконагруженном режиме throughput
Оптимальный стандартный вариант дляНадёжная рекурсия и воспроизводимая отладкаЛатентность — чувствительное, восстанавливаемое сессия состояние

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

PostgreSQL: стандартный вариант с высокой надёжностью хранения данных

PostgreSQL представляет собой более надёжный стандарт для большинства команд. Благодаря способности Чекпоинты выдерживать сбои, он обеспечивает полную семантику транзакций, а наличие истории чекпоинт значительно упрощает отладку путём «путешествий во времени».

Из checkpointer_setup.py:

from langgraph.checkpoint.postgres.aio import AsyncPostgresSaver

async def create_postgres_checkpointer(connection_string: str) -> AsyncPostgresSaver:
    """Create a PostgreSQL-backed checkpoint store.

    PostgreSQL gives us ACID guarantees — if a checkpoint write succeeds,
    the state is durable even if the process crashes immediately after.
    """
    checkpointer = AsyncPostgresSaver.from_conn_string(connection_string)

    # Create the checkpoint tables if they don't exist.
    # This is idempotent — safe to call on every startup.
    await checkpointer.setup()

    return checkpointer

# Usage: wire into the graph compilation
checkpointer = await create_postgres_checkpointer(
    "postgresql://user:pass@localhost:5432/agent_memory"
)
graph = create_graph(checkpointer=checkpointer)

# Every invoke/stream call now persists state automatically
config = {"configurable": {"thread_id": "user-123-session-1"}}
result = await graph.ainvoke({"messages": [HumanMessage(content="Analyze NVDA")]}, config)

# Resume later — loads the latest checkpoint for this thread
result = await graph.ainvoke({"messages": [HumanMessage(content="approved")]}, config)

Этот AsyncPostgresSaver использует langgraph-checkpoint-postgres пакет, который создаёт три таблицы: checkpoints (сериализованное состояние), checkpoint_blobs (большие бинарные данные), и checkpoint_writes (Ожидаются операции записи для восстановления после сбоя). Данная схема поддерживает одновременный доступ и использует консультативные блокировки для предотвращения конфликтов при записи.

Redis: когда латентность является боттлнек

Когда критически важна скорость обработки на уровне нескольких субмиллисекунд чекпоинт латентность (в реальном времени для конверсационных агентов или при высокочастотных циклах работы инструментов), Redis представляет собой более подходящий выбор.

Из checkpointer_setup.py:

from langgraph.checkpoint.redis.aio import AsyncRedisSaver

async def create_redis_checkpointer(redis_url: str) -> AsyncRedisSaver:
    """Create a Redis-backed checkpoint store.

    Redis stores checkpoints in memory for sub-millisecond access.
    Trade-off: less durable than PostgreSQL unless AOF is enabled.
    """
    checkpointer = AsyncRedisSaver.from_conn_string(redis_url)

    # Initialize Redis data structures
    await checkpointer.setup()

    return checkpointer

# Usage: same graph API, different backend
checkpointer = await create_redis_checkpointer("redis://localhost:6379")
graph = create_graph(checkpointer=checkpointer)

Этот AsyncRedisSaver из langgraph-checkpoint-redis хранит чекпоинты в виде документов JSON, идентифицируемых по идентификатору потока. v0.1.0 — переработка дизайна заменил несколько операций поиска на одну JSON.GET этот механизм позволяет существенно снизить латентность. В Redis 8.0+ по умолчанию включены модули RedisJSON и RediSearch — установка дополнительных модулей не требуется.

Для систем с ограниченными ресурсами памяти деплои, ShallowRedisSaver Сохраняет только самую свежую версию чекпоинт для каждой нити — без истории изменений, однако с минимальным потреблением оперативной памяти. Используйте этот режим тогда, когда вам необходимы функции паузы/продолжения работы, но нет нужды в отладке с возможностью возврата к предыдущим состояниям.

Когда использовать тот или иной инструмент

Используйте PostgreSQL в следующих случаях:

Используйте Redis в следующих случаях:

Другие варианты: langgraph-checkpoint-sqlite подходит для локальной разработки и однопроцессных сред деплои. Для стеков, оптимизированных под AWS, langgraph-checkpoint-aws предоставляет DynamoDBSaver Благодаря интеллектуальной обработке пайлоадов небольшие чекпоинты (менее 350 КБ) остаются в DynamoDB, а крупные данные автоматически переносятся в S3. Модель без серверов и отсутствие необходимости в управлении инфраструктурой делают этот решение привлекательным для сценариев с переменной нагрузкой деплои.


Долгосрочная память: сохранение состояния в течение сессии

Текущее общение обрабатывается с помощью «горячей» памяти. Однако как быть с пользователем, который вернётся на следующей неделе? Долгосрочная память хранит факты, предпочтения и историю взаимодействий, которые сохраняются между разными диалогами.

LangGraph предоставляет функционал для Store интерфейс для обмена данными между потоками через него BaseStore класс. Каждый элемент памяти представляет собой (namespace, key) сопоставляется с значением JSON и необязательным вектором эмбеддинг. Обычно этот пространство имён кодирует пользователя или организацию: ("user", "user-123", "preferences").

Долгосрочная память поток

Хранение векторов: семантическое восстановление с использованием Qdrant

Когда агенту необходимо восстановить структурированную информацию («Что сказал пользователь о сроках инвестирования?»), vector search обеспечивает семантическое восстановление данных. Вместо поиска по точным ключам агент выполняет запросы на основе смысла.

Qdrant это специально разработанная векторная база данных, написанная на Rust, которая обеспечивает хранение эмбеддинг, индексацию (HNSW) и фильтрованный поиск. Я подробно рассмотрел HNSW и связанные с ним компромиссы в своем пост об ранжировании результатов поиска. Qdrant также предоставляет сервер MCP это функционирует как слой семантическая память — что очень удобно, если ваш агент фреймворк поддерживает протокол контекста Модель.

Из memory_store.py:

from qdrant_client import QdrantClient
from qdrant_client.models import PointStruct, Distance, VectorParams
from langchain_anthropic import ChatAnthropic
import hashlib
import json

class UserMemoryStore:
    """Long-term memory backed by Qdrant vector search.

    Stores user facts as embedded vectors for semantic retrieval.
    Each fact is a short natural-language statement about the user.
    """

    def __init__(self, qdrant_url: str, collection_name: str = "user_memory"):
        self.client = QdrantClient(url=qdrant_url)
        self.collection_name = collection_name
        self._ensure_collection()

    def _ensure_collection(self):
        """Create the collection if it doesn't exist."""
        collections = [c.name for c in self.client.get_collections().collections]
        if self.collection_name not in collections:
            self.client.create_collection(
                collection_name=self.collection_name,
                vectors_config=VectorParams(
                    size=1536,  # text-embedding-3-small dimensions
                    distance=Distance.COSINE,
                ),
            )

    def store_fact(self, user_id: str, fact: str, embedding: list[float]):
        """Store a user fact with its embedding."""
        point_id = hashlib.md5(f"{user_id}:{fact}".encode()).hexdigest()
        self.client.upsert(
            collection_name=self.collection_name,
            points=[PointStruct(
                id=point_id,
                vector=embedding,
                payload={"user_id": user_id, "fact": fact},
            )],
        )

    def recall(self, user_id: str, query_embedding: list[float], top_k: int = 5):
        """Retrieve the most relevant facts for a user given a query."""
        results = self.client.query_points(
            collection_name=self.collection_name,
            query=query_embedding,
            query_filter={"must": [{"key": "user_id", "match": {"value": user_id}}]},
            limit=top_k,
        )
        return [hit.payload["fact"] for hit in results.points]

Последовательность действий следующая: (1) после каждого разговора LLM извлекает ключевые факты из взаимодействия («у пользователя высокая толерантность к риску», «пользователь заинтересован в акциях полупроводниковых компаний»), (2) эти факты сохраняются в базе данных Qdrant, (3) в начале следующего разговора агент отправляет запрос в Qdrant с новым сообщением пользователя для восстановления соответствующего контекста.

Retrieval оценка качества: за пределами косинусного сходства

Чистое сходство по косинусу является лишь отправной точкой, однако системы памяти в продакшене требуют более разнообразных retrieval. Статья «Генеративные агенты» (Park и др., 2023) предложили функцию оценки, объединяющую три сигнала:

Конечный балл retrieval представляет собой взвешенную сумму: score = alpha * recency + beta * importance + gamma * relevance. Это предотвращает то, что актуальные и важные факты остаются под слоем устаревших, но семантически похожих данных. Для Агент аналитика рынка, У элемента вес наивысшая релевантность (0,5), за которой следуют показатели свежести (0,3) и значимости (0,2) — поскольку самый важный фактор при обработке запроса пользователя — это его текущая цель. Эти начальные значения веса были адаптированы из статьи «Generative Agents» (в которой использовалось равное взвешивание всех параметров); я обнаружил, что упор на релевантность лучше всего срабатывает для запросов, связанных с финансовым анализом, однако эти коэффициенты основаны на интуиции, а не на эмпирической оптимизации.

Vector search обладает высокой эффективностью, однако не всегда является наиболее подходящим инструментом. Вот ситуации, когда целесообразно использовать альтернативы:

ПодходЛучше всего подходит дляОсновные операционные затраты
Vector search (Qdrant)Семантическое воспроизведение неструктурированных фактовЭмбеддинг и жизненный цикл индекса
Хранилище типа «ключ-значение» (Redis)Структурированные профили пользователей и их предпочтенияПолитика использования памяти и сохранения данных
Хранилище документов (файлы)Знания проекта и заметки, управляемые агентомОдновременная обработка, разрешения и поиск
Поиск по всему тексту (PostgreSQL) индекс GIN)**Показатель воспроизведения ключевых слов на основе истории разговораРост индекса и настройка запросов
Граф знаний (Neo4j)Отношения между сущностями и запросы с несколькими промежуточными шагамиМоделирование графов и другие системы хранения данных
Гибридный (векторный + поисковый по ключевым словам)Вспомните случаи, когда намерение запроса меняетсяДва пути расчёта оценок, подлежащих настройке и тестированию

Хранилища типа “ключ-значение” эффективно справляются с структурированными данными. Если ваш долгосрочная память представляет собой профиль пользователя — уровень толерантности к риску, горизонт инвестирования, предпочтительные сектора — то использование хеша в Redis или столбца JSONB в PostgreSQL будет проще и быстрее, чем работа с эмбеддинг и поиск векторов. Применяйте vector search в тех случаях, когда данные находятся в неструктурированном виде, а формулировки запросов retrieval постоянно меняются.

Встроенный хранилище LangGraph предоставляет интерфейс типа «ключ-значение» на основе пространства имён с факультативной поддержкой vector search. BaseStore API представляет собой простую структуру: put(), get(), search(), и delete() с иерархическим ограничением области имён. Существуют три варианта реализации:

Этот index Данная конфигурация позволяет использовать vector search над хранимыми элементами с применением настраиваемого эмбеддинг-модель. Во многих сценариях использования такой встроенный хранилище полностью достаточно, что исключает необходимость в применении специализированной векторной базы данных.

from langgraph.store.memory import InMemoryStore

# Create a store with vector search enabled
store = InMemoryStore(
    index={
        "dims": 1536,
        "embed": my_embedding_function,  # e.g., OpenAI text-embedding-3-small
    }
)

# Store a user preference (namespace scopes to user)
await store.aput(
    namespace=("user", "user-123", "preferences"),
    key="risk-profile",
    value={"risk_tolerance": "high", "horizon": "long-term"},
)

# Semantic search across user's memories
results = await store.asearch(
    namespace=("user", "user-123"),
    query="What is their investment style?",
    limit=5,
)

Выбор стратегии долгосрочная память

Начните с формата ключ-значение, если ваша структура данных четко определена и имеет явную организацию (профили пользователей, настройки, именованные сущности). Добавляйте vector search тогда, когда требуется семантическое обработание retrieval над неструктурированными данными или при условии непредсказуемой формулировки запросов.

Графы знаний находят своё применение там, где важны связи между сущностями, например, при задаче «Какие компании, о которых спрашивал пользователь, являются конкурентами NVDA?». Самым интересным недавним проектом в этой области является Графити (автор — Zep), который формирует временно-ориентированную графовую структуру знаний, позволяющую отслеживать когда те или иные факты считались истинными, а не только что считалось истинным. Каждая рёбро сопровождается интервалами действительности, благодаря чему изменение уровня рисков пользователя приводит к аннулированию старого значения вместо его тихого перезаписывания. Graphiti предоставляет отчёты Точность составляет 94,8% на наборе данных DMR бенчмарк, Благодаря своей двухвременной архитектуре модель решается проблема устаревших данных на уровне хранилища информации.

Проблема кроется в операционной части. Запуск графовой базы данных — задача непростая, и для большинства приложений агентов vector search фильтрация метаданных позволяет достичь аналогичных результатов с меньшими затратами на инфраструктуру.

Управляемая память фреймворки подобная Mem0 и Летта (formerly MemGPT) берут на себя задачи извлечения, консолидации и retrieval пайплайн. Подход Mem0 отличается особенностью: специальный LLM выделяет кандидатов в память, двигатель принятия решений сравнивает каждый новый факт с уже существующими записями в векторном хранилище, а механизм разрешения принимает решение о том, следует ли его добавить, обновить или удалить, что обеспечивает целостность и отсутствие дубликатов в хранилище памяти. Letta использует подход, характерный для операционных систем: агенты самостоятельно управляют своей контекстное окно с помощью инструментов управления памятью, автономно перемещая данные между «основной памятью» (в рамках контекста) и «архивной памятью» (вне контекста). Оба решения стоит рассмотреть, если вам необходимо сократить время вывода продукта на рынок и не требуется полный контроль над процессом управления памятью пайплайн.


Память документов: шкаф для хранения данных агента

В таксономиях памяти файловая память получила более широкое применение на практике, чем указано в официальных классификациях. В одной из оценок LoCoMo, проведённых определённым поставщиком, Летта сообщил 74,0% — таков показатель эффективности подхода, основанного на файловой системе. Необходимо сохранять этот результат в рамках условий модель, бенчмарк и харнесс, однако операционные преимущества очевидны: разработчики могут напрямую читать, редактировать и сравнивать хранящиеся данные.

Более длинные контекстные окна позволяют реализовывать полноценное чтение всего файла в рамках некоторых проектных документов. Хотя разбитые на части retrieval подходят и для крупных корпусов данных, короткий файл с правилами или инструкциями по передаче информации часто можно загрузить напрямую. Выбор метода зависит от размера документа, уровня retrieval точности, доступного объёма памяти и того, как часто требуется пересматривать или редактировать содержимое.

Векторные хранилища и структурированные хранилища типа «ключ-значение» бэкенды эффективно справляются с задачами семантического поиска и структурированных запросов. Однако существует ещё одна категория знаний агента, которую ни те, ни другие не могут обрабатывать оптимально — это накопленный контекст проекта, включающий установленные правила, записи исследований и принятые решения, необходимые агенту на протяжении всего сессии. Для таких данных критически важны возможности человекочитаемости и контроля версий.

Это и есть память документов: агент читает и записывает структурированные файлы (Markdown, JSON, YAML) в определённую директорию. Никаких эмбеддинги, никаких баз данных, никакой инфраструктуры — только файлы на диске, доступные как для агента, так и для разработчика. cat, grep, git diffи вручную вносить правки.

Почему файлы?

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

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

Вот так и выглядит процесс. инструменты Claude Code CLAUDE.md и .claude/ Работа с директориями. Агент читает информацию на уровне проекта CLAUDE.md файлы с конвенциями и инструкциями, а также выполняет запись в ~/.claude/MEMORY.md для обмена знаниями между сессия. Файлы представлены в простом формате Markdown: их можно читать, редактировать, коммитить в Git и делиться ими с командой. курсора .cursorrules и виндсерфинг .windsurfrules файлы в простом формате, которые агент загружает при запуске для получения контекста проекта.

Реализация хранилища в памяти для файлов

Реализация преднамеренно оставлена простой. Агент обладает четырьмя операциями: запись документа, чтение документа, получение списка доступных документов и поиск в документах по ключевому слову.

Из file_memory.py:

from pathlib import Path
import json
import fnmatch

class FileMemory:
    """Document memory backed by the local filesystem.

    Stores agent knowledge as human-readable files organized by topic.
    No embeddings, no database — just files that both the agent and
    the developer can read, edit, and version-control.
    """

    def __init__(self, base_dir: str | Path):
        self.base_dir = Path(base_dir)
        self.base_dir.mkdir(parents=True, exist_ok=True)

    def write_doc(self, path: str, content: str, metadata: dict | None = None):
        """Write or overwrite a document at the given path.

        Paths are relative to base_dir. Directories are created automatically.
        Metadata (if provided) is stored as a JSON sidecar file.
        """
        full_path = self.base_dir / path
        full_path.parent.mkdir(parents=True, exist_ok=True)
        full_path.write_text(content, encoding="utf-8")

        if metadata:
            meta_path = full_path.with_suffix(full_path.suffix + ".meta")
            meta_path.write_text(json.dumps(metadata, indent=2), encoding="utf-8")

    def read_doc(self, path: str) -> str | None:
        """Read a document by path. Returns None if not found."""
        full_path = self.base_dir / path
        if full_path.exists():
            return full_path.read_text(encoding="utf-8")
        return None

    def list_docs(self, pattern: str = "**/*") -> list[str]:
        """List documents matching a glob pattern."""
        return [
            str(p.relative_to(self.base_dir))
            for p in self.base_dir.glob(pattern)
            if p.is_file() and not p.name.endswith(".meta")
        ]

    def search_docs(self, query: str, pattern: str = "**/*.md") -> list[dict]:
        """Search documents by keyword. Returns matching files with context.

        This is intentionally simple — grep-style keyword search.
        For semantic search, use a vector store instead.

        NOTE: This is a sketch for demonstration. A simple substring check
        won't scale beyond a few hundred documents. For production with 500+
        documents, use TF-IDF/BM25 scoring (e.g., rank_bm25) or a full-text
        search backend (PostgreSQL GIN index, Elasticsearch).
        """
        results = []
        for path in self.base_dir.glob(pattern):
            if not path.is_file() or path.name.endswith(".meta"):
                continue
            content = path.read_text(encoding="utf-8")
            if query.lower() in content.lower():
                # Return the paragraph containing the match for context
                for paragraph in content.split("\n\n"):
                    if query.lower() in paragraph.lower():
                        results.append({
                            "path": str(path.relative_to(self.base_dir)),
                            "match": paragraph.strip()[:500],
                        })
        return results

Структура папок

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

.agent-memory/
    README.md                  # What this directory is, for human readers
    user-profiles/
        user-123.md            # Preferences, history, risk profile
        user-456.md
    research/
        NVDA-2026-02.md        # Research notes from recent analysis
        TSLA-2026-01.md
    conventions/
        analysis-format.md     # How to structure analysis reports
        data-sources.md        # Preferred data sources and API patterns
    learnings/
        common-errors.md       # Mistakes the agent has learned to avoid
        tool-patterns.md       # Effective tool call sequences

Каждый файл представляет собой файл в формате Markdown. Назначение любого файла очевидно из его пути. Вы можете git diff полный каталог памяти для анализа того, что изучил агент в сессия. git revert Плохая процедура обучения или копирование директории в другой проект — попробуйте применить любой из этих подходов к коллекции Qdrant.

Когда использовать память документов, векторы или структуры ключ-значение

Три блока памяти бэкенды обеспечивают различные схемы доступа:

РазмерностьХранилище векторовХранилище ключей-значенийХранилище документов
Шаблон запроса”Найти факты, аналогичные X”Получить значение по ключуПрочитайте документ, расположенный по указанному пути.
Лучше всего подходит дляНеструктурированное, разнообразное воспроизведениеСтруктурированные поискиКонтекст проекта, примечания
Читаемый человекомНет (эмбеддинги)Частично (JSON)
Поддающийся отладкеЛёгкий режим (точные клавиши)Trивиальный (открыть файл)
Контролируемая версияНетВозможный
Эмбеддинг инфраструктураОбязательноНе требуетсяНе требуется
Масштабируется доМиллионы фактовМиллионы ключейТысячи документов
Возможности поискаСемантическое сходствоточное совпадениеОснованный на ключевых словах/путих

Используйте память документа в следующих случаях:

Используйте векторные хранилища в следующих случаях:

Используйте хранилища типа key-value в следующих случаях:

На практике в производственных агентах часто объединяются все три компонента. Агент аналитика рынка для хранения данных в оперативной памяти используется PostgreSQL чекпоинты, для восстановления семантически значимых фактов о пользователях — сервис Qdrant, а для сохранения проектных стандартов и исследовательских заметок применяется файловый хранилище документов.

Примеры из реальных проектов

Этот подход уже широко распространён в помощниках по кодированию AI:

Общий механизм: во всех этих решениях знания агента хранятся в виде текстовых файлов, доступных для чтения человеком, при этом используются прямые операции записи и чтения. Никакого эмбеддинги отсутствует. Также нет никакой векторной инфраструктуры. Агент сам определяет, что записывать, разработчик может просматривать и редактировать всё содержимое, причём вся система помещается в один git diff.

За пределами ассистентов по программированию

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

Этот Семинар MemAgents на конференции ICLR 2026 Одним из признаков того, что исследовательское сообщество нагоняет те решения, которые уже созданы практиками, является то, что системы документирования памяти явно вышли за рамки своих первоначальных задач в качестве инструментов помощи при написании кода.

Скрипты используют документацию для упаковки процедурных инструкций. Стандарт навыков агента хранит эти инструкции в SKILL.md файлы с YAML-фронтматтером и телом в формате Markdown. Это напоминает структуру «памяти документа» на уровне хранилища, однако функции у них разные: скилл указывает агенту, как выполнять определённый класс задач, тогда как память хранит факты, полученные в ходе выполнения проекта или предыдущих запусков. Часть 3 обеспечивает учёт этого различия с точки зрения инструмента.

MCP (Модель Протокол контекста) идет в том же направлении: определения инструментов представляют собой файлы JSON Schema, которые любой агент может обнаружить и использовать. Протокол имеет 97 миллионов ежемесячных загрузок SDK Этот инструмент поддерживается компаниями OpenAI, Google, Microsoft и AWS. MCP не является технологией, специфичной для программирования. Те же самые серверы обеспечивают связь агентов с базами данных, внутренними APIs и корпоративными системами.

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

Масштабирование памяти документов в продакшене

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

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

Три распространённых подхода:

Подход А: гибридная архитектура с тонким слоем базы данных

Сохраняйте файлы для редактирования (разработчики работают с Markdown локально), но обслуживайте их из базы данных в рантайм. При деплой происходит синхронизация файлов с записями в PostgreSQL. Агент читает данные непосредственно из базы данных, а не с диска. Это позволяет вам:

Подход B: хранилище объектов + вспомогательный компонент для индексации векторов

Документы хранятся в S3/GCS в виде объектов, причем существует коллекция Qdrant, которая индексирует их эмбеддинги. Агент запрашивает у Qdrant идентификаторы соответствующих документов, после чего загружает их содержимое из системы хранения объектов. Такой подход позволяет осуществлять горизонтальное масштабирование и обеспечивает semantic search, однако он увеличивает сложность: требуется управление двумя системами, наличие эмбеддинг пайплайн для поддержки работы, а также обеспечение консистентности между хранилищем и индексом.

Подход C: хранилище структурированных документов с PostgreSQL (рекомендуется)

Для хранения документов используются строки формата JSONB в базе данных PostgreSQL, оснащенные функцией полнотекстового поиска (индекс GIN) и, при необходимости, поддержкой векторных данных эмбеддинги (pgvector). Такой подход позволяет реализовать гибридный способ поиска (на основе ключевых слов и семантики), обеспечивает соблюдение принципов ACID для транзакций, а также упрощает управление всей системой через единую операционную среду.

Набросок подхода C:

from typing import Optional
import asyncpg

class ProductionDocumentMemory:
    """PostgreSQL-backed document memory with hybrid search.

    Schema:
        CREATE TABLE documents (
            id SERIAL PRIMARY KEY,
            tenant_id TEXT NOT NULL,
            path TEXT NOT NULL,
            content TEXT NOT NULL,
            metadata JSONB,
            embedding vector(1536),  -- pgvector extension
            ts_vector tsvector GENERATED ALWAYS AS (to_tsvector('english', content)) STORED,
            created_at TIMESTAMPTZ DEFAULT NOW(),
            UNIQUE(tenant_id, path)
        );
        CREATE INDEX ON documents USING GIN(ts_vector);
        CREATE INDEX ON documents USING ivfflat(embedding vector_cosine_ops);
    """

    def __init__(self, pool: asyncpg.Pool):
        self.pool = pool

    async def write(
        self,
        tenant_id: str,
        path: str,
        content: str,
        metadata: Optional[dict] = None,
        embedding: Optional[list[float]] = None,
    ):
        """Write or update a document."""
        async with self.pool.acquire() as conn:
            await conn.execute(
                """
                INSERT INTO documents (tenant_id, path, content, metadata, embedding)
                VALUES ($1, $2, $3, $4, $5)
                ON CONFLICT (tenant_id, path) DO UPDATE
                SET content = EXCLUDED.content,
                    metadata = EXCLUDED.metadata,
                    embedding = EXCLUDED.embedding
                """,
                tenant_id, path, content, metadata, embedding,
            )

    async def search(
        self,
        tenant_id: str,
        query: str,
        embedding: Optional[list[float]] = None,
        limit: int = 5,
    ) -> list[dict]:
        """Hybrid search: full-text + optional vector similarity."""
        async with self.pool.acquire() as conn:
            if embedding:
                # Hybrid scoring: 0.6 * text relevance + 0.4 * vector similarity
                rows = await conn.fetch(
                    """
                    SELECT path, content, metadata,
                           (0.6 * ts_rank(ts_vector, plainto_tsquery('english', $2)) +
                            0.4 * (1 - (embedding <=> $3))) AS score
                    FROM documents
                    WHERE tenant_id = $1
                      AND ts_vector @@ plainto_tsquery('english', $2)
                    ORDER BY score DESC
                    LIMIT $4
                    """,
                    tenant_id, query, embedding, limit,
                )
            else:
                # Full-text search only
                rows = await conn.fetch(
                    """
                    SELECT path, content, metadata,
                           ts_rank(ts_vector, plainto_tsquery('english', $2)) AS score
                    FROM documents
                    WHERE tenant_id = $1
                      AND ts_vector @@ plainto_tsquery('english', $2)
                    ORDER BY score DESC
                    LIMIT $3
                    """,
                    tenant_id, query, limit,
                )
            return [dict(row) for row in rows]

Что вы получаете:

Файлы отлично подходят для рабочих процессов, где задействован только один разработчик. Однако в средах многоклиентской эксплуатации структурированный хранилище документов на базе PostgreSQL обычно обеспечивает оптимальный баланс между простотой использования, производительностью и уровнем готовности к операционному обслуживанию.


Сборка в единое целое: полная архитектура

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

Архитектура полной памяти

Архитектура включает три пути доступа к памяти:

  1. Горячий путь (чекпоинт хранилище): Каждый узел в LangGraph записывает свое состояние графа, поддерживающее возобновление работы, в чекпоинт хранилище. Когда граф сталкивается с interrupt_before узел (аналог репортера в) Часть 1), Во время выполнения возможны паузы. Пользователь может закрыть приложение, и по возвращении график продолжит работу с чекпоинт. Журналы событий Рантайм и механизмы обработки трейсы представляют собой отдельные аспекты, требующие внимания в производственной среде.

  2. Холодный путь (долгосрочное хранилище): В начале каждого диалога агент запрашивает долгосрочное хранилище с целью получения соответствующей контекстной информации о пользователе. В конце диалога он извлекает новые факты и сохраняет их. Эта операция выполняется асинхронно — она никогда не должна блокировать основной цикл ризонинга.

  3. Путь к документу (хранилище файлов): При запуске агент загружает стандарты проекта и соответствующие исследовательские заметки из хранилища документов. Во время выполнения он записывает новые краткие отчеты об исследованиях и выявленные закономерности обратно на диск. В отличие от режима «холодного» доступа, чтение документов происходит синхронно (это необходимо для выполнения текущей задачи), тогда как запись может быть отложена.

В структуре подключений в LangGraph всё довольно просто — хранилище чекпоинт и долгосрочное хранилище передаются при компиляции графа, в то время как хранилище документов встраивается в качестве зависимости. Приведённый ниже локальный скетч использует InMemoryStore Поэтому фрагмент остаётся небольшим: в примере топологии Docker для реализации аналогичной функции по восстановлению семантической связности используется Qdrant.

from langgraph.checkpoint.postgres.aio import AsyncPostgresSaver
from langgraph.store.memory import InMemoryStore

# Hot memory: PostgreSQL for durable checkpoints
checkpointer = await create_postgres_checkpointer(pg_connection_string)

# Cold memory: local sketch with vector search
# (The reference Docker topology uses Qdrant for persistent recall.)
memory_store = InMemoryStore(
    index={"dims": 1536, "embed": embedding_function}
)

# Document memory: file-based store for project knowledge
doc_memory = FileMemory(base_dir=".agent-memory")

# Checkpoint store and long-term store wired into the graph
graph = create_graph(
    checkpointer=checkpointer,
    store=memory_store,
)

# The store is accessible inside any node via the store parameter
def planner_node(state: AgentState, *, store: BaseStore) -> dict:
    """Plan with user context from long-term memory."""

    # Recall relevant user facts from vector store
    user_memories = store.search(
        namespace=("user", state.user_id),
        query=state.messages[-1].content,
        limit=5,
    )

    # Load project conventions from document memory
    conventions = doc_memory.read_doc("conventions/analysis-format.md")

    # Inject both into planning context
    memory_context = "\n".join(m.value["fact"] for m in user_memories)
    # ... rest of planning logic with personalized context and conventions

Полный поток обработки данных

Что происходит, когда возвращающийся пользователь отправляет запрос «Analyze TSLA» на сервер? Агент аналитика рынка:

  1. Запись нагрузки на память документов: При запуске агент загружает из хранилища документов стандарты проекта: предпочтения по формату анализа, источники данных, которые используются в первую очередь, а также шаблоны работы с инструментами. Все это определяет базовое поведение системы.

  2. Восстановление данных из холодной памяти: перед тем как будет выполнен узел роутер, граф обращается к долгосрочному хранилищу с сообщением пользователя. В результате извлекаются следующие данные: «У пользователя высокая толерантность к риску», «Пользователь предпочитает подробный анализ конкурентов», «Ранее пользователь изучал акции NVDA и AMD».

  3. Роутер + Планировщик: Класс роутер относит это к DEEP_RESEARCH. планировщик формирует план исследований из 5 шагов, адаптированный под учтённые предпочтения пользователя. В него включается этап анализа конкурентов, поскольку история действий пользователя указывает на его потребность в таком анализе. План составлен в соответствии с форматом, описанным в документе с правилами стандартизации.

  4. Экзекьютор цикл (горячая память): Каждый шаг выполняется с использованием паттерна ReAct Часть 1. После обработки каждого узла (роутер, планировщик, каждого экзекьютор шага) LangGraph записывает чекпоинт в базу данных PostgreSQL. Если процесс сбрасывается после 3-го из 5 шагов, его необходимо запустить заново и продолжить с 4-го шага.

  5. HITL прерывание: график достигает reporter узел с interrupt_before. Предварительный вариант отчёта находится в чекпоинт. Через несколько часов пользователь его просматривает, и график загружается в чекпоинт, после чего работа продолжается.

  6. Обновление памяти: После завершения разговора: (a) асинхронный процесс извлекает новые факты о пользователе («пользователь теперь отслеживает TSLA», «пользователь одобрил формат отчёта») и сохраняет их в хранилище долгосрочных векторов, а (b) агент записывает краткое резюме исследования в хранилище документов.research/TSLA-2026-02.md) — для последующего использования.

Паттерн трёх уровней позволяет чётко разделить функциональные обязанности компонентов. Хранилище чекпоинт отвечает за обеспечение долговечности данных и возобновление работы после сбоев; это инфраструктурный слой. Долгосрочное хранилище используется для реализации функций персонализации; здесь реализуется логика продукта. Хранилище документов содержит накопленные знания по проекту; оно выполняет роль блокнота агента.


Компромиссы и факторы, требующие учёта

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


Основные выводы

  1. Память агента представляет собой набор отдельных хранилищ с различными схемами доступа. Необходимо сохранять разделение между возможностью возобновления работы чекпоинты, структурированными фактами, механизмом семантического воспроизведения информации и документацией проекта.
  2. До начала персонализации следует реализовать функции паузы и возобновления работы агента. Потеря прогресса выполнения задачи является первым проявлением сбоя в работе памяти у долгосрочно работающего агента.
  3. Детерминистичные факты следует хранить в структурированных форматах. В случаях неоднозначных запросов с изменяющейся формулировкой следует применять vector search.
  4. Для хранения проектной информации, которую люди должны просматривать, редактировать, контролировать версии или сравнивать изменения, следует использовать файлы.
  5. Каждому типу памяти необходимо определить правила истечения срока хранения, выявления конфликтов и удаления данных. Память, которую система не может исправить, превращается в «деятельность, создающую долг» продукта.
  6. Следует ограничивать объём данных, возвращаемых в модель. Хранимая память имеет ценность лишь тогда, когда retrieval включает соответствующие доказательства в текущий контекст.

Следующий уровень — это выполнение действий

Часть 3, ИИ-агент Tool Use к 2026 году, Происходит переход от сохранённого состояния к выполнению действия. В нём рассматривается вопрос о том, как агент находит и вызывает инструменты, а также о том, как границы этих инструментов возвращают ошибки, которые может использовать цикл ризонинга. Части 5 и 6 занимаются возвратом данных из операционной среды в память: рантайм восстанавливает чекпоинт, в то время как харнесс определяет, что должно быть передано следующему модель сессия.

Список литературы

Статьи

Документация LangGraph

Чекпоинт бэкенды

Базы данных векторов и инструменты памяти

Память, основанная на документах и файлах

Память фреймворки

Бенчмарки

Семинары

Проект-демонстрация


полный код агента Market Analyst Agent, включая описанную здесь архитектуру памяти, доступен по GitHub если хотите следить за прогрессом чтения.

Серия: Проектирование стека Агентный