Skip to main content

План развития памяти Veles

Дата: 2026-03-25 Основано на: Исследование памяти OpenClaw Цель: Внедрить систему долговременной памяти в стиле OpenClaw в Veles с минимальными изменениями основного цикла.

Текущее состояние

Файловая память (veles/agent/memory.py)

  • MemoryStore: управляет memory/MEMORY.md (структурированные долгосрочные факты).
  • MemoryConsolidator: консолидация на базе LLM, которая архивирует старые сообщения в MEMORY.md, когда контекст превышает половину окна.
  • Содержимое MEMORY.md встраивается в системный промпт через ContextBuilder.
  • Консолидация использует принудительный вызов инструмента save_memory с откатом к обычному архивированию.

Векторная память (veles/agent/vector_memory.py)

  • VectorMemoryManager: индексирует workspace/docs/<project>/ с использованием гибридного поиска (BM25 + векторный).
  • SQLite + sqlite-vec + FTS5, эмбеддинги через litellm.
  • Фоновый цикл синхронизации (интервал 60с), поиск с ограничением по проекту.
  • VectorSearchTool: предоставляет агенту инструмент vector_search.

Сессии (veles/session/manager.py)

  • JSONL-файлы в workspace/sessions/ (один на пару канал:chat_id).
  • Строка метаданных + дополняемые словари сообщений.
  • get_history() возвращает messages[last_consolidated:].

Что отсутствует (по сравнению с OpenClaw)

  1. Нет датированных файлов памяти ✅ Реализовано (Фаза 1)
  2. Нет сброса памяти перед сжатием контекста ✅ Реализовано (Фаза 2)
  3. Файлы памяти не индексируются для поиска ✅ Реализовано (Фаза 3)
  4. Нет инструмента memory_search ✅ Реализовано (Фаза 4)
  5. HISTORY.md избыточен ✅ Удален (заменен датированными файлами + memory_search)
  6. Нет временного затухания (temporal decay) ✅ Реализовано (отдельная конфигурация для памяти и документов)

Что мы создаем

Четыре функции в порядке реализации:
#ФункцияИсточник вдохновенияВлияние на основной цикл
1Датированные файлы памяти по завершении сессииХук session-memory в OpenClaw1 строка в обработчике /new
2Сброс памяти перед сжатием контекстаmemory-flush.ts в OpenClaw1 вызов перед консолидацией
3Индексация файлов памятиИндексация memory-core в OpenClawРасширение VectorMemoryManager
4Инструмент memory_searchИнструмент memory_search в OpenClawРегистрация 1 инструмента
Что остается без изменений:
  • Текущий алгоритм гибридного поиска (BM25 + векторный).
  • Текущий конвейер эмбеддингов (litellm).
  • Текущая логика консолидация (MemoryConsolidator).
  • Текущий формат сессий JSONL.
  • Наличие MEMORY.md в системном промпте.

Фаза 1: Датированные файлы памяти по завершении сессии

Цель: При вызове /new резюмировать завершающуюся сессию в файл memory/YYYY-MM-DD-slug.md.

Новый класс: SessionMemoryWriter

Файл: veles/agent/memory.py (добавить в существующий файл)
class SessionMemoryWriter:
    """Создает датированные файлы памяти из стенограмм сессий при их завершении."""

    def __init__(self, workspace: Path, provider: LLMProvider, model: str):
        self.memory_dir = workspace / "memory"
        self.provider = provider
        self.model = model

    async def write_session_memory(
        self, session_key: str, messages: list[dict], max_messages: int = 20,
    ) -> Path | None:
        """Резюмирует недавние сообщения и записывает в memory/YYYY-MM-DD-slug.md."""

