前言

上一篇 完成 Customer Account 系列;接下來四篇改看放在同一工作目錄、但架構上獨立的內部估點系統。它不是 Shopify App,也不會呼叫 Shopify API。案例要解決的是更普遍的問題:PM 收到 PDF、文字說明與畫面附件後,如何先整理需求、參考過去案例,再產生一份可核對的估點建議。

「把 PDF 交給 AI」聽起來像一次 API call,實際上至少包含附件保存、文字抽取、案例檢索、結構化輸出、人工確認、核准與預扣。任何一層失敗,都不該把不完整結果變成承諾。

原本的做法與問題症狀

第一個做法是把附件檔名和 PM 寫的摘要放進估點欄位。這很快,卻沒有讀到 PDF 內真正的頁面、功能與限制;同一份附件由不同人摘要,也可能產生不同範圍。

另一個方向是把所有附件一律當成可讀文字。掃描 PDF 與圖片其實沒有 searchable text,若 parser 回傳空字串後仍繼續分析,模型只能根據標題與少量描述猜測。畫面上看似成功,資料品質卻最危險。

最後一個陷阱是把「AI 建議點數」直接寫成 approved points。只要附件缺頁、檢索到不相似案例或模型漏掉驗收工作,錯誤就會立刻進入後續預扣與結算。

問題是怎麼推敲出來的?

來源的 attachment extractor 明確回傳三種狀態:

純文字/可搜尋 PDF → TEXT_EXTRACTED
圖片/無文字 PDF   → OCR_REQUIRED
不支援或解析失敗   → FAILED

PDF path 使用本地 parser 取得文字;結果為空時,不是假裝成功,而是標成需要 OCR。圖片也不嘗試用檔名推論內容。這個狀態會跟摘要和 extracted text 一起進入 provider input。

Estimate runner 再把 request、attachments 與 reference cases 組成共同輸入。Provider 回來的資料仍要通過 structured schema parser;成功後 request 只進入 PENDING_APPROVAL,不是 APPROVEDHELD

這條狀態線證明估點不是單一模型輸出,而是證據逐層縮小不確定性的工作流。

最後採用的架構

需求表單+附件
  → 附件保存
  → 純文字/searchable PDF extraction
  → OCR_REQUIRED/FAILED 明確停損
  → 歷史案例檢索
  → AI provider
  → Structured schema validation
  → AiEstimate+AnalysisRun
  → PENDING_APPROVAL
  → PM 確認/修正
  → 核准與預扣

附件抽取只負責「我能可靠讀到什麼」,案例檢索只負責「哪些完成案件可能相關」,AI 只負責產生建議。核准層才決定可以承諾與預扣多少,三個責任不能合併。

關鍵實作

Extractor 不把空白 PDF 當成功:

if (mimeType === 'application/pdf') {
  const text = await extractSearchableText(bytes);

  if (!text) {
    return {
      status: 'OCR_REQUIRED',
      error: 'PDF contains no searchable text',
    };
  }

  return {status: 'TEXT_EXTRACTED', extractedText: text};
}

Estimate write 則強制停在人工核准前:

const analysis = parseStructuredAnalysis(providerOutput);

return {
  requestStatus: 'PENDING_APPROVAL',
  aiEstimate: {
    summary: analysis.summary,
    suggestedPoints: analysis.suggestedPoints,
    risks: analysis.risks,
    requiredClarifications: analysis.requiredClarifications,
  },
};

OpenAI 現行 File Inputs 已能直接把 PDF 的 extracted text 與 page images 放進模型 context;但這個案例沒有採用該路徑。它目前仍先在 server 本地抽 searchable text,再把文字交給 provider,兩者不能混寫成同一項已實作能力。

實際驗證

來源測試可證明:

  • 純文字附件可抽出 UTF-8 內容與摘要。
  • Searchable PDF fixture 可抽出預期文字。
  • Image attachment 會回傳 OCR_REQUIRED
  • Extracted text 確實會進入 analysis provider input。
  • Provider output 會寫入 structured estimate 與 successful analysis run。
  • Provider 丟出錯誤時,request 留在 draft,並建立 failed analysis run,而不是帶著半成品前進。

這些是來源專案既有 test contract 與 2026-07-31 source inspection。本次沒有執行來源 App、上傳真實附件、呼叫 live AI provider 或做正式環境驗收。

仍然存在的限制

第一,掃描 PDF、Screenshot 與照片都還沒有 OCR。OCR_REQUIRED 是安全停損,不是已完成的影像理解。

第二,目前附件 extraction 只處理文字與 PDF;DOCX、試算表、設計檔與壓縮檔沒有 parser。檔名出現在 prompt 裡也不代表內容被讀取。

第三,來源的案例檢索是結構化欄位加關鍵字排序,並非 embedding/vector search。文章標題中的 RAG 指 retrieval-augmented 的工作流方向,不代表向量 RAG 已上線。

第四,附件可能包含客戶識別、登入資訊、訂單截圖或內部商業資料。正式系統還需要 size limit、malware scan、encryption、retention、deletion、access log 與送往模型前的資料最小化;provider 能讀 PDF 不等於所有 PDF 都應送出。

第五,AI estimate 有 confidence、risk 與 clarification 欄位,卻仍可能遺漏需求。Reviewer 必須能回看原始附件與抽出的文字,不能只看一個分數。

可以延伸到哪些情境?

這套資料流適合規格書初審、維護工單、內容上架清單與設計驗收,但關鍵不是「用了哪個模型」,而是:

讀不到 → 明確停下
讀得到 → 保存可追溯文字
找到案例 → 當參考,不當答案
產生建議 → 進待核准,不直接承諾

下一篇處理同一條分析流程如何切換執行介面:同一套 AI 分析流程如何支援 Codex CLI 與 OpenAI API?

參考資料

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