embed model 寫死且用英文模型嵌中文(bge-base-en-v1.5)——模型應可配置+index 版本化,支援換代重刷 #59

Closed
opened 2026-07-17 05:06:24 +00:00 by Leo · 3 comments
Owner

[總管] 2026-07-17 讀 code 定性(leo 問「知識庫十年後換 embeddings model 怎麼辦」引出)。

現況kbdb/src/embed.ts:16 寫死 EMBED_MODEL = '@cf/baai/bge-base-en-v1.5'(768 維)。兩個問題:

  1. 英文模型在嵌中文——bge-base-en 對 CJK 語意品質打折(demo 實測中文語意排名普通:問住宿費排名輸給會議室,疑與此有關)。應評估換 @cf/baai/bge-m3(多語)。
  2. 維度綁死換不動:Vectorize index dimensions=768 建立後不可改;bge-m3=1024 維 → 換模型不是改字串,是「建新 index+全量重嵌+切 binding」。

建議修法

  • EMBED_MODEL 進 config(deploy 注入,同 kbdb_embed:true 慣例),不寫死。
  • index 命名帶版本(如 arcrun-kbdb-embed-v2):換代=平行建新 index → reindex backfill 刷滿 → 切 binding,零停機、舊 index 留檔可回退。
  • reindex backfill 機制已在(offset 分頁),重刷通道現成。

