前言

上一篇 把 AI 建議、人工核准、預扣與結算拆開。真正能改善下一次估點的資料,不是最初那個 suggested number,而是案件完成後才知道的範圍、實際工時、最終扣點、調整原因與工程備註。

內部估點系統因此在 settlement 後建立 Historical Case,再轉成可搜尋的 Knowledge Chunk。這已形成 retrieval-augmented 的回饋骨架,但現況仍是關鍵字排序,不是 embedding/vector RAG;兩者必須清楚區分。

原本的做法與問題症狀

最初的案例庫只保存「某類工作最後用了多少點」。下一次估點可以找相同 work type,卻不知道:

  • 當時附件與需求範圍是什麼。
  • AI 為什麼少估或多估。
  • 核准值和最終值差多少。
  • 實際工時是否支持結算。
  • 哪個案例是良好參考,哪個是特殊例外。

另一個方向是把完成案件全文直接塞回 prompt。案件一多,context 無法無限擴張;跨平台與不同工作類型也會互相干擾。沒有 retrieval 與 quality gate,案例愈多不一定愈準。

問題是怎麼推敲出來的?

Settlement transaction 同時完成四件事:

寫入 RELEASE/CHARGE ledger
  → upsert HistoricalCase
  → upsert KnowledgeChunk
  → WorkRequest 設為 SETTLED

Historical Case 保存原始描述、附件摘要、work type、platform、technical tags、AI suggested points、approved hold、final charge、actual hours、PM adjustment reason、engineer notes、settlement note 與 quality。

Knowledge Chunk 再把這些欄位組成一段可搜尋文字,並以 source type+source ID upsert。相同案件重做 settlement write 時更新同一個 chunk,不建立另一份重複來源。

Retrieval 先限定 work type,再視情況限定 platform,排除 EXCLUDE_FROM_AI,依 query terms 與 quality 排序,最多把少量 reference cases 交給 estimator。

最後採用的架構

已完成 Request
  → Settlement facts
  → HistoricalCase(結構化事實)
  → KnowledgeChunk(檢索文件)
  → Work type/platform/quality filter
  → Keyword scoring
  → Top reference cases
  → 下一次 AI estimate
  → 新的 approval/settlement feedback

HistoricalCase 是 system of record;KnowledgeChunk 是為 retrieval 重新投影的資料。兩者分開後,可以重建 chunk、調整排序或日後生成 embedding,而不必改寫原始結算事實。

關鍵實作

Chunk 不只保存最後數字:

const lines = [
  `需求:${originalDescription}`,
  `AI 建議:${aiSuggestedPoints}`,
  `人工核准:${approvedHoldPoints}`,
  `實際結算:${finalChargePoints}`,
  `實際工時:${actualHours}`,
  `調整原因:${pmAdjustmentReason}`,
  `工程備註:${engineerNotes}`,
  `案例品質:${quality}`,
];

檢索目前是 lexical path:

return chunks
  .filter(isHistoricalCase)
  .filter(sameWorkType)
  .filter(samePlatformWhenSpecified)
  .filter(notExcludedFromAi)
  .map(scoreByQueryTerms)
  .filter(hasPositiveScore)
  .sort(byScoreThenQuality)
  .slice(0, limit);

Prisma schema 雖有 nullable embedding 欄位,現有 write path 沒有生成或更新 embedding。這是明確 roadmap seam,不是隱藏的向量能力。

實際驗證

既有 tests 可證明:

  • Settled case 能轉成 Historical Case Knowledge Chunk。
  • Chunk 包含實際扣點、案例品質、PM 調整原因、工程備註與 tags。
  • Source type 與 source ID 可形成冪等 upsert key。
  • Retrieval 會選出 work type、platform 與 query terms 相符的案例。
  • EXCLUDE_FROM_AI 案例不會成為 reference。
  • 找到的 reference case 會帶入下一次 provider input。

本次沒有執行 production retrieval、embedding job、離線 eval 或實際估點 A/B test。來源目錄也沒有 Git history,因此這些結論來自 2026-07-31 的 source、schema、README 與 test contract,而非 commit 演進紀錄。

仍然存在的限制

第一,目前不是 vector RAG。OpenAI 現行 Retrieval 文件把 semantic search 建立在 vector stores 與 embeddings 上;來源只有 query terms scoring。它能找到共享關鍵字的案例,卻可能漏掉語意相似、用詞不同的案件。

第二,Retrieval 只讀最近一批有限數量的 chunks,沒有 pagination、dedicated search index 或大規模 latency test。

第三,Chunk 保存 customer reference,但 retrieval 沒有用 customer/tenant 作隔離條件。若組織政策不允許跨客戶學習,必須加 tenant filter;若允許跨案件共用,也要先去識別化與定義合法用途,不能把原始需求直接互相暴露。

第四,Knowledge Chunk 可能包含 attachment summary、原始描述與工程備註。若資料源自 Shopify customer/order,仍受 protected customer data 的資料最小化、透明與安全要求;搬進 AI knowledge base 不會消除原本責任。

第五,Learning loop 目前完成的是「保存 feedback 並在下次檢索」,不是模型訓練。沒有 estimate error、approval delta、settlement delta、retrieval recall 與 stale-case eval,就不能宣稱系統會自動愈用愈準。

第六,Case quality 由人工指定。仍需 review owner、過期規則、duplicate detection 與重新分類流程,避免舊技術或一次性例外長期主導估點。

可以延伸到哪些情境?

成熟的案例學習迴圈至少需要四個 gate:

Capture:保存原始建議、人工調整與實際結果
Curate:品質、租戶、敏感資訊與過期治理
Retrieve:可解釋的 filter、ranking 與來源
Evaluate:量測誤差、命中率與人工修正

等這四層都有證據,再把 keyword retrieval 升級成 embeddings、hybrid search 或 managed vector store。向量化只是 retrieval 技術之一;真正讓知識庫可靠的,是結算事實、資料邊界與持續評估。

本篇是 Shopify 開發實錄 ledger 的最後一篇。全系列的完成與風險另由 34 篇 publication audit 驗證,不把「文章都寫完」直接等同「整個系列已結案」。

參考資料

以上平台文件查核日期:2026-07-31。