Skip to main content
Glama
thomaskawas

agent-context-substrate

by thomaskawas

agent-context-substrate

Субстрат — это актив; модель — взаимозаменяемый клиент.

git clone https://github.com/thomaskawas/agent-context-substrate.git
cd agent-context-substrate
make setup && make demo

Требования: Python 3.12+, Docker, make. make setup создаёт виртуальное окружение и устанавливает зависимости, около 1,4 ГБ, поскольку демо работает на CPU и пропускает CUDA-колёса; на медленном соединении дайте несколько минут. База данных привязывается к 127.0.0.1:5432, поэтому остановите всё, что уже занимает этот порт.

Один запрос, прослеженный через четыре этапа поиска, затем таблица абляции и базовый шлюз

Зачем это существует

Я создаю долгосрочные проекты с ИИ-агентами, и восстановление контекста в начале каждой сессии было налогом, который я платил чаще всего. Загрузка одних и тех же файлов, повторное объяснение одних и тех же решений, наблюдение за тем, как полезная часть окна заполняется материалом, который модель уже видела дважды. Выходила новая модель — и ничего из этого не переносилось. Проблема никогда не была в том, что контекст отсутствовал. Проблема была в том, что контекст не был адресуемым: не было способа задать вопрос и получить только то, что на него отвечает, поэтому вы отправляете всё и надеетесь. Решение состояло в том, чтобы перестать относиться к контексту как к чему-то, что вы приносите в сессию, и начать относиться к нему как к чему-то, что вы запрашиваете.

Эталонная реализация независимого от модели субстрата памяти для ИИ-агентов: память проекта живёт вне модели в запрашиваемом, версионируемом хранилище, доступном через единый MCP-шлюз. Меняйте модель — сохраняйте всё. Сегодня Claude, завтра Gemini или GPT, под ними та же память проекта. Вместо вставки истории в каждую сессию поиск выбирает небольшой набор записей, которые действительно нужны текущей задаче.

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

Ключи API не требуются: make demo работает полностью на локальных компонентах. Зафиксированные локальные модели (имя и ревизия) — это профиль адаптера по умолчанию, local (make warmup, запускается автоматически через make demo, предварительно загружает ~180 МБ один раз); герметичный профиль deterministic без загрузок поддерживает тесты и постоянно включённый CI-шлюз.

Related MCP server: marrow

Структура

src/acs/adapters/base.py — это тезис в коде: четыре небольших интерфейса, за которыми стоит каждая внешняя возможность. src/acs/store/ рассматривает память как систему записи (версионируемую, аудируемую, по-настоящему удаляемую). src/acs/retrieval/ — это конвейер из небольших, отдельно тестируемых этапов. eval/ — это шлюз: изменения попадают в релиз, если соответствуют или превосходят baseline.lock.json, иначе не попадают.

Обоснование решений находится в docs/adr/: девять записей о решениях. Большинство — полстраницы; три длиннее, где аргументу нужно было место.

Также в docs/: architecture.md — зачем существует каждый слой, threat-model.md — о границах угроз и где находится каждая защита, principles.md — правила, из которых следует остальное, и build-your-own.md — последовательность сборки, которой следовал этот репозиторий.

Что это демонстрирует

  • Приём записывает оба представления за один проход: эмбеддинги для сходства, граф сущностей/связей для структуры. Каждый документ встраивается; документ, не содержащий связей, не добавляет рёбер.

  • Поиск — это конвейер из четырёх этапов: гибридный векторный + полнотекстовый поиск с настраиваемым смешиванием, мультизапросное слияние (RRF), переранжирование кросс-энкодером и раздел, привязанный к сущностям, где граф переупорядочивает переранжированный список, чтобы тематический ранжировщик перестал путать один компонент с его одноимённым собратом. Профили поиска для каждого потребителя — это данные, а не код.

  • Управление: изменения поиска попадают в релиз, если соответствуют или превосходят заблокированный базовый уровень оценки. Память версионируется по SCD2 с чтением на момент времени, очистка действительно удаляет (включая векторы), а журнал аудита отказывает в изменении на уровне базы данных.

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

  • Переносимость: каждый провайдер стоит за адаптером; эмбеддер зафиксирован намеренно.

что вы хотите увидеть

команда

запрос, прослеженный через каждый этап поиска

make query Q="..."

бенчмарк абляции (recall@5, MRR на каждом этапе)

make bench

