# 檢索模型

了解 KuraDB 執行的兩個檢索 branch、semantic search 如何縮小 candidate 範圍，以及 query embedding 如何快取。

## 雙重檢索

搜尋可以執行 keyword retrieval、semantic retrieval，或同時執行兩者。

| 策略 | Query 準備 | 檢索 | 排序 |
|---|---|---|---|
| Keyword | gse 斷詞、trim、lowercase、去重 | 對 active content 執行 SQLite `LOWER(content) LIKE` | 命中 token 數，再依 row ID |
| Semantic | 從 cache 或 OpenAI 取得 query embedding | 兩階段記憶體 cosine search，再由 SQLite hydrate | Cosine score，最低門檻 `0.3` |

兩個 branch 同時執行時會並行運作，並在 response 中維持分離。KuraDB 不會將兩者 ranking 合併成單一 score。任一 branch 出錯，整個 request 即失敗。Query 處理細節見 [搜尋與檢索](/search-and-retrieval)。

## Source-level vector 過濾

Semantic search 會從 chunk vector 為每個 source 衍生一個 normalized vector。搜尋先排序所有 source vector，保留約 5%，且最少 20 個 candidate，再只對這些 source 內的 chunk 計算 cosine similarity。若 source vector 不存在，則 fallback 為搜尋所有 chunk vector。逐階段演算法見 [語意搜尋](/search-and-retrieval-semantic)。

## Query cache

`openai.Cache` 會將完整 query string 對應至 embedding。Cache miss 時，semantic search 會呼叫 OpenAI 並將 vector 儲存在記憶體。在 daemon 中，`OnSet` callback 會以五秒 timeout 非同步將編碼後的 vector 寫入 `global.db`。啟動時會預載有效 entry，且不會再次觸發 persistence。

`kura mcp` 會預載同一張表，但不註冊 `OnSet` callback，因此它計算出的 query embedding 只存在於該 session。
