Векторный поиск и обработка текста
PRX включает конвейер обработки текста, обеспечивающий семантическое извлечение из памяти. Этот конвейер обрабатывает разбиение текста на чанки, векторное преобразование в эмбеддинги, извлечение тем и фильтрацию контента -- преобразуя необработанный текст разговора в поисковые, организованные записи памяти.
Архитектура
Конвейер обработки текста состоит из четырёх этапов, каждый из которых настраивается независимо:
Необработанный текст
│
▼
┌──────────┐ ┌───────────┐ ┌───────────┐ ┌──────────┐
│ Чанкер │───►│ Эмбеддер │───►│ Экстрактор│───►│ Фильтр │
│ │ │ │ │ тем │ │ │
└──────────┘ └───────────┘ └───────────┘ └──────────┘
Разбиение Векторизация Классификация Решение о
текста на каждого по темам сохранении
чанки чанкаВекторный поиск
Векторный поиск обеспечивает извлечение по семантическому сходству -- нахождение воспоминаний, концептуально связанных с запросом, даже при несовпадении точных слов.
Как это работает
- Индексация -- каждый чанк памяти преобразуется в плотный вектор (напр., 768 измерений)
- Хранение -- векторы сохраняются в векторном индексе (sqlite-vec, pgvector или in-memory)
- Запрос -- поисковый запрос преобразуется в эмбеддинг той же моделью
- Извлечение -- индекс возвращает top-K векторов по косинусному сходству
- Переранжирование -- опционально результаты переранжируются с помощью кросс-энкодера для повышения точности
Конфигурация
[memory.vector]
enabled = true
index_type = "sqlite-vec" # "sqlite-vec", "pgvector" или "memory"
similarity_metric = "cosine" # "cosine", "dot_product" или "euclidean"
top_k = 10
similarity_threshold = 0.5
rerank = false
rerank_model = "cross-encoder/ms-marco-MiniLM-L-6-v2"Типы индексов
| Тип индекса | Хранение | Персистентность | Лучше всего для |
|---|---|---|---|
sqlite-vec | Локальный файл | Да | Один пользователь, локальные развёртывания |
pgvector | PostgreSQL | Да | Многопользовательские, продакшен-развёртывания |
memory | В процессе | Нет (только сессия) | Тестирование и эфемерные сессии |
Справочник конфигурации
| Поле | Тип | По умолчанию | Описание |
|---|---|---|---|
enabled | bool | true | Включить или отключить векторный поиск |
index_type | String | "sqlite-vec" | Бэкенд векторного индекса |
similarity_metric | String | "cosine" | Метрика расстояния для сравнения сходства |
top_k | usize | 10 | Количество возвращаемых результатов на запрос |
similarity_threshold | f64 | 0.5 | Минимальный балл сходства (0.0--1.0) для включения в результаты |
rerank | bool | false | Включить переранжирование кросс-энкодером для повышения точности |
rerank_model | String | "" | Имя модели кросс-энкодера (используется только при rerank = true) |
ef_search | usize | 64 | Параметр поиска HNSW (выше = точнее, медленнее) |
Разбиение текста на чанки
Перед преобразованием в эмбеддинги длинный текст должен быть разбит на чанки меньшего размера. PRX предоставляет две стратегии разбиения: с учётом токенов и семантическую.
Разбиение с учётом токенов
Разбиение с учётом токенов разделяет текст по границам токенов, чтобы каждый чанк вмещался в контекстное окно модели эмбеддингов. Оно соблюдает границы слов и предложений, чтобы избежать разрыва посередине слова.
[memory.chunker]
strategy = "token"
max_tokens = 512
overlap_tokens = 64
tokenizer = "cl100k_base" # Токенизатор, совместимый с OpenAIАлгоритм:
- Токенизация входного текста с помощью настроенного токенизатора
- Разбиение на чанки не более
max_tokensтокенов - Каждый чанк перекрывается с предыдущим на
overlap_tokensдля сохранения контекста на границах - Границы чанков корректируются для выравнивания с разрывами предложений или абзацев, когда это возможно
Семантическое разбиение
Семантическое разбиение использует сходство эмбеддингов для нахождения естественных тематических границ в тексте. Вместо разбиения по фиксированному количеству токенов оно определяет, где происходит смена темы.
[memory.chunker]
strategy = "semantic"
max_tokens = 1024
min_tokens = 64
breakpoint_threshold = 0.3Алгоритм:
- Разбиение текста на предложения
- Вычисление эмбеддингов для каждого предложения
- Расчёт косинусного сходства между последовательными предложениями
- Когда сходство падает ниже
breakpoint_threshold, вставляется граница чанка - Мелкие чанки (ниже
min_tokens) объединяются с соседними
Справочник конфигурации разбиения
| Поле | Тип | По умолчанию | Описание |
|---|---|---|---|
strategy | String | "token" | Стратегия разбиения: "token" или "semantic" |
max_tokens | usize | 512 | Максимум токенов на чанк |
overlap_tokens | usize | 64 | Перекрытие между последовательными чанками (только токенная стратегия) |
tokenizer | String | "cl100k_base" | Имя токенизатора для подсчёта токенов |
min_tokens | usize | 64 | Минимум токенов на чанк (только семантическая стратегия) |
breakpoint_threshold | f64 | 0.3 | Порог падения сходства для тематических границ (только семантическая стратегия) |
Выбор стратегии
| Критерий | С учётом токенов | Семантическое |
|---|---|---|
| Скорость | Быстро (без вызовов эмбеддингов при разбиении) | Медленнее (требует эмбеддинг для каждого предложения) |
| Качество | Хорошо для однородного контента | Лучше для многотемных документов |
| Предсказуемость | Стабильные размеры чанков | Переменные размеры чанков |
| Применение | Логи чатов, короткие сообщения | Длинные документы, заметки совещаний |
Извлечение тем
PRX автоматически извлекает темы из записей памяти для организации по категориям. Темы улучшают извлечение, обеспечивая фильтрованный поиск в конкретных областях.
Как это работает
- После разбиения каждый чанк анализируется на тематические ключевые слова и семантическое содержание
- Экстрактор тем назначает одну или несколько тематических меток из настраиваемой таксономии
- Темы хранятся вместе с записью памяти как метаданные
- При вспоминании запросы могут опционально фильтроваться по теме для сужения результатов
Конфигурация
[memory.topics]
enabled = true
max_topics_per_entry = 3
taxonomy = "auto" # "auto", "fixed" или "hybrid"
custom_topics = [] # используется только при taxonomy = "fixed" или "hybrid"
min_confidence = 0.6Режимы таксономии
| Режим | Описание |
|---|---|
auto | Темы генерируются динамически из контента. Новые темы создаются по необходимости. |
fixed | Назначаются только темы из custom_topics. Контент, не совпадающий ни с одной темой, остаётся без категории. |
hybrid | Предпочитает custom_topics, но создаёт новые темы, когда контент не совпадает с существующими метками. |
Справочник конфигурации тем
| Поле | Тип | По умолчанию | Описание |
|---|---|---|---|
enabled | bool | true | Включить или отключить извлечение тем |
max_topics_per_entry | usize | 3 | Максимум тематических меток на запись памяти |
taxonomy | String | "auto" | Режим таксономии: "auto", "fixed" или "hybrid" |
custom_topics | [String] | [] | Пользовательские тематические метки для fixed/hybrid таксономий |
min_confidence | f64 | 0.6 | Минимальный балл уверенности (0.0--1.0) для назначения темы |
Фильтрация контента
Не каждое сообщение стоит сохранять в долговременной памяти. Фильтр контента применяет эвристики автосохранения для решения, какое содержимое следует сохранять, а какое -- отбрасывать.
Эвристики автосохранения
Фильтр оценивает каждый кандидат записи памяти по нескольким критериям:
| Эвристика | Описание | Вес |
|---|---|---|
| Плотность информации | Соотношение уникальных токенов к общему количеству. Малоплотный текст (напр., "ок", "спасибо") отфильтровывается | Высокий |
| Новизна | Сходство с существующими воспоминаниями. Контент, слишком похожий на уже сохранённый, пропускается | Высокий |
| Релевантность | Семантическое сходство с известными интересами пользователя и активными темами | Средний |
| Действенность | Наличие элементов действий, решений или обязательств (напр., "я сделаю...", "давайте...") | Средний |
| Смещение к свежести | Недавний контекст получает больший вес для краткосрочной релевантности | Низкий |
Составной балл вычисляется как взвешенная сумма. Записи с баллом ниже autosave_threshold не сохраняются.
Конфигурация
[memory.filter]
enabled = true
autosave_threshold = 0.4
novelty_threshold = 0.85 # пропуск при >85% сходства с существующей памятью
min_length = 20 # пропуск записей короче 20 символов
max_length = 10000 # обрезка записей длиннее 10 000 символов
exclude_patterns = [
"^(ok|thanks|got it|sure)$",
"^\\s*$",
]Справочник конфигурации фильтра
| Поле | Тип | По умолчанию | Описание |
|---|---|---|---|
enabled | bool | true | Включить или отключить фильтрацию контента |
autosave_threshold | f64 | 0.4 | Минимальный составной балл (0.0--1.0) для сохранения воспоминания |
novelty_threshold | f64 | 0.85 | Максимальное сходство с существующими воспоминаниями перед дедупликацией |
min_length | usize | 20 | Минимальная длина символов для записи памяти |
max_length | usize | 10000 | Максимальная длина символов (более длинные записи обрезаются) |
exclude_patterns | [String] | [] | Регулярные выражения для контента, который не следует сохранять |
Полный пример конвейера
Полная конфигурация, объединяющая все четыре этапа:
[memory]
backend = "embeddings"
[memory.embeddings]
provider = "ollama"
model = "nomic-embed-text"
dimension = 768
[memory.vector]
enabled = true
index_type = "sqlite-vec"
top_k = 10
similarity_threshold = 0.5
[memory.chunker]
strategy = "semantic"
max_tokens = 1024
min_tokens = 64
breakpoint_threshold = 0.3
[memory.topics]
enabled = true
taxonomy = "hybrid"
custom_topics = ["coding", "architecture", "debugging", "planning"]
[memory.filter]
enabled = true
autosave_threshold = 0.4
novelty_threshold = 0.85Связанные страницы
- Обзор системы памяти
- Бэкенд эмбеддингов -- настройка провайдера эмбеддингов
- Бэкенд SQLite -- локальное хранилище для sqlite-vec индекса
- Бэкенд PostgreSQL -- хранилище для pgvector индекса
- Гигиена памяти -- стратегии компактизации и очистки