С появлением больших контекстных окон (1M–2M токенов) среди инженеров возникло иллюзорное предположение, что задача управления контекстом решена простым помещением всей истории взаимодействия в один массив сообщений. Однако в производственной эксплуатации автономных AI-агентов 2026 года этот наивный подход наталкивается на жесткие архитектурные барьеры:
Автономный агент требует не бесконечного монолитного контекста, а модульной многоуровневой системы памяти, способной сжимать события, извлекать инвариантные факты и динамически инжектировать в промпт только то, что необходимо для текущего шага выполнения.
В когнитивной архитектуре автономных систем 2026 года память разделена на три функциональных уровня:
+-----------------------------------------------------------------------------------+
| USER INTERACTION / AGENT EXECUTION |
+-----------------------------------------------------------------------------------+
| |
| (Каждый шаг рассуждения) | (Смена сессии / задачи)
v v
+------------------------------------+ +------------------------------------+
| 1. WORKING MEMORY (Scratchpad) | | 2. EPISODIC MEMORY |
| - Стек текущих вызовов Tools | | - Хронология прошлых сессий |
| - Промежуточный ход мысли ReAct | | - Трассировки успехов и сбоев |
| - Токен-лимит: 8k-16k (Ephemera) | | - Векторизованный лог решений |
+------------------------------------+ +------------------------------------+
| |
+-------------------------------+-------------------------------+
|
v (Асинхронная экстракция фактов)
+------------------------------------+
| 3. SEMANTIC MEMORY (Mem0 / Zep) |
| - Атомарные факты и сущности |
| - Граф темпоральных связей |
| - Дедупликация и операции: |
| [ADD] [UPDATE] [DELETE] [NOOP] |
+------------------------------------+
|
v (Dynamic Just-in-Time Injection)
[ Re-constructed Minimal Prompt: System + Memory + Current Task ][t_start, t_end]. Новые факты не перезаписывают историю, а помечают устаревшие утверждения неактивными.
| Уровень | Срок жизни | Хранилище | Стоимость чтения | Применение | | :--- | :--- | :--- | :--- | :--- | | Working (Scratchpad) | Минуты (сессия задачи) | In-Memory / Redis | $0 (уже в RAM) | Выполнение текущей цепочки Tool Calls | | Episodic | Недели / Месяцы | Vector DB / S3 Parquet | Низкая (Similarity Search) | Извлечение схожих инцидентов и решений | | Semantic | Постоянно | Zep / Mem0 / Graph DB | Минимальная (Top-K фактов) | Профиль пользователя, архитектурные инварианты |
React.FC». Эти правила извлекаются семантической памятью и подставляются в промпт без необходимости вручную дублировать их в .cursorrules.OOMKilled агент обращается к эпизодической памяти: «Полгода назад аналогичный инцидент в поде Payment был вызван утечкой памяти в библиотеке XML-парсера; тогда помог откат на патч v2.4.1».При поступлении новой информации агент не просто конкатенирует текст, а вычисляет семантическую дельту с существующими фактами через строгие операции: ADD (добавить новый факт), UPDATE (обновить существующий с изменением значения), DELETE (удалить опровергнутый факт) или NOOP (факт уже известен, действие не требуется).
import { z } from "zod";
export const MemoryActionSchema = z.enum(["ADD", "UPDATE", "DELETE", "NOOP"]);
export const MemoryDeltaItemSchema = z.object({
id: z.string().optional().describe("ID существующего факта при UPDATE или DELETE"),
action: MemoryActionSchema,
fact: z.string().describe("Атомарная формулировка факта в утвердительной форме"),
entity: z.string().describe("Ключевая сущность, к которой относится факт (e.g., 'User', 'PostgresDB')"),
confidence: z.number().min(0).max(1).default(1.0),
reason: z.string().describe("Обоснование решения на основе контекста"),
});
export const MemoryExtractionPayloadSchema = z.object({
operations: z.array(MemoryDeltaItemSchema),
});
export type MemoryDeltaItem = z.infer<typeof MemoryDeltaItemSchema>;
export type MemoryExtractionPayload = z.infer<typeof MemoryExtractionPayloadSchema>;
export interface StoredMemoryFact {
id: string;
entity: string;
fact: string;
createdAt: string;
updatedAt: string;
vector?: number[];
}Ниже приведен production-ready сервис, реализующий извлечение и согласование фактов памяти без замусоривания базы дубликатами.
import OpenAI from "openai";
import { v4 as uuidv4 } from "uuid";
import {
MemoryExtractionPayloadSchema,
StoredMemoryFact,
MemoryDeltaItem,
} from "./memory-schema";
export class AgentMemoryManager {
private openai: OpenAI;
// Локальное in-memory хранилище фактов (в проде: pgvector / Qdrant)
private memoryStore: Map<string, StoredMemoryFact> = new Map();
constructor(apiKey: string) {
this.openai = new OpenAI({ apiKey });
}
/**
* Получение всех сохраненных фактов по конкретной сущности
*/
public getFactsForEntity(entity: string): StoredMemoryFact[] {
return Array.from(this.memoryStore.values()).filter(
(m) => m.entity.toLowerCase() === entity.toLowerCase()
);
}
/**
* Асинхронное обновление семантической памяти на основе завершенного диалога
*/
public async processConversationTurn(
entity: string,
userMessage: string,
assistantMessage: string
): Promise<void> {
const existingFacts = this.getFactsForEntity(entity);
const prompt = `
Ты — контроллер долговременной семантической памяти автономного агента.
Проанализируй диалог и актуализируй список фактов о сущности "${entity}".
СУЩЕСТВУЮЩИЕ ФАКТЫ В БАЗЕ:
${
existingFacts.length > 0
? existingFacts.map((f) => `[ID: ${f.id}] ${f.fact}`).join("\n")
: "База памяти пуста."
}
ТЕКУЩИЙ ДИАЛОГ:
User: ${userMessage}
Assistant: ${assistantMessage}
ПРАВИЛА ОБНОВЛЕНИЯ:
1. Если диалог содержит НОВЫЙ долгосрочный факт -> action: "ADD".
2. Если факт противоречит существующему или уточняет его -> action: "UPDATE" с указанием ID старого факта.
3. Если пользователь явно опроверг факт -> action: "DELETE" с ID.
4. Если информация уже полностью зафиксирована или тривиальна (приветствия, временный статус) -> action: "NOOP".
`;
const response = await this.openai.chat.completions.create({
model: "gpt-4o",
temperature: 0.0,
messages: [{ role: "user", content: prompt }],
response_format: { type: "json_object" },
});
const parsed = MemoryExtractionPayloadSchema.parse(
JSON.parse(response.choices[0]?.message.content ?? "{}")
);
// Применение дельт к хранилищу
for (const op of parsed.operations) {
this.applyOperation(op, entity);
}
}
private applyOperation(op: MemoryDeltaItem, defaultEntity: string): void {
const now = new Date().toISOString();
switch (op.action) {
case "ADD": {
const id = uuidv4();
this.memoryStore.set(id, {
id,
entity: op.entity || defaultEntity,
fact: op.fact,
createdAt: now,
updatedAt: now,
});
break;
}
case "UPDATE": {
if (op.id && this.memoryStore.has(op.id)) {
const old = this.memoryStore.get(op.id)!;
this.memoryStore.set(op.id, {
...old,
fact: op.fact,
updatedAt: now,
});
}
break;
}
case "DELETE": {
if (op.id) {
this.memoryStore.delete(op.id);
}
break;
}
case "NOOP":
// Никаких модификаций
break;
}
}
}При генерации нового ответа агент не вставляет всю историю сообщений, а динамически формирует минимальный компактный контекст: выжимка из долговременной памяти + скользящее окно последних реплик.
import { AgentMemoryManager } from "./agent-memory-manager";
export interface ContextPayload {
systemPrompt: string;
memoryBlock: string;
recentMessages: Array<{ role: "user" | "assistant"; content: string }>;
}
export class ContextSynthesizer {
private memoryManager: AgentMemoryManager;
private readonly maxRecentTurns: number = 3;
constructor(memoryManager: AgentMemoryManager) {
this.memoryManager = memoryManager;
}
/**
* Синтез строго бюджетированного контекста для инференса LLM
*/
public buildPrompt(
entity: string,
history: Array<{ role: "user" | "assistant"; content: string }>
): Array<{ role: "system" | "user" | "assistant"; content: string }> {
// 1. Получаем актуальные факты из семантической памяти
const facts = this.memoryManager.getFactsForEntity(entity);
const factsText =
facts.length > 0
? facts.map((f) => `- ${f.fact}`).join("\n")
: "Долговременных сведений нет.";
const systemPrompt = `
Ты — интеллектуальный автономный агент-инженер.
Используй подтвержденные долговременные знания о контексте для предоставления точных ответов.
АКТУАЛЬНЫЕ ФАКТЫ О КОНТЕКСТЕ СЕССИИ:
${factsText}
`.trim();
// 2. Отбираем только последние N сообщений диалога для скользящего окна
const slidingWindow = history.slice(-this.maxRecentTurns * 2);
return [
{ role: "system", content: systemPrompt },
...slidingWindow,
];
}
}При росте диалога разработчики часто вызывают метод history = await summarize(history). При многократном каскадном обобщении (саммари от саммари) происходит фатальная деградация деталей («Memory Fade»): числовые значения портов, хэши коммитов, специфические названия библиотек безвозвратно стираются в пользу общих фраз. Память должна хранить атомарные факты, а не абстрактные пересказы.
Сохранение в постоянную базу данных полного лога промежуточных размышлений: «Пробую вызвать Bash... получил ошибку... теперь пробую curl...». Долговременная память забивается сотнями страниц нерелевантного шума. В постоянную память должен попадать только финальный верифицированный результат: «В сервисе X эндпоинт доступен по порту 8080».
Пользователь год назад сказал: «Мы используем PostgreSQL 13». Спустя полгода он сообщил: «Мы полностью мигрировали на PostgreSQL 16». Если система не умеет определять конфликтующие факты и делать инвалидацию старых записей, агент будет генерировать запросы, несовместимые с новой мажорной версией базы.
Вызов LLM для извлечения новых фактов перед отдачей ответа пользователю. Это добавляет 2–4 секунды к задержке отклика интерфейса. Обновление долговременной семантической памяти всегда должно производиться асинхронно (в фоне через очередь задач BullMQ или Kafka) после того, как ответ успешно доставлен клиенту.
Получение реплики пользователя и завершение ReAct-цикла в оперативной памяти (Scratchpad).
Отправка завершенного диалогового окна в фоновый воркер без блокировки ответа пользователю.
LLM анализирует диалог и формирует структурированный список операций: ADD, UPDATE, DELETE, NOOP.
Инвалидация устаревших фактов, обновление векторов в pgvector/Zep с фиксацией темпоральных меток.
Перед следующим шагом ретривер подтягивает top-k актуальных фактов в системный промпт агента.