Всички проекти

RAG база знания

pacod-kb

Превърнете файлове и уеб страници във версионирано знание с възможност за търсене — със стабилен договор за моделите, които го четат.

pacod-kb зарежда файлове и уеб страници, преобразува ги в каноничен Markdown, индексира ги за хибридно семантично търсене и търсене по ключови думи, пази всяка версия и подава на моделите надолу по веригата фрагменти със стабилен договор за метаданните. Работи само на CPU.

  • Apache-2.0
  • Версия 1.0.0
  • Стабилна

Възможности

  • Зарежда всичко

    PDF, DOCX, HTML, Markdown, текст и JSON — качени, пуснати в папка, изтеглени от URL или наблюдавани за промени.

  • Каноничен Markdown

    Заглавия, съобразени със структурата, за правни текстове на осем езика, научни статии и публикации; шаблонният текст се филтрира.

  • Сигурност на съдържанието

    Многостепенна проверка за prompt injection и спам блокира документите или ги поставя под карантина, преди да бъдат индексирани; резултатите се ограждат като недоверени данни.

  • Хибридно търсене

    Плътни вектори от BGE-M3 в Qdrant плюс ключови думи с BM25, обединени чрез reciprocal rank fusion.

  • Всяка версия се пази

    Заменените версии остават достъпни за търсене чрез заявки към момент във времето; git архив записва всяка промяна.

  • Калибрирана релевантност

    Незадължителен cross-encoder reranker дава калибрирана оценка на релевантността от 0 до 1.

  • Само CPU

    Ембедингите, OCR и търсенето остават отзивчиви само на CPU, дори докато се зареждат документи.

  • UI и CLI

    Уеб интерфейс и CLI за документи, проекти, задачи, използване и разходи за AI, и членове с роли viewer, editor и admin.

Мястото в системата

Хора и услугиLLM доставчициAPpacod-apCMpacod-cmsKBpacod-kbGWpacod-gwIDpacod-id
Хора и услугиLLM доставчициAPpacod-apCMpacod-cmsKBpacod-kbGWpacod-gwIDpacod-id
Диаграма: как се свързват проектите на pacod Извиквания към LLM Докоснете проект, за да видите с какво е свързан.

Защо съществува

По-голямата част от работата в retrieval-augmented generation се случва, преди моделът да прочете и дума: да вкараш документите, да ги поддържаш чисти, да намериш правилния пасаж и да кажеш на модела откъде идва. pacod-kb е точно тази част, изградена като самостоятелна услуга.

Три изисквания са я оформили. Отговорите трябва да могат да се цитират, затова всеки фрагмент носи пътя си от заглавия и байтови отмествания в стабилен Markdown текст. Източниците се променят, затова нищо не се презаписва: новата версия заменя старата, която остава достъпна за търсене по дата. А зареденият текст е недоверен вход за модела, затова се проверява за prompt injection преди индексиране и се огражда като данни на изхода.

От документи до отговори

Документът минава по един и същ път, независимо дали е качен, пуснат в папката dropzone, изтеглен от URL или изтеглен отново от наблюдаван уеб източник:

  1. Приемане. SHA-256 на байтовете на източника е идентификаторът на документа, така че един и същ файл никога не се зарежда два пъти.
  2. Парсинг. PDF (docling, с незадължително OCR за сканирани страници), DOCX, HTML, Markdown, текст и JSON се превръщат в Markdown с YAML front matter.
  3. Проверка на езика. Приемат се английски, немски, български, руски, сръбски, македонски, хърватски и словенски; останалите се отказват.
  4. Проверка на детерминистичния парсинг за prompt injection и спам, преди какъвто и да е LLM да види текста.
  5. Преобразуване (незадължително). LLM обработка през pacod-gw подрежда Markdown-а. Прекъснат, отказан или празен отговор запазва детерминистичния парсинг.
  6. Почистване и структуриране. Филтър за шум премахва номера на страници, колонтитули и шаблонен текст; повишаването на заглавия разпознава структурата на правни текстове, научни публикации и статии.
  7. Съхраняване на document.md, манифест и моментно копие на източника.
  8. Индексиране. Фрагменти до 500 токена, съобразени със заглавията, се вграждат с BGE-M3 в Qdrant и се записват в индекс по ключови думи, в собствената колекция на проекта.

Архитектура

pacod-kb се състои от две услуги, kb-pipeline и kb-ui, както и от модела и хранилището, които те ползват:

Част Роля
Pipeline API (kb-pipeline, :8000) Зареждане, индексиране, търсене, задачи, настройки; единствената част, която вика AI шлюза
Уеб интерфейс (kb-ui, :8080) Вход през pacod-id, сесии, членове, страниците; вика конвейера с API ключ
BGE-M3 Ембедингите, в собствения процес на конвейера или през обща услуга за ембединги
Qdrant Плътни вектори, вградени в конвейера или като сървър, който могат да ползват и други продукти
SQLite FTS5 или PostgreSQL Индексът по ключови думи с BM25
Файлова система или PostgreSQL Документи, манифести и регистърът на използването и разходите за AI