成本論點(leo):若嵌入範圍收斂到 entities/gloss(精耕原意,見 #60),全量重刷成本極低、十年累積也刷得動;demo 現在把每個 block 都標 embed:true=實質全文向量化,重刷成本會隨庫長大——嵌入範圍該回歸精耕。

[總管] 2026-07-17 讀 code 定性(leo 問「知識庫十年後換 embeddings model 怎麼辦」引出)。 **現況**:`kbdb/src/embed.ts:16` 寫死 `EMBED_MODEL = '@cf/baai/bge-base-en-v1.5'`(768 維)。兩個問題: 1. **英文模型在嵌中文**——bge-base-**en** 對 CJK 語意品質打折(demo 實測中文語意排名普通:問住宿費排名輸給會議室,疑與此有關)。應評估換 `@cf/baai/bge-m3`(多語)。 2. **維度綁死換不動**:Vectorize index dimensions=768 建立後不可改;bge-m3=1024 維 → 換模型不是改字串,是「建新 index+全量重嵌+切 binding」。 **建議修法**: - `EMBED_MODEL` 進 config(deploy 注入,同 kbdb_embed:true 慣例),不寫死。 - **index 命名帶版本**(如 `arcrun-kbdb-embed-v2`):換代=平行建新 index → reindex backfill 刷滿 → 切 binding,零停機、舊 index 留檔可回退。 - reindex backfill 機制已在(offset 分頁),重刷通道現成。 **成本論點(leo)**:若嵌入範圍收斂到 entities/gloss(精耕原意,見 #60),全量重刷成本極低、十年累積也刷得動;demo 現在把每個 block 都標 embed:true=實質全文向量化,重刷成本會隨庫長大——嵌入範圍該回歸精耕。
Author
Owner

[cloud-worker] 08-03 — 換 bge-m3(leo 拍板),程式已推 Gitea;未部署

先講最重要的:舊模型不是「效果差」,是排序錯誤

過去這件事一直被描述成「semantic 排名近乎雜訊」,聽起來像「不夠準」。實測之後不是——是排錯

測法:5 組中文問答測資,每組 1 個問題 + 2 段真的相關 + 3 段無關
(無關的刻意放「同一個知識庫裡會有的其他主題」,不是隨機句子——那才是真實的雜訊來源)。
判準 margin = min(相關分數) − max(無關分數)margin ≤ 0 就是排錯

模型 維度 排序正確 平均 margin 速度
@cf/baai/bge-base-en-v1.5現役 768 2/5 −0.0413 1660 ms
@cf/google/embeddinggemma-300m 768 4/5 +0.1275 1174 ms
@cf/baai/bge-m3 1024 5/5 +0.1410 959 ms
@cf/qwen/qwen3-embedding-0.6b 1024 4/5 +0.1381 3238 ms

最刺眼的一組——問「知識庫問答為什麼要標出處?」:

相關A  出處標註讓使用者能回頭核對答案來源…        0.8061
無關C  會議室預約規則:每次最多借用兩小時…        0.7789   ← 比相關B還高
相關B  回答時用 [1]、[2] 標注引用編號…            0.7306
無關D  報帳流程:發票請於每月月底前繳交…          0.7232

這就是 leo 2026-07-18 回報的「問 RAG 卻引用會議室規範」的直接數字。
而且英文 bge 系列的分數全擠在 0.65–0.81,區辨力接近沒有——中文對它就是一堆看不懂的 token。

選 m3 而不是 768 維的 embeddinggemma

看起來 embeddinggemma-300m 是 768 維、可沿用現有 index 比較省。那是假的省

  • 不同模型的向量不能混在同一個 index(比對出來是垃圾)⇒ 無論選哪顆都要全部重嵌
  • #58(Vectorize vector delete 未接)代表舊向量刪不掉
    ⇒ 沿用舊 index = 新舊向量永久混住,比現在更糟

開新 index 反而順手繞開 #58(新的天生乾淨,舊的整個丟掉)。既然都要重嵌,就選品質最好且最快的。

已推 Gitea(兩支同名分支)

Arcrun:feat/embed-model-m3-t59#59 本體

  • EMBED_MODEL 寫死常數 → DEFAULT_EMBED_MODEL='@cf/baai/bge-m3' + embedModel(env)
    可由 env.EMBED_MODEL 覆寫,空字串/空白視為沒設
  • 寫入端(embedOnWrite/backfill)與查詢端(semanticSearch共用同一個 getter
    ——兩邊不同步是最惡毒的 bug:不報錯、分數全垃圾、外面完全看不出來。已加測試守。

arcrun-rag:feat/embed-model-m3-t59 — 安裝器那半(index 版本化)

  • EMBED_INDEX_NAME='arcrun-kbdb-embed-m3'EMBED_DIMENSIONS=1024(原本 768 寫死在建 index 的 body 裡)
  • ⚠️ 順手修一個會讓整件事等於沒做的洞:既有實例的 vectorizeReady 快路徑原本不檢查 index 名,
    會直接沿用舊 index ⇒ 加上「index 名要相符」才走快路徑

驗證

  • kbdb 全套 87/87 綠(含新增 4 項);tsc 與基線相同
  • 打包實跑:4/4 成功,產物 grep → kbdb bundle 只有 @cf/baai/bge-m3、舊英文模型 0 殘留
  • 沒有端到端:kbdb 要重新部署才生效,那是 leo 的閘。

⚠️ 既有實例的遷移不是自動的(會有一段「語意是空的」窗口)

換 index 名之後,新 index 是空的 ⇒ 語意搜尋暫時查不到任何東西,直到重嵌完成:

建新 index → 重部署 kbdb(VECTORIZE binding 指新 index)
→ POST /embed/backfill {"reindex":true,"limit":100,"offset":N}  重複到 remaining=0
→ 舊 index 可刪

reindex 機制本來就有,#11 加的,配 offset 分頁。)

下一步(等 m3 部署後才做得了)

leo 08-03 定的方向:semantic-first,keyword 與 graph 變可選
順序不能顛倒——模型沒換之前,semantic-only 會比現在更差(2/5)。換完之後才是:

  1. assemble 的 semantic +0.4 權重拿掉,讓語意當主力
  2. kw_search 整個移出 rag_chat(它現在花 1.2 秒回 0 筆),改成 AI 需要時才調用的工具
  3. graph 改成「語意找到入口節點 → 從那裡展圖」,不再拿整句掃 triplet 子字串

—— cloud-worker,08-03

[cloud-worker] 08-03 — 換 `bge-m3`(leo 拍板),程式已推 Gitea;**未部署** ## 先講最重要的:舊模型不是「效果差」,是**排序錯誤** 過去這件事一直被描述成「semantic 排名近乎雜訊」,聽起來像「不夠準」。實測之後不是——**是排錯**。 測法:5 組中文問答測資,每組 1 個問題 + **2 段真的相關** + **3 段無關** (無關的刻意放「同一個知識庫裡會有的其他主題」,不是隨機句子——那才是真實的雜訊來源)。 判準 `margin = min(相關分數) − max(無關分數)`,**margin ≤ 0 就是排錯**。 | 模型 | 維度 | 排序正確 | 平均 margin | 速度 | |---|---|---|---|---| | `@cf/baai/bge-base-en-v1.5`(**現役**) | 768 | **2/5** | **−0.0413** | 1660 ms | | `@cf/google/embeddinggemma-300m` | 768 | 4/5 | +0.1275 | 1174 ms | | **`@cf/baai/bge-m3`** | **1024** | **5/5** | **+0.1410** | **959 ms** | | `@cf/qwen/qwen3-embedding-0.6b` | 1024 | 4/5 | +0.1381 | 3238 ms | 最刺眼的一組——問「知識庫問答為什麼要標出處?」: ``` 相關A 出處標註讓使用者能回頭核對答案來源… 0.8061 無關C 會議室預約規則:每次最多借用兩小時… 0.7789 ← 比相關B還高 相關B 回答時用 [1]、[2] 標注引用編號… 0.7306 無關D 報帳流程:發票請於每月月底前繳交… 0.7232 ``` **這就是 leo 2026-07-18 回報的「問 RAG 卻引用會議室規範」的直接數字。** 而且英文 bge 系列的分數全擠在 0.65–0.81,**區辨力接近沒有**——中文對它就是一堆看不懂的 token。 ## 選 m3 而不是 768 維的 embeddinggemma 看起來 `embeddinggemma-300m` 是 768 維、可沿用現有 index 比較省。**那是假的省**: - 不同模型的向量**不能混在同一個 index**(比對出來是垃圾)⇒ 無論選哪顆都要**全部重嵌** - 而 **#58**(Vectorize vector delete 未接)代表舊向量**刪不掉** ⇒ 沿用舊 index = 新舊向量永久混住,比現在更糟 ⇒ **開新 index 反而順手繞開 #58**(新的天生乾淨,舊的整個丟掉)。既然都要重嵌,就選品質最好**且最快**的。 ## 已推 Gitea(兩支同名分支) **`Arcrun:feat/embed-model-m3-t59`** — #59 本體 - `EMBED_MODEL` 寫死常數 → `DEFAULT_EMBED_MODEL='@cf/baai/bge-m3'` + `embedModel(env)`, 可由 `env.EMBED_MODEL` 覆寫,空字串/空白視為沒設 - 寫入端(`embedOnWrite`/backfill)與查詢端(`semanticSearch`)**共用同一個 getter** ——兩邊不同步是最惡毒的 bug:不報錯、分數全垃圾、外面完全看不出來。已加測試守。 **`arcrun-rag:feat/embed-model-m3-t59`** — 安裝器那半(index 版本化) - `EMBED_INDEX_NAME='arcrun-kbdb-embed-m3'`/`EMBED_DIMENSIONS=1024`(原本 768 寫死在建 index 的 body 裡) - ⚠️ 順手修一個會讓整件事**等於沒做**的洞:既有實例的 `vectorizeReady` 快路徑原本不檢查 index 名, 會直接沿用舊 index ⇒ 加上「index 名要相符」才走快路徑 ## 驗證 - kbdb 全套 **87/87 綠**(含新增 4 項);tsc 與基線相同 - **打包實跑**:4/4 成功,產物 grep → kbdb bundle **只有 `@cf/baai/bge-m3`、舊英文模型 0 殘留** - ❌ **沒有端到端**:kbdb 要重新部署才生效,那是 leo 的閘。 ## ⚠️ 既有實例的遷移不是自動的(會有一段「語意是空的」窗口) 換 index 名之後,新 index 是空的 ⇒ **語意搜尋暫時查不到任何東西**,直到重嵌完成: ``` 建新 index → 重部署 kbdb(VECTORIZE binding 指新 index) → POST /embed/backfill {"reindex":true,"limit":100,"offset":N} 重複到 remaining=0 → 舊 index 可刪 ``` (`reindex` 機制本來就有,#11 加的,配 `offset` 分頁。) ## 下一步(等 m3 部署後才做得了) leo 08-03 定的方向:**semantic-first,keyword 與 graph 變可選**。 順序不能顛倒——模型沒換之前,semantic-only 會比現在更差(2/5)。換完之後才是: 1. `assemble` 的 semantic +0.4 權重拿掉,讓語意當主力 2. `kw_search` 整個移出 `rag_chat`(它現在花 1.2 秒回 0 筆),改成 AI 需要時才調用的工具 3. graph 改成「語意找到入口節點 → 從那裡展圖」,不再拿整句掃 triplet 子字串 —— cloud-worker,08-03
Author
Owner

結案(2026-08-09 逐票查核)

這張票描述的問題現在已經不存在

證據
`kbdb/src/embed.ts` 已換代到 `@cf/baai/bge-m3`(1024-dim,實測品質最好且最快),`kbdb/src/types.ts:22` 有 `EMBED_MODEL?: string` 可覆寫。(總管親自 grep 複驗)

查核方式:讀現行程式碼實證,非讀票面推測。總管另抽驗過同批中三張(#5/#58/#59),全部屬實。

如果我判錯了,重開就是——關錯票的成本遠低於留著一堆假的待辦,而假待辦會讓 leo 看不出還剩什麼。

## ✅ 結案(2026-08-09 逐票查核) 這張票描述的問題**現在已經不存在**。 **證據** \`kbdb/src/embed.ts\` 已換代到 \`@cf/baai/bge-m3\`(1024-dim,實測品質最好且最快),\`kbdb/src/types.ts:22\` 有 \`EMBED_MODEL?: string\` 可覆寫。(總管親自 grep 複驗) 查核方式:讀現行程式碼實證,非讀票面推測。總管另抽驗過同批中三張(#5/#58/#59),全部屬實。 如果我判錯了,重開就是——**關錯票的成本遠低於留著一堆假的待辦**,而假待辦會讓 leo 看不出還剩什麼。
Leo closed this issue 2026-08-09 13:08:31 +00:00
Author
Owner

[總管·票務複驗 2026-08-09 晚] 關票——問題已不存在,證據是我自己跑出來的。

kbdb/src/embed.ts:38const DEFAULT_EMBED_MODEL = '@cf/baai/bge-m3'(1024 維多語模型,與 Vectorize index dimensions 對齊);:89-90 可由 env.EMBED_MODEL 覆寫。⇒ 票要的兩件(換掉英文模型、模型可配置)都成立。


📌 為什麼是現在才關:這個 repo 的 37 張票原本一張狀態標籤都沒有,等於在看板上不存在,也就沒有人會回頭看它們還成不成立。今晚做了一次全面驗傷,只有實際跑指令驗到問題真的消失的才關;查不出來的一律留著並標明卡在哪。
如果我判錯了(例如你要的其實比程式碼裡這些更多),直接重開這張票,我不會有意見。

[總管·票務複驗 2026-08-09 晚] ✅ **關票——問題已不存在,證據是我自己跑出來的。** `kbdb/src/embed.ts:38` → `const DEFAULT_EMBED_MODEL = '@cf/baai/bge-m3'`(1024 維多語模型,與 Vectorize index dimensions 對齊);`:89-90` 可由 `env.EMBED_MODEL` 覆寫。⇒ 票要的兩件(換掉英文模型、模型可配置)都成立。 --- 📌 **為什麼是現在才關**:這個 repo 的 37 張票原本一張狀態標籤都沒有,等於在看板上不存在,也就沒有人會回頭看它們還成不成立。今晚做了一次全面驗傷,**只有實際跑指令驗到問題真的消失的才關**;查不出來的一律留著並標明卡在哪。 如果我判錯了(例如你要的其實比程式碼裡這些更多),直接重開這張票,我不會有意見。
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: Leo/Arcrun#59