English translation is not available yet. Showing Russian content.

Агент с памятью через векторную БД

ТЕХНИЧЕСКОЕ ЗАДАНИЕ: Агент с памятью через векторную БД

1. Цель задачи

Разработать агента на базе LangGraph, который сохраняет долгосрочную память в векторной базе данных Qdrant. Агент должен уметь извлекать релевантные факты из прошлых диалогов и использовать их для ответов, даже после десяти и более смен тем. Главная задача — не просто хранить историю чата, а реализовать семантический поиск для релевантного контекста, чтобы агент «помнил» важные детали сквозь диалоги.

Ключевой результат Рабочий агент, который корректно отвечает на вопрос, требующий знания факта из раннего диалога (из перечня 10+ диалогов), с точностью recall@1 ≥ 0.7.


2. Исходные данные

Что нужноОткуда взять
LangGraph агент (заготовка)Создать самому (простой ReAct-агент) или взять из Pet 220
Векторная БД QdrantDocker-образ qdrant/qdrant или SaaS на cloud.qdrant.io
Модель эмбеддинговsentence-transformers/all-MiniLM-L6-v2 (локально) или OpenAI text-embedding-3-small
LLM (для агента)OpenAI GPT-4o / Ollama (llama3.2:3b)
Набор тестовых диалоговСгенерировать самостоятельно (10+ уникальных сценариев)

Если нет реального инструмента — симулируем:

  1. Qdrant — запустить локально через Docker:
    docker run -d --name qdrant -p 6333:6333 qdrant/qdrant
    
  2. LLM — использовать Ollama + модель llama3.2:3b (бесплатно, локально).
    ollama pull llama3.2:3b
    
  3. Тестовые диалоги — написать Python-скрипт, который генерирует 12 коротких диалогов (по 3-4 реплики) на разные темы, с перекрестными ссылками. Например:
    • Диалог 1: пользователь говорит, что любит готовить пасту.
    • Диалог 9: вопрос «Какой рецепт пасты я упоминал?».

3. Технологический стек

КомпонентИнструментыНазначение
Фреймворк агентаLangGraph (Python)Построение графа агента с состояниями
Векторная БДQdrant (v1.12+)Хранение и поиск семантических фактов
Эмбеддингиsentence-transformers (all-MiniLM-L6-v2)Преобразование текста в векторы
LLMOpenAI API / OllamaГенерация ответов и синтез памяти
Клиент Qdrantqdrant-client (Python)Взаимодействие с коллекциями
ТестированиеPytest + скриптыПроверка recall и воспроизводимости

4. Этапы выполнения

Этап 1: Создание базового LangGraph агента (1 час)

Действия

  1. Установить зависимости: langgraph, langchain-openai (или langchain-ollama), qdrant-client, sentence-transformers.
  2. Реализовать класс MemoryAgentState с полями:
    • messages: list — история текущего диалога (включая системные сообщения)
    • memory_summaries: list — извлечённые факты из прошлых диалогов (short-term память)
  3. Построить граф с узлами:
    • retrieve_memory — получение релевантных фактов из Qdrant по последнему запросу пользователя
    • `generate_response`` — вызов LLM с промптом, включающим память и историю
    • `update_memory`` — после ответа агента извлечение ключевых фактов и сохранение в Qdrant
  4. Определить рёбра: после generate_response → всегда update_memory → цикл.

Ожидаемый результат этапа Агент отвечает на простые вопросы без памяти, граф работает.


Этап 2: Интеграция Qdrant и эмбеддингов (1 час)

Действия

  1. Создать класс VectorMemory:
    • __init__: подключение к Qdrant (QdrantClient(host="localhost", port=6333))
    • create_collection(name="agent_memory", size=384): размер эмбеддинга для all-MiniLM-L6-v2
    • add_fact(session_id, text, metadata=None): эмбеддинг текста → upsert в коллекцию
    • search(query_text, top_k=5): эмбеддинг запроса → search → возвращает тексты и метаданные
  2. В узле retrieve_memory:
    • Извлечь последнее пользовательское сообщение из state.messages
    • Вызвать memory.search(last_user_message)
    • Добавить найденные факты в state.memory_summaries
  3. В узле update_memory:
    • Извлечь ответ агента из state.messages[-1]
    • С помощью LLM выделить ключевые факты (например, через промпт «Извлеки факты из последнего ответа»)
    • Сохранить каждый факт в Qdrant через memory.add_fact(session_id, fact_text)

Ожидаемый результат этапа Агент может сохранять однократный факт и потом его извлекать.


Этап 3: Генерация тестовых диалогов и сквозной сценарий (45 мин)

Действия

  1. Написать скрипт generate_dialogs.py, который создаёт 12 диалогов вида:
    user: Моё любимое блюдо — карбонара.
    assistant: Запомнил! Карбонара — твоё любимое блюдо.
    
    (для разных тем: хобби, работа, личные данные и т.д.)
  2. В диалогах №6, №9, №12 задать перекрёстные вопросы, например:
    • Диалог 6: «Помнишь, что я говорил про карбонару?»
    • Диалог 9: «Какое моё любимое блюдо?»
    • Диалог 12: «Что я люблю готовить?»
  3. Запустить цикл: для каждого диалога очистить memory_summaries (но не Qdrant), передать сообщения агенту, собрать ответы.
  4. Сохранить все факты в Qdrant с единым session_id (например, "test_user_1").

