1. Статичность LLM как архитектурная данность

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

В работах по геометрии эмбеддингов и исследованиях внутренней размерности (intrinsic dimensionality) было экспериментально показано:

- **Пространство эмбеддингов LLM статично:** главные компоненты (PC), полученные методом PCA на различных текстовых корпусах, совпадают более чем на 95%, что указывает на стабильность геометрии пространства независимо от входных данных.

- **Эффективная размерность значительно ниже номинальной:** в ряде исследований показано, что intrinsic dimensionality часто лежит в диапазоне 50–150 против 384–4096 номинальных измерений (зависит от слоя, модели и датасета), что говорит о жёсткой концентрации информации.

- **Распределение векторов крайне анизотропно:** среднее попарное косинусное сходство достигает ~0.85–0.90 (соответствует метрикам анизотропии в работах Ethayarajh, 2019 и последующих исследованиях), а норма векторов почти идеально равна единице. Все векторы лежат на поверхности гиперсферы, но сконцентрированы в её ограниченных областях.

- **Единственная наблюдаемая динамика — эффект «снежного кома»:** накопление контекстных токенов смещает результирующий вектор ответа, но не меняет саму геометрию пространства.

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

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

## 2. MSP как внешний функциональный аналог рекуррентности: послойное устройство и операционный цикл

> **Важно:** далее под «рекуррентностью» понимается не внутреннее скрытое состояние модели, а циклическое обновление внешнего контекста, обеспечивающее непрерывность поведения системы во времени.

MSP (Memory-State-Processing) — архитектурная концепция, в которой рекуррентное поведение системы возникает не из внутреннего скрытого состояния модели, а из внешней структуры, состоящей из трёх слоёв памяти и четырёхфазного рабочего цикла. Рассмотрим каждый слой и фазу отдельно, на уровне конкретных структур данных и операций.

### 2.1 Эпизодическая память

**Назначение:** хранить хронологию событий — «что происходило» в хронологическом порядке.

**Структура записи (JSON):**

    {

      "session_id": "uuid",

      "timestamp": "ISO8601",

      "step_number": 42,

      "type": "tool_call" | "user_message" | "agent_response" | "observation",

      "content": { ... },

      "metadata": {

        "tool_name": "...",

        "duration_ms": 120,

        "token_count": 340

      }

    }

**Физическое хранение:**

- В простейшем случае — JSON-файл или SQLite-таблица с индексом по `session_id + timestamp`.

- В продвинутых реализациях — векторная база (Chroma, Pinecone, Qdrant, FAISS), где каждая запись имеет embedding, полученный либо эмбеддером модели, либо лёгким энкодером (например, `all-MiniLM-L6-v2`).

**Ключевая особенность:** эпизодическая память растёт линейно с числом шагов агента. Без механизма консолидации она быстро приведёт к переполнению контекстного окна и деградации внимания на длинных дистанциях. Именно поэтому вводится следующий слой и фаза консолидации.

### 2.2 Семантическая память

**Назначение:** хранить факты и знания, извлечённые из эпизодов или предоставленные извне, без привязки к конкретному моменту времени.

**Структура записи (фактоид, JSON):**

    {

      "id": "uuid",

      "created_at": "ISO8601",

      "updated_at": "ISO8601",

      "content": "Пользователь предпочитает Python для анализа данных",

      "embedding": [0.123, -0.456, "..."],

      "source_episodes": ["ep_uuid1", "ep_uuid2"],

      "confidence": 0.92,

      "access_count": 5,

      "last_accessed": "ISO8601"

    }

**Процесс консолидации (детально):**

1. **Триггер:** агент завершает сессию, либо накоплено `N` новых эпизодов (N — конфигурируемый порог, например, 20).

2. **Сбор:** все эпизоды с момента последней консолидации объединяются в один текстовый блок.

3. **Запрос к LLM (или отдельной модели-экстрактору):** «Из следующей истории диалога извлеки все устойчивые факты о пользователе, его предпочтениях и контексте задачи. Для каждого факта укажи степень уверенности (0-1). История: `{text}`».

4. **Дедупликация:** каждый извлечённый кандидат сравнивается по embedding-близости с уже существующими фактоидами. Если косинусное сходство > 0.95 — факт считается дубликатом и не добавляется (или обновляется существующий).

5. **Запись:** новые фактоиды сохраняются в векторную базу.

**Результат:** семантическая память растёт логарифмически, а не линейно, храня сжатое смысловое ядро всей истории взаимодействий.

### 2.3 Процедурная память

