Graph-RAG на AlloyDB Omni: семантическая память для AI-агентов | AiManual
AiManual Logo Ai / Manual.
13 Фев 2026 Гайд

Семантическая память для ИИ-агента на AlloyDB Omni: Graph-RAG, который не забывает

Пошаговое руководство по реализации долгосрочной семантической памяти для ИИ-агента с использованием AlloyDB Omni и Graph-RAG архитектуры.

Проблема: агенты с короткой памятью

Ты запускаешь ИИ-агента. Он работает отлично первые несколько диалогов, запоминает детали, строит логические цепочки. А потом... обнуляется. Спросишь про вчерашний разговор - он смотрит на тебя пустыми глазами (ну, метафорически). Проблема контекстного рота в AI-агентах - это не просто неудобство, это фундаментальное ограничение всей архитектуры.

Классический RAG с векторами в Pinecone или Chroma - это как кратковременная память. Отлично для фактов, ужасно для связей между ними. Graph-RAG добавляет то, чего не хватало: семантические отношения.

Традиционные системы долговременной памяти для LLM работают с изолированными фрагментами. Graph-RAG превращает эти фрагменты в сеть, где каждая сущность связана с другими. Это не просто "найти похожий текст" - это "найти все, что связано с этой идеей".

Архитектура: SPO + векторы = семантическая сеть

SPO - Subject-Predicate-Object. Триплеты. Основа графовых баз знаний. В Graph-RAG мы используем их для хранения отношений между сущностями, а векторы - для семантического поиска самих сущностей.

Компонент Что хранит Для чего
Векторное хранилище Эмбеддинги сущностей и документов Семантический поиск по смыслу
Графовая база Триплеты SPO (отношения) Поиск связей между сущностями
AlloyDB Omni И то, и другое в одной БД Единый запрос к векторам и графу

Зачем AlloyDB Omni? Потому что он умеет в векторы из коробки (расширение pgvector) и при этом остается полноценной PostgreSQL-совместимой СУБД для графовых данных. Один запрос - получаешь и семантически похожие сущности, и все связи между ними.

💡
На 13.02.2026 AlloyDB Omni поддерживает векторные индексы HNSW и IVFFlat с улучшенной производительностью. Последняя версия включает оптимизации для смешанных запросов (векторы + граф).

Пошаговая реализация: от нуля до работающего агента

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 в зависимости от сложности

Для масштабирования:

  1. Шардируйте по agent_id. Каждый агент - свой набор таблиц или схема.
  2. Используйте материализованные представления для частых графовых путей.
  3. Настройте autovacuum агрессивнее для таблиц отношений - они часто обновляются.

А что дальше? Эволюция семантической памяти

Graph-RAG на AlloyDB Omni - это только начало. На горизонте 2026 года:

  • Мультимодальные эмбеддинги: один вектор для текста, изображений и аудио
  • Временные графы: отношения с временными метками ("знал с 2025 по 2026")
  • Автоматическое сжатие памяти: ИИ определяет, что важно сохранить, а что можно забыть

Самый интересный тренд - распределенная семантическая память. Несколько агентов с разными специализациями, но общей памятью в AlloyDB Omni. Один агент узнает что-то о пользователе - все остальные сразу имеют доступ к этим знаниям. Это уже похоже на архитектуру коллективного разума, только с единым хранилищем вместо роутинга.

🚀
Попробуйте начать с малого. Возьмите одного агента, настройте базовый Graph-RAG. Через неделю вы удивитесь, насколько умнее он стал. Память меняет все.

И последний совет: не пытайтесь построить идеальную систему с первого раза. Семантическая память - это живой организм. Она учится вместе с агентом. Начните, итератируйте, наблюдайте за тем, как меняется поведение системы. Это самый интересный процесс в разработке ИИ-агентов на сегодняшний день.