Ваш ассистент не помнит, о чем вы говорили вчера? Лечим склероз LLM
Вы сидели вечером, настраивали своего ИИ-помощника. Он идеально отвечал на вопросы, напоминал о задачах, шутил в меру. А наутро — будто его перезагрузили. Новый диалог, чистый лист. Никаких воспоминаний о ваших предпочтениях, проектах, даже о том, что вы просили не упоминать.
Знакомо? Это не злая воля модели — это архитектурное ограничение. LLM живут в моменте. Их контекстное окно — как оперативная память: всё, что выходит за пределы 128K токенов, испаряется. А ещё они путают факты, если не подсунуть им правильный контекст.
Рынок облачных решений предлагает OpenAI с GPT-4o, но каждый запрос стоит денег, а данные утекают на чужие серверы. Многие уже перешли на локальные модели через Ollama, как я описывал в статье «Развёртывание ИИ-агента за один день: Ollama, n8n и локальная языковая модель». Но там мы обходились без персистентной памяти. Сегодня исправляем это.
К июню 2026 года стек созрел: Ollama стабильно держит tool calling, pgvector интегрирован в PostgreSQL, а локальные модели уровня Qwen 3.1, DeepSeek-Coder V3 или Llama 4 Scout работают на обычных игровых видеокартах. Я покажу, как собрать ассистента, который помнит всё, может вызывать инструменты и даже смотреть на картинки. Всё локально, без единого API-ключа.
Архитектура, которая не развалится под грузом памяти
Забудьте про монолитный промпт, который растёт как снежный ком. Проектируем систему из трех слоёв:
- LLM-ядро — Ollama с моделью общего назначения (рекомендую Qwen 3.1 7B Q4_K_M для CPU или 14B для GPU). Она отвечает за генерацию, рассуждения и принятие решений.
- Долговременная память — RAG на pgvector. Каждое сообщение, факт, документ превращается в векторное представление и хранится в PostgreSQL. По запросу извлекаем релевантные куски.
- Агентный слой — набор инструментов (tool calling), которые модель может вызвать: поиск по памяти, добавление факта, обработка изображения, отправка email. Плюс оркестратор, который решает, какой инструмент использовать.
Если вам нужна более сложная организация навыков — взгляните на мой подход Agent Skills. Там каждый навык — это отдельный модуль с собственными инструкциями и памятью. Мы сейчас построим упрощённую версию, но принцип тот же.
Почему pgvector, а не FAISS или Milvus?
Короткий ответ: потому что вы уже используете PostgreSQL. Зачем тащить ещё одну базу? pgvector (актуальная версия 0.8.0) добавляет тип данных vector и индексы IVFFlat или HNSW. Это даёт точный поиск по косинусной близости без лишних движений. На миллионе векторов запрос занимает десятки миллисекунд — для ассистента более чем достаточно.
FAISS быстрее, но требует отдельного сервиса и сложнее в управлении. Для дома или стартапа — pgvector побеждает удобством. Docker-образ PostgreSQL с pgvector есть в официальном реестре.
Пошаговая сборка: от установки до работающего ассистента
1 Поднимаем Ollama и модель
Устанавливаете Ollama (на 22.06.2026 последняя стабильная версия — 0.6.0). Команда для Linux/Mac:
curl -fsSL https://ollama.com/install.sh | sh
Качаем модель. Для ассистента с памятью советую Qwen 3.1 7B — в ней улучшена работа с длинным контекстом и tool calling.
ollama pull qwen3.1:7b-q4_K_M
Проверяем:
ollama run qwen3.1:7b-q4_K_M
2 Разворачиваем PostgreSQL + pgvector
Проще всего через Docker:
docker run -d --name pgvector -e POSTGRES_PASSWORD=mysecret \
-p 5432:5432 pgvector/pgvector:0.8.0-pg16
Создаём базу и таблицу для памяти:
CREATE DATABASE assistant;
\c assistant
CREATE EXTENSION vector;
CREATE TABLE memory (
id SERIAL PRIMARY KEY,
content TEXT,
embedding vector(768), -- для эмбеддингов модели BAAI/bge-small-en-v1.5
metadata JSONB,
created_at TIMESTAMP DEFAULT NOW()
);
CREATE INDEX ON memory USING hnsw (embedding vector_cosine_ops);
Важно: Размерность вектора должна совпадать с эмбеддером. Для bge-small-en-v1.5 — 384, для intfloat/multilingual-e5-large — 1024. Уточните модель, которую используете.
3 Пишем Python-приложение на FastAPI
Создаём виртуальное окружение, ставим зависимости:
mkdir assistant && cd assistant
python -m venv venv && source venv/bin/activate
pip install fastapi uvicorn ollama psycopg2-binary sqlalchemy sentence-transformers
Базовая структура: один файл main.py. Подключаемся к Ollama и PostgreSQL.
4 Слой памяти: RAG-запросы
Эмбеддинги будем получать через отдельную модель (не через саму LLM). Для русского текста хорош intfloat/multilingual-e5-large. Загружаем один раз.
from sentence_transformers import SentenceTransformer
embedder = SentenceTransformer('intfloat/multilingual-e5-large') # 1024
def add_memory(content, metadata={}):
vec = embedder.encode(content).tolist()
conn.execute("INSERT INTO memory (content, embedding, metadata) VALUES (%s, %s, %s)",
(content, vec, json.dumps(metadata)))
conn.commit()
def search_memory(query, top_k=5):
vec = embedder.encode(query).tolist()
rows = conn.execute("""
SELECT content, 1 - (embedding <=> %s::vector) AS score
FROM memory
ORDER BY embedding <=> %s::vector
LIMIT %s
""", (vec, vec, top_k)).fetchall()
return [r[0] for r in rows]
5 Tool calling: как научить модель пользоваться инструментами
Ollama поддерживает функции (tools) с версии 0.4.0. Мы опишем инструменты в формате JSON Schema и передадим их в запросе. Модель сама решит, какой вызвать.
import ollama
tools = [
{
"type": "function",
"function": {
"name": "search_memory",
"description": "Ищет похожие факты в долговременной памяти",
"parameters": {
"type": "object",
"properties": {
"query": {"type": "string", "description": "Запрос"}
},
"required": ["query"]
}
}
},
{
"type": "function",
"function": {
"name": "add_memory",
"description": "Сохраняет новый факт в память",
"parameters": {
"type": "object",
"properties": {
"content": {"type": "string"},
"tags": {"type": "string"}
},
"required": ["content"]
}
}
},
{
"type": "function",
"function": {
"name": "describe_image",
"description": "Распознаёт содержимое изображения",
"parameters": {
"type": "object",
"properties": {
"image_path": {"type": "string"}
},
"required": ["image_path"]
}
}
}
]
response = ollama.chat(
model='qwen3.1:7b-q4_K_M',
messages=[{"role": "user", "content": "Что я говорил про Java в прошлом разговоре?"}],
tools=tools
)
Обрабатываем вызов инструмента в ответе — response.message.tool_calls. После выполнения результат возвращаем модели, чтобы она сформировала финальный ответ.
6 Бинго: Vision-возможности (ассистент видит)
Ollama поддерживает мультимодальные модели. Например, llama4-vision:11b или более лёгкий phi-4-vision:4b. Устанавливаем:
ollama pull llama4-vision:11b
В tool calling добавляем функцию:
response = ollama.chat(
model='llama4-vision:11b',
messages=[{"role": "user", "content": "Опиши это изображение", "images": ["base64_string"]}]
)
Теперь ассистент может анализировать скриншоты, мемы, документы. Результат сохраняем в память.
Запускаем и тестируем
Соберите всё вместе: FastAPI endpoint принимает вопрос, вызывает LLM с инструментами, обрабатывает tool calls, возвращает ответ. Пример curl:
curl -X POST http://localhost:8000/ask \
-H "Content-Type: application/json" \
-d '{"message": "Напомни, что я просил купить", "session_id": "user1"}'
Ассистент сначала ищет в памяти, потом, если ничего нет, спрашивает или сохраняет новое.
Грабли, о которые я споткнулся
- Модель для эмбеддингов vs LLM. Не пытайтесь использовать ту же модель для эмбеддингов — она не для этого. Берите BGE или E5. Загружайте её в Python, а не в Ollama, чтобы не смешивать.
- Осторожно с размером контекста. Если в память скинуть слишком много фактов, модель начнёт их игнорировать. Ограничивайте top_k до 5-10.
- Tool calling на маленьких моделях. Phi-4-mini и подобные могут путать параметры. Qwen 3.1 7B справляется отлично. Llama 4 Scout 8B — тоже хорош.
- Скорость. На CPU Qwen 3.1 7B выдаёт 5-10 токенов/с. На RTX 3060 — 50+. Если нет GPU, берите Phi-4-mini 4B.
- Безопасность. Если даёте инструмент «отправить email» — проверяйте адрес и содержимое. LLM может написать глупость.
Что дальше? Превращаем поделку в продукт
Наш ассистент уже умеет:
- Помнить всё, что вы ему сказали (и возвращать это при необходимости)
- Вызывать функции: поиск, сохранение, распознавание изображений
- Работать полностью локально, без интернета
Но это ещё не полноценный Agent с планированием. Если хотите добавить оркестратор, который сам разбивает задачу на шаги — читайте «Как спроектировать современного AI-агента: от planner/executor до stateful memory». А для круглосуточного дежурства в Telegram — «AI-агент, который не спит: почта, Telegram, systemd и LLM под одной крышей».
Ваш ассистент с долговременной памятью и агентами — это не игрушка. Это замена облачным помощникам, которые стоят денег и воруют данные. Соберите один раз, и он будет служить годами, помня каждый ваш запрос.
Пробуйте, ломайте, улучшайте. И помните: лучший AI — тот, который работает на вас, а не на облачного провайдера.