前言
上一篇 把 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 驗證,不把「文章都寫完」直接等同「整個系列已結案」。
參考資料
- OpenAI:Retrieval
- OpenAI:Vector stores API
- OpenAI:Structured model outputs
- OpenAI:Data controls
- Shopify:Work with protected customer data
以上平台文件查核日期:2026-07-31。