Логика

  1. Взять последние max_messages сообщений пользователя/ассистента из снимка сессии (пропустить вызовы инструментов для сокращения контекста LLM).
  2. Если сообщений от пользователя меньше 3 — пропустить (слишком короткая сессия).
  3. Вызвать LLM со специализированным промптом:
    • System: “Вы — составитель памяти. Создайте краткое резюме этого диалога.”
    • Использовать принудительный вызов create_session_memory с параметрами:
      • slug: короткий идентификатор файла в kebab-case (макс. 40 символов, например “api-design-review”).
      • summary: описание ключевых тем, решений и фактов в формате markdown.
  4. Записать в memory/YYYY-MM-DD-slug.md:
# Память сессии: 2026-03-25 14:30

- **Сессия**: telegram:12345
- **Дата**: 2026-03-25 14:30:00

## Резюме

[Текст резюме от LLM]

## Ключевые сообщения

user: [фрагмент первого сообщения]
assistant: [фрагмент ответа]
...
  1. При ошибке вызова LLM записать сырой фрагмент стенограммы (по аналогии с _raw_archive в MemoryStore).

Точка интеграции в loop.py

Текущий обработчик /new:
if cmd == "/new":
    snapshot = session.messages[session.last_consolidated:]
    session.clear()
    self.sessions.save(session)
    self.sessions.invalidate(session.key)
    if snapshot:
        self._schedule_background(self.memory_consolidator.archive_messages(snapshot))
    return OutboundMessage(...)
Добавляем одну строку — запуск записи памяти сессии в фоне:
if cmd == "/new":
    snapshot = session.messages[session.last_consolidated:]
    session.clear()
    self.sessions.save(session)
    self.sessions.invalidate(session.key)
    if snapshot:
        self._schedule_background(self.memory_consolidator.archive_messages(snapshot))
        self._schedule_background(self.session_memory_writer.write_session_memory(
            session.key, snapshot,
        ))
    return OutboundMessage(...)

Дополнение в конфиг (schema.py)

class SessionMemoryConfig(Base):
    """Настройка создания датированных файлов памяти сессий."""
    enabled: bool = True
    max_messages: int = 20       # Макс. кол-во сообщений для резюме
    min_user_messages: int = 3   # Пропускать слишком короткие сессии
Вложить в ToolsConfig рядом с vector_memory:
class ToolsConfig(Base):
    ...
    session_memory: SessionMemoryConfig = Field(default_factory=SessionMemoryConfig)

Измененные файлы

  • veles/agent/memory.py — добавлен класс SessionMemoryWriter (~80 строк).
  • veles/agent/loop.py — инициализация self.session_memory_writer + 1 строка в /new.
  • veles/config/schema.py — добавлена SessionMemoryConfig.

Фаза 2: Сброс памяти перед сжатием контекста

Цель: Перед тем как maybe_consolidate_by_tokens начнет архивировать сообщения, запустить выделенный ход LLM для записи важных фактов в memory/YYYY-MM-DD.md.

Новый класс: MemoryFlusher

Файл: veles/agent/memory.py (добавить в существующий файл)
class MemoryFlusher:
    """Запускает ход LLM для извлечения фактов перед сжатием контекста."""

    def __init__(self, workspace: Path, provider: LLMProvider, model: str):
        self.memory_dir = workspace / "memory"
        self.provider = provider
        self.model = model
        self._flushed_sessions: set[str] = set()  # отслеживание внутри цикла сжатия

Логика

  1. Условие срабатывания: estimated_tokens > context_window - threshold_tokens.
  2. Защита: Пропускать, если для этой сессии в текущем цикле сжатия сброс уже выполнялся.
  3. Дедупликация: Прочитать текущий memory/YYYY-MM-DD.md, чтобы не дублировать информацию.
  4. Вызвать LLM с системным промптом:
    Вы — агент по извлечению памяти. Проанализируйте диалог ниже и выделите
    важные факты, решения, предпочтения и задачи, достойные запоминания.
    
    Запишите их в виде списка. Если ничего достойного упоминания нет, ответьте
    ровно одной фразой: "[silent]".
    
    Целевой файл: memory/YYYY-MM-DD.md (только дозапись, никогда не перезаписывайте старое)
    
  5. Если ответ [silent] — пропустить запись.
  6. Иначе — дозаписать в memory/YYYY-MM-DD.md:
