Проблема: агенты с короткой памятью
Ты запускаешь ИИ-агента. Он работает отлично первые несколько диалогов, запоминает детали, строит логические цепочки. А потом... обнуляется. Спросишь про вчерашний разговор - он смотрит на тебя пустыми глазами (ну, метафорически). Проблема контекстного рота в AI-агентах - это не просто неудобство, это фундаментальное ограничение всей архитектуры.
Классический RAG с векторами в Pinecone или Chroma - это как кратковременная память. Отлично для фактов, ужасно для связей между ними. Graph-RAG добавляет то, чего не хватало: семантические отношения.
Традиционные системы долговременной памяти для LLM работают с изолированными фрагментами. Graph-RAG превращает эти фрагменты в сеть, где каждая сущность связана с другими. Это не просто "найти похожий текст" - это "найти все, что связано с этой идеей".
Архитектура: SPO + векторы = семантическая сеть
SPO - Subject-Predicate-Object. Триплеты. Основа графовых баз знаний. В Graph-RAG мы используем их для хранения отношений между сущностями, а векторы - для семантического поиска самих сущностей.
| Компонент | Что хранит | Для чего |
|---|---|---|
| Векторное хранилище | Эмбеддинги сущностей и документов | Семантический поиск по смыслу |
| Графовая база | Триплеты SPO (отношения) | Поиск связей между сущностями |
| AlloyDB Omni | И то, и другое в одной БД | Единый запрос к векторам и графу |
Зачем AlloyDB Omni? Потому что он умеет в векторы из коробки (расширение pgvector) и при этом остается полноценной PostgreSQL-совместимой СУБД для графовых данных. Один запрос - получаешь и семантически похожие сущности, и все связи между ними.
Пошаговая реализация: от нуля до работающего агента
1 Развертывание AlloyDB Omni
Берем AlloyDB Omni потому что он работает где угодно: локально, в своем дата-центре, в облаке. Не привязан к конкретному вендору. Устанавливаем:
# Скачиваем последнюю версию на 13.02.2026
curl -LO https://storage.googleapis.com/alloydb-omni/releases/latest/alloydb-omni-installer.sh
chmod +x alloydb-omni-installer.sh
# Запускаем установку
sudo ./alloydb-omni-installer.sh \
--install \
--components=alloydb \
--pg-version=17 \
--vector-extension=pgvector-0.7.0
Не забудьте настроить аутентификацию! AlloyDB Omni по умолчанию использует scram-sha-256. Для продакшена настройте TLS и ограничьте доступ по IP.
2 Создаем схему для семантической памяти
Здесь важна структура. Нам нужны таблицы для сущностей, отношений и векторные индексы:
-- Включаем расширения
CREATE EXTENSION IF NOT EXISTS vector;
CREATE EXTENSION IF NOT EXISTS pg_trgm;
-- Таблица сущностей (предметы, люди, концепции)
CREATE TABLE entities (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name TEXT NOT NULL,
type TEXT, -- 'person', 'organization', 'concept', 'event'
description TEXT,
embedding vector(1536), -- для моделей типа text-embedding-3-large
metadata JSONB,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
-- Таблица отношений (триплеты SPO)
CREATE TABLE relationships (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
subject_id UUID REFERENCES entities(id) ON DELETE CASCADE,
predicate TEXT NOT NULL, -- 'works_at', 'knows', 'created', 'is_a'
object_id UUID REFERENCES entities(id) ON DELETE CASCADE,
confidence FLOAT DEFAULT 1.0,
context TEXT, -- оригинальное предложение, откуда извлекли
metadata JSONB,
created_at TIMESTAMP DEFAULT NOW()
);
-- Векторный индекс для быстрого поиска
CREATE INDEX ON entities USING hnsw (embedding vector_cosine_ops);
-- Индексы для графовых запросов
CREATE INDEX ON relationships(subject_id);
CREATE INDEX ON relationships(object_id);
CREATE INDEX ON relationships(predicate);
3 Извлечение знаний из диалогов
Вот где появляется OpenClaw - фреймворк для извлечения структурированных данных из текста. Берем диалог агента и вытаскиваем сущности и отношения:
import openclaw
from pgvector.psycopg2 import register_vector
import psycopg2
# Инициализируем OpenClaw с последней моделью на 13.02.2026
# OpenClaw 2.3 поддерживает мультимодальное извлечение
claw = openclaw.OpenClaw(
model="claw-2.3-mistral", # Последняя версия на февраль 2026
device="cuda" # или "cpu" для локального запуска
)
# Подключаемся к AlloyDB Omni
conn = psycopg2.connect(
host="localhost",
database="agent_memory",
user="agent",
password="secure_password"
)
register_vector(conn)
cur = conn.cursor()
def extract_and_store(dialog_text: str, agent_id: str):
"""Извлекает сущности и отношения из диалога"""
# OpenClaw извлекает триплеты SPO
triplets = claw.extract_triplets(dialog_text)
# Также извлекаем сущности для векторного поиска
entities = claw.extract_entities(dialog_text)
for entity in entities:
# Генерируем эмбеддинг с помощью text-embedding-3-large
embedding = generate_embedding(entity["name"] + " " + entity["description"])
# Сохраняем в базу
cur.execute("""
INSERT INTO entities (name, type, description, embedding, metadata)
VALUES (%s, %s, %s, %s, %s)
ON CONFLICT (name, type) DO UPDATE
SET description = EXCLUDED.description,
embedding = EXCLUDED.embedding,
updated_at = NOW()
RETURNING id
""", (entity["name"], entity["type"], entity["description"], embedding, {"agent_id": agent_id}))
entity_id = cur.fetchone()[0]
entity["db_id"] = entity_id
# Сохраняем отношения
for triplet in triplets:
subject_id = find_entity_id(triplet["subject"], entities)
object_id = find_entity_id(triplet["object"], entities)
if subject_id and object_id:
cur.execute("""
INSERT INTO relationships
(subject_id, predicate, object_id, context, metadata)
VALUES (%s, %s, %s, %s, %s)
""", (subject_id, triplet["predicate"], object_id,
triplet["context"], {"source": "dialog"}))
conn.commit()
4 Гибридный поиск: векторы + граф
Магия Graph-RAG в одном запросе. Ищем не только похожие сущности, но и все, что с ними связано:
def semantic_search(query: str, agent_id: str, limit: int = 10):
"""Поиск в семантической памяти"""
# Эмбеддинг запроса
query_embedding = generate_embedding(query)
# Гибридный запрос: похожие сущности + их связи
cur.execute("""
WITH similar_entities AS (
-- Векторный поиск похожих сущностей
SELECT id, name, description,
embedding <=> %s as similarity
FROM entities
WHERE metadata->>'agent_id' = %s
ORDER BY embedding <=> %s
LIMIT 5
),
related_entities AS (
-- Графовый поиск связанных сущностей
SELECT DISTINCT e.id, e.name, e.description,
r.predicate as relation_type
FROM similar_entities se
JOIN relationships r ON r.subject_id = se.id OR r.object_id = se.id
JOIN entities e ON e.id = CASE
WHEN r.subject_id = se.id THEN r.object_id
ELSE r.subject_id
END
WHERE e.metadata->>'agent_id' = %s
)
-- Объединяем результаты
SELECT * FROM (
SELECT id, name, description, similarity,
'direct' as source FROM similar_entities
UNION
SELECT id, name, description, 0.0 as similarity,
'related_via_' || relation_type as source
FROM related_entities
) results
ORDER BY similarity ASC
LIMIT %s
""", (query_embedding, agent_id, query_embedding, agent_id, limit))
return cur.fetchall()
Интеграция с ИИ-агентом
Теперь подключаем семантическую память к агенту. Вместо того чтобы каждый раз начинать с чистого листа, агент может запрашивать контекст:
class AgentWithMemory:
def __init__(self, agent_id: str):
self.agent_id = agent_id
self.memory_db = MemoryDatabase() # Наш Graph-RAG
def process_message(self, user_input: str) -> str:
# 1. Поиск в семантической памяти
relevant_context = self.memory_db.semantic_search(
user_input,
self.agent_id
)
# 2. Формируем промпт с контекстом
context_str = "\n".join([
f"- {row['name']}: {row['description']} (источник: {row['source']})"
for row in relevant_context
])
prompt = f"""
Ты - ИИ-агент с долгосрочной памятью.
Контекст из предыдущих диалогов:
{context_str}
Текущий запрос пользователя: {user_input}
Ответь, учитывая контекст выше.
"""
# 3. Генерируем ответ
response = generate_response(prompt)
# 4. Сохраняем новый диалог в память
self.memory_db.store_interaction(
user_input=user_input,
agent_response=response,
agent_id=self.agent_id
)
return response
Ошибки, которые все совершают (и как их избежать)
Ошибка 1: Хранить все подряд. Каждый чих агента - в память. Через неделю поиск замедляется в 10 раз.
Решение: Фильтруйте. Сохраняйте только значимые взаимодействия. Настройте политику очистки: старые малозначимые связи удаляйте.
Ошибка 2: Одинаковые эмбеддинги для разных типов сущностей. "Яблоко" (фрукт) и "Apple" (компания) получат похожие векторы.
Решение: Добавляйте тип сущности в текст для эмбеддинга: "фрукт яблоко" vs "компания Apple".
Ошибка 3: Игнорировать confidence score в отношениях. OpenClaw может ошибаться в извлечении триплетов.
Решение: Используйте порог уверенности. Отношения с confidence < 0.7 помечайте для проверки или игнорируйте.
Производительность и масштабирование
AlloyDB Omni на февраль 2026 показывает такие цифры:
- Векторный поиск по 1M записей: < 50ms с индексом HNSW
- Графовые запросы с 3+ уровнями связей: < 100ms
- Смешанные запросы: 70-150ms в зависимости от сложности
Для масштабирования:
- Шардируйте по agent_id. Каждый агент - свой набор таблиц или схема.
- Используйте материализованные представления для частых графовых путей.
- Настройте autovacuum агрессивнее для таблиц отношений - они часто обновляются.
А что дальше? Эволюция семантической памяти
Graph-RAG на AlloyDB Omni - это только начало. На горизонте 2026 года:
- Мультимодальные эмбеддинги: один вектор для текста, изображений и аудио
- Временные графы: отношения с временными метками ("знал с 2025 по 2026")
- Автоматическое сжатие памяти: ИИ определяет, что важно сохранить, а что можно забыть
Самый интересный тренд - распределенная семантическая память. Несколько агентов с разными специализациями, но общей памятью в AlloyDB Omni. Один агент узнает что-то о пользователе - все остальные сразу имеют доступ к этим знаниям. Это уже похоже на архитектуру коллективного разума, только с единым хранилищем вместо роутинга.
И последний совет: не пытайтесь построить идеальную систему с первого раза. Семантическая память - это живой организм. Она учится вместе с агентом. Начните, итератируйте, наблюдайте за тем, как меняется поведение системы. Это самый интересный процесс в разработке ИИ-агентов на сегодняшний день.