Priming v2: от каталога знаний к полезным рекомендациям
Статус: реализовано. Документ — план эпохи принятия; что изменилось в текущей реализации после внедрения (IDF-фильтр, семантический тир с квотой, часы переподтверждения, переходы состояний), — в §18.
#1. Цель и ключевой принцип
Подсказки (hints) — это не каталог знаний, а ограниченный по бюджету набор рекомендаций, предназначенных повлиять на конкретное решение агента в текущей задаче.
Из этого принципа следуют требования к системе priming:
- находить и подавать опыт, полезный именно для данной задачи;
- сознательно возвращать меньше подсказок или ни одной, если подходящего опыта нет;
- не тратить контекст на повторы, мусорные совпадения и устаревшие правила;
- делать отбор детерминированным и воспроизводимым, чтобы две версии алгоритма можно было сравнивать на одних и тех же задачах.
Документ фиксирует ревизию текущей реализации, целевую модель отбора и план работ P0/P1/P2. Жизненный цикл Hint (proposed → used/ignored → outcome) и разделение Experience/Knowledge/Skill/Hint определены в docs/knowledge-evolution.md и здесь не пересматриваются.
Связанные документы: knowledge-evolution.md (модель опыта), knowledge-extraction.md (появление Knowledge), knowledge-model.md (сущность Knowledge и связи), living-skills.md §14–16 (связь навыков и знаний), agent-teams.md §9 (программные раны без подсказок).
#2. Ревизия реализации на момент проектирования
На момент написания в коде сосуществовали два механизма формирования
подсказок — рабочий контур и параллельный прототип (§2.2). Проблема
устранена: прототип удалён, единственный движок — observation.FindHints.
#2.1. Рабочий контур активации (observation/hints.go)
Путь, который реально исполняется в рантайме:
AgentRun(kernel/agent/workflow.go) перед циклом ходов вызывает activitykernel.knowledge_hintsсquery = input.Prompt; лимит зашит в activity — 8 подсказок. Обращение best-effort: при недоступности пишетсяmemory.read.failed, ран продолжается.- Activity
KnowledgeHints(kernel/agent/activities.go) делает POST/v1/observations/hints. - Observation (
observation/httpapi/server.go) пишет событиеhint.query, вызываетFindHints(observation/hints.go) и пишетhint.offeredна каждую отобранную подсказку (с proposition, state, matched_by). FindHints:- единица отбора — отдельное Knowledge, не группа;
- терминальные состояния (
invalidated/superseded/corrected) исключены полностью; - матчинг: пересечение Entities (tier 0) → Topics (tier 1) → фраза (tier 2) → термы, ≥2 совпадений (tier 3);
- одношаговое расширение по Relationships (
related:,via:) с tier+1; - сортировка детерминированная: matchTier → kindTier (claim < observation) → stateTier (confirmed < proposed < challenged) → KnowledgeID как tie-breaker;
- cautions для
proposed/challenged/at_risk; evidence ≤8, history ≤5.
- Workflow вставляет подсказки одним блоком (см. §18; на момент проектирования — отдельным system-сообщением на подсказку).
- Обратная связь уже существует: extraction вычисляет
hint.used/hint.ignoredпо отражению терминов пропозиции в ответе модели, а также фиксируетhint.outcome.
Что уже хорошо и сохраняется в v2: единица отбора — отдельное знание; детерминированная сортировка с tie-breaker; исключение терминальных состояний из выдачи; cautions; события полного цикла offered → used/ignored → outcome.
Дефекты рабочего контура:
| # | Дефект | Следствие |
|---|---|---|
| Р1 | Лимит по количеству (8), токен-бюджета нет вообще; каждая пропозиция вставляется целиком без ограничения | Контекст расходуется непредсказуемо; одна длинная пропозиция может съесть больше места, чем пять полезных коротких |
| Р2 | Матчинг бинарный: любые совпавшие Entities дают tier 0 независимо от специфичности; внутри тира нет градации релевантности | «gateway» и «temporality» весят одинаково; content-based сравнение фактически отсутствует |
| Р3 | Лексика: точное совпадение токенов, нет словоформ и нормализации идентификаторов; русские стоп-слова неполные («не», «без» — не в списке) | Реальные трейсы: matched_by: term:не, term:узел — мусорные совпадения проходят отбор |
| Р4 | Отсутствует сигнал полезности: отбор не знает, помогало ли знание раньше (hint.outcome собирается, но в рейтинг не попадает) |
Ранжирование по формальным признакам, а не по пользе |
| Р5 | Инвалидированное исключено молча: нет ни отрицательного опыта, ни подсказки о замене | Агент повторяет уже опровергнутые подходы |
| Р6 | Нет дедупликации: 8 почти одинаковых observation занимают весь лимит | Бюджент набора тратится на повторы |
| Р7 | Контекст агента не учитывается: query = сырой промпт; активные Skills, системный промпт, ранее выданные подсказки не влияют | Temporality конкурирует с собственным контекстом агента |
| Р8 | Каждая подсказка — отдельное system-сообщение с полной пропозицией | Нет формата cue «правило + условие + основание»; проверяемого контракта knowledge_id нет |
#2.2. Параллельный прототип (kernel/priming/priming.go)
Пакет kernel/priming выставлен как GET /v1/agent/priming, но рабочим контуром AgentRun не используется. Все дефекты, из-за которых он возник, подтверждены кодом:
- группировка Knowledge по одному
primaryScope(topics[0] → entities[0] → первые два слова → «misc»), заголовок группы —scope (N items); отдельные пропозиции в сравнении с задачей не участвуют; scorePatternскладывает объём и качество в одну сумму:activeRatio*2 + min(N,10)*0.3 + Σ signalWeights*0.1 + overlap*3— группа из 20 элементов получает высокий балл без единого совпадения с задачей, аMinScore = 0.1не фильтрует нерелевантное (базовый балл 2–6);tokenizeотбрасывает токены короче 4 символов (теряетgo,r,ui,jwt,v2,api) и знает только английские стоп-слова;ReuseCountнапрямую увеличивает вес сигнала (1.0 + reuse*0.1) — повторное использование принимается за доказательство полезности;- инвалидированные записи участвуют как сигналы (вес 0.5) и увеличивают размер группы;
- обход map без гарантии порядка +
sort.Sliceпо одному Score без tie-breaker — недетерминизм на равных оценках; - ограничение только по числу паттернов (
MaxPatterns = 7); токен-бюджета нет; priming_test.goпокрывает группировку, относительный рейтинг простого случая, токенизацию и конфиг — но не доказывает, что подсказки помогают решать задачи.
#2.3. Первый долг — консолидация
Два механизма с разной семантикой — это риск расхождения поведения и удвоение стоимости правок. Решение:
- единый движок отбора —
FindHintsv2 в observation (туда сходятся и рантайм-запросы, и любые отладочные эндпоинты); kernel/priming— исключить из рантайма: эндпоинт/v1/agent/primingлибо удалить, либо превратить в тонкий прокси к единому движку (решается в P0);- группировка (Experience Pattern) сохраняется только как слой подачи (см. §3.1), но не как единица релевантности.
#3. Целевая модель отбора
#3.1. Три уровня: Knowledge / Experience Pattern / Cue
- Knowledge — основная единица оценки релевантности. Сравнивается с задачей всегда отдельная пропозиция, а не «тема» или «scope».
- Experience Pattern — необязательная группировка связанных знаний для компактной подачи: несколько подтверждённых правил одной области могут быть объединены в один cue. Паттерн — результат отбора, а не его вход. Нельзя заранее считать, что тема целиком достойна контекста: в группе «API» могут лежать правило про перегенерацию клиента, правило про Docker для интеграционных тестов и правило про миграции БД — задача «исправить API-клиент» не должна получать все три.
- Cue (подсказка) — итоговый артефакт: отобранное знание (или компактная группа), уложенное в формат §5.3 и в бюджет.
Обратная крайность тоже запрещена: семь независимых подсказок об одном и том же случае — это провал бюджета. Нужны индивидуальный рейтинг (§3.3) плюс дедупликация (§9).
#3.2. Этап A — допуск (gating)
Допуск отвечает на вопрос «можно ли показывать это знание в данном контексте вообще». Это ограничители-инварианты, а не слагаемые рейтинга: критический недостаток не должен компенсироваться массой положительных факторов.
- A1. Область применимости. Scope знания (проект / org-unit / агент) должен покрывать контекст запуска. Проверка видимости — через существующую модель доступа, без изобретения новой.
- A2. Жизненный цикл. Политика состояний — §6: терминальные состояния не выдаются как действующие правила;
proposedдопускается условно;challenged/at_riskдопускаются только как сигналы риска. - A3. Основания. Знание без единого подтверждения не попадает в выдачу при среднем матче; допуск
proposedтребует высокой релевантности (§6). - A4. Права. Дозагрузка и выдача проходят те же проверки доступа, что и чтение Knowledge.
#3.3. Этап B — ранжирование полезности
Ранжирование отвечает на вопрос «что полезнее именно сейчас». Ранжируются четыре независимых свойства, которые сегодня смешаны в одну сумму:
| Свойство | Вопрос | Источник сигнала |
|---|---|---|
| Релевантность текущей задаче | похоже ли содержание на то, что решается | лексический матч по признакам §4 |
| Достоверность | можно ли на это опираться | состояние + cautions (вход допуска и подачи, не слагаемое) |
| Полезность в прошлом | помогало ли это раньше | агрегированный hint.outcome (§11), а не ReuseCount |
| Объём свидетельств | насколько это проверено | количество/свежесть evidence — влияет на формулировку основания, не на рейтинг |
Факторы ранжирования:
- B1. Соответствие содержанию — взвешенный матч признаков (§4), где вес терма зависит от его информативности (редкий в корпусе термин весит больше частотного).
- B2. Совпадение технических сущностей и операций — Entities, идентификаторы, класс операции (миграция / рефакторинг / отладка / тестирование / настройка).
- B3. Применимость к этапу работы — разведка / реализация / проверка (опционально, включается по мере появления метаданных этапа).
- B4. Подтверждённая практическая полезность — производная от
hint.outcome=helpful, а не факт автоматической выдачи. - B5. Новизна относительно уже подключённого контекста (Skills, системный промпт, ранее выданные cue) — штраф за дублирование, а не исключение (§7).
Веса факторов конфигурируются, детерминированы и версионируются вместе с алгоритмом (§8).
#4. Содержательная релевантность
Пересечение токенов — необходимый, но не достаточный механизм. Сравнивать нужно не заголовок группы со задачей, а признаки знания с признаками задачи:
| Признак | Что искать | Где взять |
|---|---|---|
| Содержание | смысл пропозиции | Proposition |
| Технические сущности | библиотеки, API, классы, сервисы, файлы, CLI-флаги | Entities, идентификаторы в пропозиции |
| Операция | миграция, рефакторинг, отладка, тестирование, настройка | глагольные формы, словарь классов операций |
| Условия применимости | версия, окружение, ограничения, предпосылки | пропозиция + evidence |
| Результат | какой эффект подтверждён | формулировка + состояние |
| Контекст | org, проект, агент, Skill | метаданные знания |
#4.1. Нормализация для русского и английского
Текущий contentTokens (lowercase, буквы/цифры/_/-, токены длиннее 1 руны, короткий список стоп-слов) недостаточен: term:не в реальных трейсах — прямое следствие.
Требования к нормализации:
- регистр и пунктуация — уже есть, сохранить;
- сегментация идентификаторов:
camelCase,snake_case,kebab-caseразбиваются на составные токены (AUTH_TOKEN→auth,token); - словоформы: «миграция», «миграции», «миграцию» не должны терять связь — минимальный русский стемминг (усечение типовых окончаний) или словарь форм; английский — плюрализм;
- стоп-слова ru/en — расширить (добавить как минимум «не», «без», «над», «под», «также», «его»…), список — в конфиг с версией;
- короткие токены не выбрасывать бездумно:
go,r,ui,jwt,v2,c#значимы — минимум длины 2 руны (как сейчас) плюс белый список технических терминов; изъятие только через стоп-слова.
#4.2. Порядок внедрения
- Детерминированный лексический матч по признакам с IDF-подобным взвешиванием (P0).
- Если бенчмарк (§12) покажет недостаточность — семантическая оценка кандидатов после лексического префильтра (embeddings или LLM), но не векторный retrieval по всей базе сразу (P2).
#5. Бюджеты и формат cue
#5.1. Три отдельных ограничения
| Ограничение | Назначение | Стартовое значение |
|---|---|---|
| Общий бюджет подсказок | верхняя граница затрат контекста на priming | ~600 токенов на запуск |
| Бюджет одного cue | один cue не съедает весь набор | ~120 токенов |
| Лимит элементов в cue | группа не превращается в простыню | ≤3–5 знаний |
Токен-бюджет обязателен: сегодня лимит «8 подсказок» при неограниченной длине пропозиций бюджетом не является.
#5.2. Отбор: максимизация пользы набора
Цель — максимизировать ожидаемую пользу всего набора, а не сумму индивидуальных рейтингов:
max_{S} Σ_{i∈S} U_i при ограничениях: Σ tokens(S) ≤ Budget,
redundancy(S) ≤ R, |S| ≤ MaxCues
где U_i — оценка полезности cue (§3.3), а не популярности или достоверности.
На первом этапе достаточно жадного отбора: взять лучший cue, пересчитать новизну остальных с учётом уже выбранного (повторы штрафуются), взять следующий, пока бюджет не исчерпан или полезность не упала ниже порога. Сложный оптимизатор не нужен. Если первый cue сообщает важное правило, а следующие пять повторяют его другими словами — они не проходят.
#5.3. Формат cue
Подсказка содержит три вещи:
- Правило/вывод — что нужно знать.
- Условие применимости — когда это имеет значение.
- Основание/статус — насколько проверено и куда обратиться за подробностями (
knowledge_id).
Пример:
При изменении API-контракта в этом проекте проверь generated client и
integration tests. Правило подтверждено предыдущими запусками.
knowledge_id=K123
Это полезнее перечисления фактов из одной темы. В P0 cue рендерится шаблонно и детерминированно (пропозиция + условия + маркер состояния + id); LLM-компакция — опциональный P2, допускается только если обгоняет шаблон на бенчмарке.
Инъекция в промпт — одним структурированным блоком с соблюдением бюджета, а не N отдельными system-сообщениями неограниченной длины.
#6. Политика состояний и отрицательный опыт
Инвалидированное знание нельзя выдавать как действующее правило. Но именно оно часто содержит самый ценный опыт: какой подход уже пробовали и почему он оказался ошибочным.
| Состояние | Режим выдачи |
|---|---|
confirmed |
действующее правило при подходящем контексте |
proposed |
только при высокой релевантности, с явной маркировкой неопределённости («гипотеза, не подтверждена») |
challenged / at_risk |
не как истина; учитывать при оценке риска, с caution |
invalidated / superseded / corrected |
не как активная инструкция; допускается короткое предупреждение о прежнем способе или ссылка на заменившее знание |
Требования:
- Связи замены. Если система знает, что K123 заменено на K456, надо сразу предлагать K456, а не просто исключать K123. Нужна типизированная связь
replaces/superseded_byв Relationships (модель Knowledge уже имеет Relationships — требуется закрепить тип и заполнять при инвалидации; сегодня замена упоминается только в свободном текстеreason). - Отрицательный опыт дозированно. Не показывать каждый провал; показывать предупреждение, только если прежний подход правдоподобен для текущей задачи (высокий матч) и заменяющее знание найдено.
ReuseCount≠ доказательство полезности. Знание могло многократно выдаваться автоматически, не помогая. Повторное использование отличать от подтверждённого положительного результата: полезность — только изhint.outcome(§11).
#7. Учёт существующего контекста агента
Если агенту подключён Skill, подробно описывающий процедуру миграции, не нужно выдавать ту же процедуру как подсказку при каждом запуске. Вход отбора расширяется:
- активные Skills (id + summary);
- системный промпт (сводка/хэш);
- история текущего диалога и подсказки, уже выданные в этом запуске;
- знания, уже дозагруженные агентом по
knowledge_id.
Правила:
- Knowledge, связанное с активным Skill, не исключается автоматически — оно может быть важным уточнением, частным случаем или предупреждением, отсутствующим в Skill; оно получает штраф новизны (B5) за пересечение содержания.
- Цель — максимум новой полезной информации при минимальном дополнительном контексте, а не минимальное число подсказок само по себе.
Технически: HintRequest пополняется полем контекста (список skill-ids, digest уже выданного); ядро передаёт его при запросе /v1/observations/hints.
#8. Детерминизм
Детерминизм — необходимое условие отладки и A/B-сравнения версий алгоритма.
Единый порядок отбора:
- Допуск по scope и lifecycle (§3.2) — стабильный набор кандидатов.
- Рейтинг по содержательной релевантности и полезности (§3.3).
- Устойчивый tie-breaker: score по убыванию, затем
KnowledgeIDпо возрастанию. - Детерминированный жадный отбор в бюджете (§5.2).
Дополнительно фиксируются: порядок сигналов/элементов внутри cue (например, по времени evidence), правила дедупликации, алгоритм усечения.
Контракт: одинаковый вход и конфигурация → одинаковое множество и порядок cue (отличаться могут только GeneratedAt и идентификаторы). Каждый результат несёт algorithm_version, по которому воспроизводится конфигурация весов и порогов. Текущий FindHints уже детерминирован — это свойство сохраняется и защищается тестом на N прогонов.
#9. Дедупликация и разнообразие
Даже идеальный скоринг выдаст почти-дубликаты: задача про OAuth может получить три формулировки одного правила аутентификации — все релевантны, но вторая и третья почти ничего не добавляют.
Этап diversification после ранжирования:
- удалять точные дубликаты (нормализованная пропозиция);
- удалять почти-дубликаты (Jaccard по множеству признаков выше порога);
- снижать приоритет уже представленных фактов (реализуется через пересчёт новизны в жадном отборе);
- ограничивать число cue из одной тематической группы (один primaryScope/топик) — например, не более двух;
- не позволять одной группе вытеснить всё остальное.
Разнообразие не самоцель: если задача требует пяти разных правил одной темы, их нельзя разбавлять нерелевантными. Смысловая дедупликация моделью — P2, если детерминированных методов не хватит (по бенчмарку).
#10. Дозагрузка по knowledge_id
Компактная подсказка — точка входа в подробное знание, а не его урезанная копия.
- Priming возвращает короткий cue с
knowledge_id. - Агент оценивает, достаточно ли этого для решения.
- Если нужны обоснование или детали — запрашивает полное Knowledge по ID через инструмент
knowledge_lookup(новый агентский инструмент; activitykernel.knowledge_lookupуже существует как внутренняя — её нужно вынести в доступный агенту инструмент с тем же контрактом). - Полное Knowledge содержит proposition, evidence, состояние, scope и связи (включая замены).
- Дозагрузка проходит те же проверки авторизации и доступа к проекту, что и обычное чтение Knowledge.
Правила:
- не заставлять агента дозагружать каждое знание — это уничтожит выигрыш от компактности;
knowledge_id— рабочий контракт между priming и агентом, а не просто поле ответа: он обязан присутствовать в каждом cue и разрешаться инструментом.
Сегодня дозагрузку подменяет доставка evidence (≤8) и history (≤5) внутри структуры Hint, но в промпт они не попадают, а инструмента у агента нет — контракт разорван.
#11. Замкнутый цикл полезности
Инфраструктура обратной связи уже есть и является преимуществом Temporality:
hint.offered/hint.used/hint.ignored— отражение терминов пропозиции в ответе модели (kernel/agent/knowledgeextract.go);hint.outcome— итоговая оценка, помогла ли подсказка.
Что добавить:
- агрегированная полезность знания (доля
helpfulсреди выдач с исходом) становится фактором ранжирования B4; - авторство сигнала различается:
used(модель воспользовалась) ≠helpful(задача решена лучше) — в рейтинг идёт только второе; - статистика применения (
applied_count,helpful_count,last_helpful_at) хранится рядом со знанием и видна в UI наблюдаемости; - цикл замыкает адаптацию: P2 допускает подстройку весов факторов по исходам, но не самообучение на каждом ране.
#12. Benchmark качества
Главная недостающая вещь: никакие существующие тесты (priming_test.go, server_test.go) не доказывают, что подсказки помогают решать задачи.
#12.1. Корпус
Постоянный набор из 30–50 реальных задач из запусков Temporality (затравка — сценарии из фикстур benchmark-корпуса). Для каждой задачи фиксируется:
- описание задачи;
- доступные на тот момент Knowledge со состояниями и связями;
- разметка: какие знания реально полезны, какие нерелевантны, какие устарели;
- эталонный набор ожидаемых подсказок;
- бюджет контекста.
Формат — JSON-фикстуры в репозитории; прогон — командой/тестом в CI.
#12.2. Метрики
| Метрика | Что измеряет |
|---|---|
| Precision@K / Precision@Budget | доля выбранных подсказок, действительно относящихся к задаче |
| Recall@Budget | сколько из известных полезных подсказок передано в пределах бюджета |
| Redundancy ratio | доля бюджета, потраченная на повторяющуюся информацию |
| Stale / invalidated leakage | как часто устаревшее знание попадает в контекст как действующая инструкция |
| Token efficiency | полезных подсказок на единицу токен-бюджета |
| Behavioral impact | изменилось ли поведение и результат агента благодаря подсказкам |
Behavioral impact — важнейшая и самая сложная метрика: одинаковые задачи с priming и без, одна модель и инструменты, несколько повторов для стохастики. Качество подсказки ≠ улучшение результата: высокая точность retrieval не доказывает, что агент воспользовался подсказкой.
#12.3. Правило сравнения
Каждое изменение алгоритма (веса, нормализация, пороги) прогоняется на корпусе; отчёт сравнивает версии по всем метрикам. Без улучшения на корпусе изменение не принимается.
#13. Наблюдаемость
- Событие
hint.offeredдополняется:algorithm_version,score,budget_tokens,tokens,reason(краткое why: какие признаки сматчились, что решающим стало). - В UI трейса подсказка показывается человеком-понятным предложением (уже делается) + причина отбора; для отсеянных кандидатов — режим отладки «почему не выдано» (P1).
- Статистика §11 (applied/helpful) видна в панели Knowledge.
#14. План работ
#Статус реализации (2026-10-10)
Происхождение реализации: P0 доставлена в main одной веткой, P1 — последующими коммитами (diversification, replacement, usefulness loop + benchmark-корпус).
Сделано в рамках P0:
- п.1 консолидация — ✅
kernel/primingи эндпоинты/v1/agent/priming*удалены; единственный движок —observation.FindHints; - п.2, п.3 — ✅ жили и закреплены тестами в живом движке (гейтинг invalidated/superseded/corrected, индивидуальный рейтинг, honest zero);
- п.4 — ✅ детерминизм +
observation.HintsAlgorithmVersionв событияхhint.query/hint.offeredи ответе; - п.5, п.6 — ✅
observation.RenderHintBlock: один блок, бюджеты 600/120/8, cue-контрактправило [статус] (почему сматчилось) knowledge_id; инъекция одним system-сообщением вAgentRun; - п.10 (P1) — ✅ тул
knowledge_lookup(авто-апрув, project-scoped) замыкает контрактknowledge_id; - п.7 — ✅ retired-знание с матчем и непустой заменой предлагает замену как кандидата (
matched_by=replaces:<oldID>); manual-invalidate принимаетreplacement_id(эмитknowledge.superseded), цепочка lifecycle и trajectory несут ссылку; - п.8 (P1) — ✅ diversification в
FindHintsпосле ранжирования: точные дубли (нормализованная пропозиция), почти-дубли (Jaccard ≥ 0.8 по content-токенам), кап 2 cue на первичный топик; порядок входа не влияет на результат (тест).
Сделано в рамках P1 (завершено, HintsAlgorithmVersion → lexical-entity-topic.v3):
- п.9 — ✅ контекст агента (§7):
HintQuery.ActiveSkills+IssuedKnowledgeIDs; ядро передаёт дайджесты активных навыков (HintRequest.Skills→active_skillsв/v1/observations/hints), движок понижает (не исключает) кандидатов, чьё содержание покрыто навыком на 2/3+ токенов (containment ≥ 0.75); уже выданное в ранее знание подавляется; - п.12 — ✅ замыкание полезности (§11): extractor (уже существующим вызовом модели,
ExtractorVersion→knowledge-extractor.v3) оцениваетhint_outcomesдля реально предложенных подсказок — helpful/harmful, «нет явного эффекта» не эмитится; workflow пишетhint.outcome(matcher=extraction-judgment.v1), проекция агрегируетhelpful/harmful_outcomes; фактор B4 в ранжировании — 2/3-большинство при ≥3 исходах (целочисленно, симметрично), статистика видна в панели Observability; used ≠ helpful сохранён: механическое отражение терминов остаётсяhint.used; - п.11 — ✅ benchmark-корпус (§12): 34 кейса в
observation/testdata/priming/*.json(затравка — сценарии бенчмарка + дедупликация, lifecycle, контекст навыков, бюджеты, ru/en); ранерTestPrimingBenchmarkCorpusQualityв CI: жёсткие инварианты (stale leakage = 0, детерминизм, бюджет блока, порядок) + метрики с полами (captured: precision@k = 1.000, recall@budget = 0.992, redundancy = 0.000, эффективность 18.7 полезных cue / 1000 токенов; полы 0.90 / 0.85 / 0.05 / 5.0). Behavioral impact — осознанно вне CI (требует модельных прогонов), остаётся ручным пилотом; - п.13 — осознанно дескоупнуто: Experience Pattern как слой подачи (объединение отобранных знаний в один cue) не подтверждён потребностью — компактный cue-контракт уже держит бюджет, а группировка до отбора была исходным дефектом (§3.1); вернуть при появлении свидетельств от бенчмарка.
Попутно исправлено: RenderHintBlock не учитывал руны-разделители \n при склейке блока — блок мог превысить бюджет на ~1 токен; теперь каждая строка несёт свой сепаратор (ceil субаддитивен, инвариант доказуем), RenderResult.KeptIDs открывает попозиционный учёт.
Не сделано: P2 целиком (семантика/LLM-оценка/адаптация весов — только если бенчмарк покажет потолок текущего движка).
#P0 — базовая семантика (консолидация и контракт)
- Консолидация: единственный движок отбора —
FindHintsv2 в observation;kernel/primingвыводится из рантайма (эндпоинт — удалить или проксировать). - Разделить допуск и рейтинг: gating-инварианты (§3.2) отдельно от ранжирования (§3.3); исключить выдачу инвалидированного как действующего правила.
- Ранжировать отдельные Knowledge по содержанию: признаки §4, нормализация ru/en (§4.1), IDF-взвешивание, расширение стоп-слов, сегментация идентификаторов.
- Детерминированная сортировка с tie-breaker +
algorithm_versionв результате (тест на воспроизводимость). - Бюджеты: общий (~600 токенов), на cue (~120), лимит элементов; жадный отбор по marginal utility.
- Формат cue (правило + условие + статус +
knowledge_id) и инъекция одним блоком в промпт. - Связь замены: типизированный
replaces/superseded_byзаполняется при инвалидации; замена предлагается вместо исключения.
#P1 — полезность набора
Дедупликация и разнообразие (точная, Jaccard, лимит на группу) — §9.✅Учёт активных Skills и уже выданного контекста — §7.✅Инструмент✅knowledge_lookupдля агента — §10.Benchmark-корпус 30–50 задач, метрики §12, сравнение версий в CI.✅Замыкание полезности: агрегированный✅hint.outcomeкак фактор B4 — §11.- Опционально: Experience Pattern как слой подачи — дескоупнуто (см. статус выше).
#P2 — дорогие методы (только если оправданы бенчмарком)
- Семантическое ранжирование кандидатов после лексического префильтра.
- LLM-оценка полезности кандидатов.
- Смысловая дедупликация моделью.
- Адаптация весов стратегии по исходам применений.
- LLM-компакция cue (против шаблонной — решает бенчмарк).
#15. Критерии готовности
P0:
- один движок отбора;
/v1/agent/primingне дублирует логику; - допуск отделён от рейтинга (код и тесты);
- бюджет соблюдается: суммарные токены выданных cue ≤ конфигурации (тест);
- при отсутствии релевантного опыта возвращается ноль подсказок (тест);
- ни одно
invalidated/superseded/correctedзнание не выдаётся как действующее правило; при наличии замены предлагается заменяющее (тест); - одинаковый вход + конфиг → одинаковый вывод на N прогонов (тест);
- каждый cue содержит правило, условие, статус и валидный
knowledge_id; - мусорные матчинги вида
term:неотсутствуют (тест на расширенных стоп-словах).
P1:
- доля почти-дубликатов в выдаче ниже порога (Redundancy ratio на корпусе);
- подсказки, дублирующие активный Skill, штрафуются (тест);
knowledge_lookupдоступен агенту и проходит авторизацию;- корпус бенчмарка прогоняется в CI, отчёт сравнивает версии.
Общие:
- Behavioral impact измерен на пилоте: сравнение задач с priming и без;
- документ актуализируется по итогам P0 (фактические веса, пороги, размеры бюджетов).
#16. Что не входит в скоуп
- изменение контракта extraction и правил появления Knowledge (
knowledge-extraction.md); - пересмотр жизненного цикла Hint и разделения Experience/Knowledge/Skill/Hint (
knowledge-evolution.md); - векторный семантический тир — вне скоупа этого плана, но реализован отдельно (см. §18);
- изменение модели доступа — используются существующие проверки видимости (
org-structure.md).
#17. Открытые вопросы
- Значения весов факторов B1–B5 и порогов — подбираются на бенчмарке P0/P1; стартовые зафиксировать в конфиге с версией.
- Хранение агрегированной полезности (
applied/helpful) — в journal рядом со знанием или в observation-слое. - Должен ли
knowledge_lookupвозвращать связанные знания одним ответом (граф) — решить при реализации инструмента. - Формат корпуса бенчмарка: наследовать ли схему существующих фикстур или завести отдельную.
#18. Что изменилось после внедрения (текущее состояние)
План выше выполнен, но механика выросла за его пределы:
- Порядок сортировки — не score:
matchTier → kindTier → stateTier → staleTier → usefulTier → noveltyTier → KnowledgeID(см. «Политика состояний» ниже и §8). - IDF-фильтр вместо IDF-весов: токены запроса, живущие в ≥5 знаниях и
≥5% корпуса, отбрасываются как неразличающие (
discriminativeTokens) — «клеевые» слова вида «не»/«файл» больше не проводят мусорные совпадения. - Семантический тир: косинусная близость на эмбеддингах (порог 0.35,
до 3 кандидатов),
semantic:<score>вmatched_by; квота (reserveSemanticSlots) держит до 2 мест бюджета под семантику, чтобы лексический шум не вытеснял смысловые совпадения. - Часы переподтверждения: якорь
LastEvidenceAt(создание, использование, judged-вердикт; предложение подсказки часы не сбрасывает); знание без подтверждений дольше 14 дней выдаётся с caution «not re-verified for N days» и уступает свежим равным (staleTier). - Aging sweep (
aging.v1): proposal старше 14 дней и confirmed старше 28 дней без перепроверки получаютknowledge.challengedи попадают в триаж гигиены. - Вердикты ранов двигают состояние:
hint.outcome: helpfulподтверждает proposal;harmfulс причиной переводит вchallenged; два независимых вреда без поддержки —invalidated; смешанные вердикты остаются спорными. - Формат cue (
renderCue):- правило [state] (match: …) knowledge_id=…; caution: …— без отдельного «условия применимости». - Payload
hint.offered:hint_id,activation_id,knowledge_id,state,matched_by,proposition,algorithm_version. - Команды: у слотов есть
TeamRunKnowledgeIDs— знания, подтверждённые в командном дереве, видны последующим слотам и держатся когортой выше лексических совпадений.
Полезность (B4), новизна (B5), дедупликация и бюджеты — как в плане.