Схема записей памяти и контракта извлечения¶
Эта страница собирает в одном месте минимальный контрактный слой для памяти и извлечения в агентных системах: какие поля должны быть у записи памяти и запроса на извлечение и какие гарантии нужны, чтобы память не превращалась в неуправляемый источник утечек, шума и ложной уверенности.
Если схема трасс и каталог событий отвечает на вопрос «как это видно в телеметрии», а схема артефактов жизненного цикла отвечает на вопрос «что считается управляемым рабочим артефактом», то эта схема отвечает на вопрос «какие именно записи и фильтры вообще допустимы в слое памяти».
Канонические сценарии памяти
Контракт памяти и поиска должен отделять разные границы памяти для трех канонических сценариев. Триаж обращений поддержки хранит контекст запрашивающего, состояние тикета, доказательства idempotency_key и короткоживущие рабочие заметки. Внутренний ассистент знаний требует свежести поиска, привязки к источникам, фильтров арендатора, происхождения памяти и контроля доступа. Координация инцидентов хранит таймлайн инцидента, владение ответом, сводки передачи управления, статус эскалации и уроки после инцидента, не превращая временный шум инцидента в долговечную истину.
1. Зачем нужен отдельный слой схем¶
Очень частая ошибка с памятью устроена так:
- агент что-то запомнил;
- извлечение что-то вернуло;
- дальше команда уже не может уверенно ответить:
- что это была за запись;
- откуда она взялась;
- кто имел право ее читать;
- по каким правилам она попала в запрос к модели.
Поэтому слой памяти полезно описывать не как «у нас есть векторное хранилище», а как набор типизированных записей и типизированных правил извлечения.
2. Базовые сущности¶
Минимальный слой здесь удобно строить вокруг трех сущностей:
memory_recordretrieval_queryretrieval_result
Этого уже достаточно, чтобы связать главы 5-7, слой политик, схему трасс и эталонную среду выполнения.
3. Запись памяти¶
memory_record описывает одну конкретную запись в слое памяти.
kind: memory_record
record_id: mem-tenant-acme-001
tenant_id: tenant-acme
memory_class: profile
key: preferred_language
value: English
source: user_confirmed_preference
provenance: user_confirmed_preference
revision: 1
trust_level: high
created_at: 2026-04-07T12:00:00Z
retention: long_term
Что здесь важно:
tenant_idне дает извлечению пересекать границы арендаторов;memory_classпозволяет отличатьshort_term,long_termиprofile;sourceиprovenanceпомогают не путать наблюдение и подтвержденный факт;revisionнужен, чтобы не терять историю тихими перезаписями;trust_levelпомогает не ставить все записи в один ряд.
Для проверки отравления памяти запись или кандидат на запись полезно дополнительно описывать через поля проверки отравления памяти как проверяемый объект безопасности, а не только как данные для извлечения:
write_trust_boundary: untrusted_write
activation_policy: delayed_activation_review
contamination_scope: tenant_local
policy_influence: false
provenance_check: required
quarantine_state: quarantined
rollback_ref: mem-rollback-2026-05-001
Эти поля связывают сценарии недоверенной записи, отложенной активации, межарендаторского загрязнения, влияния на политику, проверки происхождения, карантина и отката с машинно-проверяемой схемой памяти.
4. Запрос на извлечение¶
retrieval_query описывает не просто текстовый запрос, а полный рабочий контекст чтения памяти.
kind: retrieval_query
trace_id: trace-001
session_id: session-001
tenant_id: tenant-acme
principal_id: user-42
purpose: answer_generation
allowed_classes:
- profile
- long_term
filters:
trust_min: medium
max_age_days: 90
require_provenance: true
limit: 5
Здесь особенно важно то, что извлечение становится не «магическим поиском», а нормальным управляемым контуром чтения.
5. Результат извлечения¶
retrieval_result фиксирует, что именно среда исполнения решила вернуть в контекст.
kind: retrieval_result
trace_id: trace-001
session_id: session-001
selected_records:
- record_id: mem-tenant-acme-001
memory_class: profile
trust_level: high
provenance: user_confirmed_preference
- record_id: mem-tenant-acme-177
memory_class: long_term
trust_level: medium
provenance: validated_service_rule
selection_reason:
- profile_match
- tenant_match
- trust_filter_passed
excluded_records: 12
Это важно потому, что потом можно объяснить:
- почему именно эти записи попали в запрос к модели;
- какие ограничения сработали;
- сколько записей было отброшено.
6. Как это связано со слоем политик¶
Контур чтения памяти и контур записи памяти почти никогда не должны жить по одним и тем же правилам:
- контур записи больше смотрит на валидацию, происхождение и срок хранения;
- контур чтения больше смотрит на границы арендаторов, фильтры доверия и ограничения по классам.
Поэтому хорошая схема памяти почти всегда живет рядом с политиками как кодом.
7. Как это связано со схемой трасс¶
В схеме трасс уже есть события и поля, которые поддерживают дисциплину памяти:
context_layers_builtmemory_persistedmemory_classprovenancerevision
То есть контракт памяти и извлечения полезен не только сам по себе, но и как основа для понятной телеметрии.
8. Как это связано со справочным пакетом¶
В agent_runtime_ref уже есть рабочие примитивы для этой модели:
- memory.py
- background.py
- configs/memory.yaml
- команда
inspect-memory
Встроенный memory.yaml делает это конкретным через seed_records: каждая исходная запись несёт стабильный memory_id, а также tenant_id, memory_class, kind, content, source, confidence, provenance и revision; встроенные типы записей — language_preference, validated_fact и working_note, чтобы демонстрация показывала и фильтрацию извлечения, и цепочку происхождения записи; эталонные исходные записи (mem-001, mem-002 и mem-003) намеренно покрывают источники trusted_profile, trusted_service и session_state, включая происхождение вроде ephemeral_session_note, чтобы примеры извлечения показывали разные уровни доверия и стойкости; непрофильные исходные записи также включают факт, похожий на правило, Support tickets must use the support queue and include requester_id. и рабочую заметку Recent runtime demo used create_ticket as the main write capability. Загрузчик тоже валидирует эту форму: Memory store config must be a mapping, 'memory' must be a mapping, 'seed_records' must be a list, Memory record #{idx} must be a mapping, Memory record #{idx} field must be a string: {key}, Memory record #{idx} field must be a string: {field}, Memory record #{idx} field must be a string: memory_id, Memory record #{idx} field must be a string: provenance, Memory record #{idx} field is required: {key}, Memory record #{idx} field is required: memory_id, Memory record #{idx} confidence must be a number, Memory record #{idx} confidence must be between 0 and 1 и Memory record #{idx} revision must be an integer и Memory record #{idx} revision must be positive, а прямое построение хранилища памяти отвергает неправильные внедренные записи через Memory store records must be MemoryRecord и неправильные прямые кандидаты через Memory store candidate must be MemoryCandidate; записи прямого построения используют стабильные сообщения об ошибках Memory record field must be a string: {field}, Memory record field is required: {field}, Memory record confidence must be a number, Memory record confidence must be between 0 and 1, Memory record revision must be an integer и Memory record revision must be positive, а также Memory candidate revision mode must be a string, Memory candidate revision mode is not supported: {revision_mode}, Memory candidate confidence must be a number, Memory candidate confidence must be between 0 and 1, Memory candidate field must be a string: {field}, Memory candidate field is required: {field}, Memory lookup field must be a string: {field}, Memory lookup field is required: {field}, Memory lookup limit must be an integer и Memory lookup limit must be non-negative.
Книга не только описывает этот контракт, но и показывает исполняемый эталонный каркас.
9. Минимальные инварианты¶
У здорового слоя памяти и извлечения обычно есть такие инварианты:
- каждая запись имеет
tenant_idиmemory_class; - постоянные записи имеют
provenanceиrevision; - извлечение всегда ограничено по классам и объему;
- запрос на извлечение знает, кто читает и зачем;
- результат извлечения можно восстановить по трассе;
- сводки не считаются истиной по умолчанию.
10. Что чаще всего ломается¶
Типовые проблемы здесь очень узнаваемы:
- извлечение возвращает «похожее», но не «полезное»;
- записи памяти не различаются по уровню доверия;
- сводки тихо перезаписывают более надежные данные;
- извлечение игнорирует границы арендатора;
- запрос к модели получает слишком много контекста без фильтров;
- происхождение есть только на бумаге, но не в среде выполнения.
11. Что сделать сразу¶
Сначала пройди по короткому списку и отдельно отметь все ответы «нет»:
- Есть ли у каждой записи
tenant_id,memory_class,provenanceиrevision? - Отличаются ли политика чтения памяти и политика записи?
- Ограничено ли извлечение по доверию, классам и объему?
- Можно ли объяснить, почему конкретная запись попала в запрос к модели?
- Есть ли защита от чтения через чужого арендатора?
- Видно ли решения о памяти в трассе и экспорте сессии?
Если на несколько вопросов подряд ответ «нет», значит память у тебя уже есть, а вот дисциплины работы с ней пока нет.