**Назначение:** хранить знания о том, «как действовать» — доступные инструменты, системные инструкции, поведенческие шаблоны.

**Состав процедурной памяти:**

- **System prompt:** неизменяемая (или редко изменяемая) системная инструкция, задающая роль агента и базовые правила.

- **Зарегистрированные инструменты:** список доступных функций/инструментов, каждый со своей JSON-схемой для function calling.

- **Поведенческие паттерны:** шаблоны «если произошло X, следует вызвать инструмент Y» (в Qwen‑Agent это неявно закодировано в способности модели к планированию, но может быть вынесено в явный rule-движок).

**Ключевое отличие:** процедурная память меняется редко и, как правило, административно, а не автоматически. Она задаёт «скелет» поведения агента.

### 2.4 Рабочая память (Working Memory)

**Назначение:** активный контекст, который модель «видит» прямо сейчас.

**Формирование рабочей памяти для каждого вызова LLM:**

1. Берётся `system prompt` из процедурной памяти.

2. Добавляются последние `K` эпизодов из эпизодической памяти (K — параметр, например, последние 10 шагов).

3. Выполняется **Retrieve**: из семантической памяти извлекаются фактоиды, релевантные текущему запросу. Используется embedding запроса → косинусное сходство с embedding'ами фактоидов → top-M по сходству.

4. Формируется финальный промпт:

    System: {system_prompt}

    Relevant facts from memory:

    - {fact_1}

    - {fact_2}

    ...

    Recent conversation history:

    User: ...

    Agent: ...

    Tool result: ...

    User's current request: {user_message}

Именно этот промпт подаётся на вход LLM.

### 2.5 Операционный цикл: Write → Consolidate → Retrieve → Inject

Теперь, имея четыре слоя памяти, можно детально описать, как они взаимодействуют в течение одного шага агента. Это и есть та самая рекуррентная петля, которая заменяет внутреннее состояние.

**Шаг 0. Инициализация**

Загружается система: процедурная память, пустая (или сохранённая) эпизодическая и семантическая память. Приходит первый запрос пользователя.

**На каждом шаге t:**

1. **Retrieve (Поиск и формирование контекста)**

   - Вычисляется embedding запроса.

   - Векторный поиск по эпизодической памяти: `top_k_episodes`.

   - Векторный поиск по семантической памяти: `top_m_facts`.

   - Из процедурной памяти извлекаются `system_prompt` и схемы инструментов.

   - Собирается промпт (см. 2.4).

2. **Inject (Вызов модели)**

   - Сформированный промпт подаётся в LLM через API.

   - Модель возвращает текстовый ответ или `tool_call`.

3. **Execution (Исполнение, если был tool call)**

   - Фреймворк вызывает соответствующий инструмент (code_interpreter, web_search, API по MCP и т.п.).

   - Возвращается результат выполнения.

4. **Write (Запись в эпизодическую память)**

   - Текущий шаг сохраняется как новый эпизод. При использовании векторной базы вычисляется embedding.

5. **Consolidate (Консолидация) — асинхронно или по условию**

   - Запускается каждые N шагов или по завершении сессии.

   - LLM-экстрактор извлекает факты, проходит дедупликация, новые фактоиды сохраняются в семантическую память.

6. **Переход к шагу t+1**

   - Цикл повторяется с обновлённой рабочей и семантической памятью.

**Диаграмма цикла (Mermaid):**

    graph LR

**Почему это рекуррентность**

В классической RNN рекуррентность описывается как:

`h_t = f(x_t, h_{t-1})`

В архитектуре с MSP:

    h_t = LLM(Retrieve(MSP_{t-1}, x_t))

    MSP_t = Write(MSP_{t-1}, x_t, h_t)

    MSP_{t+1} = Consolidate(MSP_t)

> **Важно:** это архитектурная, а не строгая математическая эквивалентность. В отличие от RNN, где `h_t` — непрерывный вектор фиксированной размерности, состояние MSP дискретно, явно наблюдаемо, модифицируемо и обновляется с задержкой, определяемой инфраструктурой памяти. Функция `LLM` статична, а динамика полностью определяется операциями над MSP. Это и есть вынос рекуррентности наружу.

## 3. Глубокая архитектура Qwen‑Agent: как MSP воплощается в коде

> **Примечание:** примеры кода и имена классов упрощены для наглядности и соответствуют архитектуре Qwen-Agent v0.1–v0.2. Актуальные методы могут отличаться в новых версиях. Рекомендуется сверяться с официальным репозиторием.

### 3.1 Компонент Memory (эпизодическая память)

Класс `Memory` управляет двумя хранилищами:

