Skip to content

技術決策 — 選型、協作方式、與中途轉向

先講限制 — 選型都是從這裡長出來的

  • 時程:hackathon 等級 — 以「週」為單位,不是「季」
  • 團隊:4 人 — 1 PM、2 編輯、1 工程;工程實作是一人 + AI 協作
  • 硬體:demo 機是 2 vCPU、無 GPU 的小 VPS;預算 $0
  • 內容:中文片庫 — 所有模型選擇都要先問「中文行不行」

底層原則:簡化選擇 — 把複雜度預算全部花在「服務如何整合 AI」上,基礎設施一律選最無聊、最不會半夜出事的(boring technology)。重點從來不是堆技術,而是 AI 進來之後,搜尋、標籤、營運的工作流程怎麼變。

初始選型 — 選了什麼、為什麼

選擇為什麼選它
Python + FastAPI自動生 API 文件(Swagger)— 跟 PM / 編輯溝通介面零成本;全專案統一 Python,AI 生態同語言
NiceGUI(純 Python UI)框架包掉前端細節,不用分心管前端 — 同樣 Python-based,一個人顧全棧
SQLite簡單,小專案剛好 — 零維運、單一檔案可備份可搬遷
Qdrant之前用過、社群活躍,踩坑容易查到解法
bge-m3(embedding)主流開源 embedding model,中文表現好、可完全本地跑
LLM:免費雲端優先、可切回本地(LLM)重活(embedding、rerank、評測 judge)全留本地;只有需要大模型推理的 LLM(讀片選標籤、讀懂查詢)走雲端。路線繞了一圈:雲端免費 → 太不穩(429、模型下架)一度改全本地 Ollama → 再回到 OpenRouter 免費(會自動跳可用模型),並保留「一鍵切回全本地 local LLM」當後路 — 零成本,又不被單一雲端綁死
Docker Compose + Traefik @ VPS自有 VPS 零邊際成本、公開 URL、無冷啟動;四個 service 一份 compose 檔講完

怎麼協作 — 不是 vibe coding

工程實作是「一人 + AI」,但每一步都有可驗證的紀律,AI 負責產出、人負責方向與把關:

機制做法擋掉什麼
ADR 決策紀錄每個重要技術轉向寫一篇:背景、選項、理由、影響(共 8 篇)「為什麼當初這樣做」失憶;AI 重構時亂動既有決策
評測閉環45 條真實查詢自動評分,每輪改動跑分 — 贏的留、輸的回滾(見「評測迭代」頁)憑感覺調參;「看起來變好了」的錯覺
pre-commit 關卡lint、格式、secret 掃描、測試,連「前端不准寫死中文文案」都有自動檢查AI 大量產碼時夾帶的低級錯誤與壞習慣
git-based 部署一律 commit → push → 伺服器 pull → rebuild;禁止直接上機改檔demo 機與程式庫漂移;出事無法回滾定位
人工審核迴圈AI 建議標籤 → 編輯逐一核可/退回 → 回饋進 wiki 累積成知識庫AI 的品味問題被靜默放行
AI-native 工作流匯入新片、抓獎項、片庫健檢等營運流程包成自然語言指令(agent skills),AI 跑流程、人下指令看結果重複性營運工作吃掉工程時間

中途的重要轉向(ADR 摘要)

① 純向量搜尋 → Hybrid(BM25 + 向量 + RRF + 精排)

**痛點:**只用向量 cosine 時分數全擠在 0.55–0.65 窄帶、片名等專有名詞抓不準。

**轉向:**參考開源專案 qmd 的做法 — 字面(BM25)與語意(向量)兩路各自召回,用 RRF 融合排名,再交給精排模型。

**理由:**兩種檢索的失敗模式互補 — 字面救專有名詞,語意救意圖;融合用「排名」而非「分數」,迴避兩邊分數尺度不可比的問題。

② 手刻關鍵字解析 → LLM 查詢理解(雙保險)

**痛點:**手刻關鍵字表只覆蓋 3 個維度,「被仙人跳分手該看什麼療傷」這種句子完全無解。

**轉向:**用一次 LLM 呼叫把查詢展開成:14 維標籤訊號 + 假想劇情(HyDE)+ 檢索關鍵字。

**理由:**LLM 懂語意但會失敗(限流/壞輸出)— 所以設計成「LLM 失敗就退回手刻 parser」,搜尋永遠不會因為 AI 掛掉而開天窗。快取讓同查詢只花一次。

③ 旋鈕寫死在程式裡 → 熱載設定 + 可解釋輸出

**痛點:**調一個權重要改 code 重建;搜尋是黑盒,怪片排高無從 debug。

**轉向:**所有權重/門檻集中到一個 JSON,存檔即生效;每個結果帶「為什麼上榜」(符合哪些條件、哪條路找到的)。

**理由:**調參迭代速度 = 實驗次數;可解釋性同時服務 debug 與產品信任,一魚兩吃。

④ 手設權重 → 自我矯正評測閉環(LLM-as-judge)

**痛點:**設定值全是拍腦袋的先驗;demo 沒有真實流量,沒有點擊數據可學。

**轉向:**讓 LLM 當裁判對搜尋結果打分,建自動評測 — 系統不靠流量也能自己量、自己調。

**理由:**沒有訊號就製造訊號。這個閉環後來支撐了 v1–v8 全部的調參敘事(見「評測迭代」頁)。

⑤ 戰壕系列:把本地 LLM 裁判跑穩(四篇 ADR 的連續劇)

裁判搬到本地後連環踩坑,每個坑一篇 ADR:

  • 取消傳不到伺服器 → LLM 呼叫改 streaming,client 斷線才擋得住失控生成
  • 模型還在熱身就被打 → 先繞過(跑前探活),後來拆解成熟開源 agent 怎麼打同一個服務,改成「SDK + 重試吃掉熱身期」— 借鑑比硬造好
  • 回應神祕變空字串 → 不是壞掉,是思考型模型把輸出額度全花在「想」上;加大輸出預算解決

**理由(整個系列的共同教訓)😗*基礎設施問題要追到「別人怎麼解的」為止,不滿足於第一個能跑的 workaround — 每次誤判也照實記錄在 ADR 裡。

INFO

完整 ADR(含被推翻的誤判過程)保存在私有程式庫;此頁為對外摘要。