Найти в Дзене
AI в Продакшене

pgvector: как «дать память» AI-ассистенту

Представьте медсервис, где AI ассистент отвечает не общими фразами, а ссылками на конкретные клинические рекомендации, выписки и результаты анализов. Он не «угадывает», а быстро находит релевантные фрагменты среди тысяч страниц. Секрет — в векторах. А аккуратным «чемоданом» для них становится расширение pgvector. Обычный поиск по словам («болит голова») часто промазывает: термины могут отличаться, формулировки — тоже. Векторный поиск работает по смыслу: «головная боль после физнагрузки у подростка» окажется близок к «эксерционная цефалгия в подростковом возрасте». Для ассистента это критично. Он сначала подбирает контекст, а уже потом генерирует ответ — тот самый RAG. Мы превращаем текст в точку в многомерном пространстве — эмбеддинг. Похожие тексты → близкие точки.
Дальше остаётся: хранить, быстро искать ближайшие точки и возвращать оригинальные кусочки текста. CREATE TABLE chunks (
id bigserial PRIMARY KEY,
doc_id bigint NOT NULL,
section text,
conten
Оглавление
pgvector в ИИ
pgvector в ИИ

Представьте медсервис, где AI ассистент отвечает не общими фразами, а ссылками на конкретные клинические рекомендации, выписки и результаты анализов. Он не «угадывает», а быстро находит релевантные фрагменты среди тысяч страниц.

Секрет — в векторах. А аккуратным «чемоданом» для них становится расширение pgvector.

Зачем это вообще нужно

Обычный поиск по словам («болит голова») часто промазывает: термины могут отличаться, формулировки — тоже. Векторный поиск работает по смыслу: «головная боль после физнагрузки у подростка» окажется близок к «эксерционная цефалгия в подростковом возрасте». Для ассистента это критично. Он сначала подбирает контекст, а уже потом генерирует ответ — тот самый RAG.

Вектора на пальцах

Мы превращаем текст в точку в многомерном пространстве — эмбеддинг. Похожие тексты → близкие точки.

Дальше остаётся: хранить, быстро искать ближайшие точки и возвращать оригинальные кусочки текста.

Почему именно PostgreSQL

  • Одна база, меньше зоопарка. Документы, пользователи, права, биллинг и векторы — всё рядом.
  • ACID и бэкапы. Те же привычные транзакции, реплики, восстановление.
  • Прозрачные права. Легко разделять данные по проектам и пользователям.
  • Стоимость. Часто дешевле отдельных «векторных» движков, особенно в начале.

Что даёт pgvector

  • Поле для «смыслового отпечатка» текста.

    В таблице появляется колонка vector(...) — в неё мы кладём числовой «отпечаток смысла» фрагмента текста. Думаете о нём как о компактном резюме содержания в цифрах.
  • Поиск «по смыслу», а не по словам.

    Есть операции сравнения, которые понимают, насколько два отпечатка похожи. Итог: «мигрень после нагрузки» найдёт «эксерционная головная боль», даже если словоформы разные.
  • Быстрые индексы для такого поиска.

    Как и для обычного поиска по тексту, тут есть специальные индексы, чтобы не перебирать всё подряд:
    Простой быстрый индекс (под капотом — разбиение на «коробки»). Хорош при больших объёмах, но иногда требует тонкой настройки.
    Умный граф-индекс (строит сеть «похожих на похожих»). Очень хорошо ищет на чтении и обычно даёт более точные результаты.

    Не важно, как они называются внутри — важнее, что поиск становится
    быстрым и точным.
  • Работает прямо в PostgreSQL.

    Всё — обычные таблицы и индексы вашей базы. Те же бэкапы, реплики, права доступа. Не нужно поднимать отдельный «векторный» сервис.

Как это выглядит вживую

  • Храним фрагменты (кусочки документов) и их эмбеддинги. Например:
CREATE TABLE chunks (
id bigserial PRIMARY KEY,
doc_id bigint NOT NULL,
section text,
content text NOT NULL,
embedding vector(768), -- та самая «точка»
created_at timestamptz default now()
);
  • Индекс для ANN-поиска (пример для HNSW*с косинусом):
CREATE INDEX ON chunks
USING hnsw (embedding vector_cosine_ops);
  • Запрос «найди смыслово близкие кусочки»:
-- :q — эмбеддинг вопроса пользователя
SELECT id, doc_id, content
FROM chunks
ORDER BY embedding <=> :q -- метрика близости (чем меньше, тем ближе)
LIMIT 5;
  • Дальше ассистент склеит эти 5 фрагментов в контекст и сформирует ответ. Тут в ответ можно добавить ссылки на источники и предупредит о границах ответственности.

* Индекс HNSW (Hierarchical Navigable Small World) — это современный, высокоэффективный алгоритм для приблизительного поиска ближайших соседей (ANNS)

Мини-история из медицины

Пациентка спрашивает: «Можно ли сочетать препарат А с Б при гипотиреозе?»

Ассистент превращает вопрос в вектор, за миллисекунды вытягивает из базы пару релевантных фрагментов: выдержку из методички по лекарственным взаимодействиям и пункт из локального протокола. В ответе — аккуратная рекомендация с цитатами, ссылкой на источник и датой версии документа. Магии нет — есть хороший векторный поиск.

Тонкости про которые лучше не забывать

Размерность и нормализация.

«Эмбеддинг» = числовой отпечаток текста. У разных моделей длина этого отпечатка разная (например, 384, 768, 1024 чисел).
Для метрики «косинусное сходство» полезно
нормировать вектор (привести длину к 1) — так сравнение работает стабильнее.

Параметры индекса.

  • IVFFlat (Inverted File Index). Идея: сначала грубо разбиваем пространство на «корзины», потом ищем внутри лучших корзин.
    Два главных рычага:
    lists — сколько корзин сделать. Больше списков → точнее, но дольше строится и больше памяти.
    probes — в скольких корзинах искать при запросе. Больше зондов → точнее, но медленнее ответ.
    Простое правило: начните с lists ≈ sqrt(числа_строк) и probes ≈ 1–5% от lists, дальше подбирайте по замерам.
  • HNSW (Hierarchical Navigable Small World). Идея: строится «граф похожести» и поиск идёт по «соседям соседей». Обычно даёт отличную точность на чтении.
    Параметры:
    m — среднее количество связей у узла (чем больше, тем точнее и тяжелее по памяти).
    ef_construction — тщательность при построении (влияет на качество и время построения).
    ef_search — тщательность при поиске (чем больше, тем точнее и медленнее).
    Старт: m=16, ef_construction=200, ef_search=40–100, потом доводите по метрикам.

Гибридный поиск. BM25 + векторы.

BM25 — классический текстовый поиск «по словам» (как в поисковиках).
Схема: сначала BM25 быстро отбирает верхние N кандидатов по словам, потом
пересортируем их по «смысловой близости» (косинус по эмбеддингам).
Это уменьшает шум и ускоряет работу, особенно на больших базах.

Гигиена данных.

  • Чанки без мусора. Режем документы на фрагменты, но:
    не допускаем длинных хвостов «шапка/футер/меню»;
    не делаем сильных пересечений между кусками (только небольшой «оверлап» 10–15% при необходимости).
  • Версии и актуальность. Храним поля вроде valid_from / valid_to, чтобы ассистент не тянул устаревшее.
  • Метаданные. Источник, дата, тип материала — потом пригодится для фильтров и объяснимости.

Эксплуатация (чтобы не «грелось» и не падало)

  • Память и тепло. Большие индексы = большой RAM и CPU при построении. Планируйте окно построения/перестроения.
  • Автовакуум и обслуживание. Следим, чтобы таблицы и индексы не раздувались; подстраиваем autovacuum и maintenance_work_mem под реальные размеры данных.
  • Бэкапы и реплики. Это обычный Postgres — используйте ваш стандартный WAL-бэкап, репликацию и мониторинг.

Как понять, что всё работает

  • Recall@k (процент «правильных» среди топ-k).
    Берём набор тестовых запросов, для каждого смотрим топ-k найденных фрагментов.
    Recall@k показывает, как часто среди них есть нужный фрагмент. Хотим, чтобы рос при приемлемом времени ответа.
  • Время ответа P95 / P99.
    P95 — 95-й перцентиль: 95% запросов быстрее этого времени. P99 — 99-й перцентиль. Смотрим, чтобы «хвосты» не улетали (иначе пользователи страдают).
  • Доля ответов с источниками.
    Ассистент должен ссылаться на найденные фрагменты. Чем чаще есть понятный источник, тем меньше «придуманных» ответов.
  • Обратная связь пользователей: простые лайки/дизлайки + комментарии сильно ускоряют улучшения. Простая кнопка сильно ускоряет улучшение качества: можно автоматически переобучать ранжирование и корректировать параметры индекса.

Pgvector превращает PostgreSQL в «память по смыслу» — именно ту, что нужна AI-ассистенту. Вы не строите новый зоопарк сервисов, не таскаете данные туда-сюда, а просто добавляете ещё один тип и индекс. В AI агентах это даёт ощутимую практическую пользу: точные ответы, проверяемые источники и уверенность, что ассистент не выдумает то, чего нет в документах.

Если у вас есть куча PDF, протоколов и «локальных правил» — первый шаг прост: нарежьте тексты на аккуратные чанки, посчитайте эмбеддинги, положите их в pgvector. Остальное — дело инженерной дисциплины и пары удачных параметров индекса.