- `history` — список сообщений текущей сессии (эпизодическая память в оперативном виде).

- `rag` — компонент для работы с документами (семантическая память).

Метод `get_memory()` реализует фазу **Retrieve** и формирует рабочую память, комбинируя историю и RAG-чанки с учётом лимита токенов. Запись (**Write**) происходит неявно через `session.add_message()`. Консолидация в базовой версии не автоматизирована, но архитектура позволяет добавить её как post-processing модуль.

### 3.2 RAG как семантическая память

Класс `RAG` реализует:

- Парсинг документов (PDF, DOCX, MD, TXT) с настраиваемым размером чанка и перекрытием.

- Индексацию через embedding (DashScope text-embedding-v2 или локальные модели) и сохранение в FAISS/Chroma/DashVector.

- Гибридный поиск (sparse BM25 + dense cosine similarity) при вызове `rag.retrieve(query)`.

### 3.3 Инструменты как процедурная память

Базовый класс `BaseTool` содержит `name`, `description`, JSON-схему параметров и метод `call()`. При инициализации `Assistant` описания всех инструментов автоматически инжектируются в system prompt. Qwen‑Agent также поддерживает MCP (Model Context Protocol), транслируя схемы внешних сервисов в формат `BaseTool`.

### 3.4 Планировщик (Agent / Assistant)

Цикл работы `Assistant` точно реализует петлю Write → Retrieve → Inject:

    # Python (упрощённый псевдокод)

    def run(self, user_message):

        self.memory.session.add_message(user_message)

        while not task_completed:

            context = self.memory.get_memory(current_query, max_token=MAX_LLM_INPUT)

            response = self.llm.chat(context, functions=self.function_list)

            if response.has_tool_calls():

                for tc in response.tool_calls:

                    result = self._call_tool(tc)

                    self.memory.session.add_message(result)

            else:

                self.memory.session.add_message(response.content)

                return response.content

### 3.5 Контекст-менеджмент

При превышении `max_token` применяются стратегии: FIFO-обрезка старых сообщений или опциональная LLM-суммаризация. Параметр обычно выставляется как `LLM_CONTEXT_SIZE - RESERVED_FOR_RESPONSE`.

## 4. Детальный разбор решений крупных игроков: внутренняя кухня

### 4.1 OpenAI: Agents SDK и Session как persist-слой

В OpenAI Agents SDK (2025) память реализована как pluggable-абстракция:

- `Session` управляет списком сообщений и их сохранением между вызовами.

- `Memory`-компоненты поддерживают семантические факты, автоматически подмешиваемые в system prompt.

- Бэкенд памяти заменяем: SDK работает с InMemory, Redis, векторными БД или OpenAI Conversations API через единый интерфейс.

### 4.2 Google: Vertex AI Agent Memory

В составе Vertex AI Agent Builder / ADK доступен управляемый сервис памяти:

- Работает поверх Cloud Spanner (реляционная часть) и Vertex AI Vector Search.

- Разделяет `Memory Session` (эпизоды) и `Memory Fact` (семантика).

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

### 4.3 Anthropic: MCP и mcp-agent

MCP — это протокол подключения внешних ресурсов, а не хранилище. Однако референсный `mcp-server-memory` реализует семантическую память в виде графа знаний (`create_entities`, `create_relations`, `search_nodes`). В связке с `SessionMemory` из `mcp-agent` получается полноценная MSP-петля, где эпизодическая и семантическая память разделены, но доступны через стандартный протокол.

### 4.4 Microsoft: AutoGen и Memory Banks как агенты

В экосистеме AutoGen 0.4+ и смежных проектах (например, Magentic-One) память часто моделируется как активный агент:

- `MemoryAgent` подписывается на события системы, сохраняет эпизоды и запускает экстракцию фактов.

- Реализуются банки: Episodic, Semantic, Short-Term (кольцевой буфер), Procedural.

- Используется паттерн Whiteboard: агенты читают/пишут в общее состояние через Pub/Sub. Векторный поиск реализуется через `sqlite-vec` или Azure AI Search.

### 4.5 LangChain / LangGraph

`LangGraph` явно моделирует граф состояний (`StateGraph`). Состояние сохраняется между шагами через checkpointing (SQLite/Postgres). Библиотека `LangMem` автоматически извлекает релевантные воспоминания из Store, добавляет их в состояние, а после вызова агента сохраняет новые факты. Процедурная память управляется через динамические system prompt'ы и инструменты.

### 4.6 Letta (бывшая MemGPT)

Letta строит агентную среду как ОС памяти:

