核心概念
了解定義 KuraDB 行為的狀態、一致性、安全性與檢索概念。
唯讀服務邊界
從 consumer 角度來看,KuraDB 是唯讀服務。HTTP API 接受 health、list 與 search request,但不接受內容 mutation。Filesystem ingestion 是唯一的內容寫入路徑:
watched inbox → parser → databaseHandler.Upsert → SQLite
此邊界可避免 API client 在 watcher 控制的 pipeline 外修改 retrieval corpus。
Registry 與已載入資料庫
db.json 中的 registry 記錄預期的資料庫。Daemon 只會在啟動時開啟這些 entry。因此:
kura add會修改持久 registry state 並建立目錄。/api/list會區分registeredentry 與目前loaded名稱。- 新增的資料庫重新啟動前無法搜尋。
- Rename 與 remove 時必須了解執行中的 process 仍持有啟動時建立的 map。
SQLite 作為 source of truth
每個資料庫都將解析後的 chunk 與 embedding 儲存在 {db}/data.db。SQLite 決定 row 處於 active、pending embedding 或 dismissed 狀態。記憶體快取只用來提升查詢速度,隨時可捨棄:
| 狀態 | 持久來源 | 重建行為 |
|---|---|---|
| Chunk content | file_data.content |
絕不從 vector cache 取得 |
| Embedding | file_data.embedding |
啟動時載入 vector bucket |
| Query embedding | query_cache.embedding |
預載至 openai.Cache |
| Source vector | 在記憶體衍生 | 由 chunk vector 平均並正規化後重建 |
| Watch snapshot | record.json |
下次比較目錄前載入 |
Chunk 生命週期
解析後的檔案會產生有編號的 chunk。Upsert 會先將來源既有的 active row 標記為 dismissed,再於同一 transaction 中插入或更新目前 chunk。若 chunk content 未變,其 embedding 會保留;若 content 已變,則清除 embedding 並將 is_embed 重設為 FALSE。
刪除的檔案不會被實體移除。Watcher 會呼叫 Dismiss,將相符 row 標記為 dismiss = TRUE。每條 active query path 都會過濾這些 row。
Embedding 一致性
OpenAI client 會要求 text-embedding-3-small 的 512 維向量。編碼格式使用 little-endian float32,因此有效 blob 為 2,048 bytes。KuraDB 在多個位置維持一致性:
- OpenAI response 必須包含要求數量的向量。
- 每個回傳向量都必須正好有 512 個元素。
- Query-cache preload 會略過 byte length 不等於
openai.Dim() * 4的 blob。 - Vector search 會忽略維度與 query 不同的向量。
- Embedding update 的 SQL predicate 會包含原始 content,避免檔案變更後套用過期結果。
雙重檢索
搜尋可以執行 keyword retrieval、semantic retrieval,或同時執行兩者。
| 策略 | Query 準備 | 檢索 | 排序 |
|---|---|---|---|
| Keyword | gse 斷詞、trim、lowercase、去重 | 對 active content 執行 SQLite LIKE |
命中 token 數,再依 row ID |
| Semantic | 從 cache 或 OpenAI 取得 query embedding | 兩階段記憶體 cosine search,再由 SQLite hydrate | Cosine score,最低門檻 0.3 |
兩個 branch 同時執行時會並行運作,並在 response 中維持分離。KuraDB 不會將兩者 ranking 合併成單一 score。
Source-level vector 過濾
Semantic search 會從 chunk vector 為每個 source 衍生一個 normalized vector。搜尋先排序所有 source vector,保留約 5%,且最少 20 個 candidate,再只對這些 source 內的 chunk 計算 cosine similarity。若 source vector 不存在,則 fallback 為搜尋所有 chunk vector。
Query cache
openai.Cache 會將完整 query string 對應至 embedding。Cache miss 時,semantic search 會呼叫 OpenAI 並將 vector 儲存在記憶體。OnSet callback 會以五秒 timeout 非同步將編碼後的 vector 寫入 global.db。啟動時會預載有效 entry,且不會再次觸發 persistence。
API response 契約
搜尋結果會依 source 分組,且只暴露:
{
"source": "/path/to/file.md",
"matches": [
{"chunk": 1, "content": "..."}
]
}
Row ID、semantic score、keyword hit count、chunk total 與 cache state 等內部欄位仍屬 implementation detail。
平台假設
Watcher 使用 size 與 modification time 比較直接目錄 entry。KuraDB 支援具可靠 POSIX 語義的本機 macOS 與 Linux filesystem;Windows、SMB、NFS 或 FUSE mount 無法保證這些假設,因此不在正確性承諾範圍內。