изменение поиска, проваливающее CI против заблокированного базового уровня

make check

идентичности памяти и полная цепочка версий одной памяти

make history

память, заменённая, но старая версия всё ещё читается

make supersede LINEAGE=<id> CONTENT="..."

чтение памяти на момент в прошлом

make asof LINEAGE=<id> TS=<timestamp>

субъект очищен, включая эмбеддинги

make purge SUBJECT=contributor-03

цепочки замены + соседи сущностей из графа

make graph ENTITY=CHG-4568

два ограниченных вызывающих на одном субстрате, один вызов отклонён

make gateway-client

исследовательский цикл заполняет пробел, с цитированием и в карантине

make research затем make vet

Идентификатор происхождения и временные метки берутся из make history: без аргументов он выводит текущие памяти с их идентификаторами; с LINEAGE=<id> он проходит по цепочке версий одной памяти и выводит окно действия каждой версии. Эти окна — ISO-временные метки, так что TS=, который вы вставляете, разрешается в версию, которую вы действительно читали, а не на секунду раньше или позже. Идентификаторы генерируются для каждого клона, поэтому ваши не совпадут с показанными здесь.

make purge действительно удаляет (включая цели золотого набора, когда они принадлежат очищенному субъекту), поэтому бенчмарк против очищенного корпуса отказывается запускаться как неполный, а не тихо сообщает о более низком recall. make demo сбрасывает к чистому корпусу.

Каждое число бенчмарка на этой странице получено из абляции на посеянном синтетическом корпусе (corpus/generate.py), воспроизводимо из чистого клона и контролируется в CI (профиль deterministic на каждом пуше, профиль local на метке bench-local) против заблокированного базового уровня, который также фиксирует дайджест корпуса. Читайте дельты, а не абсолюты: recall@5 / mrr@5 на синтетическом корпусе показывают, что даёт каждый этап, а не реальное качество. Чтобы увидеть, где этап зарабатывает свою дельту, запустите .venv/bin/python eval/run_benchmark.py --by-family.

Абляция, локальный профиль

этап

recall@5

mrr@5

что даёт этап

vector-only

0.6333

0.4340

пол: только сходство

+hybrid

0.9667

0.5742

recall. Лексический канал восстанавливает то, что пропускают эмбеддинги

+fusion

0.9750

0.6026

ранжирование, и почти без recall (recall +0.0083)

+rerank

0.9917

0.9072

ранжирование. mrr +0.3046 при recall, который почти не двигается

+graph

0.9917

0.9315

идентичность. Раздел сущностей, а не дополнительный поиск

Каждый этап даёт разное, что является аргументом в пользу конвейера, а не одного лучшего поисковика. tests/test_readme_table.py падает, если эта таблица и eval/baseline.lock.json когда-либо расходятся, поэтому таблица не может отклониться от чисел, которые обеспечивает шлюз. Шлюз — это нижняя граница, поэтому изменение, улучшающее метрику, проходит его, и числа здесь остаются до тех пор, пока базовый уровень не будет намеренно перезафиксирован с помощью make lock-baseline, что затем приводит к падению этой таблицы, пока она не будет приведена в соответствие. Локальный профиль, 120 золотых запросов, k=5, слияние этапа 1 rank, дайджест корпуса ad7bf7ca. Воспроизведите с помощью make demo.

Что эти числа поддерживают, а что нет, включая то, почему сравнение модельных дорожек является границей, а не кривой, изложено в docs/limitations.md.

Maintenance

ActivityStale
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables multiple MCP-compatible AI clients to share persistent, versioned project knowledge across sessions with conflict-safe updates, provenance, hybrid retrieval, stale-memory handling, and context-budgeted recall.
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Provides persistent, shared memory for AI agents via MCP, enabling retrieval of relevant memories instead of loading entire context. Allows agents across projects, machines, and tools to share a single auditable, markdown-native brain.
    3
    AGPL 3.0
  • A
    license
    Not graded
    quality
    C
    maintenance
    Provides persistent, multi-project memory for AI agents via MCP, enabling them to store and retrieve tasks, decisions, errors, checkpoints, and documentation while keeping context isolated by project.
    2
    MIT
  • A
    license
    Not graded
    quality
    A
    maintenance
    Provides AI agents with persistent, human-like memory infrastructure via MCP, enabling them to store, search, summarize, and forget episodic, semantic, procedural, and working memories across sessions.
    1,440 npm
    MIT