## Сброс в 14:30 (сессия: telegram:12345)

- Пользователь предпочитает REST вместо GraphQL для нового API.
- Решение: использовать PostgreSQL для сервиса аналитики.
- Задача: проверить предложение вендора до пятницы.

Точка интеграции

В MemoryConsolidator.maybe_consolidate_by_tokens() (memory.py), добавить вызов флеша перед циклом консолидации:
async def maybe_consolidate_by_tokens(self, session: Session) -> None:
    ...
        # НОВОЕ: Сброс памяти перед сжатием
        if self.memory_flusher:
            await self.memory_flusher.maybe_flush(
                session.key,
                session.messages[session.last_consolidated:],
                estimated,
                self.context_window_tokens,
            )

        # ... далее стандартный цикл консолидации ...

Измененные файлы

  • veles/agent/memory.py — добавлен класс MemoryFlusher (~70 строк), изменен MemoryConsolidator.__init__ для его приема.
  • veles/agent/loop.py — передача экземпляра MemoryFlusher в MemoryConsolidator.
  • veles/config/schema.py — добавлена MemoryFlushConfig.

Фаза 3: Индексация файлов памяти

Цель: Расширить VectorMemoryManager для индексации memory/MEMORY.md и memory/*.md, сделав их доступными для поиска наравне с документацией.

Изменения в VectorMemoryManager

Файл: veles/agent/vector_memory.py

1. Расширение _discover_files()

Добавляем поиск в папке memory/ с зарезервированным именем проекта _memory.
def _discover_files(self) -> list[tuple[Path, str]]:
    results: list[tuple[Path, str]] = []
    # ... существующий поиск в docs/ ...

    # НОВОЕ: файлы памяти
    if self.memory_dir.exists():
        memory_md = self.workspace / "MEMORY.md"
        if memory_md.exists():
            results.append((memory_md, "_memory"))
        for fpath in sorted(self.memory_dir.glob("**/*.md")):
            if not fpath.name.startswith("."):
                results.append((fpath, "_memory"))
    return results

2. Добавление метода search_memory()

Удобный метод для поиска только по файлам памяти (фильтр project='_memory').

Измененные файлы

  • veles/agent/vector_memory.py — расширено обнаружение файлов, добавлен метод search_memory().

Цель: Дать агенту инструмент для поиска по его собственным файлам памяти.

Новый файл: veles/agent/tools/memory_search.py

Инструмент memory_search позволяет агенту искать по MEMORY.md и датированным логам в папке memory/, используя гибридный поиск. Это критически важно для восстановления контекста прошлых диалогов, решений и предпочтений.

Регистрация в loop.py

Добавить регистрацию нового инструмента в _register_default_tools() после vector_search.

Обновление системного промпта (context.py)

Обновить описание рабочего пространства в _get_identity(), указав на наличие инструментов поиска по памяти.

Архитектура после реализации

Veles получает многослойную систему памяти:
  • MEMORY.md: Долгосрочные, отобранные факты (всегда в промпте).
  • Датированные логи: Автоматически создаваемые резюме сессий (доступны через поиск).
  • Поиск по памяти: Инструмент memory_search для доступа к истории.
  • Векторная база: Единое хранилище для документации проектов и личной памяти агента.

Жизненный цикл сессии

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

План работ и оценка

ФазаФункцияОбъем кодаФайлыОценка
1Датированные логи сессий~80 строкmemory.py, loop.py2-3 часа
2Флеш перед сжатием~70 строкmemory.py, loop.py2-3 часа
3Индексация памяти~20 строкvector_memory.py1 час
4Инструмент memory_search~50 строкtools/memory_search.py1-2 часа
Итого: ~220 новых строк кода, около 6-9 рабочих часов.

Зависимости

  • Фазы 3 и 4 требуют включенной векторной памяти (tools.vector_memory.enabled: true).
  • Фазы 1 и 2 работают независимо (записывают обычные markdown-файлы).
  • Фаза 4 зависит от Фазы 3.