Ian Chou's Blog

Hybrid Search 實戰:從中文分詞到向量資料庫選型完整指南

Hybrid Search 實戰:從中文分詞到向量資料庫選型完整指南

TL;DR


Part 1:中文 BM25 的問題與解決

問題背景

我的 Career RAG 專案使用 Hybrid Search(向量搜尋 + BM25 關鍵字搜尋):

Query → [BM25 Score] + [Vector Score] → Fusion (0.7v + 0.3b) → Rerank → Results

但中文 BM25 效果很差,因為預設 tokenizer 只處理英文:

// 原本的 tokenizer
function tokenize(text: string): string[] {
  return text.toLowerCase().split(/\s+/);  // 按空白分割
}

英文"Kubernetes deployment"["kubernetes", "deployment"]
中文"台積電技術經理"["台積電技術經理"] ❌(整塊)

解決方案:TypeScript + Python 混合架構

TypeScript (BM25 計算)
    │
    ▼ 偵測到中文
Python Script (jieba 分詞)
    │
    ▼ JSON 回傳 tokens
TypeScript (繼續計算)

核心實作

# scripts/tokenize_zh.py
import jieba
import json
import sys

# 載入自訂詞彙(公司名、技術詞)
jieba.load_userdict("user_dict.txt")

def tokenize(text):
    return [t for t in jieba.cut(text.lower()) if len(t) > 1]

print(json.dumps(tokenize(sys.argv[1]), ensure_ascii=False))
// bm25.ts
function tokenize(text: string): string[] {
  if (/[\u4e00-\u9fff]/.test(text)) {
    // 呼叫 Python jieba
    const result = execSync(`python tokenize_zh.py "${text}"`);
    return JSON.parse(result);
  }
  return text.toLowerCase().split(/\s+/);
}

效果驗證

python tokenize_zh.py "台積電技術經理 Kubernetes 機器學習"
# 輸出: ["台積電", "技術經理", "kubernetes", "機器學習"]
指標 改進前 改進後
中文分詞 1 token(整塊) 正確分詞
BM25 召回率 ~30-50% ~80-90%
專有名詞匹配

自訂詞彙字典

jieba 預設詞庫對專有名詞效果差,需要 user_dict.txt

台積電 10 nz
聯發科 10 nz
機器學習 10 n
技術經理 10 n

Part 2:向量資料庫選型全景圖

解決了分詞問題後,我深入研究了向量資料庫的選擇。以下是不同規模場景的對比。

2.1 三種定位的比較

維度 LanceDB Supabase Vector DashVector (阿里雲)
本質 列式儲存格式 PostgreSQL + pgvector 雲原生向量 DB
類比 「更適合 AI 的 Parquet」 「帶向量的 Postgres」 「向量版 RDS」
部署 嵌入式/本地 Postgres 擴充 全託管雲服務
開源度 ✅ 開源 ✅ 開源 ❌ 封閉(SDK)

2.2 中國雲端生態的向量資料庫競爭

公司 產品 特色 開源參與
火山引擎(ByteDance) LanceDB + LAS 數據湖 嵌入式、多模態、Spark 相容 高(LanceDB Committer)
阿里雲 DashVector 雲原生、全託管、Proxima 引擎 低(封閉)

火山引擎自 2024 年起深度整合 LanceDB,貢獻核心工程師,推出 AI 數據湖 LAS,將 LanceDB 無縫對接 Spark/Iceberg 生態,用於內部多模態向量儲存。

阿里雲則走自研路線,推出 DashVector 對抗 Pinecone 等雲向量市場。

2.3 Lance 格式 vs 傳統格式

Lance 是由 Apache Arrow、Hadoop、HBase 專家開發(Rust 編寫),設計為取代 Parquet/ORC/Iceberg

效率指標 Lance Parquet
隨機存取 ✅ 優化 ❌ 需全讀
Schema 演進 零成本 重寫檔案
多模態支援 原生 有限
AI 訓練場景 專為此設計 通用大數據

隨機存取是 Lance 核心:AI 訓練需要從 PB 級資料集隨機抽取樣本,傳統 Parquet 效率低。

零成本 Schema 演進:為數億條記錄添加新 Embedding 維度時,不需重寫整個檔案。

2.4 DashVector 效能規格

阿里雲 DashVector 基於 Proxima 引擎,雲原生架構,支援水平擴展:

實例類型 規模 top-k=1 QPS / 延遲 top-k=100 QPS / 延遲
效能型 P.large 100萬×768維 962 / <30ms 134 / <250ms
儲存型 S.large 500萬×768維 297 / <30ms 37 / <300ms
Serverless 自動擴展 QPS<2 按請求計費

量化後 QPS 可再升 48%,適合高併發 RAG。

2.5 選型決策樹

你的場景是什麼?

├── 個人/小型專案(<100萬向量)
│   ├── 需要本地優先 → LanceDB ✅
│   ├── 已用 Postgres → Supabase Vector / pgvector
│   └── 需要雲託管 → Supabase
│
├── 中型專案(100萬-1億向量)
│   ├── 需要高 QPS → DashVector / Pinecone
│   ├── 需要開源 → Milvus / Qdrant
│   └── 已用阿里雲 → DashVector
│
└── 大型/企業級(>1億向量、AI 訓練)
    ├── 需要數據湖整合 → 火山引擎 LAS + Lance
    ├── 需要多模態 → Lance 格式
    └── 需要全託管 → DashVector / Pinecone

2.6 我選擇 LanceDB 的理由

對於我的 Career RAG 專案(~100 條素材,512 維向量):

  1. 本地優先:資料存專案資料夾,不需外部服務
  2. 零配置npm install lancedb 直接用
  3. 原生 Hybrid Search:Vector + BM25 內建支援
  4. 輕量:整個 DB 就是資料夾,可直接 git 版控
  5. AI 血統:前 Runway ML、Google 工程師創辦

實測效能(本地環境):

操作 LanceDB DashVector 估計
冷啟動 ~50ms ~200-500ms (網路)
向量搜尋 ~5-10ms ~20-50ms (網路)
批次寫入 100 條 ~200ms ~500ms+

對於本地 RAG,LanceDB 延遲優勢明顯。DashVector 的高 QPS 在我的場景屬於過殺。


Part 3:架構選擇思考

為什麼不整個專案改用 Python?

維持 TypeScript 改用 Python
✅ AI Agent Skills 整合順暢 ❌ 需要額外橋接層
✅ 現有代碼可用 ❌ 需要重寫
✅ 只需橋接分詞 ✅ 原生 jieba 支援

結論:混合架構(TS 主體 + Python 分詞)比全面重寫更務實。

什麼時候值得重構為 Python?

  1. 需要更複雜的中文 NLP(關鍵詞提取、情感分析)
  2. 需要本地 embedding 模型(BGE-M3, text2vec-chinese)
  3. 需要 LangGraph 進階工作流
  4. 與 ML pipeline 整合(Pandas, scikit-learn)

Skills 整合說明

Skills 可以呼叫任何語言:

## 用 uv 執行 Python
cd mcp-server && uv run search_material.py --focus "AI"

uv 會自動處理虛擬環境,無需手動 activate。


關鍵學習總結

  1. 中文分詞:jieba + 自訂詞彙是最務實的解決方案
  2. 混合架構可行:TS + Python 橋接比全面重寫更高效
  3. 向量 DB 選型:小型用 LanceDB,企業級考慮 DashVector/Milvus
  4. Lance 格式趨勢:火山引擎深度採用,適合 AI 訓練場景
  5. uv 是好朋友:現代 Python 管理用 uv,比 pip 快 10-100 倍

相關資源