Память — система управления памятью
В этом разделе описывается механизм управления памятью Managed Auto-Memory (управляемая автоматическая память) в Qwen Code, условия его срабатывания и детали реализации.
Содержание
- Обзор
- Структура хранения
- Типы памяти
- Формат записей памяти
- Основной жизненный цикл
- Extract — Извлечение
- Dream — Интеграция
- Recall — Припоминание
- Forget — Забывание
- Перестроение индекса
- Телеметрические точки
Обзор
Managed Auto-Memory — это постоянная система памяти, которая автоматически накапливает, интегрирует и извлекает знания, связанные с пользователем, в ходе сеансов ИИ. Она поддерживает жизненный цикл памяти с помощью четырёх основных операций:
| Операция | Английский | Триггер | Назначение |
|---|---|---|---|
| Извлечение | Extract | Автоматически (после каждого раунда диалога) | Выделение новых знаний из записей диалога и запись в файлы памяти |
| Интеграция | Dream | Автоматически (периодическая фоновая задача) | Дедупликация, слияние файлов памяти для поддержания чистоты |
| Припоминание | Recall | Автоматически (перед каждым раундом диалога) | Поиск релевантных записей памяти и внедрение в системный промпт |
| Забывание | Forget | Вручную (команда пользователя /forget) | Точное удаление указанных записей памяти |
Структура хранения
Расположение директорий
~/.qwen/ ← Глобальная базовая директория (по умолчанию)
└── projects/
└── <sanitized-git-root>/ ← Идентификатор проекта (на основе корня Git)
├── meta.json ← Метаданные (временные метки извлечения/интеграции, статус)
├── extract-cursor.json ← Курсор извлечения (обработанное смещение диалога)
├── consolidation.lock ← Мьютекс для процесса Dream
└── memory/ ← Основная директория памяти
├── MEMORY.md ← Индексный файл (автоматически генерируется, собирает все записи)
├── user.md ← Память о предпочтениях пользователя (пример)
├── feedback.md ← Память о правилах обратной связи (пример)
├── project/
│ └── milestone.md ← Память о проекте (поддерживает поддиректории)
└── reference/
└── grafana.md ← Память о внешних ресурсахПереопределение через переменные окружения:
QWEN_CODE_MEMORY_BASE_DIR— заменяет глобальную базовую директориюQWEN_CODE_MEMORY_LOCAL=1— использует путь внутри проекта.qwen/memory/
Описание ключевых файлов
| Файл | Описание |
|---|---|
meta.json | Записывает время последнего Extract / Dream, ID сессии, затронутые типы памяти, статус выполнения |
extract-cursor.json | Записывает, на каком смещении в истории диалога остановилась обработка текущей сессии, чтобы избежать повторного извлечения |
consolidation.lock | Файловая блокировка во время работы Dream, содержит PID владельца; автоматически теряет силу через 1 час |
MEMORY.md | Индекс всех тематических файлов, перестраивается после каждого Extract/Dream, формат — список Markdown |
Типы памяти
Система поддерживает четыре встроенных типа памяти, каждый из которых соответствует определённому измерению информации:
| Тип | Содержимое | Когда записывается | Когда считывается |
|---|---|---|---|
user | Роль пользователя, навыки, рабочие привычки | Когда узнаётся роль/предпочтения/фон знаний пользователя | Когда ответ требует настройки под конкретного пользователя |
feedback | Указания пользователя по поведению ИИ: чего избегать, что продолжать | Когда пользователь исправляет ИИ или подтверждает неочевидные действия | Когда это влияет на поведение ИИ |
project | Ход проекта, цели, решения, сроки, отслеживание ошибок | Когда узнаётся, кто что делает, почему и к какому сроку | Когда помогает ИИ понять рабочий контекст и мотивацию |
reference | Указатели на внешние системные ресурсы (дашборды, тикет-системы, каналы Slack и т.п.) | Когда становится известно о внешнем ресурсе и его назначении | Когда пользователь упоминает внешнюю систему или связанную информацию |
Что не должно сохраняться в памяти: шаблоны/соглашения кода, история Git, варианты отладки, временные статусы задач, содержимое, уже задокументированное в QWEN.md/AGENTS.md.
Формат записей памяти
Каждый тематический файл использует формат YAML frontmatter + Markdown body:
---
name: Имя памяти
description: Краткое описание (для оценки релевантности при припоминании; должно быть конкретным)
type: user|feedback|project|reference
---
Основное содержимое памяти (строка summary)
Why: Причина (чтобы ИИ понимал граничные случаи, а не слепо следовал правилам)
How to apply: Сценарии применения и способ использованияДля типов feedback и project настоятельно рекомендуется заполнять поля Why и How to apply, чтобы память правильно применялась даже в граничных ситуациях.
Основной жизненный цикл
Extract — Извлечение
Условие срабатывания
После каждого раунда завершения ответа ИИ автоматически запускается функция scheduleAutoMemoryExtract (фоновая, неблокирующая).
Логика планировщика (extractScheduler.ts)
Пояснения причин пропуска:
| Причина | Значение |
|---|---|
memory_tool | Главный агент в этом раунде уже напрямую записал файл памяти; пропуск для избежания конфликта |
already_running | Извлечение уже выполняется и постановка в очередь невозможна |
queued | Извлечение уже выполняется, текущий запрос поставлен в очередь |
Основной процесс извлечения (extract.ts)
Примечание: Проверка
isUnderMemoryPressureнаходится вMemoryManager.runExtract(), а не в этом потоке. Когда монитор сообщает о давлении hard/critical,MemoryManagerпропускает вызов extract и не продвигает cursor.
Курсор извлечения (Cursor):
- Поля:
{ sessionId, processedOffset, updatedAt } - Перед извлечением вызывается
readExtractCursorдля чтения текущего прогресса, затемhistory.slice(processedOffset)обрабатывает только непрочитанную часть. - После каждого извлечения
processedOffsetобновляется до текущей длины истории (params.history.length). - При смене сессии (
sessionIdменяется) offset сбрасывается на 0. - Обратите внимание: больше не используются
buildTranscriptMessages/loadUnprocessedTranscriptSliceдля построения транскрипта —hasNewUserMessagesпроверяется черезhistory.slice(startOffset).some(m => m.role === 'user' && partToString(m.parts).trim().length > 0), только лёгкое строковое преобразование на необработанном срезе; полная история больше не обрабатывается.
Правила фильтрации патчей:
- Длина summary < 12 символов → отбрасывается
- Summary заканчивается на
?→ отбрасывается (вопросительное предложение) - Содержит временные ключевые слова (today/now/currently/temporary и т.п.) → отбрасывается
- Комбинация
topic:summaryуже существует → дедупликация
Dream — Интеграция
Условие срабатывания
После каждого раунда завершения ответа ИИ автоматически запускается функция scheduleManagedAutoMemoryDream (фоновая, неблокирующая). Однако она защищена несколькими шлюзовыми условиями, поэтому в большинстве случаев будет пропущена.
Шлюзовые проверки планировщика (dreamScheduler.ts)
Параметры шлюзов:
| Параметр | Значение по умолчанию | Описание |
|---|---|---|
minHoursBetweenDreams | 24 часа | Минимальный интервал между двумя Dream |
minSessionsBetweenDreams | 5 сессий | Минимальное количество новых сессий для срабатывания Dream |
SESSION_SCAN_INTERVAL_MS | 10 минут | Интервал троттлинга сканирования файлов сессий |
DREAM_LOCK_STALE_MS | 1 час | Порог, после которого файл блокировки считается истёкшим |
Механизм блокировки:
- Файл блокировки находится в
<project-state-dir>/consolidation.lock - Содержимое — PID процесса-владельца
- При проверке: если процесс с PID больше не существует (сбой
kill(pid, 0)) или блокировке больше 1 часа → считается истёкшей, автоматически очищается
Процесс выполнения интеграции (dream.ts)
Логика механической дедупликации:
- Внутри каждого тематического файла: дедупликация по
summary.toLowerCase(), объединение полейwhy/howToApply - Пересортировка по алфавиту summary
- Между файлами: записи с одинаковым
type:summaryобъединяются в первый обнаруженный файл, дублирующий файл удаляется
Recall — Припоминание
Условие срабатывания
Перед каждым раундом обработки пользовательского запроса ИИ автоматически вызывается функция resolveRelevantAutoMemoryPromptForQuery, которая внедряет релевантные воспоминания в системный промпт.
Процесс припоминания (recall.ts)
Правила оценки (эвристика):
| Условие | Бонус |
|---|---|
| Токен query присутствует в содержимом документа | +2 (за каждый токен) |
| Токен query является характерным ключевым словом типа | +1 (за каждый токен) |
| Body документа непустое | +1 |
Ключевые слова для каждого типа:
user: user, preference, background, role, tersefeedback: feedback, rule, avoid, style, summaryproject: project, goal, incident, deadline, releasereference: reference, dashboard, ticket, docs, link
Правила построения промпта:
- Не более 5 документов (
MAX_RELEVANT_DOCS) - Body каждого документа обрезается до 1200 символов (
MAX_DOC_BODY_CHARS) - При обрезке добавляется подсказка: “NOTE: Relevant memory truncated for prompt budget.”
- Включается информация о свежести документа (на основе mtime файла)
Forget — Забывание
Условие срабатывания
Запускается вручную командой пользователя /forget <query>.
Процесс забывания (forget.ts)
Дизайн Entry ID:
- Одноэлементный файл (распространённый случай):
relativePath(например,feedback/no-summary.md) - Многоэлементный файл:
relativePath:index(например,feedback/style.md:2) - Стабильный ID позволяет модели точно указать запись, не затрагивая другие записи в том же файле.
Перестроение индекса
MEMORY.md — навигационный индекс по всем тематическим файлам. Перестраивается вызовом rebuildManagedAutoMemoryIndex после каждого Extract или Dream:
- [Предпочтения пользователя](user/preferences.md) — пользователь — опытный Go-инженер, впервые сталкивается с React
- [Правила обратной связи](feedback/style.md) — отвечать кратко, без итоговых резюме
- [Веха проекта](project/milestone.md) — окно замёрзших изменений перед слиянием ветки перед релизом мобильного приложенияОграничения индекса:
- Не более 150 символов на строку (если превышает — обрезается с
…) - Не более 200 строк
- Общий размер не более 25 000 байт
Телеметрические точки
Система включает три типа телеметрических событий для мониторинга производительности и эффективности операций памяти.
Телеметрия Extract
| Поле | Тип | Описание |
|---|---|---|
trigger | 'auto' | Способ запуска (сейчас только автоматический) |
status | 'completed' | 'failed' | Результат выполнения |
patches_count | number | Количество извлечённых валидных патчей |
touched_topics | string[] | Список затронутых типов памяти |
duration_ms | number | Общее время выполнения (мс) |
Телеметрия Dream
| Поле | Тип | Описание |
|---|---|---|
trigger | 'auto' | Способ запуска |
status | 'updated' | 'noop' | 'failed' | Результат выполнения |
deduped_entries | number | Количество записей, дедуплицированных механическим путём |
touched_topics | string[] | Список изменённых типов памяти |
duration_ms | number | Общее время выполнения (мс) |
Телеметрия Recall
| Поле | Тип | Описание |
|---|---|---|
query_length | number | Длина строки запроса |
docs_scanned | number | Общее количество просканированных документов |
docs_selected | number | Количество внедрённых документов |
strategy | 'none' | 'heuristic' | 'model' | Стратегия выбора |
duration_ms | number | Общее время выполнения (мс) |
Указатель связанных исходных файлов
| Файл | Обязанности |
|---|---|
packages/core/src/memory/types.ts | Определения типов: AutoMemoryType, AutoMemoryMetadata, AutoMemoryExtractCursor |
packages/core/src/memory/paths.ts | Вычисление путей: getAutoMemoryRoot, isAutoMemPath, различные helpers для путей файлов |
packages/core/src/memory/store.ts | Инициализация каркаса: ensureAutoMemoryScaffold, чтение/запись индекса и метаданных |
packages/core/src/memory/scan.ts | Сканирование тематических файлов: scanAutoMemoryTopicDocuments, парсинг frontmatter |
packages/core/src/memory/entries.ts | Парсинг и рендеринг записей: parseAutoMemoryEntries, renderAutoMemoryBody |
packages/core/src/memory/extract.ts | Основная логика извлечения: runAutoMemoryExtract, управление курсором, дедупликация патчей |
packages/core/src/memory/extractScheduler.ts | Планировщик извлечения: ManagedAutoMemoryExtractRuntime, очередь/состояние выполнения |
packages/core/src/memory/extractionAgentPlanner.ts | Агент извлечения: runAutoMemoryExtractionByAgent |
packages/core/src/memory/dream.ts | Основная логика интеграции: runManagedAutoMemoryDream, путь агента + механическая дедупликация |
packages/core/src/memory/dreamScheduler.ts | Планировщик интеграции: ManagedAutoMemoryDreamRuntime, шлюзовые проверки, управление блокировками |
packages/core/src/memory/dreamAgentPlanner.ts | Агент интеграции: planManagedAutoMemoryDreamByAgent |
packages/core/src/memory/recall.ts | Логика припоминания: resolveRelevantAutoMemoryPromptForQuery, двойной путь эвристика+модель |
packages/core/src/memory/forget.ts | Логика забывания: forgetManagedAutoMemoryEntries, генерация кандидатов + точное удаление |
packages/core/src/memory/indexer.ts | Перестроение индекса: rebuildManagedAutoMemoryIndex, buildManagedAutoMemoryIndex |
packages/core/src/memory/prompt.ts | Шаблоны системного промпта: описание типов памяти, примеры форматов, правила использования |
packages/core/src/memory/governance.ts | Типы предложений по управлению: AutoMemoryGovernanceSuggestionType |
packages/core/src/memory/state.ts | Состояние выполнения Extract: isExtractRunning, markExtractRunning, clearExtractRunning |
packages/core/src/memory/memoryAge.ts | Описание свежести: memoryAge, memoryFreshnessText |