RAG и базы знаний
Как Cradle обосновывает ответы агентов вашими документами — chunking, embedding, retrieval, цитирование и веб-краулинг.
Cradle не отвечает от обобщённой облачной модели. Когда у агента есть одна или несколько баз знаний, входящее сообщение эмбеддится, сопоставляется с локальным векторным хранилищем, а top-фрагменты вставляются в промпт с inline-цитатами.
Поток от начала до конца
Сообщение пользователя
│
▼
TriageOrchestrator
├── оценка риска
├── router выбирает агента
└── если agent.knowledgeBaseIds.length > 0:
├── acquireEmbedder()
├── search(query, embedder, { kbIds, topK: 6 })
│ embed(query) → vector
│ sqlite-vec MATCH → top chunks
│ join documents + knowledge_bases
├── Hits → SourceSnippet[]
└── buildPrompt(agent, turns, sources)
«Используй нумерованные источники ниже, если они релевантны. Цитируй как [1].»
[1] Заголовок документа (источник)
содержимое...
[2] ...
│
▼
runner.generate → черновик с цитатами → Inbox / автоответВекторное хранилище
Cradle использует sqlite-vec для векторного поиска. Каждая база знаний получает
собственную виртуальную таблицу под размерность embedding-модели:
CREATE VIRTUAL TABLE vec_kb_<kbId> USING vec0(
chunk_id TEXT PRIMARY KEY,
embedding FLOAT[<dim>]
);Старые базы знаний без registry-записи продолжают работать через legacy общую
таблицу vec_chunks.
Таблицы
knowledge_bases (id, name, description, embedding_model_id, embedding_dim, created_at)
documents (id, kb_id, source_kind, source_uri, title, mime, sha256,
status, char_count, chunk_count, error_message, ingested_at)
document_chunks (id, document_id, kb_id, position, content, token_count, metadata)agents.knowledge_base_ids — JSON-список id баз знаний, доступных агенту.
Стратегия chunking
Paragraph-first chunker держит связанный текст вместе:
- Разбивает по пустым строкам на абзацы.
- Накапливает абзацы, пока сумма не превышает 2000 символов.
- Если абзац больше лимита — разбивает по границам предложений.
- Если отдельное предложение всё ещё больше лимита — жёсткий обрез по символам.
- Сохраняет overlap 200 символов между соседними chunks.
Каждый chunk хранит content, position и оценочное число токенов
(chars / 4).
Ingestion
await ingestText({
kbId,
title,
text,
sourceKind: 'upload' | 'url' | 'crawl' | 'inline',
sourceUri,
mime,
embedder,
batchSize = 16,
})- Идемпотентность по SHA-256 текста.
- Chunks вставляются со статусом
indexing, эмбеддятся батчами, затем переводятся вready. - Ошибки откатывают документ в
status='error'с сохранённым сообщением. - Прогресс отчитывается между батчами.
Парсеры
| Расширение | Реализация |
|---|---|
.md, .markdown | читается как plain text |
.txt, .log, .csv | читается как plain text |
.pdf | pdf-parse v2 |
.docx | mammoth.extractRawText |
.xlsx, .xls | exceljs, одна текстовая строка на строку |
parseFile(filePath) возвращает { text, title, mime }. isSupported(filePath)
проверяет расширение перед попыткой ingestion.
Retrieval
await search(query, embedder, { kbIds, topK = 6, maxDistance })- Эмбеддим запрос.
- Выполняем
SELECT chunk_id, distance FROM vec_kb_... WHERE embedding MATCH ?. - JOIN с
document_chunksиdocumentsдля обогащения. - Фильтруем по запрошенным базам знаний.
- Опционально фильтруем по
maxDistance. - Возвращаем
topKрезультатов какSearchHit[].
Хелперы deleteDocument(id) и deleteKnowledgeBase(id) каскадно чистят chunks.
Drizzle FK cascades покрывают большинство таблиц, но sqlite-vec virtual tables
чистятся явно.
Цитирование
Каждый chunk, использованный в ответе, сохраняется в ticket_sources со
снимком:
ticket_sources (
id, ticket_id, message_id, position,
document_id, chunk_id, kb_id,
document_title, source_uri,
content_preview, content_full,
chunk_position, distance, created_at
)Снимки делают тикеты воспроизводимыми, даже если оригинальный документ позже
удалён или переиндексирован. UI показывает нумерованные бейджи, совпадающие с
[1], [2], ... которые модель ставит в тексте ответа.
Веб-краулинг
Базы знаний можно наполнять веб-краулингом:
rag:ingestUrl({ kbId, url })— одна страница или документ.rag:crawlSite({ kbId, seedUrl, maxPages, maxDepth, sameDomain, followDocs, respectRobots })— BFS-задача с live-прогрессом.
Модули краулера в src/core/rag/crawler/:
url.ts— нормализация URL и проверка same-domain.html.ts— cheerio + turndown extraction, удаляет script/style/nav/footer/aside.robots.ts— кешированный robots.txt для каждого origin.fetcher.ts— fetch HTML или документов.crawler.ts— BFS с политeness-задержкой 500 мс, лимитами depth/pages, follow-документами.
Лимиты по умолчанию: HTML до 10 MB, документы до 50 MB, таймаут запроса 20 с.
RAG + finetuning
RAG поставляет факты (прайсы, спецификации, пункты договоров). Finetuning поставляет стиль и паттерны рассуждений. Они дополняют друг друга; см. finetune.