Глава 7. Извлечение контекста, уплотнение и фоновые обновления¶
1. Память бесполезна, если ты не умеешь возвращать из нее нужное¶
После того как ты развел краткосрочную, долговременную и профильную память, возникает следующий практический вопрос: как именно агент должен доставать нужные записи обратно в подсказку?
Именно здесь многие системы начинают деградировать:
- в подсказку летит слишком много нерелевантного контекста;
- извлечение возвращает похожее, но не полезное;
- сводки растут, но не становятся понятнее;
- каждая новая итерация делает контекст только тяжелее.
То есть проблема уже не в том, что память есть. Проблема в том, что память стала слишком шумной и дорогой для чтения.
2. Извлечение — это не поиск “всего похожего”, а отбор того, что помогает решить текущую задачу¶
У извлечения очень плохая привычка: если его не ограничить, он пытается быть слишком щедрым. В итоге в подсказку попадает не самый полезный контекст, а самый похожий по эмбеддингам или пересечению ключевых слов.
Для эксплуатационных систем полезнее думать так:
- извлечение не обязано возвращать много;
- извлечение обязано возвращать объяснимо;
- извлечение должно уважать арендатора, источник и границы доверия;
- извлечение должно подчиняться бюджету размера контекста.
Нормальный конвейер извлечения почти всегда учитывает не только похожесть, но и:
- изоляцию арендаторов;
- класс памяти;
- свежесть;
- уверенность;
- происхождение;
- фильтры политики.
2.1. Семантический разрыв между пользователем и слоем знаний реален¶
Еще одна частая проблема здесь почти не видна на демо: пользователь формулирует запрос разговорно, а документы и записи знаний обычно написаны формально, технически или в терминах внутренних систем.
Из-за этого извлечение может дать слабый результат не потому, что данных нет, а потому, что между пользовательским запросом и корпусом есть семантический разрыв.
Практически это означает, что запрос извлечения иногда полезно дополнительно обрабатывать:
- нормализовать названия сущностей и внутренних статусов;
- переписывать запрос в более "документный" стиль;
- добавлять управляемое расширение запроса;
- в отдельных случаях использовать HyDE, когда система сначала строит гипотетический ответ в стиле документа, а уже потом ищет по нему.
Но здесь важна одна дисциплина: такой промежуточный помощник запроса не должен превращаться в новый "факт". HyDE или переписывание запроса полезны как инструмент извлечения, а не как замена обоснованного ответа.
2.2. Обычно стоит начинать с RAG, а не с обучения¶
Если проблема в том, что агенту не хватает свежих знаний или доступа к внутренним документам, самый практичный первый шаг обычно не обучение, а нормальный слой извлечения.
Причина простая:
- RAG быстрее обновлять;
- извлечение проще аудировать и ограничивать;
- дрейф знаний проще чинить обновлением корпуса, чем переобучением модели;
- изменяющиеся документы и изменяемые источники знаний лучше ложатся в извлечение, чем в веса модели.
При этом полезно различать две разные задачи:
- продолженное предобучение в первую очередь помогает адаптировать распределение знаний;
- SFT в первую очередь помогает адаптировать поведение, стиль и шаблон решений.
Практическое правило обычно такое: сначала доведи извлечение до внятного уровня, а уже потом решай, уперлась ли система в потолок и нужно ли обучение.
Хороший эксплуатационный сигнал тоже довольно простой: если агент поддержки долго работал нормально, а потом просел без заметных изменений подсказки и маршрутизации модели, сначала стоит подозревать устаревший корпус извлечения, дрейф индексации или проблему свежести данных, а не мистическую "деградацию модели".
Сквозной кейс: что доставать обратно
В кейсе сортировки обращений поддержки извлечение не должно просто поднимать все прошлые обращения клиента. Для текущего запуска полезны последние открытые тикеты, проверенный профильный факт вроде предпочитаемого языка и актуальная выдержка из инструкции поддержки. Старые черновики, непроверенные жалобы и устаревшие сводки должны либо уйти в фоновое сжатие контекста, либо вообще не попадать в подсказку.
3. Хорошая подсказка любит не полноту, а плотность сигнала¶
Очень соблазнительно думать, что “чем больше контекста, тем умнее агент”. На практике часто наоборот: чем больше мусора ты кладешь в подсказку, тем слабее модель держит приоритеты.
Поэтому извлечение должно отвечать не на вопрос “что мы можем достать?”, а на вопрос “что сейчас повышает шанс на правильное решение?”.
Полезное практическое правило:
- лучше 3 очень релевантные записи, чем 20 условно похожих;
- лучше маленькая сводка с источником, чем длинный сырой документ;
- лучше отдельная профильная подсказка, чем целая история предпочтений;
- лучше пустое извлечение, чем извлечение без доверия и объяснимости.
4. Сжатие контекста — это не косметика, а способ удержать систему в рабочем состоянии¶
Если слой памяти только растет, рано или поздно сборка подсказки начинает работать как мусоросборник без правил. Именно поэтому сжатие контекста должно быть частью архитектуры, а не разовым проектом уборки.
Сжатие контекста может означать разные вещи:
- сжать несколько записей в сводку;
- удалить устаревшие рабочие заметки;
- объединить дубликаты;
- заменить большой фрагмент на нормализованную запись плюс ссылку на источник;
- понизить приоритет старых записей вместо вечного хранения “на первом плане”.
Извлечение и сжатие контекста лучше мыслить как один цикл обслуживания памяти
flowchart TD
A["Новый запуск"] --> B["Запросить память"]
B --> C["Применить фильтры и ранжирование"]
C --> D["Собрать контекст подсказки"]
D --> E["Модель + инструменты"]
E --> F["Создать кандидаты в память"]
F --> G["Фоновое сжатие и разбор"]
G --> H["Нормализованное хранилище памяти"]
H --> B 5. Не все обновления памяти должны происходить в горячем пути¶
Это один из самых полезных архитектурных сдвигов для агентных систем. В начале почти все пытаются сделать память “сразу готовой”: агент что-то увидел, сразу переписал сводки, сразу обновил профиль, сразу сохранил знания.
Но это почти всегда слишком дорого и слишком рискованно.
Что обычно разумно оставить в горячем пути:
- минимальное состояние сессии;
- короткие рабочие заметки;
- безопасные временные записи с понятным TTL;
- обновление, без которого текущий рабочий процесс реально ломается.
Что обычно лучше уводить в фон:
- сжатие длинных сессий;
- пересборку сводок;
- нормализацию фактов;
- дедупликацию;
- разбор кандидатов в память перед устойчивой записью.
Именно фоновые обновления позволяют сделать память аккуратной, а не просто быстрой.
6. Хорошая система разделяет запрос извлечения и задачи обслуживания¶
В зрелой архитектуре почти всегда есть два разных контура:
- путь чтения: быстро и безопасно достать контекст для текущего запуска;
- путь обслуживания: спокойно улучшить хранилище памяти без давления задержки.
Это важно не только для производительности, но и для качества решений. Когда одна и та же цепочка одновременно:
- выполняет задачу;
- пересобирает сводки;
- пишет профильную память;
- чистит дубликаты;
- обновляет метаданные ранжирования,
она очень быстро становится хрупкой и плохо объяснимой.
6.1. Передовой край памяти идет в сторону адаптивного формирования, но эксплуатация пока требует дисциплины¶
Свежие исследовательские работы по памяти подталкивают архитектуру еще дальше: не просто хранить записи и иногда их сжимать, а постепенно перестраивать слой памяти под реальные паттерны использования.
Это перспективное направление, потому что оно намекает на более умную систему:
- сводки могут эволюционировать;
- классы памяти могут становиться богаче;
- хранилище может лучше отражать реальные повторяющиеся задачи.
Но именно здесь нельзя перепрыгивать через эксплуатационную дисциплину.
Пока у команды нет устойчивых:
- правил происхождения;
- семантики ревизий;
- проверяемых записей в память;
- трассируемых задач обслуживания;
- пути отката для производных артефактов,
адаптивное формирование памяти лучше воспринимать как направление исследований, а не как эксплуатационный паттерн по умолчанию.
Практически это означает простую вещь: развивающуюся память интересно изучать, но живой контур системы пока должен держаться на объяснимом извлечении, управляемом сжатии и проверяемом происхождении записей.
7. Пример политики для извлечения и фоновых обновлений¶
Ниже очень практичный шаблон. Он не пытается быть универсальным, но хорошо показывает, какие решения стоит сделать явными.
retrieval:
max_records: 5
max_tokens: 1800
allowed_classes:
- short_term
- long_term
- profile
require_tenant_match: true
min_confidence: 0.75
deny_sources:
- raw_external_html
- unreviewed_summary
compaction:
run_mode: background_only
summary_max_tokens: 400
deduplicate: true
merge_similar_records: true
drop_expired_short_term: true
Когда такие правила явны, команда уже не спорит о памяти на уровне ощущений. Она спорит о конкретных ограничениях и компромиссах.
8. Простой кодовый пример ранжирования перед сборкой подсказки¶
Ниже не “умный” движок извлечения, а специально понятный пример. Он показывает, что ранжирование полезно строить не только по похожести, но и по доверию, свежести и важности.
from dataclasses import dataclass
@dataclass
class RetrievedRecord:
text: str
similarity: float
confidence: float
recency_weight: float
trusted: bool
def score(record: RetrievedRecord) -> float:
trust_bonus = 0.15 if record.trusted else -0.2
return (
record.similarity * 0.5
+ record.confidence * 0.25
+ record.recency_weight * 0.1
+ trust_bonus
)
def select_for_prompt(records: list[RetrievedRecord], limit: int = 3) -> list[RetrievedRecord]:
ranked = sorted(records, key=score, reverse=True)
return ranked[:limit]
Такая логика грубая, но у нее есть важное достоинство: ее можно обсуждать, тестировать и постепенно заменять чем-то более точным без потери объяснимости.
9. Сводки должны помогать читать, а не скрывать происхождение данных¶
Очень часто команды используют сводки как способ “впихнуть больше памяти в меньше токенов”. Это нормально, но есть одна ловушка: сводка не должна превращаться в новую анонимную истину.
Хорошая сводка:
- короче исходных записей;
- сохраняет происхождение;
- не смешивает арендаторов;
- не теряет критические ограничения;
- помечена как производный артефакт, а не сырой факт.
Плохая сводка:
- звучит уверенно, но неясно, откуда она взялась;
- объединяет конфликтующие факты;
- теряет дату и владельца данных;
- подсовывается модели как доверенная инструкция.
10. Частые ошибки¶
Обычно проблемы повторяются:
- в подсказку попадают дубликаты;
- извлечение не знает про границы классов;
- ранжирование не учитывает доверие;
- сводки становятся слишком общими;
- фоновые задачи отсутствуют, и память только пухнет;
- никто не знает, почему был извлечен именно этот фрагмент.
Последний пункт особенно важен. Если ты не можешь объяснить, почему контекст оказался в подсказке, система уже плохо управляется.
11. Что сделать сразу¶
Сначала пройди по короткому списку и отдельно отметь все ответы «нет»:
- Есть ли лимит по количеству записей и бюджету токенов?
- Учитывает ли ранжирование не только похожесть, но и уверенность, свежесть и доверие?
- Разделены ли путь чтения и путь обслуживания?
- Есть ли сжатие контекста как регулярный процесс, а не ручная уборка?
- Можно ли у сводки увидеть происхождение?
- Есть ли защита от извлечения через чужого арендатора или неподходящий класс?
Если на несколько вопросов подряд ответ “нет”, значит память у тебя уже есть, а вот дисциплины памяти пока нет.
12. Что делать дальше¶
На этом базовая часть про память уже складывается. Дальше можно либо углубиться в сроки хранения и удаление, либо перейти к части про инструменты и выполнение.