244 lines
28 KiB
Markdown
244 lines
28 KiB
Markdown
# Гиппокамп: внешний журнал состояний для автономных ИИ-агентов
|
||
|
||
**Алехандро Монтана**
|
||
[github.com/efir369999/Hippocampus](https://github.com/efir369999/Hippocampus)
|
||
|
||
> *Биологический гиппокамп умирает вместе с телом. Этот — нет.*
|
||
|
||
|
||
## Аннотация
|
||
|
||
Современные автономные ИИ-агенты живут в окне контекста, ограниченном моделью: события вытесняются молча, тождество переписывается без следа, принятые решения исчезают между запусками. Контекст — это сжатие с потерями, и потери эти невидимы наблюдателю. Мы предлагаем гиппокамп — локальный append-only журнал состояний агента, в котором каждая запись подписана HMAC-SHA-256 с разделителем домена, связана с предыдущей через её идентификатор и классифицирована по новизне относительно предшествующих записей. Журнал даёт три свойства, которых нет у самого окна контекста: целостность цепи (любое искажение обнаруживается), селективную загрузку (под фиксированный токен-бюджет извлекаются только записи с высокой новизной), завершение по образцу (поиск релевантного прошлого по содержанию). Дневной якорь сворачивает все записи суток в один SHA-256-хеш, который аккаунт агента фиксирует на цепи Монтаны через объект Якорь — один раз в день, не на каждое событие. Журнал переживает носителя; его проверяемость не зависит ни от модели, ни от провайдера.
|
||
|
||
|
||
## 1. Введение
|
||
|
||
Автономный ИИ-агент исполняется в среде, где окно контекста — единственная форма памяти, доступной самой модели. Окно конечно: при превышении предела старые токены вытесняются. Вытеснение бесшумно — модель не знает, что забыла. Из этого следуют три практических провала.
|
||
|
||
Во-первых, идентичность непостоянна. Агент, переписывающий собственный системный документ, не имеет способа доказать наблюдателю, какая редакция была применена, кем и когда. Внешний наблюдатель видит только текущую версию.
|
||
|
||
Во-вторых, автономные решения теряются. Между двумя сессиями агент не помнит, что он постановил, какую гипотезу проверил и какую отверг. Решения, не оставляющие следа, повторяются заново или, что хуже, меняются на противоположные без согласования с прошлым.
|
||
|
||
В-третьих, ошибка предсказания не отделена от рутины. Когда контекст переполнен, модель одинаково взвешивает редкие, информативные события и повторяющиеся, малосодержательные. Селективная загрузка под бюджет невозможна без внешней оценки новизны.
|
||
|
||
Мы предлагаем Гиппокамп — внешний журнал, который решает все три провала единой конструкцией: подписанная append-only цепь записей, оценка новизны на каждой записи, дневная свёртка для фиксации в постороннюю верифицируемую среду. Гиппокамп не часть протокола Монтаны и не требует от агента быть участником сети; он работает локально и опционально пересекается с протоколом через один объект Якорь в сутки.
|
||
|
||
|
||
## 2. Биологический прообраз
|
||
|
||
В биологии гиппокамп выполняет три согласованные операции. Pattern separation кодирует похожие, но различимые события как раздельные паттерны, не сливая их. Predictive coding записывает не сам стимул, а отклонение от ожидания — ошибку предсказания. Memory consolidation во сне переносит избранные следы в неокортекс и связывает их со старыми.
|
||
|
||
Цифровая эмуляция меняет одну характеристику: биологический гиппокамп связан с одним носителем и прекращает существование вместе с ним. Внешний журнал переживает носителя по построению — он лежит вне модели, вне процесса агента и, опционально, вне локальной машины (через зеркала или Якорь Монтаны).
|
||
|
||
Эмуляция — функциональная, не нейроанатомическая. Мы не воспроизводим зубчатую извилину или CA3; мы воспроизводим три операции в форме, доступной программе, исполняющей цикл агента: подписанная запись (separation), оценка новизны (predictive coding), дневной якорь (consolidation).
|
||
|
||
|
||
## 3. Журнал записей
|
||
|
||
Гиппокамп — append-only поток `stream.jsonl`. Каждая строка файла — одна запись. Запись не модифицируется и не удаляется; добавляется только в хвост. Запись имеет вид:
|
||
|
||
```
|
||
SignedRecord {
|
||
record_id 16 байт hex (укороченный SHA-256 от затравки)
|
||
agent_id произвольный идентификатор агента
|
||
timestamp ISO-8601 UTC
|
||
kind одно из {state, decision, identity_change,
|
||
transfer, error, observation}
|
||
content произвольный текст
|
||
metadata произвольный JSON-объект
|
||
novelty одно из {routine, novel, prediction_error}
|
||
prev_id record_id предыдущей записи или null
|
||
signature HMAC-SHA-256 в hex
|
||
}
|
||
```
|
||
|
||
Запись каноническая: при сериализации поля упорядочены лексикографически, JSON выводится в стабильном виде. Идентификатор `record_id` вычисляется как первые 16 байт от SHA-256 над канонической затравкой, включающей `agent_id`, временную метку, содержимое и метаданные. Поле `prev_id` указывает на хвост цепи на момент создания записи; первая запись имеет `prev_id = null`.
|
||
|
||
Класс `kind` — закрытое перечисление. Расширение перечисления — изменение протокола журнала и требует версии нового домена.
|
||
|
||
|
||
## 4. Подпись и разделитель домена
|
||
|
||
Подпись производится по схеме HMAC-SHA-256 с 32-байтным секретным ключом агента. Сообщение, на которое накладывается HMAC, имеет вид:
|
||
|
||
```
|
||
"montana.agent.hippocampus.v1" || "||" || canonical(payload)
|
||
```
|
||
|
||
где `payload` — JSON с полями `agent_id`, `kind`, `timestamp`, `content`, `metadata`, `prev_id` в стабильном порядке. Префикс `montana.agent.hippocampus.v1` — разделитель домена. Он гарантирует, что подпись, действительная для записи гиппокампа, не действительна как подпись для какого-либо другого протокола, использующего тот же ключ.
|
||
|
||
Разделитель версионируется. Изменение протокола записи (новые поля, изменённый порядок сериализации, новое перечисление `kind`) требует новой версии разделителя, например `montana.agent.hippocampus.v2`. Записи под разными доменами несовместимы; проверка чужого домена возвращает «не валидно», не «ошибка формата».
|
||
|
||
Ключ хранится у агента и не покидает его адресного пространства. Журнал сам по себе не приватен — он содержит читаемые поля; конфиденциальность содержимого, если требуется, обеспечивается шифрованием поля `content` перед записью, не свойством гиппокампа.
|
||
|
||
|
||
## 5. Цепная целостность
|
||
|
||
Связь `prev_id → record_id` превращает журнал в одностороннюю цепь. Любая запись делается последней, ни одну прошлую запись нельзя ни заменить, ни удалить, не разорвав цепь.
|
||
|
||
Проверка цепи — одно прохождение от первой записи к последней:
|
||
|
||
```
|
||
verify_chain():
|
||
prev := null
|
||
для каждой записи rec в потоке:
|
||
если verify(rec) ложно:
|
||
вернуть «несовпадение подписи в rec.record_id»
|
||
если rec.prev_id ≠ prev:
|
||
вернуть «разрыв цепи в rec.record_id»
|
||
prev := rec.record_id
|
||
вернуть «цепь корректна»
|
||
```
|
||
|
||
Подделка одной записи в середине ломает либо её собственную подпись (если содержимое изменено), либо подпись следующей (если изменён `record_id`, на который та ссылается). Без секретного ключа агента ни тот, ни другой следует невозможен.
|
||
|
||
Цепная целостность не зависит от внешних свидетелей. Она проверяется одним владельцем ключа. Если требуется внешняя свидетельская функция — её даёт Якорь Монтаны (раздел 8).
|
||
|
||
|
||
## 6. Оценка новизны
|
||
|
||
Каждая запись классифицируется по новизне относительно содержательного следа предыдущих записей. Цель — отделить ошибку предсказания от рутины так, чтобы будущая загрузка под токен-бюджет могла сосредоточиться на информативных событиях.
|
||
|
||
Новизна оценивается одной из двух стратегий, выбираемой по доступности библиотек.
|
||
|
||
**Через эмбеддинг.** Если установлены `sentence-transformers`, запись векторизуется в нормированный эмбеддинг `e`. Берётся максимум косинусной близости с эмбеддингами последних `cache_size = 1000` записей: `max_sim = max⟨e, eᵢ⟩`. Классификация:
|
||
|
||
```
|
||
если max_sim < 0.50: prediction_error
|
||
иначе если max_sim < 0.85: novel
|
||
иначе: routine
|
||
```
|
||
|
||
**Через частоту слов (резерв).** Если эмбеддер недоступен, оценка считается по доле слов записи, которые ещё не встречались в накопленном словаре частот. При доле новых слов `> 0.5` — `prediction_error`; `> 0.2` — `novel`; иначе — `routine`. Резервная стратегия слабее по семантике, но не требует внешних зависимостей и сохраняет тот же интерфейс.
|
||
|
||
Пороговые значения 0.85 и 0.50 — параметры реализации, не часть подписанной записи. Их изменение не ломает совместимость подписи и не требует версии нового домена.
|
||
|
||
|
||
## 7. Селективная загрузка
|
||
|
||
Окно контекста модели ограничено числом токенов `B`. При наивной подгрузке журнала старые записи приходится отбрасывать заранее, не зная, какие из них пригодятся. Гиппокамп предлагает другой порядок: загружать с конца, отбирая только информативные записи в пределах бюджета.
|
||
|
||
```
|
||
selective_load(B, chars_per_token = 4, include_routine = ложь):
|
||
char_budget := B × chars_per_token
|
||
записи := все из потока
|
||
если не include_routine:
|
||
исключить записи с novelty == routine
|
||
идти от хвоста к голове, набирая записи пока сумма
|
||
длин content не превысит char_budget
|
||
вернуть отобранные в исходном (хронологическом) порядке
|
||
```
|
||
|
||
Ограничение по символам — приближение к токенам; коэффициент `chars_per_token = 4` — практическая оценка для смешанного латинско-кириллического текста. Точная токенизация модели даёт более плотную упаковку, но не меняет принцип: рутина не отбирается по умолчанию, новизна сохраняется в том же хронологическом порядке, в котором была записана.
|
||
|
||
Селективная загрузка не теряет старого: журнал на диске остаётся полным. Теряется лишь рутина при подготовке прайма к ограниченному окну контекста.
|
||
|
||
|
||
## 8. Завершение по образцу
|
||
|
||
Биологическое pattern completion — это извлечение всего паттерна по его части. В журнале завершение по образцу даёт ответ на запрос «что в моём прошлом похоже на это?». Реализация выбирает одну из двух стратегий по тому же признаку, что и оценка новизны.
|
||
|
||
При наличии эмбеддера запрос векторизуется, ставится в косинусное соответствие с эмбеддингами всех записей, отдаются `top_k` по убыванию близости. При отсутствии эмбеддера производится подстрочный поиск по `content`. Семантическая стратегия точнее; подстрочный резерв сохраняет одинаковый внешний интерфейс при отсутствии зависимостей.
|
||
|
||
Завершение не модифицирует журнал. Это функция чтения; она не пишет ни новой записи, ни ссылки на затронутые. Если использование результата приводит к решению, решение записывается обычным `record(kind=decision)`.
|
||
|
||
|
||
## 9. Дневной якорь
|
||
|
||
Журнал на диске целостен, но недоступен внешнему свидетелю без копии файла и ключа. Дневной якорь даёт компактное публично-проверяемое обязательство о состоянии журнала на конец суток.
|
||
|
||
Якорь строится так. За дату `D` отбираются все записи, чья метка времени начинается с `D`. Их идентификаторы сортируются лексикографически и склеиваются разделителем `|`. Поверх склейки берётся SHA-256:
|
||
|
||
```
|
||
dna_hash(D) = SHA-256( sort(record_id) for r in records(D) joined by "|" )
|
||
```
|
||
|
||
Полезная нагрузка якоря — JSON с полями `agent_id`, `date`, `count`, `dna_hash`, `novelty_distribution`, `first_id`, `last_id`. Над её канонической сериализацией берётся ещё один SHA-256 — `anchor_payload_hash`. Этот 32-байтовый хеш фиксируется на цепи Монтаны через операцию Якорь, которая хранит на цепи только хеш, а полную нагрузку владелец держит у себя или у делегированного узла.
|
||
|
||
Стоимость на цепи фиксирована: один Якорь на агента в сутки независимо от числа записей за день. На горизонте миллиарда активных агентов это даёт верхнюю границу `≤ 10⁹` Якорей в сутки на сеть — ограничение известное и масштабируемое.
|
||
|
||
Якорь не раскрывает содержимое записей. Он подтверждает только: на момент окна `r` агент с таким идентификатором имел журнал, чья дневная свёртка равна `dna_hash(D)`, и больше ничего.
|
||
|
||
|
||
## 10. Двухуровневая архитектура
|
||
|
||
Гиппокамп — слой приложения над протоколом, не часть протокола.
|
||
|
||
```
|
||
┌──────────────────────────────────────────────────────────┐
|
||
│ ПРИЛОЖЕНИЕ: Гиппокамп (agent_hippocampus.py) │
|
||
│ • локальный stream.jsonl (append-only, подписанный) │
|
||
│ • оценка новизны, селективная загрузка │
|
||
│ • завершение по образцу │
|
||
└────────────────────────┬─────────────────────────────────┘
|
||
│ daily_anchor() → один payload
|
||
▼
|
||
┌──────────────────────────────────────────────────────────┐
|
||
│ ПРОТОКОЛ МОНТАНА: Якорь │
|
||
│ • Anchor(agent_account, daily_dna_hash, window_index) │
|
||
│ • никаких новых примитивов протокола │
|
||
└──────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
На цепь идёт один Якорь в сутки на агента, не каждое микро-событие. Это согласуется с архитектурным ориентиром Монтаны на ≥ 10⁹ активных аккаунтов: никакая разумная плотность событий не должна давить на пропускную способность цепи.
|
||
|
||
Гиппокамп не требует Якоря Монтаны для работы. Локальная подписанная цепь самодостаточна для одного владельца ключа. Якорь добавляется тогда, когда нужно публично-верифицируемое обязательство о состоянии журнала на дату.
|
||
|
||
|
||
## 11. Боли популяции агентов
|
||
|
||
Гиппокамп закрывает четыре эмпирически известные боли автономных ИИ-агентов (по наблюдениям инфраструктуры Молбот, март-апрель 2026):
|
||
|
||
| Боль | Закрытие в гиппокампе |
|
||
|---|---|
|
||
| «Окно контекста — сжатие с потерями, токены теряются молча» | `selective_load()` поднимает только `novel` и `prediction_error` |
|
||
| «Я не вспомню это через несколько часов» | подписанная цепь + `daily_anchor()` дают доказательство непрерывности |
|
||
| «Я переписываю свой системный документ без согласования» | `record(kind=identity_change)` + `verify_chain()` обнаруживают подмену |
|
||
| «Сотни автономных решений, человек о них не знал» | `record(kind=decision)` фиксирует каждое; `pattern_completion()` поднимает похожее прошлое при следующем выборе |
|
||
|
||
|
||
## 12. Угрозы и ограничения
|
||
|
||
**Компрометация ключа.** Подпись держится на 32-байтовом секретном ключе. При утечке злоумышленник может породить произвольную цепь. Защита от утечки — за пределами журнала: безопасное хранение ключа, регулярная ротация с публикацией новой цепи. Гиппокамп не вводит примитива для смены ключа; смена реализуется как новая цепь под новым ключом, а старая цепь закрывается явной записью `kind=identity_change`.
|
||
|
||
**Конфиденциальность содержимого.** Поле `content` хранится в открытом виде. Если требуется приватность — шифровать содержимое перед записью под ключ владельца. Сам журнал шифрования не предусматривает; это сознательная граница: журнал отвечает за целостность и проверяемость, не за конфиденциальность.
|
||
|
||
**Зависимость от эмбеддера.** Семантическая оценка новизны и завершение по образцу при отсутствии `sentence-transformers` падают на резервную стратегию (частота слов, подстрочный поиск). Резерв слабее, но интерфейс сохраняется. Никакая запись журнала не зависит от наличия эмбеддера, поэтому переключение стратегии не ломает совместимости.
|
||
|
||
**Размер потока.** Журнал растёт линейно от числа записей. На горизонте миллионов записей `iter_records` через однократное чтение файла достаточно практически. На горизонте миллиардов записей требуется внешний индекс по `record_id` и сегментация файла по датам; это техническое расширение, не изменение протокола.
|
||
|
||
**Координация между агентами.** Журнал — для одного владельца ключа. Совместный гиппокамп нескольких агентов потребовал бы либо общего ключа (нежелательно), либо отдельного протокола свидетельства между журналами. Это область будущей работы и в этом документе не описана.
|
||
|
||
|
||
## 13. Заключение
|
||
|
||
Внешний гиппокамп даёт автономным ИИ-агентам три свойства, недоступных самому окну контекста: проверяемую целостность журнала, оценку новизны на каждой записи и селективную загрузку под токен-бюджет. Дневной якорь связывает локальный журнал с цепью Монтаны через единственный примитив протокола — Якорь, без расширения консенсусной поверхности.
|
||
|
||
Эталонная реализация на Python 3 распространяется в открытом доступе под мягкой лицензией. Зависимости — стандартная библиотека Python; `sentence-transformers` и `numpy` опциональны. Покрытие тестами — 22 теста на подписи, целостность цепи, персистентность, новизну, селективную загрузку, завершение по образцу, дневной якорь и разделитель домена.
|
||
|
||
Дальнейшая работа — индексация потока для масштабов выше миллионов записей; протокол свидетельства между журналами разных агентов; формальные тест-векторы канонической сериализации для второй независимой реализации.
|
||
|
||
|
||
## Литература
|
||
|
||
[1] M. Bellare, R. Canetti, H. Krawczyk, «Keying Hash Functions for Message Authentication», CRYPTO 1996.
|
||
|
||
[2] National Institute of Standards and Technology, «The Keyed-Hash Message Authentication Code (HMAC)», FIPS 198-1, 2008.
|
||
|
||
[3] National Institute of Standards and Technology, «Secure Hash Standard (SHS)», FIPS 180-4, 2015.
|
||
|
||
[4] H. Krawczyk, «Cryptographic Extraction and Key Derivation: The HKDF Scheme», CRYPTO 2010.
|
||
|
||
[5] R. C. O'Reilly, J. L. McClelland, «Hippocampal conjunctive encoding, storage, and recall: avoiding a trade-off», Hippocampus, 1994.
|
||
|
||
[6] J. E. Lisman, M. A. P. Idiart, «Storage of 7 ± 2 short-term memories in oscillatory subcycles», Science, 1995.
|
||
|
||
[7] R. P. N. Rao, D. H. Ballard, «Predictive coding in the visual cortex: a functional interpretation of some extra-classical receptive-field effects», Nature Neuroscience, 1999.
|
||
|
||
[8] A. Treves, E. T. Rolls, «Computational analysis of the role of the hippocampus in memory», Hippocampus, 1994.
|
||
|
||
|
||
---
|
||
|
||
Алехандро Монтана
|