Узнайте, как построить AI-агента с настоящей памятью: забывание устаревшей информации, консолидация и обнаружение противоречий. Реализация на Qwen Cloud с примерами кода.
Каждый «AI-агент с памятью», который я видел, делает одно и то же: сохраняет каждое сообщение в векторную базу данных, а при запросе ищет top-k похожих кусков. Это не память. Это поисковый индекс. Он никогда не забывает, одинаково относится к «хорошая сегодня погода» и «у меня аллергия на пенициллин», и со временем тормозит, потому что с каждым почти дубликатом шум в результатах растёт.
Для Global AI Hackathon Series с Qwen Cloud (Track 1: MemoryAgent) требовались три вещи: эффективное хранение и поиск, своевременное забывание устаревшей информации и извлечение критически важных воспоминаний в ограниченном контексте. Именно забывание — то, что никто не строит, потому что наивное векторное хранение не знает, что такое «устарело». Я построил это — реальную математику затухания, консолидацию, обнаружение противоречий — и протестировал против наивного подхода, чтобы доказать, что это работает.
Каждое воспоминание получает оценку значимости (salience), которая меняется со временем:
import math
def salience(t, importance_score, recall_count, half_life_hours):
"""Вычисляет значимость воспоминания в момент t."""
recall_boost = 1 + math.log(1 + recall_count)
lam = math.log(2) / half_life_hours
return importance_score * recall_boost * math.exp(-lam * t)
Здесь importance_score — не эвристика по ключевым словам, а результат структурированного вызова Qwen в момент записи. Модель оценивает явные сигналы («запомни это»), релевантность для принятия решений и конкретность. Время полураспада не единое для всех: эпизодические детали (что вы сказали в случайный вторник) затухают за ~72 часа, если не подкрепляются; семантические факты (стабильные предпочтения, «я вегетарианец») затухают за 30 дней. Эта асимметрия — ключевая идея: система должна забывать, о чём вы говорили, но не то, что вы сказали, что это важно.
Кроме затухания, фоновый «спящий проход» делает ещё две вещи:
Все LLM-вызовы в проекте — ответы чата, оценка важности, извлечение памяти, суждение о противоречиях, суммаризация кластеров и даже оценка в бенчмарке — идут через реальный эндпоинт Qwen Cloud. Никаких замоканных ответов. Это было жёсткое правило: если механизм не работает по-настоящему, я лучше откажусь от утверждения, чем подделаю результат.
Qwen Cloud использует эндпоинт, совместимый с OpenAI, но специфичный для рабочего пространства: ws-<workspace-id>.<region>.maas.aliyuncs.com. Модели qwen-max / qwen3.7-plus использовались для чата, оценки и извлечения, а text-embedding-v3 — для эмбеддингов.
Одна неожиданность: при переключении на более быструю модель qwen3.6-flash для ускорения бенчмарка иногда возвращался некорректный JSON — пустой {} вместо реальной оценки. Вместо того чтобы подставлять значение по умолчанию, я написал обёртку с повторными попытками при ошибке формы, а не только сети:
def _chat_json_retrying(system_prompt, user_prompt, validate, temperature=0.2, max_attempts=3):
"""Повторяет запрос при невалидной форме ответа."""
for attempt in range(max_attempts):
result = _chat_json(system_prompt, user_prompt, temperature)
if validate(result):
return result
raise ValueError("Qwen вернул невалидную форму после всех попыток")
Это разница между бенчмарком, который молча выдаёт мусор, и честным отказом при реальной проблеме.
Проход консолидации должен сравнивать временные метки, чтобы определить, какое из противоречащих воспоминаний новее. Я запустил полный бенчмарк — 110 шагов через симулированный 40-дневный разговор — с поддельным значением now, чтобы сжать 40 дней в один запуск скрипта.
Но одна функция не использовала это поддельное время. Она тихо падала на datetime.now() — реальное системное время — при решении, какое воспоминание «новее». Все воспоминания в симуляции, независимо от их вымышленной даты, записывались примерно в один реальный момент. Так что сравнение временных меток в проверке противоречий сравнивало шум, а не реальную хронологию.
Я нашёл баг, напрямую запросив базу данных после того, как бенчмарк показал обратный результат — система уверенно отвечала устаревшим фактом вместо актуального. Исправил, явно передавая симулированное now во все функции, работающие с временными метками, и написал регрессионный тест, воспроизводящий точную ошибку:
def test_stale_fact_loses_even_when_inserted_after_correct_one():
"""Правильный факт «старше» по симулированному времени, но вставлен в БД
ПОСЛЕ устаревшего — доказывает, что исправление не полагается на порядок вставки."""
# ... код теста
Я построил второго агента — те же модели Qwen, те же эмбеддинги, единственное отличие — нет затухания, консолидации и удаления — и прогнал через идентичный разговор. Реальные результаты:
Я мог бы выбрать две метрики, которые выглядят отлично, и остановиться. Вместо этого я разобрался, почему Synapse проиграл по сырой точности, и нашёл две конкретные, исправимые причины: предварительный фильтр по сходству, который отвергал реальное противоречие, выраженное другими словами (сходство 0.59 при пороге 0.75), и формула переранжирования, где часто вспоминаемый общий факт мог перевесить менее подкреплённый, но более релевантный. Я исправил обе, проверил исправления регрессионными тестами и сквозным тестом на развёрнутом приложении, и задокументировал всё — включая то, что не успел перезапустить полный многочасовой бенчмарк до дедлайна.
График, которому можно доверять, стоит больше, чем график, который льстит.
Если ваш механизм памяти тестируется только в малом масштабе, вы не найдёте настоящих багов. Мои проявились только после 100+ шагов, когда временные метки и значимость реально начали расходиться.
Стройте наивный базовый вариант сначала или хотя бы параллельно. Иметь с чем сравнивать — это превратить «поверьте, это умно» в число.
Когда что-то ломается в середине долгого запуска, сопротивляйтесь желанию замолчать проблему. Мои обёртки повторных попыток и обработка ошибок с откатом и продолжением родились из отказа позволить одному плохому LLM-ответу убить двухчасовой прогон.
Synapse запущен на Alibaba Cloud ECS, код открыт под лицензией MIT, а полное честное описание — включая баги, исправления и цифры до и после — в репозитории.
Репозиторий: github.com/Boweii22/Synapse
Демо: http://8.208.98.93
Видео: youtu.be/0SXzcWqlZog
Создано для Track 1 (MemoryAgent) Global AI Hackathon Series с Qwen Cloud.
Прямо сейчас: если вы строите AI-агента с памятью, не полагайтесь только на векторный поиск. Реализуйте затухание значимости с разным периодом для эпизодических и семантических фактов, добавьте фоновую консолидацию и обнаружение противоречий. Протестируйте на длинных разговорах (100+ шагов), чтобы найти баги с временными метками. И всегда сравнивайте с наивным подходом — только так вы узнаете, действительно ли ваше решение лучше.
Хочешь закрепить знания на практике?
Решай задачи на Algolit — интерактивная платформа для обучения
Начать бесплатно →