Dataflow: Local Knowledge Base
Dataflow: Local Knowledge Base
Заголовок раздела «Dataflow: Local Knowledge Base»Постройте базу знаний на собственной машине — создайте векторное хранилище, затем
разбейте документы на чанки и загрузите их в него. Это компаньон по созданию данных к
руководству по RAG: здесь вы поднимаете и наполняете локальную базу
знаний; там вы извлекаете из неё и генерируете ответы. Оба используют модуль
wippy/embeddings поверх локального векторного хранилища SQLite.
Что вы построите
Заголовок раздела «Что вы построите»- Локальное приложение, чья база данных хранит векторное хранилище размерности 512.
- Миграцию, которая создаёт таблицу
embeddings_512при запуске. - Функцию загрузки, которая разбивает markdown на чанки и записывает встраивания в хранилище.
Предварительные требования
Заголовок раздела «Предварительные требования»- Проект Wippy (склонируйте app-template или
выполните
wippy init). - LLM-провайдер с настроенной моделью встраивания (например,
text-embedding-3-small) — см. LLM-фреймворк. Векторное хранилище создаётся локально без него, но загрузка (которая вызываетllm.embed) требует настроенного провайдера.
Установите зависимости:
wippy add wippy/embeddingswippy add wippy/migrationwippy add wippy/bootloaderwippy add wippy/llmwippy installСоздание хранилища
Заголовок раздела «Создание хранилища»База знаний живёт в локальной базе данных SQLite. wippy/embeddings поставляет
миграцию, которая создаёт векторную таблицу; bootloader выполняет её при запуске.
Свяжите части вместе:
version: "1.0"namespace: app
entries: - name: db kind: db.sql.sqlite file: ./data/app.db lifecycle: auto_start: true
- name: processes kind: process.host host: max_processes: 1000 workers: 8
- name: embeddings kind: ns.dependency component: wippy/embeddings parameters: - name: target_db value: app:db
- name: migration kind: ns.dependency component: wippy/migration parameters: - name: app_db value: app:db
- name: bootloader kind: ns.dependency component: wippy/bootloader parameters: - name: application_host value: app:processes - name: app_db value: app:db - name: env_storage value: app.env:storeBootloader-у нужно хранилище окружения; добавьте стандартное в его собственном пространстве имён:
version: "1.0"namespace: app.env
entries: - name: file kind: env.storage.file auto_create: true file_path: .env lifecycle: auto_start: true
- name: os kind: env.storage.os lifecycle: auto_start: true
- name: store kind: env.storage.router lifecycle: auto_start: true storages: - app.env:file - app.env:osСоздайте директорию данных и запустите приложение:
mkdir -p datawippy runПри запуске выполняется миграция, и хранилище появляется в data/app.db:
$ sqlite3 data/app.db ".tables"_migrations embeddings_512 embeddings_512_chunksembeddings_512_info embeddings_512_rowids embeddings_512_vector_chunks00...embeddings_512 — это виртуальная таблица SQLite vec0; теневые таблицы
embeddings_512_* хранят её чанки, идентификаторы строк и метаданные. (На PostgreSQL та
же миграция использует pgvector.)
Загрузка документов
Заголовок раздела «Загрузка документов»Загрузка состоит из двух шагов: разбейте текст на чанки модулем text, затем запишите
их через embeddings.add_batch, который встраивает и сохраняет каждый чанк.
-- src/ingest.lualocal text = require("text")local embeddings = require("embeddings")
local function ingest(doc_id, title, markdown) local splitter, err = text.splitter.markdown({ chunk_size = 800, chunk_overlap = 100, heading_hierarchy = true, code_blocks = true, }) if err then return nil, err end
local chunks, split_err = splitter:split_text(markdown) if split_err then return nil, split_err end
local batch = {} for i, chunk in ipairs(chunks) do table.insert(batch, { content = chunk, content_type = "doc_chunk", origin_id = doc_id, context_id = tostring(i), meta = { title = title, chunk = i }, }) end
return embeddings.add_batch(batch)end
return { ingest = ingest }Зарегистрируйте функцию:
- name: ingest kind: function.lua source: file://ingest.lua method: ingest modules: - text imports: embeddings: wippy.embeddings:embeddingsКлючевые моменты:
origin_idгруппирует все чанки из одного исходного документа — удаляйте и повторно загружайте по документу черезembedding_repo.delete_by_origin(doc_id).content_typeпозволяет держать разные корпуса (doc_chunk,faq,code_snippet) в одном хранилище и фильтровать на этапе запроса.add_batchавтоматически разделяет, когда батч превышает лимит запроса в 8000 токенов.
Проверка содержимого
Заголовок раздела «Проверка содержимого»После загрузки документов убедитесь, что строки появились, и выполните поиск по сходству:
local embeddings = require("embeddings")
local results, err = embeddings.search("how do I configure TLS?", { content_type = "doc_chunk", limit = 5,})-- results[i].content, .similarity, .meta, .origin_id, .context_idОтсюда руководство по RAG показывает, как передать эти результаты в LLM для обоснованных ответов.
Эксплуатационные заметки
Заголовок раздела «Эксплуатационные заметки»- Размер чанка: 500–1000 токенов — хорошая отправная точка. Используйте
chunk_overlap(~10–20 % размера чанка), чтобы предложения не разрезались на границах. - Размерности:
text-embedding-3-smallпри 512 измерениях экономична по стоимости и соответствует таблицеembeddings_512. Бо́льшие векторы означают больший объём хранилища и более медленный поиск. - Локальное vs. общее: SQLite (
vec0) держит всю базу знаний в одном локальном файле — идеально для разработки и одноузловых приложений. Укажитеtarget_dbнаdb.sql.postgresсpgvectorдля общего, продакшен-хранилища; код загрузки не меняется.
Следующие шаги
Заголовок раздела «Следующие шаги»- RAG — извлекайте из этого хранилища и генерируйте обоснованные ответы
- LLM-фреймворк —
llm.embed, модели встраивания, провайдеры - Модуль Text — сплиттеры и токенизация