Ожидаемый результат этапа Подготовлены 12 диалогов и скрипт для автоматического прогона.


Этап 4: Тестирование долгосрочной памяти (1 час)

Действия

  1. Написать тест в pytest:
    • После завершения всех 12 диалогов симулировать новый диалог с вопросом «Какое моё любимое блюдо?»
    • Проверить, что ответ агента содержит слово «карбонара» (или полное название).
    • Измерить recall@1: из Qdrant по запросу «любимое блюдо» должен вернуться факт с текстом «карбонара» на первой позиции.
  2. Если recall@1 < 0.7:
    • Увеличить top_k при поиске до 10
    • Улучшить промпт в update_memory — добавить дедупликацию (проверить по cosine similarity > 0.9 с существующими фактами)
    • Перетестировать.
  3. Дополнительно: проверить, что агент не «забывает» при смене темы между диалогами.

Ожидаемый результат этапа recall@1 ≥ 0.7, ответ на сквозной вопрос корректен.


Этап 5: Оптимизация и документирование (30 мин)

Действия

  1. Добавить логирование (logging.debug) для каждого шага — чтобы дебажить.
  2. Написать краткую документацию в README:
    • Архитектура агента (граф).
    • Команды запуска.
    • Как воспроизвести тест.
  3. Сложить код в структуру:
    agent_memory/
    ├── agent.py          # граф
    ├── vector_memory.py  # класс для Qdrant
    ├── prompts.py        # шаблоны
    ├── tests/
    │   └── test_memory.py
    ├── requirements.txt
    └── README.md
    

Ожидаемый результат этапа Проект готов к демонстрации и повторному использованию.


5. Критерии приемки (Definition of Done)

  • Агент отвечает на вопросы без памяти (базовый функционал).
  • Факты из первых 5 диалогов доступны в 10-м диалоге (проверено тестом).
  • Qdrant хранит не менее 50 фактов после всех диалогов.
  • recall@1 при поиске факта по смыслу не ниже 0.7.
  • Код размещён в структурированном репозитории, есть requirements.txt.
  • Написана документация (README) с инструкцией по запуску.
  • Агент корректно обрабатывает пустой результат поиска (нет релевантных фактов).
  • Граф агента не зацикливается (максимум 5 итераций за один диалог).

6. Ожидаемый результат

Основной артефакт папка agent_memory/ с рабочим кодом, файлы:

  • agent.py — граф LangGraph
  • vector_memory.py — обёртка Qdrant
  • tests/test_memory.pypytest с тестом на recall

Дополнительно

  • Дамп фактов из Qdrant (можно экспортировать как JSON)
  • Лог работы агента за 12 диалогов (по желанию)

Содержание agent.py: граф из трёх узлов, функция компиляции, точка входа для интерактивного чата.


7. Возможные сложности и их решение

СложностьРешение
LLM извлекает шум вместо фактовУточнить промпт: «Извлеки только конкретные факты, не обобщения». Использовать few-shot примеры.
Дублирование фактов в QdrantПеред вставкой проверить cosine similarity с существующими фактами в коллекции. Не добавлять, если >0.95.
Размер эмбеддингов не совпадаетall-MiniLM-L6-v2 возвращает 384, проверить collection.get_info().config.params.vectors.size.
Агент отвечает слишком длинноОграничить max_tokens и добавить в системный промпт «Отвечай кратко».
Qdrant не отвечает локальноПроверить Docker-контейнер, порт 6333, использовать python -m qdrant_client для теста.
Тест не проходит из-за случайности LLMЗаморозить seed для LLM (если есть поддержка) или перезапустить несколько раз.

8. Бюджет времени (оценка)

ЭтапВремя
1. Базовый LangGraph агент1 ч
2. Интеграция Qdrant1 ч
3. Генерация тестовых диалогов45 мин
4. Тестирование памяти1 ч
5. Оптимизация и документация30 мин
Итого4 ч 15 мин

Примечание Если выполняете задачу первый раз, заложите +1-2 часа на отладку Qdrant и эмбеддингов.


9. Связанные вопросы из базы знаний

ВопросТема
42LangGraph: StateGraph vs MessageGraph
57Интеграция Qdrant с LangChain
128Семантический поиск с cosine similarity
301ReAct агент с памятью
512Извлечение фактов с помощью LLM
789Pytest для RAG-систем
850Деплой Qdrant через Docker Compose

10. Чек-лист самопроверки

  • Я установил все зависимости из requirements.txt и запустил Qdrant.
  • Я проверил, что агент отвечает на обычный вопрос без памяти (до интеграции).
  • Я написал тест test_memory.py и запустил его — он проходит.
  • Я убедился, что в коде нет хардкода паролей/токенов (только переменные окружения).
  • Я закоммитил код в Git с осмысленным сообщением.