Разделението е умишлено. Конвейерът парсва недоверени документи и изтегля произволни URL адреси, затова не получава нито една от тайните на pacod-id; интерфейсът пък никога не вижда ключа за шлюза. Всички контейнери са в една обща Docker мрежа, pacod-net, така че разделението се крепи на тайните, а не на мрежите: всеки контейнер получава изричен списък от променливи на средата, а един тест го проверява.

Всяко извикване от интерфейса носи X-KB-Actor — идентификатора на влезлия човек. Конвейерът му се доверява само заедно с API ключа, записва го към задачите, промените в настройките и използването и го предава на шлюза. Когато pacod-id изтрие акаунт, kb заменя този идентификатор с deleted-user навсякъде, преди да потвърди изтриването.

Модел на сигурност

Сигурност на съдържанието. Проверката нормализира текста, за да неутрализира замаскирането, сравнява го с многоезичен набор от правила и връща една от три присъди:

  • block: една находка с висока тежест за injection или замаскиране или висока оценка на заплахата. Зареждането се проваля и нищо не се съхранява.
  • quarantine: документът се пази със статус review и никога не се индексира. Само спам никога не води до блокиране.
  • clean: документът се индексира.

Незадължително второ мнение от LLM през шлюза се иска само когато правилата не са блокирали; то има 15 секунди и при грешка не блокира документа. Материал, за който се знае, че е безопасен, може да прескочи проверката с kb ingest --trusted. На изхода /query огражда всеки фрагмент като недоверени данни.

Изтегляне. WEB_FETCH_ALLOW_PRIVATE=false, препоръчително в продукция, отказва зареждане от URL, който води до частни адреси — защита срещу server-side request forgery.

Хора. Интерфейсът удостоверява хората чрез pacod-id с OIDC и PKCE и пази токените в криптирана сесия на сървъра; бисквитката носи само случайна тайна. Ролите идват от потока за оторизация на pacod-id. Ако копието на интерфейса е по-старо от 60 секунди, страниците отговарят с 503, вместо да гадаят кой какво може.

Роля Може
viewer Четене и търсене
editor Зареждане, повторно индексиране и изтриване на документи; управление на проекти
admin AI Management, промптове, превключватели по време на работа, членове

Търсене, подкрепено с измервания

Заявката минава през Qdrant и през индекса по ключови думи, а двете класирания се обединяват чрез reciprocal rank fusion (k = 60). Филтрите по дата и история се прилагат вътре в двете търсения. Незадължителен cross-encoder, BAAI/bge-reranker-v2-m3, пренарежда най-добрите кандидати и дава оценка на релевантността от 0 до 1, сравнима между заявките, така че min_score може да отсее липсващите отговори.

Стойностите по подразбиране идват от инструмент за оценка на извличането: 14 документа на шест езика (GDPR, Директивата за защита на данните в правоприлагането, четири конституции, статии от Wikipedia) и 92 ръчно написани заявки — перифрази, точни термини, междуезикови, на роден език и такива без отговор. Измерено на процесора на машина за разработка — документацията подчертава, че това не са продукционни числа:

  • Без reranker правилният раздел е сред първите пет при 98,7 % от заявките с отговор; R@1 е 0,83, при около 50 ms.
  • С reranker R@1 се покачва до 0,91, при около 2 s на заявка.
  • При голямо натоварване от зареждане търсенето чакаше около 24 s за цял пакет за вграждане. Сега заявките минават пред работата по зареждането и чакат най-много един малък микропакет: около 0,4 s (p50), когато задачите за зареждане се изпълняват една след друга, както ги изпълнява конвейерът.
  • Пакетите, сортирани по дължина, правят вграждането при зареждане около 2,2× по-бързо, при непроменени вектори.

Reranker-ът е изключен по подразбиране: подобрението му остана малко под прага при отделените за проверка заявки, а латентността му тепърва трябва да се потвърди на продукционния процесор.

Какво получава моделът

POST /query връща фрагменти по стабилен, документиран договор за метаданните:

{"query": "maximum fine for a data breach", "top_k": 5, "as_of": "2025-12-30"}

Отговорът е {"results": [...], "reranked": false, "score_kind": "rrf"}. Всеки резултат съдържа:

Поле За какво служи
chunk_id Стабилен идентификатор, който кодира структурата от заглавия
source_id Идентификаторът на документа: SHA-256 на байтовете на източника
heading_path Път от заглавия като ["Chapter 1", "§ 5"], за цитиране и филтри по раздел
byte_start, byte_end UTF-8 отмествания в съхранения Markdown текст
valid_until Кога тази версия е заменена, или null, докато е актуална
text Вграденият текст, ограден като недоверени данни
score, rrf_score, rerank_score Оценката за подреждане и нейните съставки

Всеки документ има и манифест: заглавие, източник, тип документ, статус, проект, парсерът или моделът, създал текста, и дневник на жизнения цикъл (ingested, superseded, security_flagged, llm_usage и други).