- **Core Memory (RAM):** блоки персонажа и пользователя фиксированной длины. Агент может читать и перезаписывать их через `core_memory_append/replace`.

- **Recall Memory (Cache):** очередь последних событий.

- **Archival Memory (Cold Storage):** бесконечная векторная база с поиском по релевантности.

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

## 5. Механика внешней рекуррентности в действии: сквозной пример

**Задача:** агент поддержки помогает пользователю, который периодически возвращается с новыми вопросами. Агент должен помнить контекст из прошлых сессий.

**Сессия 1 (день 1).** Пользователь: «У меня проблема с установкой Python-пакета».

1. Retrieve: память пуста. Рабочая память = system_prompt + запрос.

2. Inject → LLM вызывает `web_search`.

3. Write: эпизоды (user_msg, tool_call, tool_result, agent_response) сохранены.

4. Consolidate: извлекаются факты: «Пользователь на Windows 11, Python 3.11», «Ошибка при установке пакета X». Фактоиды сохранены в семантическую память.

**Сессия 2 (день 14).** Пользователь: «Привет, у меня снова проблема с тем же самым скриптом».

1. Retrieve: векторный поиск находит фактоиды и фрагменты прошлой сессии (косинусное сходство ~0.88).

2. Inject: в промпт добавляется контекст из памяти.

3. LLM отвечает не с нуля: «В прошлый раз мы решали проблему с пакетом X на Windows 11. Эта ошибка всё ещё возникает?»

4. Write: новый эпизод добавляется. Связь между сессиями поддерживается через семантические фактоиды.

Рекуррентность проявляется в том, что состояние переходит из сессии 1 в сессию 2, хотя между ними прошло две недели, и никакое контекстное окно не могло бы это удержать.

## 6. Ограничения и риски архитектуры MSP

Внешняя рекуррентность не бесплатна. При проектировании MSP-систем необходимо учитывать:

- **Latency и стоимость:** каждый шаг требует вычисления эмбеддингов, векторного поиска и вызова LLM. Консолидация добавляет фоновые inference-запросы.

- **Дрейф консолидации:** LLM-экстрактор может сжимать нюансы, терять контекстные зависимости или галлюцинировать факты. Требуется валидация confidence-скоринга и периодическая перепроверка.

- **Retrieval misses:** косинусное сходство ≠ семантическая релевантность в сложных, многозначных или ироничных контекстах. Гибридный поиск и reranking частично решают проблему, но не устраняют её полностью.

- **Безопасность и изоляция:** внешняя память становится поверхностью атаки. Инъекции через результаты инструментов, утечка PII, несанкционированная модификация фактоидов или prompt leakage требуют отдельного контура валидации, шифрования и RBAC.

- **Масштабирование состояния:** при десятках тысяч сессий векторные базы требуют шардирования, TTL-политик и стратегий eviction. Без этого стоимость хранения и поиска растёт нелинейно.

MSP оправдан там, где ценность долгосрочного контекста, персонализации и непрерывного обучения превышает накладные расходы на его поддержку. Для stateless-чатов, коротких сессий или задач с жёстким SLA по задержкам классический контекстный стек часто остаётся оптимальным выбором.

## 7. Заключение

Transformer не запоминает. Он вычисляет. Но если вынести состояние наружу, структурировать его в эпизоды, факты и процедуры, а затем замкнуть цикл Retrieve → Inject → Write → Consolidate, статическая функция превращается в систему, способную накапливать опыт, адаптироваться и «думать» во времени.

MSP — это не замена архитектуры моделей. Это инженерный мост между статичной математикой внимания и динамикой реального мира. Qwen‑Agent, LangGraph, Letta, MCP и облачные SDK уже реализуют этот паттерн в production. Вопрос больше не в том, «возможна ли внешняя рекуррентность», а в том, как грамотно управлять её стоимостью, точностью и безопасностью.

Именно здесь заканчивается эпоха «промпт-инжиниринга» и начинается эпоха инженерии состояний.

---

### 📚 Рекомендуемые источники для углубления

1. Ethayarajh, K. (2019). *How Contextual are Contextualized Word Representations?* (метрики анизотропии)

2. Ansuini et al. (2019). *Intrinsic Dimensionality of Deep Learning Models*

3. Aghajanyan et al. (2021). *Intrinsic Dimensionality Explains the Effectiveness of Language Model Fine-Tuning*

4. Letta (MemGPT) Architecture Paper & Docs: `letta.com/docs`

5. Model Context Protocol Specification: `modelcontextprotocol.io`

6. LangGraph & LangMem Documentation: `python.langchain.com`