Паттерн для построения LLM-компилируемой базы знаний из разрозненных заметок. Вдохновлён подходом Andrej Karpathy ("LLM Knowledge Bases"). Сырые заметки собираются в папках-источниках, LLM компилирует их в связную wiki, человек читает и дополняет через Q&A. Wiki растёт инкрементально — каждый запрос обогащает базу.
Контекст: одна сессия, vault — рабочая директория. Агенту нужен доступ к файлам vault для чтения источников и создания wiki.
Ты не пишешь wiki руками. LLM компилирует её из сырья и сам поддерживает.
Человек:
LLM:
Источники (raw) Wiki (compiled)
───────────────── ─────────────────
Inbox/ ─┐
Research/ ├──→ LLM ──→ Wiki/
Podcasts/ ─┘ │ ├── _Index.md
│ ├── _Changelog.md
│ ├── Article A.md ← primary
│ ├── Article B.md ← primary
│ ├── ...
│ ├── Synthesis X.md ← second-order
│ └── Synthesis Y.md ← second-order
│
└──→ Tag sources: wiki-status: processed
Статья wiki — это единый нарратив, а не список пересказов каждого источника. LLM читает все источники кластера, находит пересечения, противоречия, паттерны, и пишет связный текст. Конкретные данные, цитаты и цифры сохраняются. Но структура — авторская, не copy-paste.
Каждый raw-файл получает поле wiki-status в метаданных (YAML frontmatter, properties, или любой аналог):
| Статус | Значение |
|---|---|
| (нет поля) | Не обработан |
raw |
Явно помечен как необработанный |
processed |
Скомпилирован в wiki |
updated |
Отредактирован после компиляции — нужна перекомпиляция |
Это даёт инкрементальность: при повторном запуске LLM обрабатывает только новые и изменённые файлы.
Все статьи на одном уровне, без вложенных папок. Причины:
_Index.md — таблица всех статей с темой, количеством источников, датой. LLM обновляет при каждой компиляции. Заменяет RAG для небольших баз — LLM читает index и знает, что где искать.
_Changelog.md — лог: дата, какие статьи скомпилированы, из каких источников. Provenance — всегда можно проследить откуда что взялось.
После компиляции — обязательный проход по всем статьям:
После первого прохода компиляции LLM анализирует ВСЕ статьи и находит темы, которые упоминаются в 3+ статьях, но нигде не раскрыты полностью. Это кандидаты на synthesis-статьи — второй порядок компиляции. Они не имеют raw-источников; их источники — другие wiki-статьи.
1. Сканировать все источники → список файлов с темами
2. Кластеризовать по темам (2+ файла = кластер)
3. Показать topic map человеку → человек выбирает
4. Запустить компиляцию кластеров (параллельно)
5. Пометить источники wiki-status: processed
6. Обновить _Index.md и _Changelog.md
7. Lint: добавить cross-links
8. Предложить synthesis-статьи → человек выбирает
9. Скомпилировать synthesis
Когда появляется один новый контент (послушал подкаст, прочитал статью):
1. Человек: "вот подкаст, сделай саммари"
2. LLM: создаёт summary → сохраняет в нужную папку-источник
3. LLM: читает _Index.md → подходит под существующую статью?
├── Да → дополняет статью новым контентом, тегает, пишет в changelog
└── Нет → оставляет как raw (подхватится при batch-компиляции)
4. Если статья обновлена → quick lint (новые cross-links)
Ключевой принцип: не копить — интегрировать сразу, если есть куда. Как у Karpathy: "I end up filing the outputs back into the wiki to enhance it for further queries. So my own explorations always add up."
Критерии "подходит":
Когда накопилось много необработанных заметок:
1. Найти файлы БЕЗ wiki-status (новые)
2. Найти файлы с wiki-status: updated (изменённые)
3. Кластеризовать только их
4. Показать topic map → человек выбирает кластеры
5. Компилировать параллельно → новые статьи или дополнения
6. Re-lint всю wiki (новые статьи могут создать новые связи)
7. Предложить synthesis-статьи если появились новые кросс-темы
1. Человек задаёт вопрос
2. LLM читает _Index.md → находит релевантные статьи
3. Читает статьи → формирует ответ
4. (Опционально) Ответ сохраняется как новая заметка → filing обратно в wiki
| Ситуация | Процесс |
|---|---|
| Послушал подкаст, прочитал статью | Single ingest — саммари + интеграция |
| Накопилось 5+ новых заметок | Batch — кластеризация + компиляция |
| Нужен ответ по теме | Q&A — вопрос по wiki |
| Давно не обновлял wiki | Batch + lint + synthesis |
Для каждого файла LLM определяет:
Группировка: файлы с пересекающимися темами → один кластер. Файлы без пары → "unclustered" → catch-all статья или ждут следующей партии.
Входные данные:
Выход:
Требования к статье:
Проходит по всем статьям wiki и:
То же, что компилятор, но:
synthesis-of вместо sources в метаданныхtype: wiki-article
created: YYYY-MM-DD
sources:
- "[[Source File 1]]"
- "[[Source File 2]]"
tags: [wiki, topic-tags]
type: wiki-article
created: YYYY-MM-DD
synthesis-of:
- "[[Wiki Article A]]"
- "[[Wiki Article B]]"
tags: [wiki, topic-tags, synthesis]
Перед сборкой агент задаёт пользователю эти вопросы, чтобы адаптировать архитектуру под конкретный контекст.
Самый частый баг — LLM генерирует ссылку [[File Name and Extra Words]], а файл называется File Name.md. Obsidian (и другие инструменты) не находят связь. После каждой компиляции стоит проверять ссылки.
Одна заметка может быть релевантна двум темам. Правило: один кластер тегает, остальные ссылаются. Иначе будут конфликты при параллельной компиляции.
Кластеры независимы → компилируются параллельно (каждый в своём агенте). Это критично при 5+ кластерах — последовательная компиляция занимает x5 времени. Единственное ограничение — файлы-пересечения (см. выше).
Karpathy отмечает: при ~100 статьях и ~400K слов LLM справляется без RAG, если index-файлы хорошо поддержаны. LLM читает _Index.md, находит нужные статьи, читает их. Для 200+ статей, возможно, понадобится поисковый слой.
Wiki — территория LLM. Если хочешь добавить свои мысли — добавляй как raw-заметку в источники и запускай перекомпиляцию. Или используй отдельную секцию в статье (## Мои заметки) которую LLM не перезаписывает.
Всегда будут файлы, не вписывающиеся ни в один кластер. Лучше собрать их в одну "Разное" статью, чем оставлять непроцессированными. При росте базы они могут стать зерном нового кластера.
LLM не знает, что файл изменился после обработки (нет файлового watcher). Два варианта:
updated вручную при редактированииПаттерн работает для:
Obsidian + AI-агент (Claude Code, Cursor, Windsurf или любой другой с доступом к файлам).
| Компонент | Реализация |
|---|---|
| Источники | 2-3 папки с сырыми заметками (inbox, research, podcasts — или как угодно) |
| Wiki | Отдельная папка (например Wiki/), плоская структура без подпапок |
| Index | Wiki/_Index.md — таблица всех статей с темой, кол-вом источников и датой |
| Changelog | Wiki/_Changelog.md — лог компиляций: дата → статья → из каких источников |
| Статусы | YAML frontmatter wiki-status: processed в каждом обработанном файле-источнике |
| Кластеризация | AI сканирует источники → строит topic map → человек выбирает кластеры |
| Компиляция | По одному агенту на кластер (параллельно, если инструмент позволяет) |
| Линтинг | Отдельный проход по всем статьям: cross-links, «См. также», проверка ссылок |
| Synthesis | Отдельный проход: темы, упомянутые в 3+ статьях → кандидаты на synthesis-статьи |
| Автоматизация | Скрипт или команда для повторного запуска (skill, slash command, Makefile — зависит от инструмента) |
Типичный результат cold start: из ~50-100 raw-заметок получается 8-15 primary-статей и 3-5 synthesis-статей.
После сборки у пользователя должны быть:
| Артефакт | Описание | Как проверить |
|---|---|---|
| Папка wiki | Отдельная папка с плоской структурой | Существует, пустая или с первыми статьями |
_Index.md |
Таблица всех статей | Файл существует, формат таблицы корректный |
_Changelog.md |
Лог компиляций | Файл существует, есть хотя бы одна запись |
| Статусы в источниках | wiki-status: processed в обработанных файлах |
Grep по источникам подтверждает |
| Primary-статьи | Скомпилированные статьи из кластеров | Есть ссылки на источники, секция "См. также" |
| Cross-links | Inline-ссылки и "См. также" между статьями | Ссылки не битые, ведут на существующие файлы |
| Skill или команда | Способ повторного запуска компиляции | Запуск команды обрабатывает новые файлы |
Необязательно при cold start, но появятся со временем:
Курс AI Obsidian — 3 недели, 9 встреч, максимум 32 человека
Записаться →