Версии, а не презаписване

Нова версия, заредена с --supersedes, или променен наблюдаван източник маркира старата с valid_until — едновременно във front matter, в манифеста, в индекса по ключови думи и във векторните данни. Търсенията връщат актуалните фрагменти по подразбиране; as_of връща валидното на дадена дата; include_historical връща всичко. Ако наблюдавана страница се върне към предишно състояние, по-ранната версия се възстановява. Замените и повторните изграждания преизползват векторите на непроменените фрагменти.

Експлоатация

kb следва общата мрежова конвенция на pacod: всеки контейнер е в една Docker мрежа, pacod-net. docker-compose.yml съдържа собствените услуги на kb, kb-pipeline и kb-ui. docker-compose.standalone.yml съдържа копията на kb от общите компоненти, които се включват с профилите на Docker Compose: Qdrant, PostgreSQL, pacod-id с база данни до тази на kb, прихващач на поща и шлюз за разработка, чиито фиктивни доставчици държат всичко на машината. make up зарежда и двата файла. На една машина може да работи само по едно копие от всеки общ компонент. В продукция насочвате kb към истински pacod-gw, поставяте pacod-id зад TLS и премахвате профилите за разработка.

pacod-demo, достъпен на demo.pacod.io, пуска kb заедно с останалите проекти на pacod. Той зарежда само файла на приложението на kb: kb държи базата си данни в общия PostgreSQL и колекциите си в общия Qdrant, вгражда през общата услуга за ембединги, а интерфейсът му се обслужва зад общия входен Caddy.

  • Хранилище. KB_STORAGE_BACKEND е filesystem или database; смяната не мигрира документите.
  • Данни. Директориите с данни са променливи (KB_ROOT, KB_MODEL_CACHE, KB_QDRANT_DATA, KB_POSTGRES_DATA). Име без наклонена черта е Docker том; под macOS make setup използва томове.
  • Процесор. TORCH_NUM_THREADS=0 следва квотата на контейнера за процесор. EMBED_BATCH_TOKENS (1024) ограничава колко дълго една заявка може да чака зад зареждане.
  • Модели офлайн. Пуснете веднъж с достъп до мрежата, за да се напълни кешът на моделите, след това задайте HF_HUB_OFFLINE=1.
  • Общи модели. С EMBEDDINGS_URL конвейерът вгражда през общата услуга за ембединги, вместо сам да зарежда BGE-M3. Векторите са същите, така че нищо не се вгражда наново, а конвейерът има нужда от около 2 GB по-малко памет. RERANKER_URL прави същото за reranker-а.
  • Общ Qdrant. На Qdrant, който ползват и други продукти, страниците за Qdrant в интерфейса показват и засягат само колекциите на kb (KB_QDRANT_COLLECTION_PREFIX, по подразбиране kb_).
  • Превключватели по време на работа. Таблото включва и изключва проверката на съдържанието, AI преобразуването и проверката на езика без рестарт; при следващото стартиране отново важат променливите на средата.
  • AI. Администраторите избират модели и редактират промптове в AI Management. Всяко извикване носи непрозрачна атрибуция (функция, задача, проект, човек), а kb записва токените с разхода, изчислен от шлюза. Ако няма конфигуриран шлюз, AI е изключен и нищо друго не се чупи.

Резервните копия обхващат KB_ROOT или базата данни на kb в PostgreSQL, хранилището на Qdrant (или го изградете наново с kb rebuild --all-projects), базата данни на pacod-id в същия PostgreSQL заедно с ключа ѝ за криптиране на ключове, и .env.

Ограничения и още за четене

  • Конвейерът и интерфейсът работят с по един worker: вграденият Qdrant държи заключване на файл, а управлението на сесиите в интерфейса предполага един процес.
  • Reranker в собствения процес на конвейера приблизително удвоява паметта му; с RERANKER_URL конвейерът не зарежда такъв.
  • Сръбският се приема, но детекторът на езици няма профил за сръбски, затова сръбски текст може да бъде разпознат грешно или отказан.
  • Документирани за следващото повторно индексиране, но не включени: разредени вектори от BGE-M3 за половината с ключови думи, почистване на разделянето на фрагменти и изграждане в колекция-сянка преди превключване.

Повече подробности:

Технологии

Написан на
  • Python
Технологии
  • FastAPI
  • Qdrant
  • BGE-M3
  • BM25
  • SQLite
  • PostgreSQL
  • HTMX
  • Docker

Бърз старт

Стартиране с Docker
make setupmake upopen http://localhost:8080/kb
Разработка и оценка
uv syncmake checkmake eval

Работи с

  • pacod-id

    Хората влизат през pacod-id; ролите viewer, editor и admin се предоставят там.

  • pacod-gw

    Незадължителното LLM почистване минава през шлюза, който остойностява и отчита всяко извикване.

  • pacod-ap

    Когато работи заедно с pacod-ap, kb може да вгражда и пренарежда през неговата обща услуга за ембединги, със същите вектори от BGE-M3.

Лиценз

Apache-2.0