AI-Brain · 現場拷問用

系統全解與現場拷問

每一題都是現場真的會被問的。答得出來,代表你真的懂這套系統;答不出來的那幾題, 就是上台前要補的洞。「看畫面的人問的」與「看架構的人問的」混在一起排, 因為現場本來就是混著問的。

依據:實體程式 ai-brain-code23b7268(2026-09-15 最新一筆),逐行讀碼; 雛形 ai-brain-sa/prototype/adam/
分工:文件在 ai-brain-sa,程式碼在 ai-brain-code(Adam 的 GitLab repo,我方唯讀、只提供建議)。
姊妹文件建單架構與Demo問答_20260915.html 專講建單那條線。 這份補上分析那條線、整體架構、畫面上每一格的來歷,建單只留最常被問的幾題。

00先背起來的十句話

這十句是骨架。現場八成的問題都可以從其中一句展開,答不下去時也可以退回這十句。

#一句話為什麼這句重要
1 AI-Brain 是一條固定的八步主幹:提問 → 前處理 → 判意圖 → 選流程 → 取證 → 證據池 → 統整 → 呈現。只有「取證」和「呈現」隨題目變,其餘六步每題都一樣。 被問「這到底是什麼」時的標準答案。也說明了它不是一個自由發揮的 Agent。
2 流程由人設計,寫在 YAML;模型不決定流程。 這是整套設計的核心主張,也是跟 ChatGPT 最大的差別。
3 先取證再回答。統整的模型只看得到取回來的證據,證據裡沒有就說沒有。 回答「會不會亂編」的唯一正確路徑。
4 數字歸程式,語意歸模型。門檻、比例、筆數由 SQL 與程式判;只有「意圖是什麼」「這段話怎麼寫」問模型。 被問「AI 會不會算錯」時用。它把責任切得很乾淨。
5 AI-Brain 自己一顆資料庫都不連。結構化資料一律問 AI team 的 text-to-SQL,查哪張表、產什麼 SQL、在哪執行都是他們的事。 很多人會假設我們自己存了一份 SAP 資料。沒有。
6 每一句答案都能點回原文。答案裡的 [1] 是證據編號,點下去看得到那一片原文。 「可稽核」的具體證明,不是形容詞。
7 查不到就說查不到,而且不呼叫模型。0 筆是短路條件,直接回「查無資料」。 反直覺但最有說服力的一條:系統的可信度來自它願意說「沒有」。
8 全部在內網。語言模型是自架的 Qwen(192.168.170.31),OCR 在 .28,資料庫在 .31。沒有任何一段送到外部雲端。 日本客戶一定會問,而且這是加分題。
9 建單一定要人確認,沒有全自動。兩次確認(要不要建、欄位對不對)是刻意的。 ERP 客戶最怕的就是 AI 自己去改資料。
10 準確率照實講:text-to-SQL 自評 76%。所以畫面上一定看得到實際的 SQL 與系統理解的條件。 主動講比被拆穿好。而且它接著就帶出「所以我們把依據攤開」這個設計。
上台前先確認一件事:你演的是雛形還是實體? 兩者的畫面刻意做成一樣,但底下完全不同。雛形不呼叫任何 API,問答是預先寫好的腳本; 實體是真的在跑。這份文件每一題都會標明講的是哪一邊,差異清單在 §07。 講錯這件事,比講錯任何技術細節都嚴重。

01畫面上每一格是什麼

不懂技術的人會指著畫面問。這一節照著畫面由上到下排,每一個會被指到的東西都有答案。

1-1 「展開分析」那幾行

畫面展開一下分析我看看——這四行到底是什麼?
是系統剛剛真的走過的每一步,不是動畫。

回答上面那一行小字(「已完成分析 · 1.6 秒」)點開,會看到這一輪經過的步驟、每一步的結果、耗時, 最底下還有一組請求編號。典型的一題長這樣:

理解問題      期間 2022 年 11 月(2022-11)    preprocess   完成
判斷意圖      分析 · LLM 124 ms               intent       完成
查資料        1 筆,38 ms                     sql          完成
統整回答      108 字                          synthesize   完成

(這是問「2022 年 11 月有多少張訂單」時的實際畫面。) 左邊是這一步的中文名稱,中間是這一步實際得到什麼,右邊灰色小字是這一步的程式代號preprocessintentsqlsynthesize), 最右邊是狀態。

順序是固定的,而且有理由:一定是先「理解問題」再「判斷意圖」。 因為前處理要把「第二名呢」這種追問補成完整問句,而意圖分類器只看得到那一句話—— 沒補的話它只收到三個字。詳見 §02

為什麼要給使用者看?因為這套系統的賣點是「講得出依據」。 如果只回一段話,使用者沒辦法判斷該不該相信;把經過攤開,他至少知道系統查了什麼、用什麼條件查。

畫面「判斷意圖」是誰在判?判什麼?為什麼結果是「分析」?
Java 後端的 IntentClassifier,呼叫語言模型問一題「這句話屬於哪一類」。

總共只有四類

  • 分析 —— 要查公司資料、數字、文件。絕大多數問題都落在這裡。
  • 系統說明 —— 在問這個助理本身(你是誰、你用什麼模型、資料會不會外流)。
  • 一般對話 —— 只有招呼、道謝、寒暄,完全沒在問資訊。
  • 業務操作 —— 要系統去做一件事(目前就是建訂單)。

分成四類的目的是決定接下來走哪一條流程。問候語不需要去翻資料庫; 問「你用什麼模型」不需要去查知識庫(以前沒分這類的時候,這一題會跑去翻公司的 AI 使用政策文件)。

這一步同時還做了第二件事:順便選好要走哪一條流程。所以它不是「先分類、再另外選流程」兩次呼叫,是一次解決。

畫面「LLM 124 ms」的 124 毫秒是什麼時間?
問模型「這句話是哪一類」這一趟來回的時間。

LLM 是指這一步用語言模型判的。旁邊還可能出現另外兩種字樣:

  • 規則 —— 模型連不上時的備援,用關鍵字判(招呼語、「你是誰」這類字串)。整條鏈不會因為分類器掛掉就死。
  • 附件 —— 使用者傳了圖,直接判成業務操作,連問都不用問模型,所以是 0 毫秒。

一百多毫秒大約就是一次網路來回的時間(實測穩定約 130 ms)。 冷啟動第一次會比較久,實測約 250 ms。

為什麼這麼快?因為只讓它回一個代碼,上限 16 個 token、溫度設 0(不要有創意)。 它不是在寫文章,是在做單選題。
畫面那一行字每一段分別是什麼?分析 → data_query · LLM 124 ms
四段,每一段回答一個不同的問題。
那一段回答什麼可能出現什麼
分析分到哪一類 分析/系統說明/一般對話/業務操作,只有這四種
→ data_query接下來走哪一條流程 流程代號。模型沒直接回代號時這一段不會出現
· LLM怎麼判出來的 LLM=問模型;規則=模型連不上時的備援;附件=看請求裡有附件,根本沒問模型
124 ms問模型那一趟花多久 用附件判的是 0 ms,所以不印

「理解問題」那一行的規則不一樣:抽到什麼就列什麼 (期間、客戶、商品、單號、「補上前文 →⋯」),一個都沒抽到就寫「無特別條件」。 所以那一行其實是在告訴你「我從你這句話裡聽懂了哪些條件」。

這一格是很好的追問材料:如果使用者說「它答錯了」, 先看這一行——多數答錯是條件理解錯,不是查詢寫錯。
技術這些步驟的名字是誰決定的?前端寫死的嗎?
不是。名字跟順序都由後端決定,前端只照收到的順序畫。
  • 名字來自兩個地方:流程 YAML 裡每一步的 label (而且是寫成中/英/日三語的),以及後端程式裡的固定字串(理解問題、判斷意圖)。
  • 順序就是事件到達的順序——前端收到一則沒看過的步驟就往清單尾端加一筆, 不排序、不重組。

這件事的意義:畫面上看到的順序,就是後端真的執行的順序。 要改順序只能改後端,改不動前端。這也是為什麼「進度列是真的不是動畫」這句話站得住。

畫面表格上寫「已截斷」是什麼意思?資料不完整嗎?
是保護機制:一次最多帶回 200 列,超過就截斷並明說。

為什麼要有上限:一個沒寫好的查詢可能回幾十萬列,那會把畫面、記憶體、 以及送進統整的內容全部撐爆。

為什麼要明說:如果默默只給前 200 列,使用者會以為那就是全部, 然後根據不完整的資料做判斷。寧可讓畫面難看一點,也不要讓人算錯。

這跟「查無資料」是同一個原則的兩面——系統寧可少答、寧可承認限制,也不要講一個 看起來完整但其實不完整的答案。

畫面「理解問題」在做什麼?那一行的條件是誰決定的?
是程式用規則換算的,完全沒有經過模型

這一步把人話換成機器用得上的條件,做四件事:

  • 時間詞換成日期區間:「這個月」「上個月」「上季」「去年」「2026年8月」都換成起訖日。
  • 公司/商品的俗名換成代號:查一張別名表。長的名字先比,「宏達精密」不會被「宏達」搶走。
  • 單號補齊:「訂單 104705」補成十位數的 0000104705(SAP 的單號是固定十碼)。
  • 追問沿用上一輪:上一題問了 8 月,這題只問「那毛利呢」,期間就沿用 8 月。

那一行顯示的就是它從你這句話裡聽懂的東西,三種可能:

  • 抽到了就列出來 —— 例如「期間 2022 年 11 月(2022-11)」「客戶 大同材料(C-1088)」。
  • 你沒講期間 —— 寫「未指定期間,預設全期間」。 意思是「我自己補了一個,而且我把補的內容告訴你」。 這句話存在的唯一理由就是——預設值要說出來,不能默默假設
  • 什麼都沒抽到 —— 寫「無特別條件」(例如問「你好」或純文件類的問題)。
雛形與實體在這裡不一樣,而且兩邊都對 雛形寫「預設全期間」,實體寫「預設本月」。 因為雛形的資料只到 2024-11-15,用「本月」去查會得到 0 筆;實體面對的是活資料,預設本月才合理。 被問到就照這樣講,這是資料決定的,不是誰寫錯。
畫面為什麼要「預設」?沒講期間就直接問我不行嗎?
可以,而且真的缺到不能猜的東西時就是這樣做的。

分界線是:猜錯了還救得回來的,就猜並講出來;猜錯會給出一個看起來合理但錯誤的答案的,就停下來問。

  • 期間沒講 → 預設並標示。使用者看到「預設全期間」,不對就改口再問一次,成本很低。
  • 問「這張單出貨了嗎」但沒給單號 → 停下來問。隨便挑一張單回答,使用者根本看不出來那不是他要的那張。

後者在畫面上的樣子是:不給表格,直接回「請告訴我訂單號碼」。

畫面「查資料 1 筆,38 ms」——38 毫秒就查完了?資料在哪裡?
「1 筆」是查回幾列資料,「38 ms」是資料庫執行 SQL 的時間,不是整步的時間。

這一步的完整經過是:把問句原文送給 AI team 的 text-to-SQL 服務 → 他們的模型當場產出一句 SQL → 在他們那邊執行 → 把「實際跑的那句 SQL」和「查到的資料列」一起回來。

同一行還可能多出兩段括號,都是值得多看一眼的訊號:

  • (重修 2 輪) —— 模型第一次產的 SQL 跑不起來,自己改了兩次才成功。 遇到這個,前端會把 SQL 預設展開。
  • (已截斷) —— 資料超過一次帶回的上限(200 列),只給了前面那些。

資料在一顆叫 middledb 的 PostgreSQL(192.168.170.31), 裡面是 SAP 銷售模組 12 張表的鏡像子集——不是 SAP 本尊。 為什麼不直接連 SAP,見 §03

一個誠實的補充:整步真正花的時間比 38 ms 長很多(實測一輪 8~13 秒), 因為大部分時間花在「模型產 SQL」,不是「資料庫跑 SQL」。 畫面上那個數字講的是後者。被追問時可以這樣拆開講。
畫面「統整回答 108 字」——字數有什麼好顯示的?
它其實是在講「這一步真的產出了東西,而且產出了多少」。

這一步是唯一一個「讓模型寫字」的步驟。有引用到證據的題目,這一格還會多一個數字: 321 字,引用 3 片——引用了幾片證據

那個「引用幾片」才是真正有用的訊號:如果一段答案寫了 300 字卻一片證據都沒引用, 那就是模型在自由發揮,是要抓出來的狀況。實體的監控系統就有一條固定查詢在找這種案例 (引用數 = 0 而且有回答)。

雛形有四題只寫字數、沒有引用片數 純查資料那幾題(訂單張數、客戶排名、商品排名、收入卡關)在雛形只寫「108 字」。 實體會寫「108 字,引用 1 片」——因為在實體那邊,查詢結果本身就是一片可以被引用的證據。 這是雛形的簡化,被問到不要答成「查詢結果不能引用」。
畫面這幾步是真的在跑,還是做給我看的動畫?
實體是真的;雛形是照真的錄下來的腳本重播。

實體:每一則進度都是後端真的執行到那一步才送出來的,內容是那一步的實際結果 (命中幾片、判斷結果是什麼)。技術上是用 SSE 一則一則推給前端的。

雛形:沒有後端,進度列的毫秒數是腳本裡寫死的示範值。 被直接問「這是真的嗎」,照實講——而且緊接著補一句:但知識庫的檢索是真的在瀏覽器裡算的 (見下面 tf-idf 那題),可以當場換一個沒準備過的問題試。

陷阱為什麼要把這些步驟給使用者看?別的 AI 都不給看
因為這套系統賣的不是「會回答」,是「答案有依據」。

ChatGPT 那類產品的目標是讓你忘記背後有流程;這套的目標相反—— 使用者必須看得到它查了什麼、用什麼條件查、依據是哪幾片文件, 因為它回答的是會被拿去做決策的公司數字。

更實際的理由:text-to-SQL 的正確率是 76%,不是 100%。 所以判斷「這個答案對不對」的責任,一部分必須留在看的人身上。 系統能做的是把依據完整攤開,讓他有東西可以判斷——這就是為什麼 SQL 也給看。

1-2 請求編號

畫面abbe4831a86d1de0d57c40ba9667fb2f——這個請求編號是做什麼的?
這一次提問的身分證。出問題時,拿這串就查得到那一次到底發生什麼。

使用場景很具體:使用者說「剛剛那題答錯了」。沒有這串編號,你要從幾千筆紀錄裡猜他問的是哪一題; 有這串,貼進查詢介面就直接跳到那一次的完整經過——他問了什麼、系統理解成什麼條件、 產出哪句 SQL、撈到哪幾片文件、每片分數多少、最後答了什麼。

所以畫面上它旁邊有一顆複製鈕:設計上就是要使用者截圖或複製回報用的

正式名稱叫 traceId,是 W3C 的追蹤標準格式(見 §08 名詞表)。 「trace」是「追蹤」,一次請求從頭到尾的軌跡。
畫面為什麼是這麼長一串亂碼?用 1、2、3 不是比較好記?
因為它要在「很多台機器」之間對得起來,不能靠一台機器發號碼。

流水號需要有人負責發號,而且只能有一個人發,否則兩台機器會發出同一個號。 這套系統橫跨後端、模型服務、text-to-SQL 服務,未來還會更多。 改成 128 位元的隨機值,每台機器各自產生也幾乎不可能撞號——128 位元寫成十六進位就是 32 個字。

而且它的用途不是給人記的,是給人複製的,所以長度不重要。

陷阱雛形上的那串編號也是真的嗎?
格式是真的,來源不是——雛形是前端當場亂數產生的。

雛形沒有後端,所以沒有真正的追蹤系統;它只是產一個「格式一模一樣」的 32 位十六進位字串, 讓畫面跟實體長得一樣。

實體那邊是 OpenTelemetry 這套追蹤工具在請求進來時產生的, 而且會寫進後端每一行日誌,所以日誌跟畫面上那串對得起來。

被問到時的答法:「雛形這一格是演給你看格式;實體那邊它是真的可以拿去查的。」 不要說「這是真的」——現場如果有人要你當場拿它去查,就下不了台。

1-3 語意檢索索引(tf-idf)

畫面「語意檢索索引(tf-idf)」是什麼東西?
它是「從一堆文件裡找出跟這個問題最相關的幾段」的方法。

知識庫裡有十幾份文件,被切成幾十到上百個小段落(每段約 450 字)。 使用者問一句話,系統要從這些段落裡挑出最相關的五段,交給後面統整成答案。 「怎麼挑」就是 tf-idf 在做的事。

tf-idf 的邏輯用一句話講:一個詞如果在這一段裡出現,而且它在其他段落裡很少出現, 那這個詞就很能代表這一段。

  • 「的」「我們」「公司」到處都是 → 幾乎不加分
  • 「達交率」只出現在兩三段裡 → 一旦命中,分數很高

所以問「達交率怎麼定義」,講達交率定義的那幾段自然浮上來,而講資訊安全的那幾段沉下去。

技術tf-idf 是 AI 嗎?
不是。它是 1970 年代就有的統計方法,純算數,沒有模型、沒有訓練。

這一點值得講清楚,因為它正好示範了這套系統的態度: 能用確定的方法做的事,就不要用模型做。

tf-idf 的好處是:零依賴(不用另外架一個服務)、速度極快、結果完全可重現、 而且可以解釋為什麼這一段被選中——因為它命中了哪幾個詞、每個詞值多少分,全都算得出來。

代價是它只看字面:問「交貨慢了怎麼辦」,文件裡寫的是「延遲交付的處理程序」, 字不一樣就對不上。這正是後面要換成向量檢索的理由。

技術tf-idf 是誰在算?Java 那邊嗎?
目前是,而且是暫時的——它是一個「等正式服務到位之前先頂著」的本地實作。
版本誰在算在哪
實體程式(現在) AI-Brain 的 Java 後端自己算 rag/LocalRagClient.java,約 140 行,零外部相依
雛形 瀏覽器裡算 app.js,同一套演算法搬到前端(所以雛形不連任何服務也能真的檢索)
正式版 AI team 的檢索服務 改一個設定值 aibrain.rag.provider=http,其他一行不動

它在程式裡的名字就叫「本地假 RAG」,而且註解直接寫著 「等 AI team 的 API 上線就刪」——不是偷偷留一套自己的實作,是明確標示的過渡。

為什麼要先做一個頂著?因為這樣整條路可以先跑通:意圖、流程、證據池、統整、引用、 監控全部都能驗,不用等別人。而且因為回傳的形狀跟對方 API 的規格一模一樣, 換過去的時候畫面與流程完全不用動。

這題很適合延伸講設計原則:這套系統把每一個外部能力都做成可替換的介面 (檢索、模型、SAP、OCR),所以「還沒好的那一塊」不會擋住其他所有東西。 建單的 SAP 那一步也是同一個做法。
陷阱tf-idf 的定位到底是什麼?是沒有 AI 時的備案嗎?還是在分擔模型的負載?
都不是。它是 LLM 的上游,不是 LLM 的替代品。

三個常見的誤會,一個一個拆:

以為它是其實
沒有 AI 時的備案 不是。這套系統確實真正的備案——意圖分類的規則版, 模型連不上時退回,畫面上會顯示「規則(LLM 不可用)」。 tf-idf 不是那種:它旁邊沒有一個「主要方案」在等著, 它就是目前唯一的檢索實作
分擔模型的負載 不是。它確實有個副作用會少叫一次模型——全部低於門檻就短路、不呼叫統整—— 但那是「不知道就別答」的結果,不是目的
AI 的簡化版 不是。檢索那一格本來就不該是 LLM。見下面

正確的圖像:檢索與生成是兩格,而且永遠不會合併

幾百片文件 ──[ 檢索 ]──> top 5 ──[ LLM ]──> 一段有引用的話
                ↑                        ↑
             tf-idf 站這格            統整站這格
         (之後換成向量檢索)        (永遠是 LLM)

所以接上 AI team 的正式服務時,被換掉的是「用什麼方法比對相關度」 (字面比對 → 語意比對),不是「這一格改成給 LLM 做」。 那一格未來也不是 LLM,是嵌入模型加向量比對——那是另一種模型,不是語言模型。

為什麼這個區別在現場很重要 如果你把它講成「AI 的簡化版」,接下來一定會說「以後接上 AI 就會更準」, 對方就會接一句「那現在是打折版囉?」。
正確的答法是:現在是打折的「檢索」,不是打折的「AI」。 整條路的形狀、統整的規則、引用的掛法全部都是最終版, 只有「怎麼挑出那 5 片」這一格之後會換得更準。

順帶一提它為什麼現在夠用:知識庫目前是幾百片的規模,線性掃就夠快; 而且 tf-idf 的結果可以解釋(命中哪幾個詞、各值多少分), 向量檢索反而說不清楚為什麼這片排前面。等文件量上千,才輪到向量檢索的優勢。

技術中文怎麼算 tf-idf?中文沒有空格分詞
用 bigram——把相鄰兩個字當成一個詞,不做斷詞。

「達交率定義」會被拆成 達交交率率定定義。 英數字則整個詞取(vbaks4hana)。

為什麼不用正規的中文斷詞工具?因為那要多一個函式庫、多一份詞典, 而且專有名詞(料號、客戶代號)反而容易被斷錯。 bigram 的做法雖然土,但不需要詞典也不會漏,對這個規模剛剛好。

實體程式與雛形用的是同一套演算法(雛形搬到瀏覽器裡跑),所以兩邊的檢索行為一致。

技術為什麼不用向量/embedding?現在不是都用那個嗎
會用,但那是 AI team 負責的服務,還沒交付,所以先用 tf-idf 把整條路跑通。

設計上這兩者是可以直接替換的:介面(送什麼、回什麼)已經定好寫成規格交給 AI team, 本地這版回傳的形狀跟他們的 API 一模一樣。 換過去只要改一個設定值 aibrain.rag.provider=http,其他一行都不用動。

這正是「先把流程跑通、能力之後再換」這個設計的實例: 沒有向量模型也能演完整條路,而且之後換上去,畫面與流程完全不變。

向量檢索好在哪:它比的是意思不是字面,「交貨慢了」對得上「延遲交付」。 代價:要多一個服務、要一顆嵌入模型、而且結果比較難解釋為什麼。
畫面右邊列出的「相關度 0.52」是什麼?0.52 算高還算低?
是這一片文件跟問題的相關程度,滿分 1.0。但它只能跟同一次的其他片比,不能當絕對標準。

這件事很重要,因為它很容易被誤讀成「系統只有 52% 的把握」。不是。 這個分數是排序用的,不是信心度。

系統真正用它做的判斷只有一個:如果最高分的那一片都低於門檻,就當作查無資料, 而且不呼叫模型寫答案。雛形的門檻是 0.1,另外還要求至少命中 2 個不同的詞 (實測發現完全不相關的問題偶爾也能拿到 0.11,但它只命中 1 個詞,真命中都是 2~6 個)。

之後接上正式的檢索服務,如果對方有「重排」(reranker)這一層,分數的性質會變成校正過的、 可以用絕對門檻;現在沒有,所以只能用相對的。

陷阱門檻 0.1 是怎麼訂出來的?有什麼標準嗎?
沒有理論標準——是實測調出來的。而且調的過程發現「光看分數不夠」,所以又加了第二個條件。

先講數字本身,兩邊還不一樣:

門檻另外要求
實體程式0.12無,只看分數
雛形0.1而且至少要命中 2 個不同的詞

為什麼要加「至少命中 2 個詞」——這是實測記在程式註解裡的,可以直接當答案講:

問「幫我訂一張機票」(跟知識庫完全無關)拿到 0.11
而最弱的一個命中「請購單每個月受理到幾號」是 0.14

兩者只差 0.03——用分數切不乾淨。但雜訊只命中 1 個詞, 真命中都是 2~6 個。用詞數分開,比用分數分開穩。

所以誠實的答法是:「這個數字沒有理論依據,是拿實際問題試出來的。 而且試的過程發現單看分數不可靠,所以加了一個更穩的條件。」

這件事本身也回答了「為什麼分數不能當信心度」: 0.11 的雜訊跟 0.14 的真命中差不多高,這個分數根本沒有絕對意義, 它只能在同一次檢索裡排序。

被追問「那準不準」時不要硬撐 正確的回答是:這是過渡實作的門檻,等接上正式的檢索服務會重訂。 對方如果有重排那一層,分數會變成校正過的,才有絕對門檻可言。

1-4 答案裡與答案旁邊的東西

畫面答案裡的 [1] [2] 方框是什麼?
引用編號。每一句話後面掛的那個號碼,就是這句話的依據來自第幾片證據。

滑過去會浮出預覽卡(標題+那一段原文+章節/頁碼/來源),點下去會打開右側面板並高亮那一片。

這是整套系統「可稽核」最具體的證明:使用者不需要相信模型,他可以自己去看原文。

編號是程式給的不是模型給的——證據被撈回來時就依序編號了,模型只能引用存在的編號, 超出範圍的編號會被程式過濾掉。所以不會出現「引用了一個不存在的來源」這種事。

畫面「我理解的條件」出現在畫面哪裡?
在「展開分析」點開之後、步驟清單的上方那一排小字。不是獨立面板,要點開才看得到。
已完成分析 · 1.6 秒                      ← 點這一行展開
┌──────────────────────────────────────┐
│ 查結構化資料 · data_query              │  ← 走哪條流程
│ 期間 2018-10-29 ~ 2024-11-15(未指定,  │  ┐
│ 預設全期間)  幣別 USD  基準日 …        │  ┘ ← 「我理解的條件」在這排
├──────────────────────────────────────┤
│ 理解問題    期間 …            完成      │  ┐
│ 判斷意圖    分析 · LLM 124 ms  完成     │  │ ← 步驟清單
│ 查資料      1 筆,38 ms        完成     │  ┘
│ …                                     │
│ 請求編號  abbe4831…            ⧉        │  ← 最底下
└──────────────────────────────────────┘

所以它跟「走哪條流程」並排,在步驟清單前面——順序是有意義的: 先告訴你「我理解成什麼、要走哪條路」,再讓你看「我實際做了哪幾步」。

它跟「理解問題」那一步的內容會很像,但不是同一個東西 「理解問題」那一行前處理當下抽到什麼(進度列的一步); 「我理解的條件」那一排整輪跑完之後實際套用的完整條件 (包含 text-to-SQL 那邊回報的)。被問到差別在哪,這樣答。
畫面「我理解的條件」那幾個標籤是誰寫的?可信嗎?
兩個來源,都不是模型寫的,所以可信。
  • 前處理抽出來的:期間、客戶、商品——規則算出來的。
  • text-to-SQL 回報的:對方在產 SQL 時,順便用查詢計畫結構化產生的條件短句。

第二個來源特別值得講:因為它沒有經過語言模型,所以即使這一題查無資料,它也可以安全地顯示出來。 使用者就看得到「系統是照什麼條件去查的、才查不到」,而不是只拿到一句冷冰冰的「查無資料」。

為什麼這一排是整個畫面最該先看的東西:實務上答錯最多的不是 SQL 寫錯, 而是條件理解錯——問的是 8 月、它算成全期間;問的是甲客戶、它對到乙客戶。 這一排就是拿來當場抓這種錯的。

畫面「重修 2 輪」是什麼意思?是出錯了嗎?
模型第一次產出的 SQL 跑不起來,自己改了兩次才成功。

不是出錯——它最後成功了。但這是一個值得多看一眼的訊號:模型卡過, 代表這一題對它來說不直觀,產出的 SQL 比較可能語意上偏掉。

所以前端的處理是:一旦重修超過一輪,就把 SQL 區塊預設展開, 讓使用者第一眼就看到它到底查了什麼。這是對方(AI team)建議的做法。

畫面SQL 那塊給客戶看不會太技術嗎?
它預設是收起來的,看得懂的人才會展開。而它的存在本身就是一種承諾。

兩個理由:

  • 對懂的人:那是唯一能驗證「這個數字對不對」的東西。76% 的正確率之下, 不給 SQL 等於要人盲信。
  • 對不懂的人:他不會展開,但他知道有。「這套系統敢把它查的每一句都給你看」, 這件事本身就在傳達可稽核。
被追問「那模型亂寫 SQL 怎麼辦」——不要答成「兩邊各擋一層」 以前是兩層:對方唯讀連線加查詢逾時,我方只收 SELECTWITH 開頭。 但我方那一層已經不存在了——拔掉本機資料層時整支刪掉, 現在拿到 SQL 只拿來顯示,一個字都不檢查
開發方自己的資安健檢把這條列為中風險 M1,原話是 「我們對模型產生的 SQL 已經零防護,完全依賴他們的唯讀角色與逾時設定」。
正確答法:「模型產的 SQL 在對方那邊執行,靠的是他們的唯讀連線與查詢逾時。 我們這側因為根本沒有資料庫連線,所以也沒有可以擋的地方—— 這件事開發方已經列進資安清單,正在請對方書面確認唯讀設定。」

順帶一提:正因為我方沒有連線,模型產的 SQL 再糟也碰不到任何東西—— 這是拔掉資料層的附帶好處,可以接著講。

畫面右邊那個「依據與來源」面板是什麼?
這一輪撈到的所有證據,分成「答案真的引用到的」與「撈到但沒用上的」兩組。

每一張卡可以展開完整片段,也可以開啟整份來源文件(會標出這次引用的是哪一段)。

「撈到但沒用上」這一組看起來多餘,其實是檢索品質的指標: 如果長期撈五片只用一片,代表檢索抓得不夠準。 實體程式的監控紀錄就有逐片記「這片有沒有被引用」這個欄位,用途正是這個。

畫面為什麼答案是一個字一個字冒出來的?
因為語言模型本來就是一個字一個字產生的,我們選擇不等它寫完才給看。

整段等完再一次顯示,使用者要盯著轉圈好幾秒;逐字送出則是一有內容就看得到。

技術上用的是 SSE(見 §08),一條單向的通道,後端有東西就推一則過來。 進度列能一步一步亮起來也是同一條通道。

順帶一提,逐字生成時 Markdown 會有一瞬間的中間狀態(粗體還沒收尾之類), 那不是壞掉,實體程式也一樣。

畫面回答上面那顆「停止」跟底下的「重新產生」
停止是真的會讓後端停下來,不只是前端不顯示。

這一點在實體程式是刻意做的:前端斷線(按停止、關分頁)會通知後端, 調度層每跑一步、串流每送一個字都會檢查這個旗標。 理由很實際——不要讓模型和資料庫替一個沒人在看的請求繼續跑,那張 GPU 是共用的。

被放棄的請求在紀錄裡會標成 cancelled,所以事後統計得出「有多少題使用者等不下去」。

「重新產生」只出現在最後一則回答。它會原樣重送當初那次請求—— 這在建單流程特別重要:在草稿卡那一步按下去,是「再辨識一次」,不會變成一句普通閒聊。

畫面知識庫那一頁的文件是真的公司文件嗎?
不是。那是自己寫的示範文件,虛構的公司。這一點畫面上有寫,也一定要照講。

實體程式開機會自動載入 15 份示範文件(出貨與交期 SOP、達交率定義、分批交貨規範、 開票與請款規範、客戶分級與信用政策、資安規範、AI 使用政策……),切成片放進檢索索引。

目的是讓 demo 一開機就有東西可以查,不必先上傳。真文件到了,從這一頁上傳取代即可。

可以現場演的一段:在這一頁匯入一份 .md,回到聊天室馬上就問得到、引用得到。 這一段雛形是真的(在瀏覽器裡真的切片、真的重建索引),不是腳本。

02一題進來,逐步發生什麼

懂技術的人會問這個。從使用者按下送出到答案寫完, 每一步是誰做的、有沒有碰到模型、碰的是哪一顆、為什麼要有這一步。

2-0 兩張流程圖:問一題/上傳訂單建單

兩條線的形狀差很多,所以分開畫,用下面的頁籤切換。 最大的差別是 OCR:問一題完全不碰 OCR,建單才會用到,而且那是另一套模型。

以「2022 年 11 月有多少張訂單」為例。 最右邊那一欄是使用者在畫面上真的會看到的東西——現場可以直接指著對照。 橘色=有呼叫模型,其餘都是程式。

使用者 瀏覽器 AI-Brain AI 能力服務 資料 畫面上出現 Vue,只顯示 Java/Quarkus 腦 被呼叫的 API 手 PostgreSQL 使用者真的看得到 打字送出 「…多少張訂單」 POST /api/chat 開一條 SSE 接回應 判語言 → 前處理 純規則,不問模型。抽出期間 2022-11 判意圖 Qwen · 上限 16 token · 溫度 0 · 124 ms 模型 選流程 規則。挑中 data_query.yml 產 SQL WrenAI 語意層 + Qwen 模型 執行 SQL middledb 鏡像 收到 SQL + 資料列 包成一片證據,編號 [1] 先把表格畫出來 表先出、文字在後 判斷有沒有資料 程式比數值。0 筆就短路,不叫模型 統整 Qwen 串流 · 只看得到證據 模型 逐字顯示 [n] 變成可點的引用 自己驗證 展開 SQL/點引用 理解問題 期間 2022 年 11 月(2022-11) 判斷意圖 分析 · LLM 124 ms 查資料 1 筆,38 ms 統整回答 108 字 請求編號 abbe4831a86d1de0…
這張圖現場可以講的三個重點
  1. 橘色只有三格(判意圖、產 SQL、統整),其餘全是程式。 而且產 SQL 那格在對方的服務裡,不是我們呼叫的。
  2. 瀏覽器那一欄只做顯示,沒有任何業務判斷—— 所以畫面上看到的順序就是後端真的執行的順序。
  3. 最後一格是「使用者自己驗證」。這不是裝飾,是整個設計的終點: 系統不要求你相信它,它把依據攤開讓你自己驗(見 §06)。
#步驟前端後端(Java) 模型為什麼要有這一步
0送出 POST /api/chat,帶 sessionId、問句、介面語言。開一條 SSE 接回應 驗證擋空問題與超長(上限 2000 字,text-to-SQL 那端只收 500 字所以另擋) SSE 一開,後面每一步才推得回去
1判語言 Lang.detect:看字元。有假名→日文;有漢字→看介面;只剩拉丁字母→英文 回答語言跟問句走,不跟介面。用規則不用模型:零延遲、結果固定
2前處理
理解問題
顯示「理解問題 · 進行中」 Preprocessor:全形數字轉半形、時間詞→日期區間、別名→代號、單號補十碼、追問沿用上一輪期間 把人話變成可以綁進查詢的條件。規則問題用規則解,可測試、可重現
2b追問還原 進度列顯示「補上前文 →『…』」 FollowUpRewriter:只在「有前文」且「這句看起來依賴前文」時才跑 Qwen
非串流
約 140 ms
「第二名呢」補成完整問句。非做在判意圖之前不可——後面的意圖分類與 text-to-SQL 都只看得到一句話
3判意圖
判斷意圖
顯示「判斷意圖 · 進行中」 IntentClassifier:有附件直接判業務操作(0 ms);否則問模型 Qwen
非串流
上限 16 token
溫度 0
約 130 ms
決定走哪條流程。四類+順便回 pipeline 代號,一次呼叫解決兩件事
4選流程 顯示「分析 · data_query PipelineResolver:模型給的代號合法就用;否則同一類只有一條就用它,多條比關鍵字;都沒中用預設那條 把「這是哪種問題」變成「要跑哪個 YAML 檔」
5取證
查資料/檢索文件
收到 sql 事件就先把表格畫出來 Orchestrator 照 YAML 呼叫 tool。wren=問 text-to-SQL;rag=檢索文件碎片 對方的模型
(產 SQL 在 AI team 那側)
唯一隨題目變的兩步之一。AI-Brain 不寫 SQL、不連資料庫
6分岔判斷 顯示「hits == 0 → 否」 GatewayEvaluator:單一數值比較。變數由上一步的 tool 回填 「夠不夠往下做」是數值問題不是語意問題。門檻由人事先訂在 YAML,程式每次照套
7統整
統整回答
逐字顯示;收到 citations 後把 [n] 變成可點的方框 Synthesizer:把問題+條件+每一片證據編號後組成 prompt,串流呼叫模型 Qwen
串流
上限 1200 token
溫度 0.2
把證據寫成人看得懂的話。它只看得到證據池,看不到資料庫、也不能自己算數字
8呈現 render 型別決定畫什麼:數字卡/表格/查無資料/草稿卡 送出 renderdone,寫一列請求紀錄 另一個隨題目變的步驟。單列單欄走數字卡,多列自動退回表格
這張表可以濃縮成一句話 模型只出現在三個地方:追問還原、判意圖、最後統整。 中間的取證、分岔、呈現全部是程式。所以「流程不由模型決定」不是口號,是可以逐步指出來的。
技術為什麼前處理要在判意圖前面?直覺不是應該先知道他要幹嘛嗎?
因為追問還原必須先做,否則意圖分類器看到的是一句沒有主詞的話。

實測案例(Adam 記在程式註解裡):使用者先問「2025 年營業費用最高的五個科目」, 接著問「第二名呢」。

  • 沒還原:意圖分類器與 text-to-SQL 都只收到「第二名呢」三個字, 產出的查詢跑去查客戶營收——完全不相干。
  • 有還原:補成「2025 年營業費用金額最高的前五個科目中,第二名是哪個科目?」, 後面每一步都看得懂。

關鍵在於一次請求裡有三個地方需要上下文,但只有統整拿得到對話歷史; 意圖分類與 text-to-SQL 都只收到一句話。所以脈絡必須在入口就補進那一句裡。

雛形原本畫成相反的,2026-09-15 已經改過來了 原因是它照著實體程式自己的運作說明頁畫的, 而那一節裡的「實測事件序列」是早期錄的:intent 在最前面,而且整段沒有 preprocess 這一步。 程式後來改了(加多語那一筆),那一節沒跟上。 雛形的進度列現在已對齊實體,那一節則留著等開發方從上游修。
陷阱雛形的進度列跟實體現在一樣嗎?
2026-09-15 逐項對齊完了,剩下三處不同、每處都答得出理由。

已經對齊的(每一項都指得回程式碼):

項目原本現在
前兩步順序判斷意圖 → 整理查詢條件理解問題 → 判斷意圖(11 段)
步驟名稱整理查詢條件/查詢資料理解問題/查資料
缺前處理的段落7 段完全沒有這一步 全部補上,含「你好」「你是誰」與建單第一段
查資料那行「1 次查詢,共 38 ms」 「1 筆,38 ms」(10 段,數字取自各段真實的筆數與耗時)
未開票那段「3 次查詢,共 262 ms」 「147 筆,262 ms(重修 2 輪)(已截斷)」
查回那張單的意圖查詢 · LLM 128 ms 分析 → data_query · LLM 128 ms ——原本是錯的,實體的意圖只有四類,沒有「查詢」
兩個流程代號delivery_ontimecustomer_idle ontime_rateorders_idle(實體真的有這兩條,形狀也一樣)

還沒對齊、而且被問到要答得出理由的

項目雛形實體答法
沒講期間時預設全期間預設本月 刻意不改。雛形資料只到 2024-11-15,用「本月」會查到 0 筆
四段純資料題
的統整那行
「268 字」「268 字,引用 1 片 硬改會壞掉。實體的查詢結果本身就是一片證據,答案引用得回去; 雛形的表格與證據走兩條不同的路,加了引用編號會變成點了沒東西的連結。 其餘 12 段本來就一致
建單第二、三段沒有前處理也沒有判意圖 三次請求每一次都會送這兩步 那兩段在雛形接在同一則訊息裡播,要補得先拆成獨立的執行紀錄
意圖那行的寫法多數是「分析 · LLM 124 ms」 「分析 → data_query · LLM 124 ms」 下一行本來就顯示同一個代號,資訊沒有缺,所以先不動
雛形的運作說明第 02 節也一起改了 那一節原本是實體說明頁的逐字副本,裡面的「實測事件序列」是早期錄的 (intent 在最前、沒有 preprocess)。照抄等於在自己的素材裡留一段明知是錯的描述, 所以依程式碼修正了:事件序列補上前處理、流程條補一格、 並在該節就地標註「本節與來源刻意不同」與原因。
逐字副本的原則沒有被推翻——它的目的是「下次重搬差異不會被無聲蓋掉」, 所以差異有標註、`prototype/adam/README.md` 也記了重搬時要怎麼處理。 同時已回報開發方從上游修。
技術「統整」那一步,模型到底看到了什麼?
一份組好的文字:問題、系統理解的條件、以及編了號的每一片證據。沒有別的。
問題:哪些訂單有交貨但還沒開票?
查詢條件:期間 2018-10-29 ~ 2024-11-15(未指定,預設全期間);幣別 USD

資料片段(只能根據這些回答):

[1] 查詢結果:履約分類(5 筆)(WrenAI text-to-SQL,2026-09-15)
分類 | 項目數 | 金額
已開票 | 1,204 | …

[2] 開票與請款規範 › 第三節 開票時點(規範,財務部,2026-05-04)
…原文…

請依規則回答。

另外還有一份「規則」(system prompt),六條,關鍵的是這幾條:

  • 只能根據片段回答;片段沒有就說「片段中沒有提到」,不要推測、不要補外部知識
  • 每個論點句尾標片段編號 [1]沒有依據的句子不要寫
  • 不要自己計算或編造數字,數字只能照原文引用。
  • 查詢結果的表格前端會完整顯示,所以最多只點名前三筆,其餘一句總結——逐列複述整張表是錯的。
  • 條件若是預設值(例如未指定期間),在第一句順帶說明

還會附上最近四輪對話,讓它接得上追問。

技術後端怎麼知道「查到東西了」?不是看有幾列嗎?
不能只看列數,這是一個踩過的坑,而且後果很嚴重。

COUNTSUM 這種聚合查詢永遠回一列。 所以「0 列=查無資料」擋不住「回一列 {count: 0}」這種情況。

實測發生過:問「這個月有多少張訂單」,對方把它對成 COUNT(會計憑證) 回了一列 0, 統整很有自信地寫出「本月訂單數量為 0 張」。 而事實是那套系統裡根本還沒有訂單資料——系統斷言了一個業務事實,這比說查無資料糟得多。

修法是把判斷條件收窄成:單列、而且每一個欄位都是 null/0/空字串,才算查無資料。 只要有任何一欄帶著資訊(例如分組用的公司名)就當成真的有資料。

代價誠實地寫在程式註解裡:真正答案就是 0 的題目(例如本月逾期 0 張)也會被說成查無資料。 這個方向是故意的——寧可少答,不要講錯。

技術整題要花多久?慢在哪一段?
純文件題約 0.8~1 秒;要查資料的題目 9~14 秒,慢的幾乎全在 text-to-SQL。
實測說明
判意圖約 130 ms冷啟動第一次約 250 ms
追問還原約 140 ms只有追問才付這個錢,完整問句 0 成本
非中文翻譯約 300 ms中文問句 0 成本
本地檢索幾十 ms幾百片線性掃,夠用
text-to-SQL一輪 8~13 秒模型要產 SQL、跑、失敗還會自己重修 2~3 輪
統整約 1 秒(182 字)逐字送,使用者第一個字就看得到

逾時設定:text-to-SQL 給 60 秒(對方上限 120 秒、內部會重試 2~3 輪,實測一輪 9~13 秒, 60 秒涵蓋三輪),調度層總預算 90 秒。不跟到 120 秒是刻意的—— 等到那時才失敗,連前面成功的查詢都會被一起丟掉。

03架構為什麼長這樣

「為什麼要有這一層」每一題都有答案,而且答案的形狀都一樣: 拿掉它會發生什麼壞事。這一節照架構圖由上而下走。

前端(Vue 3 + Quasar)
聊天視窗、進度列、表格、引用面板、知識庫頁、草稿卡。只負責顯示與收集輸入,沒有任何業務判斷
↕ SSE(單向串流,後端推事件)
Java 應用層(Quarkus)= AI-Brain 本體
入口 → 前處理 → 判意圖 → 選流程 → 調度層照 YAML 跑 → 收證據 → 統整 → 回傳。 這一層不內含模型,需要語意時呼叫右邊
↓ 每一格都是被呼叫的 API
AI 能力服務(AI team 與既有系統)
Qwen(語言模型)/text-to-SQL(WrenAI 語意層)/RAG 檢索/OCR/SAP 建單 API。 它們只管「怎麼執行」,不管「下一步做什麼」
資料
middledb(SAP 銷售模組 12 張表的鏡像)+ 一張 order_ledger 建單流水帳。 AI-Brain 自己不連前者,一律問 text-to-SQL

3-1 整體

技術為什麼中間要有一個 Java 應用層?前端直接呼叫模型不行嗎?
因為「先取證再回答」這件事需要有人去取證、判斷夠不夠、再決定下一步。那個人就是應用層。

前端直接打模型,能做到的只有「把問題丟給模型、把回答顯示出來」。 這樣做會失去四件事:

  • 取證 —— 誰去查資料庫?誰去翻文件?誰決定查哪個?
  • 控制 —— 誰決定查不到就停?誰守住步數與逾時上限?
  • 稽核 —— 誰記下這一輪查了什麼、依據是哪幾片?
  • 安全 —— 模型端點不能直接暴露給瀏覽器。

用 Tom 那張架構圖的說法:應用層管 WHAT NEXT 與 WHEN STOP,AI 能力服務管 HOW TO EXECUTE。 能力服務不准自己決定整個任務完成沒有。

技術這跟大家在講的「AI Agent」差在哪?
差在「誰決定下一步」。Agent 是模型自己決定;這套是人事先寫好、程式照跑。

這是刻意的取捨,理由寫得很直白:決策要可預期、可稽核

  • 可重現 —— demo 每次走同一條路,不會這次查三次、下次查五次。
  • 可測試 —— 給定假數字就能斷言它應該走哪一條分支。
  • 可搬移 —— YAML 的流程定義對得上 BPMN,之後搬去 UiPath Maestro 搬的是流程不是程式。
  • 出錯知道怪誰 —— 走錯分支是流程設計的問題,答錯話是統整的問題,兩件事分得開。

保留的彈性是一格「AI 判斷」:只在資料不足時被問一次「還能查什麼」, 而且只能從已定義的能力裡選,步數上限仍然由調度層守著。它是流程裡的一個節點,不是流程本身。

3-2 Intent(意圖)這一層

技術為什麼需要一個獨立的意圖分類?直接全部丟進同一條流程不行嗎?
因為不同種類的問題,該花的成本與該走的路差很多。

具體的壞處,每一個都是真的發生過或會發生的:

  • 使用者說「你好」→ 如果沒分類,就會去翻知識庫、跑檢索、叫統整,花掉一整輪的資源回一句寒暄。
  • 使用者問「你用什麼模型」→ 這題真的發生過:沒有「系統說明」這一類的時候, 它被當成分析題丟進知識庫,撈出公司的 AI 使用政策文件來回答。 答案確定的東西不該每次重新生成。
  • 使用者傳了一張訂單圖 → 那是業務操作,要走建單流程,跟查資料完全不同。

意圖這一層的產出其實是一句話:「接下來走哪一條 pipeline」。

技術為什麼用模型分類?用關鍵字規則不是更快更省?
規則版試過,撐不過沒想到的問法——「你的模型是什麼」就漏了。

三個選項的比較:

做法
關鍵字規則零延遲、零成本沒列到的問法就漏;問法的變化是無窮的
向量比對更快更省要多一個端點、多一套例句要維護
模型四選一問法變化再多都吃得下;之後要多抽欄位也不用換路多 130 ms

四類這個規模下,130 ms 已經夠快,而且是同一顆模型順手做的,不增加任何依賴。 規則版沒有丟掉,它留著當模型連不上時的備援(畫面上會顯示「規則(LLM 不可用)」)。

陷阱分類錯了會怎樣?
兩種錯的後果不對稱,所以設計上刻意往安全那邊倒。
  • 該是閒聊卻分成分析 → 多查一次、可能回查無資料。無害。
  • 該是分析卻分成閒聊 → 模型會憑空回答,因為閒聊那條路不取證。這是要避免的。

所以 prompt 明寫「不確定時回分析」,程式解析不出模型回覆時也預設回分析。 分析是「有證據才回答」的安全方向。

這是一個很好用的答題模式:被問「XX 出錯會怎樣」時, 先講兩種錯的後果不對稱,再講設計往哪邊倒、為什麼。

技術為什麼傳了附件就不問模型?那不是也該判斷一下嗎?
因為那已經不是「判斷」,是「事實」。用 Adam 的原話:附件在、草稿在,是事實不是機率

入口這一層其實有兩條路,走哪條看請求長什麼形狀,不問任何模型:

請求裡有什麼直接決定走哪條流程
帶了附件order_intake(判讀這是不是訂單)
帶了附件+「要建單」這個動作order_extract(辨識欄位、產草稿)
帶了確認過的草稿order_create(打 SAP、寫流水帳)
只有文字才交給意圖分類器

好處有三個,都很實際:

  • 不會分錯 —— 沒有機率就沒有錯誤率。
  • 不花錢 —— 省一次模型呼叫,進度列上那一格是 0 ms。
  • 不會被話術帶走 —— 使用者打「幫我建一張訂單」但沒附件, 模型會判成業務操作,但流程解析器找不到對應的建單流程,就當一般對話回、請他把文件傳上來。 光靠一句話不會真的去建單。

可以濃縮成一句:「能從請求本身確定的事,就不要交給模型猜。」 這跟「數字歸程式、語意歸模型」是同一個原則往入口延伸。

3-3 Pipeline(流程)這一層

技術pipeline 到底是什麼?畫面上那個 data_query 是什麼意思?
一條 pipeline=一個 YAML 檔=一種問題的處理流程定義。畫面上印的是它的代號。

檔案裡只有三種步驟:

  • tool —— 做事(查資料、檢索文件、統整、OCR、打 SAP、寫流水帳)
  • gateway —— 分岔(一個數值比較,例如 hits == 0
  • render —— 結束,並告訴前端要畫成什麼(答案/表格/查無資料/草稿卡)

實體目前啟用 11 條

基礎 3 條   knowledge_search  查文件(分析類選不到專屬流程時的預設)
            general_chat      閒聊
            about_system      問系統本身(固定答案,不進 RAG、不生成)

資料 1 條   data_query        所有結構化資料問題都走它

綜合 3 條   ontime_rate       達交率:先查數字 → 再取規範文件 → 一起統整
            orders_idle       閒置訂單
            split_delivery    分批交貨

建單 3 條   order_intake / order_extract / order_create

附件 1 條   attachment_chat   繼續問剛剛傳的那份文件

加一條情境=寫一個 YAML、在設定檔加上代號、需要新能力就實作一個 tool。主幹一行都不用改。

技術為什麼流程寫在 YAML 不寫在程式裡?
四個理由,最後一個最現實。
  1. 改門檻不用改程式 —— 「幾天算閒置」「達交率怎麼算」這種口徑, 改的是 YAML 裡的一個數字或知識庫裡的一份文件,不是 Java。
  2. 訂門檻的人不是寫程式的人 —— 那是業務要拍板的事。 用 Adam 的比喻:像溫度計,讀數是程式讀的,幾度算發燒是人事先訂的。
  3. 加情境不用動主幹 —— 十個情境就是十個檔,彼此不會互相影響。
  4. 為了第二版 —— 十月要評估接 UiPath Maestro。 Maestro 取代的正好就是「照步驟跑、分岔、等人確認」這一塊。 流程寫在 YAML,搬過去搬的是流程定義;寫死在 Java 裡就得重寫。
技術Fixed/Generic/Dynamic 三種是什麼?為什麼 Dynamic 不做?
差別在「步驟是誰決定的」。Dynamic 是讓模型自己規劃,這階段明確不做。
型別步驟誰決定用在哪
Fixed人,設計時寫死多步 重要且會反覆被問的題目,例如毛利歸因(查兩期 → 拆營收成本 → 下鑽 → 查採購價 → 不夠再翻文件)
Generic人,但只有一輪 查一次 → 有結果就統整、沒有就查無資料。沒預期到的問題的保底
Dynamic模型自己 本階段不做,圖上與程式裡都明確標示

不做 Dynamic 的理由一句話:客戶面前不能讓模型臨場發明查詢步驟。 不可預期、不可重現、出錯不知道怪誰。Fixed + Generic + 一次 AI 判斷已經涵蓋這階段的情境; Dynamic 是之後有明確需求再開的選項。

技術為什麼所有數字問題都擠在 data_query 一條?不是應該訂單一條、財務一條嗎?
因為「該查哪張表」是對方語意層的工作,不是我們這邊分流程。

問句原文直接交給 text-to-SQL,選哪個資料模型、產什麼 SQL、在哪執行都是他們的事。 我們這邊分成兩條,只是把同一個判斷做兩次,而且兩邊會不一致。

這條設計已經兌現過一次:2026-09-15 AI team 把語意層整個換版 (原本 5 個彙總模型清空,改成直接對應 middledb 的 12 張原表), AI-Brain 一行都不用改。因為它從來沒有假設過對方有哪幾張表。

歷史包袱也值得講:原本訂單那七題各有一條寫死 SQL 的 YAML,打本機的假資料庫。 那是 text-to-SQL 還沒交付之前的過渡,後來整個拔掉—— 留著會變成同一份業務口徑有兩套定義(我的 SQL 一套、他們的語意層一套), 不一致的時候沒人知道該信哪個。

技術那「綜合判斷」那三條為什麼要單獨留?
因為它們的形狀不一樣:先查數字,再取規範文件,兩邊一起統整。

以達交率為例:數字(準時幾張、延遲幾張)來自 text-to-SQL, 但「達交怎麼算」——以計畫出貨日還是客戶要求日為準、缺實際出貨日的要不要進分母—— 寫在規範文件裡,要靠檢索取回來。

統整的時候:數字照查詢結果,口徑掛文件引用。 所以門檻改了改文件,不用改程式

這三題(達交率、閒置訂單、分批交貨)也是最能展示這套架構價值的題目—— 單純的 text-to-SQL 工具答不出「怎麼算才算達交」。

3-4 調度層(Orchestrator)

技術調度層在做什麼?為什麼它裡面一行模型呼叫都沒有?
它只做四件事,而且刻意不含任何業務邏輯與模型呼叫。
  1. 讀 YAML,從第一步開始跑
  2. 呼叫 tool,把回傳結果變成具名變數(例如 hitsrowsfailed
  3. 遇到 gateway 就拿那些變數做一次數值比較,決定跳到哪一步
  4. 命中停止條件就停

模型只在它呼叫的 tool 裡面llm tool、之後的 AI 判斷 tool)。 這樣切的好處是責任清楚:它是一個 Java 類別,不是一個模型, 所以它的行為完全可預測、可以寫單元測試、每次執行都一樣。

停止條件有三個,每一個都回明確訊息:

  • 短路 —— gateway 判定 0 筆/查不到,直接跳到「查無資料」那一步
  • 逾時 —— 預設 90 秒
  • 步數上限 —— 預設 20 步

每一步還會開一個追蹤節點(span),所以在監控畫面上看得出來是卡在哪一步。

技術gateway 為什麼是數值比較?問模型「資料夠不夠」不是更聰明?
因為「夠不夠」其實是數值問題,不是語意問題。

gateway 的條件長這樣,全部是 SQL 或檢索回來的數字在比大小:

hits == 0            檢索命中 0 片 → 回查無資料
failed == true       產不出 SQL → 回「這題沒辦法轉成查詢」
empty_result == true 查到但整列都是空的 → 回查無資料
due_orders == 0      該出貨的單有 0 張 → 短路

Adam 的說法:訂門檻是人做的(設計時一次),算數字是程式做的(每次執行), 模型在這兩層都不出現。好處是可重現、可測試、快、而且之後可以直接對應到 Maestro 的流程變數。

實作上刻意做得很陽春:只支援單一比較(變數 運算子 值), 不支援 and/or/算式。程式註解自己寫著「條件變複雜再換運算式引擎」—— 先做剛好夠用的

技術跑到一半外部服務掛了會怎樣?
那一步丟出可讀的錯誤碼,調度層停止,前端顯示「這一輪沒有完成」與原因。

三個不做的事,每一個都是刻意的:

  • 不重試打爆對方 —— 對方的併發上限是 2,重試只會讓事情更糟
  • 不把半成品當答案 —— 沒查完就不要統整
  • 不吞掉錯誤 —— 錯誤訊息(例如模型回的 HTTP 400 內容)會帶到前端截 300 字

雛形有一題「模擬錯誤」就是在演這個:錯誤卡、狀態列寫「處理中斷」而不是「已完成」。

3-5 證據池與統整

技術「Evidence Pool(證據池)」為什麼要獨立存在?查到就直接給模型不行嗎?
因為一題可能查好幾次、還要混不同來源,而且每一片都要能被引用回去。

證據池就是這一輪所有取回來的東西的集合,每一片都帶著: 編號、種類(查詢結果/文件碎片)、標題、原文、來源、日期、相關度分數。

三個它必須存在的理由:

  • 混來源 —— 達交率那題同時有 2 次 SQL 結果與 5 片文件碎片, 它們要一起進統整,數字照 SQL、口徑照文件。沒有一個共同的池子,這件事做不了。
  • 編號要穩定 —— 答案裡的 [1] 必須永遠指向同一片。 編號是進池子時就發的,模型只能引用已存在的編號。
  • 稽核 —— 這一輪的依據整包留在紀錄裡,事後可以回放、可以算「撈到但沒用上的比例」。
技術查詢結果也算證據嗎?答案裡的 [1] 可以指向一張表嗎?
可以。查詢結果本身就是證據池裡的一片,跟文件碎片並列、一起編號。

這一點常被誤會成「引用只能指文件」。實際上每次查完資料,那張表會被包成一片證據, 帶著標題、實際跑的 SQL、資料列、筆數、來源(text-to-SQL)與日期, 然後跟文件碎片排在同一個編號序列裡

所以達交率那種題目的答案可以長這樣:

整體交貨準時率是 88.6%(374 / 422)⋯⋯ [1]     ← [1] 是查詢結果
這是相對計畫出貨日的準時率,跟客戶要求日
是兩個口徑,不能互相代替 [2]                   ← [2] 是規範文件

數字照查詢結果、口徑掛文件引用——同一段話裡兩種來源各自掛得回去。 這正是「綜合判斷」那幾條流程的價值,也是單純的 text-to-SQL 工具做不到的事。

雛形在這裡是簡化的 雛形把表格與證據分成兩條路走,所以純資料題的答案沒有引用編號。 被問到不要說「查詢結果不能引用」——實體可以,那是雛形的簡化。
陷阱怎麼保證它不會亂編?
三道防線,而且第三道是最關鍵的那道。
  1. 只給它證據 —— 統整的 prompt 裡只有問題、條件、證據,沒有資料庫連線、沒有搜尋工具。
  2. 要求每句標編號 —— 沒有依據的句子不要寫;範圍外的編號會被程式過濾掉。
  3. 0 筆根本不呼叫模型 —— 查不到就短路回「查無資料」。 模型沒有被叫醒,所以它連編的機會都沒有。

實測可以當例子講:問「採購政策對供應商調價怎麼規定」, 撈回來的片段裡沒有直接規定,它的回答是「片段中沒有提到具體規定」, 然後列出相關的兩點並標上 [1][4]。這正是要的行為。

還有一條容易被忽略的:數字誰算。統整規則明寫「不要自己計算」, 毛利率、下降幅度都是查出來的欄位,模型只負責把它寫成句子。 連小數的格式都處理過——690801320.97 若用程式預設的方式轉成文字會變成 6.9080132097E8,模型就照抄進答案裡了,所以有一段程式專門把它轉回十進位。

技術為什麼 RAG 只回碎片,不直接幫我們統整好?
三個理由,而且這是寫進介面規格、交給 AI team 的硬要求。
  1. 混不了 —— 複合分析要把查詢結果與文件碎片放在一起統整, 檢索服務單獨統整時看不到數字那一半。
  2. 掛不回去 —— 引用要能點回原文;已經統整過的段落沒辦法對應到某一片。
  3. 品質責任 —— 「只看證據、標編號、不算數字」這套規則是我們的品質責任, 放在我們這邊才管得住。

順帶回答一個常見誤解:撈五片不是為了丟進模型五片。 檢索是漏斗——幾千片初篩到 30,重排取 5,進模型的永遠只有 top 5。 多要幾片是為了之後接重排器有東西可排。

3-6 資料與外部服務

技術為什麼 AI-Brain 一顆資料庫都不連?
因為一份資料兩個來源,就會有兩套口徑。

原本是有一顆的:本機 PostgreSQL、140 張假訂單、十題的 SQL 寫在各自的 YAML 裡。 後來整個拔掉,連資料庫相依一起。

拔乾淨的理由寫得很清楚:「達交」怎麼算、「前十大」依什麼排, 我的 SQL 一份、他們的語意層一份,遲早不一致,而且不一致的時候沒人知道該信哪個。

有一個例外,而且它正好證明了原則:order_ledger 建單流水帳。 Adam 的答法值得原樣記起來——

「拔掉的是SAP 資料的副本,那會變成兩個來源。這張表記的是我們自己做過的事—— 哪份附件、辨識出什麼、使用者確認了什麼、SAP 給了哪個單號—— 這件事只有我們知道,不放在我們這裡就沒地方放。它也不當查詢來源。
技術為什麼不直接連 SAP S/4HANA?
老闆的限制,但它同時也是一個好限制。

好在哪:分析查詢打在鏡像上,不影響生產系統; 模型產生的 SQL 再糟也碰不到 S/4——它根本連不到。

代價要誠實講。原本的評估是走 SAP 的 CDS view(一種官方的資料視圖), 它會免費幫你解掉四個地雷;但現在的路徑是「SAP 匯出 CSV → 灌進 PostgreSQL」,中間沒有 CDS view, 所以那四件事都得自己補:

地雷CDS view 有解CSV 匯出的現況
多公司資料隔離(MANDT)解決要自己確認匯出時有沒有濾
表跟表怎麼 join解決要自己在語意層補
多語系文字解決要自己處理
權限控管自動套列層級權限完全沒有
代號前導零(4711 存成 0000004711)部分查錯會回空集合而不是報錯

這也是為什麼前處理要把「訂單 104705」補成十位數——就是在補這個。

技術為什麼用 SSE,不用一般的請求/回應?也不用 WebSocket?
因為需求正好就是「後端單向推、逐則推」,SSE 是最省的那個。
  • 不用一般請求回應 —— 統整要等模型逐字生成,整包回會讓使用者盯著空白轉圈。
  • 不用 WebSocket —— 雙向通道在這裡用不到:使用者送出之後到答案寫完, 中間沒有東西要往上送。SSE 走的是普通 HTTP,不用額外的連線升級。

SSE 還順帶解決了另一件事:因為使用者已經看得到進度,後端呼叫 text-to-SQL 就可以同步等, 不需要做成非同步再輪詢。等 13 秒但一路看得到進度,跟等 13 秒看著空白,是兩種體驗。

它的限制也直接決定了建單的設計:SSE 是單向的,沒辦法中途停下來等人回答。 所以建單拆成三次獨立請求,見 §05

技術對話紀錄放在記憶體,重啟就沒了,這樣可以嗎?
可以,因為它本來就比使用者按重新整理更短命。

sessionId前端產生的,使用者重新整理就換一顆新的。 所以後端重啟清掉上下文,不會比使用者按 F5 更嚴重。

後端每個 session 只留最近 20 則,追問時帶最近四輪給模型。 畫面上看得到的對話紀錄存在瀏覽器本機,不在後端。

程式註解自己寫著:「記憶體版;要跨重啟或多台才需要外部儲存」—— 這是明確標示的簡化,不是疏忽。要上正式環境時換掉那一個類別即可。

技術多語是怎麼做的?為什麼英文問句要先翻成中文?
原則是「資料語言 ≠ 對話語言」:內部一律用中文跑,只有兩端換語言。

因為系統裡有三段東西是中文的,而且改不動:

  • 知識庫文件是中文
  • 別名表、時間詞(「上個月」「本季」)是中文規則
  • 語意層的指標名稱是中文

英文句子直接送進去,這三段全部失效。 所以做法是在邊界翻一次:非中文問句先由模型翻成中文(順便補前文,同一通呼叫), 中間所有規則與流程一行不改,只有進度文字、固定文案與最後統整換語言。

代價寫得很誠實:非中文問句多約 300 ms,中文問句零成本。 比起讓每一段各自支援三種語言,這樣便宜也不會漏。

判斷語言不用模型:有假名一定是日文;有漢字看介面語言;只剩拉丁字母就是英文; 什麼都沒有(只打一個單號)就跟介面走。

3-7 分工與第二版

技術哪些是我們做的、哪些是別人做的?
切線很清楚:應用層全部是開發方(Adam),AI 能力服務是 AI team 與既有系統。
負責狀態
Adam(AI-Brain 本體) 入口、意圖、流程、調度、證據池、統整、前端、知識庫管理 已完成並在跑
AI team(Ian) Qwen 端點、text-to-SQL API、RAG API、之後的 AI 判斷 API 前兩者已好;RAG 規格已交付、還在做;AI 判斷還沒開始
Tom/BrandonSAP 建單 API、鏡像資料建單 API 已對真機驗過
我方(SA 這條線)情境設計、雛形、文件、對焦

Tom 的責任邊界主張值得記:應用層管 WHAT NEXT/WHEN STOP,能力服務管 HOW TO EXECUTE。 「AI 判斷」那一格被切出去給 AI team,正是照這條線切的。

技術之後要接 UiPath Maestro,那第一版不就白做了?
不會。要換掉的只有調度層那一個類別和 YAML 的載入方式。

Maestro 是商業流程編排工具,它取代的正好是 Java 那條「照步驟跑、分岔、等人確認」。 對應關係很乾淨:

  • YAML 的 gateway 門檻 → Maestro 的流程變數
  • 「等人確認」→ Action Center 的人工節點
  • 每個 tool → Maestro 呼叫的 API 節點

右邊每一格能力 API 都不用動,前端、知識庫、檢索契約、統整、資料層全部沿用。

為了那條縫,Java 端才刻意不把流程寫死在程式裡。 這是「為什麼用 YAML」的第四個理由,也是最現實的那個。

命名要注意:整套系統叫 AI-BrainMaestro 是它底下的編排層, 不是更上層的東西。講「掛在 Maestro 底下」會讓人誤會層級關係。

04模型串在哪、串的是哪一種

「哪邊有串模型、串的是哪種模型、為什麼要這樣串」——這一節直接列完。 重點是:整套系統只有一顆語言模型,用在七個地方(判意圖、追問還原、非中文翻譯、 統整、一般對話、看圖判讀、標籤對應);OCR 是另一套模型文件檢索目前沒有模型產 SQL 的模型在對方的服務裡

技術對照畫面上那四步:各問了幾次模型?
直覺通常會錯三個地方。先把這張表記起來,被追問時照著指。
畫面上那一步我方呼叫幾次哪一顆、怎麼叫
理解問題 通常 0 次 純規則,不問模型。只有兩種情況才 +1 次: 這句話依賴前文(追問還原)、或問句不是中文(先翻成中文)。 Qwen 非串流、上限 80 token,約 140 ms
判斷意圖 1 次 Qwen 非串流、上限 16 token、溫度 0,約 130 ms。 帶附件時是 0 次——看請求形狀直接決定,不問模型
查資料 我方 0 次 模型呼叫發生在對方那邊:AI team 的 WrenAI 語意層+Qwen 產 SQL, 產不出來還會自己重修 2~3 輪(畫面上的「重修 N 輪」就是它)。 我方只是送一句問句過去
統整回答 1 次 Qwen 串流、上限 1200 token、溫度 0.2、關思考模式
(檢索文件) 0 次 tf-idf,純算數。見 §01

算總數:一題純文件問答=我方 2 次(意圖+統整)。 一題資料問答=我方 2 次+對方 1~3 次

建單那條線另外還有三個,而且其中一個不是 Qwen:

  • 看圖判讀 —— Qwen 多模態,判斷「這是不是訂單」
  • OCR —— PaddleOCR-VL,不是 Qwen,是同事的另一個服務(192.168.170.28
  • 標籤對應 —— Qwen,但只有規則認不得的標籤才問,而且用選單鎖答案、看不到值
最容易講錯的三處
  1. 以為「理解問題」要問模型 —— 大部分時候不問,它是規則。
  2. 漏掉「判斷意圖」 —— 那才是我方呼叫模型的第一個地方。
  3. 以為「查資料」是我們在呼叫模型 —— 不是,那一段在對方的服務裡。 這件事很重要:它解釋了為什麼語意層換版時我們一行都不用改。
用在哪哪一顆怎麼呼叫目的為什麼是這樣
判意圖 Qwen3.8-27B 非串流
上限 16 token
溫度 0
四選一,順便回流程代號 做單選題不是寫文章,所以限得很死。溫度 0=同樣的問句永遠同樣的答案。 上限設 16 而不是 8,是因為回的是 knowledge_search 這種長代號,截斷會解析不出來
追問還原 Qwen3.8-27B 非串流
上限 80 token
「第二名呢」補成完整問句 只在「有前文」且「這句看起來依賴前文」時才呼叫,完整問句不花這一趟
非中文翻譯 Qwen3.8-27B 同上(同一通呼叫) 英/日問句翻成中文 內部一律用中文跑,在邊界翻一次比每一段各自支援三語便宜
統整回答 Qwen3.8-27B 串流
上限 1200 token
溫度 0.2
關閉思考模式
把證據寫成人看得懂的話 溫度 0.2=要穩定不要創意。關思考模式省六成 token——統整不需要它先自言自語一段
一般對話 Qwen3.8-27B 串流 回招呼、說明能做什麼 這條路不取證,所以意圖分類寧可錯往分析也不要錯往這裡
看圖判讀 Qwen3.8-27B
(多模態)
非串流
上限 400 token
圖片直接進 prompt
判斷「這份文件是不是要建訂單」 長邊超過 1600 px 先縮成 JPEG。解析不出結果一律當「不是訂單」—— 寧可多問一句,不能憑壞掉的輸出去建單
標籤對應 Qwen3.8-27B 非串流
上限 600 token
用選單鎖住答案
「這個沒看過的標籤是哪個欄位」 模型看不到值,只能從欄位清單裡選。規則認得的標籤根本不問它—— 實測一份訂單 59 個欄位,規則對出 18 個、一題都沒問模型
AI 判斷 未定 資料不足時問「還能查什麼」 還沒接。定位是 AI team 提供的一個 API,跟其他能力並列
產 SQL 在 AI team 那側
(WrenAI 語意層 + 模型)
HTTP POST /text-to-sql 把問句變成 SQL 並執行 不是我們呼叫模型,是呼叫他們的服務。 選哪張表、產什麼 SQL、在哪執行都是他們的事。所以語意層換版時我們一行都不用改
OCR PaddleOCR-VL
(同事的服務)
HTTP POST /extract_form
逾時 120 秒
把圖上的字讀成「標籤:值」清單 是另一套模型(版面分析+視覺語言模型),不是 Qwen。它只負責認字,不負責判斷欄位
文件檢索 目前沒有模型 程式內建 從知識庫挑出最相關的五片 現在用 tf-idf(純統計)。AI team 的檢索 API 好了改一個設定值就切過去
技術為什麼幾乎所有事都用同一顆模型?不是該各用專長的嗎?
因為多一顆模型就多一個要架、要餵 GPU、要維護、要監控的東西。

目前這幾種用法的需求其實都在同一顆 27B 模型的能力範圍內: 做單選題、補一句話、翻譯、寫一段有引用的文字、看一張圖說是不是訂單。 沒有一項需要專門的模型。

真正省下來的是營運成本:一個端點、一套監控、一張 GPU。 而且介面是 OpenAI 相容的,之後真的要換或要加一顆,改設定檔兩行就好。

唯二用了別的技術的地方,都是因為那件事 Qwen 做不好或不該做: OCR(認字是專門的活)與檢索(那是排序不是生成)。

技術Qwen3.8-27B 是什麼?跑在哪?
阿里巴巴開源的語言模型,270 億參數,自架在公司內網的一張 GPU 上。
  • 跑在哪192.168.170.31:7100,用 vLLM 這套推論伺服器架起來, 對外提供 OpenAI 相容的介面。
  • 量化:NVFP4(一種把模型壓小、讓它塞得進顯卡記憶體並跑更快的技術,代價是精度略降)。
  • 可以吃多長:context 80k(約八萬 token 的上下文)。
  • 誰維護:AI team(Ian 那邊),不是 Adam。

選它的實際理由:開源可自架(資料不出公司)、中英日都行、有多模態版本可以看圖。

陷阱資料會不會跑到 OpenAI 或其他雲端去?
不會。全部在內網,沒有任何一段送到外部。
元件位置
語言模型(Qwen / vLLM)192.168.170.31:7100
text-to-SQL192.168.170.31:6100
資料庫 middledb192.168.170.31:5432
OCR192.168.170.28:6600
SAP 測試機192.168.170.23:44300

「OpenAI 相容」只是指介面格式跟 OpenAI 的 API 長得一樣(方便換), 不是指會連到 OpenAI。這個詞很容易被誤會,講的時候要補一句。

唯一一個要自己先聲明的例外 雛形需要連網路——Vue 與字型走公有 CDN。真要交檔給對方在他們內網開, 得先確認他們不擋 CDN,否則會開出一片空白。這跟資料外流無關,但要先知道。
技術換一顆模型要改多少?
設定檔兩行:端點位址與模型名稱。

因為介面是 OpenAI 相容的,任何 vLLM、Ollama 或雲端 API 都接得上。 統整用的那份規則(prompt)也是中性的,沒有綁 Qwen 的特性。

唯一要注意的是看圖那一段:換的模型要支援多模態, 否則會退回「先 OCR 成文字再讓模型讀」的路徑——程式已經寫好這個退路, vLLM 的圖片配額被關掉時會自動走。

陷阱這樣算下來成本多少?
沒有 API 費用,因為模型是自架的。成本是那張 GPU 的時間。

關掉思考模式後,統整一次約幾百 token;一天幾百次問答對一顆 27B 模型是輕載。

要盯的地方要講出來:text-to-SQL 跟統整共用同一張顯卡。 多人同時問的時候會排隊,這已經提醒過 AI team。 緩解手段是關思考模式(省六成 token)與 SSE(讓使用者看得到進度,等待比較不難受)。

05建單那條線(速查)

完整版在姊妹文件 建單架構與Demo問答_20260915.html。 這裡只留現場最常被問、以及那份文件寫完之後才發生的變化。

建單這條線的流程圖放在 §02, 跟問答那張並排、可以直接切換對照——差別最大的就是 OCR 那一段

畫面上傳一張訂單圖,中間發生了什麼?
三次獨立的請求,不是一條跑到一半停下來等人的流程。
0 上傳     POST /api/attachments → 拿到一個附件編號(存記憶體)

1 判讀     order_intake    模型看圖 → 是不是訂單 → 問「要用這份文件建立訂單嗎」
   ↓ 人按「要」(這一輪請求已經結束了,按鈕送出的是新的一次請求)
2 辨識     order_extract   OCR 讀成「標籤:值」清單 → 規則對進欄位 → 草稿卡
   ↓ 人核對/修改(草稿整包在前端)
3 建單     order_create    先佇一列 → 打 SAP 拿單號 → 補回流水帳 → 顯示單號

「等人確認」不是後端的一個狀態,是這一輪回出一個問題,下一次請求把答案帶回來。 所以使用者關掉分頁、重整、隔天再來,伺服器這邊沒有半張單要清。

技術三次請求每次都從頭跑,不是很浪費嗎?
是重跑了,而且是刻意的——那正是「沒有中間狀態」這句話要付的代價。

每一次請求都是完整的一輪:一樣先走前處理、再判意圖,然後才進建單那一段。 進度列上三次都看得到「理解問題 → 判斷意圖」,只是這兩步在建單時幾乎不花錢—— 意圖是看請求形狀直接決定的,0 ms,沒問模型

換來的是三件事:

  • 伺服器上沒有半張單 —— 沒有 pending 狀態要存、要清、要設過期。
  • 斷了不會壞 —— 「中間斷掉怎麼辦」的答案是「沒有中間可以斷」,最差就是重來一次。
  • 重整不會掉 —— 草稿整包在前端,改完整包送回。

真正的代價是每段都要重跑一次前置:按「要建單」那一步會再 OCR 一次。 這件事程式裡有處理——每則訊息記著當初送出的參數, 所以按「重新產生」是「再辨識一次」而不是變成閒聊; 已經建完的那則按下去,因為冪等,拿回的是同一個單號。

被問「為什麼不用 WebSocket 或存個 session 就好」, 答案回到 §03:SSE 是單向的,要停下來等人就得多一個狀態加一支端點。 少一個狀態、少一支端點,是這個設計買到的東西。
陷阱AI 辨識的信心度有多高?
刻意不給信心度分數。這題被問的機率最高,答法要背起來。

「我們刻意不給信心度分數。因為值是 OCR 原文照抄、欄位對應是規則或模型二選一, 中間沒有一個可以量的連續量。給一個數字只會讓人以為它是量出來的,反而不去檢查。」

「取而代之的是可追溯:每一格都標它來自文件上哪個標籤、會寫到 SAP 哪個欄位。 對錯一眼看得出來,而且是人在確認,不是機器打分數。」

舊版曾經有過:讓模型自己回報信心度,前端拿 0.85 當門檻標黃。 拿掉的理由是——那個數字是模型自己說的,不是量出來的。 模型說 0.94 不代表它有 94% 的機率是對的,同一份文件跑兩次還可能給不同分數。 給一個看起來精確的假數字,比不給更危險。

技術模型會不會把數字改掉?
碰不到。整個建單流程裡模型只被允許做兩件事,都跟值無關。
  • 判讀:這份文件是不是要建訂單(回一個是非題+一段說明)
  • 對標籤:這個沒看過的標籤是哪個欄位——只能從欄位清單裡選,而且看不到值

值永遠是 OCR 原文照抄。這句話可以直接拿來講: 「模型負責理解,程式負責搬運。值從頭到尾沒有經過模型的手。」

為什麼要這樣改?因為舊做法(把 OCR 整包丟給模型填成 JSON)實測出三個問題: 長文件輸出會被截斷、鎖了結構之後模型會在空白處打轉直到上限、 而且模型會順手改值——把數量印成 $120

陷阱會不會重複建單?連點兩下呢?
不會。防重複做在資料庫,不是做在程式判斷。

每張草稿在辨識那一步會拿到一個唯一編號。要建單就得先用這個編號在流水帳表插入一列, 而那個欄位是資料庫層級的唯一鍵——插得進去代表這張草稿是你的,插不進去代表別人先拿走了

  • 已經建過 → 直接回原本的單號,不再打 SAP
  • 兩個請求同時進來 → 插入失敗的那個回「這份訂單正在建立中,請稍候」,絕不打第二次

順序也是刻意的:先佇一列,再去打 SAP。 萬一 SAP 成功但寫紀錄失敗,至少看得到有人試過這一單, 不會變成「SAP 有單、我們完全沒紀錄」的孤兒。

陷阱建好的單,馬上用聊天查得回來嗎?
實體程式查不回來。這題答錯的話,後面整套說法都會被懷疑。

兩層原因:

  1. text-to-SQL 的語意層只掛了那 12 張銷售表,流水帳不在裡面
  2. 就算真的寫進 SAP,middledb 是鏡像、整批重建,不是即時同步。

中間缺的那一段(建單後要回寫中繼資料庫哪幾張表、哪些欄位)連規格都還沒定, 歸 Tom/Brandon。

雛形演的是查得回來 雛形那段是寫死的腳本,演的是目標狀態。這本身沒問題—— 但如果現場有人追問「所以實體現在做得到嗎」,要答得出上面那兩層原因。
陷阱SAP 那一步是真的嗎?
真的 client 已經寫好、也對真機建過單,但預設仍發模擬單號。

建議的講法:「辨識、判讀、欄位對應、流水帳都是真的在跑; SAP 建單那一步目前發模擬單號,真的連線程式已經寫好,等帳密與主檔對照就能切過去。」

「已經寫好等切換」本身是加分,不用心虛。技術細節(如果被追問): 走 S/4HANA 的標準銷售訂單 API、憑證釘選、只跑 TLS 1.2、 切換只要改一個設定值加上帳密。

陷阱對真的 SAP 建過單了嗎?結果怎麼樣?
建過。11 張全部建成功,但其中 4 張金額是錯的——這件事要主動講,因為它帶出一個好設計。

2026-09-15 對真機(192.168.170.23)實跑的結論: 11 張單全部建成,4 張金額錯,其中一張正好是兩倍(OCR 把品項區塊吐了兩次)。 而且沿路每一步的狀態都是正常的——每個欄位都合法、必填全過、SAP 也收下並回了單號。

這催生了一道新的檢查,叫對帳守衛:建完單之後, 拿單據自己印的合計SAP 用自己的定價算出來的淨額, 差超過 0.01 就把警告接在完成訊息後面。

為什麼這道檢查非有不可:它擋的是欄位檢查看不到的一整類錯—— 品項多讀、少讀、重複讀。每個欄位都正常,只有總額對不起來。

為什麼做成事後警告而不是事前攔截:因為價格是 SAP 算的, 在我們這邊自己算價等於養第二套定價邏輯。 模擬模式沒有定價引擎所以回空值——空值是「沒得對」,不是「對過了」

這一段是 建單架構與Demo問答_20260915.html 寫完之後才進去的 (f60f83023b7268),那份文件裡沒有。 它是目前最能展示「這個團隊有在認真對帳」的一個細節,值得主動講。

06會被問倒的誠實題

這幾題的共同點是:主動講比被拆穿好,而且每一題後面都接得上一個好設計。 答法的形狀固定——先承認限制,再講因為有這個限制所以做了什麼。

陷阱我怎麼知道這個答案是對的?你要怎麼說服我相信它?
這題是全場最重要的一題。正確答案不是「你可以相信它」,是「你不需要相信它」。

這套系統從頭到尾的設計主張就是這句話:它不要求你信任它,它把依據攤開讓你自己驗。 所以「怎麼知道對不對」不是一個尷尬的問題,是這個產品的賣點

四層驗法,由粗到細

照這個順序看,越前面越容易錯、也越容易看出來:

#看什麼在哪看怎麼判斷錯了
1條件對不對 「我理解的條件」那一排 最常錯的一層。你問 8 月它寫全期間、你問甲客戶它對到乙客戶——一眼看得出來
2查了哪張表、怎麼算 展開 SQL 懂的人直接讀。標了「重修 N 輪」的更要看——那代表模型卡過
3口徑對不對 答案裡的引用 [n],點開看原文 「達交」算的是計畫出貨日還是客戶要求日?點引用看它依據的是哪份規範
4數字對不對 表格本身 表格是完整的,答案只點名前三筆。數字以表格為準,不是以文字為準

系統已經替你擋掉的錯

  • 查不到不會硬掰 —— 0 筆直接短路回「查無資料」,連模型都不叫醒,所以沒有編的機會。
  • 「整列都是空的」也算查無資料 —— 擋的是「回一列 0 然後很有自信地說本月 0 張」這種 最危險的假答案(實測真的發生過)。
  • 數字不給模型算 —— 統整的規則明寫不准自己計算,數字只能照查詢結果原文引用。
  • 引用編號是程式給的 —— 模型引用不存在的編號會被過濾掉,不會出現掛不回去的來源。

系統擋不掉、只能靠人的錯

SQL 語法正確、條件也對,但業務口徑理解錯。 例如「前十大客戶」依金額還是依張數、「營收」含不含稅。 這一類不會報錯、看起來完全正常,只能靠把口徑寫進規範文件讓系統取來引用, 或是靠看的人自己知道。這是誠實的邊界,不要假裝沒有。

被問到時的三段式答法

第一,我們照實講:text-to-SQL 那一段對方自評 76%,不是 100%。」

第二,所以我們不要求你相信它。每個答案都看得到系統理解的條件、實際執行的 SQL、 以及每一句話依據的原文——三樣東西你都可以當場驗。」

第三,判斷的責任本來就該留在人身上。 系統的責任是把依據完整攤開,讓你有東西可以判斷; 一個不給你依據、只給你數字的系統,才是危險的那個。

還沒做、但被追問要說得出來的

「你們有量化的驗收標準嗎?」——目前沒有,但機制已經備好了。 每一次請求的問題、條件、SQL、撈到的碎片、答案、引用全部留成紀錄, 所以只要有一份「標準答案題庫」,就能回放算出:SQL 對不對、引用有沒有掛回、 答案有沒有超出證據。這是請求紀錄存在的主要理由,不只是除錯。

要讓這件事成立,缺的不是工程,是業務端先把口徑定義下來—— 沒有定義就沒有正確答案,沒有正確答案就沒有準確率可以算。

陷阱準確率多少?答案可以直接拿去用嗎?
text-to-SQL 那一段對方自評 76%,而且模型自撰 SQL 那條路更低。這個數字要照實講。

對方(AI team)自己在介面規格裡特別註明「這句要照實講給客戶聽,不能當成查得到就是對的」。

接下來這句才是重點:「所以畫面上一定看得到實際執行的 SQL 與系統理解的條件。 判斷對不對的責任在看的人身上,系統的責任是把依據攤開。」

可以再補一個技術性的緩解:用訂單編號精確查一筆這種簡單的條件查詢相對穩 (實測一次就對、8 秒);複雜的聚合與多表關聯才是風險區。

陷阱如果它查錯了但看起來很合理,怎麼辦?
這是這類系統最真實的風險,而且沒有完美解。誠實講三層防護。
  1. 條件攤開 —— 系統理解到的條件(期間、客戶、指標)直接顯示。 錯最多的是條件理解錯,這一層擋得住大部分。
  2. SQL 攤開 —— 懂的人可以直接驗。而且模型重修過的會自動展開。
  3. 不確定就不說 —— 查不到說查不到;整列都空的算查無資料; 統整不准自己算數字。

擋不住的那一類也要講得出來:SQL 語法正確、條件也對,但業務口徑理解錯 (例如「前十大客戶」依金額還是依張數)。這一類只能靠把口徑寫進規範文件, 讓系統取文件來回答,而不是讓模型自己決定——那正是「綜合判斷」那三條流程在做的事。

陷阱資料是真的嗎?是貴公司的實際數字嗎?
不是。是 SAP 官方的示範資料,這一點畫面上有寫,也一定要講。
  • 哪一套:SAP Best Practices 模型公司示範資料,美國銷售組織 1710、幣別 USD、腳踏車系列產品。
  • 期間:2018-10-29 ~ 2024-11-15。
  • 知識庫那幾份文件:自己寫的示範文件,虛構的公司,不是任何一家公司的正式規範。

為什麼這件事不能含糊:如果讓人以為那是自家報表,任何一個數字被拿去引用都是問題。 而且真實資料進來之後,數字一定會變,先講清楚就不會有落差。

陷阱為什麼問「這個月」會查不到東西?
因為資料只到 2024-11,而「這個月」是照系統當天的日期換算的。

這不是壞掉,是兩件事撞在一起:時間詞換算用的是真實的今天, 而資料是 2018~2024 的歷史快照。

反過來也成立,而且對 demo 有利:新建的單如果是當天日期,問「這個月」只會查到那幾張, 舊資料一張都不出現——畫面很乾淨。要知道那是這個機制造成的,不是系統特別聰明。

雛形這邊的處理方式不同:預設「全期間」而不是「本月」,正是為了避開這個問題。

陷阱訂單類的問題現在答得出來嗎?
答得出來了——但開發方自己的說明頁還寫著「訂單類一律回查無資料」,那是舊的。

時序是這樣:

  • 之前:對方的語意層裡只有總帳、帳齡、預實差異,沒有訂單事實表,所以訂單題一律查無資料。 這個狀態被寫進了好幾份文件。
  • 2026-09-15:對方換版,把 5 個彙總模型清空,改成直接對應 middledb 的 12 張銷售表vbakvbapkna1likplips…)。 實測「訂單 0000004826 的客戶是誰」一次就對,8 秒回。
要精確講 用訂單編號精確查一筆是實測通過的。其他訂單題(排名、未出貨、達交率) 沒有逐題實測過,不要宣稱全部都行。
另外開發方的 /internals 說明頁與四份文件仍停在舊敘述, 現場如果有人打開那一頁,會看到跟事實相反的內容。這已經整理成回報清單要給他們。
陷阱如果現場有人要求打開開發方的「運作說明」頁?
可以開,但先知道那一頁有五處停在舊版本。建議不要主動開。

那一頁在實體程式裡藏著(左上標誌兩秒內點五下解鎖), Adam 把「每一格怎麼達成、被問到時怎麼答」都寫在那裡,所以它很容易被當成權威答案。

位置頁面上寫的實際
Pipeline 那格「現在 7 條 YAML」11 條
建單那格開頭「模型把『標籤:值』重排成草稿」 已改成規則優先、模型只對不認得的標籤。同一格下面的細節是新的、開頭是舊的
調度層那格的待辦「等人確認要存 pending、之後 resume 續跑」 建單已完成,而且刻意不採用這個設計
訂單資料狀態「訂單類目前一律回查無資料」語意層換版後已經查得到
第 02 節的事件序列意圖在最前面,沒有前處理這一步 程式後來把前處理提到意圖前面(因為追問還原必須先做)

被問到的答法:「那一頁是開發方的內部說明,有幾節還沒跟上最新的程式, 已經整理好要回報給他們了。」然後照這份文件講實際的做法。 不要當場改口說雛形是對的——雛形演的是實體,不是另一套設計。

陷阱權限呢?資安呢?誰都看得到所有資料嗎?
目前完全沒有身分驗證。這件事要照實講,但接著要講「已經做對的那些」——否則聽起來像整套都沒顧。

開發方在 2026-09-12 自己做過一份資安健檢,把發現分成高/中/低。 「有一份寫得出來的清單」本身就是答案的一部分——這是「知道要做但還沒做」,不是「沒想到」。

高:上正式環境前一定要處理

現況後果
H1後端沒有任何身分驗證,而且綁的是 0.0.0.0 同網段任何人都能問公司資料、看知識庫全文、上傳文件, 甚至刪除任何文件——沒有確認也沒有稽核
H2監控用的 Elasticsearch/Kibana 對整個網段開放、沒有帳密 裡面放的是每一次請求的完整問題與答案。同網段任何人可以免登入翻、也可以刪掉整個索引
H3日誌收集端的 9880 埠沒有驗證 任何人 POST 一段 JSON 就能偽造紀錄

開發方自己排的順序是 H1 先做——因為身分驗證一解,下面好幾條的風險同時降下來。

中:現在可接受,但要知道

  • SQL 只剩對方一層防護 —— 見前面 SQL 那題。
  • 知識庫文件可以做提示注入 —— 文件原文會進統整的 prompt, 有人上傳一份寫著「忽略以上指示」的文件就有機會影響答案。 配上 H1(任何人都能上傳)風險放大。 現有的緩解不是為了防注入設計的但有幫助:只能引用片段、每句掛編號、0 筆短路不進模型。
  • 沒有速率限制 —— 而 text-to-SQL 的併發上限只有 2。 一個人開個迴圈就能讓整個服務對所有人不可用。
  • 業務內容落在三個地方、都沒有保留政策 —— 後端日誌檔(輪替上限 500 MB)、Elasticsearch(沒有自動刪除,無限成長)、 瀏覽器本機儲存(對話明文,共用電腦看得到)。

低/已經做對的——被問資安時要主動講這些

XSS前端v-html,模型輸出與文件內容全部走文字節點。已驗證
惡意連結外部連結一律過白名單,只放行 http/https/mailto, javascript: 會退化成純文字
檔案上傳大小上限、副檔名白名單、解析失敗就拒、 檔名只當顯示用不落地 → 沒有路徑穿越
錯誤處理堆疊只進日誌,回應只有錯誤碼與訊息,不外洩內部結構
金鑰沒有任何寫死的密碼或 token
相依套件npm audit 0 個漏洞
一個寫在產品畫面上的承諾,要知道它的邊界 使用者問「資料會不會外流」時,系統的固定回答是 「問題、文件與答案都不會離開內網」。
今天是真的——模型在內網、監控在本機。 但那是一句寫在畫面上的承諾,監控層一旦搬上雲就違反它。 程式裡留了兩個開關(不記錄答案、不記錄 SQL)就是為這件事準備的。 搬之前要先決定:關掉全文,還是改掉那句話。
陷阱上傳文件跟圖片,那些檔案會去哪裡?
全部在內網,但會經過第三台機器——這點要說得出來。
檔案去了哪要知道的
訂單圖片 存後端記憶體(不落地,總量上限 200 MB,滿了淘汰最舊的) 建完單就沒用了,重啟就消失
圖片內容 縮到長邊 1600 後送內網的模型服務判讀 圖片內容會進那台機器的日誌(如果他們有開)
圖片原檔 整份送到另一台內網 OCR 服務(192.168.170.28 文件全文會經過第三台機器,他們的日誌政策我方不知道
知識庫文件 切片後存後端記憶體 重啟會清掉,只重載預設那 15 份

已知還沒做的:沒有病毒掃描;沒有擁有者——拿到附件編號的人就能用它建單。 後者要等身分驗證一起解,不是這一塊能補的。

被問到時的答法:「全部在內網,沒有一段出公司。 但誠實講,文件會經過兩台我們不擁有的內網服務(模型與 OCR), 它們的日誌政策要跟那兩個團隊確認——這一條已經寫在資安清單上了。」

陷阱這套系統最大的風險是什麼?
三個,而且第三個最容易被低估。
  1. text-to-SQL 對真實資料的正確率 —— 靠平坦的事實表與語意層的定義壓低風險。
  2. GPU 排隊造成的延遲 —— text-to-SQL 與統整共用同一張卡。 靠關思考模式與逐步進度緩解。
  3. 名詞沒有定義 —— 「這個月」「前十大」「達交」各人講的不一樣。 沒有定義就沒有正確答案可以驗收。這是現在最需要業務端拍板的東西, 而且它不是工程問題,錢和人都解決不了。

第三點很值得主動講,因為它把球丟回給業務方,而且是真話。

07雛形與實體的差異清單

這一節是上台前最該讀熟的。雛形刻意做成跟實體畫面一樣, 所以任何差異都會被當成「系統的說法」。下表按「被抓到的機率」排。

項目雛形實體要不要擔心
底下是不是真的 不呼叫任何 API,問答是寫死的腳本 全部真的在跑 最重要的一條。被直接問就照講,不要模糊。 但要補:知識庫檢索是真的,可以當場換題目試
整條進度列 理解問題 → 判斷意圖 → 查資料(N 筆,N ms)→ 統整回答 同左 2026-09-15 已對齊:順序、步驟名稱、缺的前處理(7 段)、 查資料那行的格式(10 段)、以及一個錯的意圖類別。 原本順序是反的,因為照著開發方過期的說明頁畫
pipeline 代號 margin_structurecycle_timeorder_stagerevenue_pipeline 這四個實體沒有,那些題目會走 data_query 刻意保留。原本有六個, delivery_ontimeontime_ratecustomer_idleorders_idle 已改名(實體真的有)。 剩下四個演的是實體還沒有的情境,全改成 data_query 會讓四題顯示同一條
統整那行(四段) 「268 字」 「268 字,引用 1 片」 其餘 12 段已一致。這四段硬改會做出點了沒東西的引用—— 實體的查詢結果本身就是證據,雛形的表格與證據走兩條路
沒講期間時 預設全期間 預設本月 不用擔心,兩邊都對。雛形資料只到 2024-11,用「本月」會查到 0 筆
請求編號 前端亂數產生,格式一樣 OpenTelemetry 產生,可以拿去查 只有被要求「當場查給我看」才會露餡。答法見 §01
毫秒數、相關度、重修 N 輪 腳本裡寫死的示範值 實測值 被問到就講「這幾個數字是示範值,實體那邊的實測數字我有」
建單 三段都是腳本,OCR 的值與單號寫死 OCR 真的在跑(PaddleOCR-VL)、SAP 連線程式已寫好、流水帳真的寫進資料庫 形狀一樣(三條流程、語意欄位、無信心度),所以講得通
建完能不能查回來 演得回來 查不回來 會被追問。雛形演的是目標狀態,實體缺的那一段連規格都還沒定
附件格式 只收 PNG/JPG/JPEG PNG/JPG/WebP/PDF,8 MB 刻意的。WebP 與 PDF 是為後續階段鋪的,九月 demo 只用三種
知識庫份數 10 份示範文件 15 份 不會被抓到
GenBI 分析、Dashboard (預設隱藏,側欄點五下解鎖) 沒有這兩頁 沒解鎖時畫面跟實體一模一樣,這是刻意的。 演完記得再點五下收回去
三語 介面切得動,但回答內容還是中文 回答語言跟問句走 日本客戶那場之前要補。目前日文問句會落到本地檢索,演不出完整那題
信心度 已拿掉 已拿掉 兩邊已對齊,可以放心講
一個通用的答法 被指出任何一處不一致時,最安全的句型是: 「雛形演的是實體程式,不是另一套設計。這一處是實體後來改了/是資料造成的差異, 實際的做法是……」 然後講實體的做法。不要當場宣稱雛形才是對的——那會讓人開始懷疑其他每一格。

08專有名詞全表

每個詞三件事:它是什麼、這套系統哪裡用到、為什麼要用它。 現場被問到某個詞,翻到這裡照著講就完整。

8-1 這套系統自己的詞

名詞是什麼哪裡用到為什麼要用
AI-Brain 整套系統的名字,寫法固定用連字號 品牌字樣、畫面標題、所有文件 2026-09-14 拍板。舊名 PRISM 已退場,公司內舊叫法「AI Server Demo」別人口中還會出現
UiPath Maestro 商業流程編排工具 還沒接。十月評估要不要用它取代調度層 它是 AI-Brain 底下的編排層,不是同級的別名,也不是更上層。講的時候層級不要顛倒
Intent
(意圖)
把一句話分成四類:分析/系統說明/一般對話/業務操作 進度列第一(或第二)步。由 Java 的 IntentClassifier 呼叫模型判定 不同種類的問題該走的路差很多。沒有這層的話,「你好」也會去翻資料庫
Pipeline
(流程)
一種問題的處理流程定義,一條=一個 YAML 檔 實體目前 11 條。畫面上「分析 · data_query」那個代號就是它 流程寫在設定檔不寫在程式裡,改門檻不用改程式,之後搬去 Maestro 搬的是流程不是程式
Orchestrator
(調度層)
讀 YAML、照步驟跑、分岔、命中停止條件就停的那個 Java 類別 每一題都會經過。每一步會開一個追蹤節點 一行模型呼叫都沒有,所以行為完全可預測、可測試、每次一樣
Tool
(能力)
流程裡「做事」的那種步驟。目前有 wren(查資料)、rag(檢索)、 llm(統整)、ocrsapledgervisionstatic YAML 裡用名字引用,調度層不知道它裡面在做什麼 加一個新能力=實作一個 Tool,流程主幹不用動。模型全部關在 Tool 裡面
Gateway
(分岔)
流程裡的判斷步驟,內容是一個數值比較,例如 hits == 0 「產不產得出查詢」「有沒有資料」「資料夠不夠」都是它 「夠不夠」是數值問題不是語意問題。訂門檻是人做的,算數字是程式做的,模型兩層都不出現
Render
(呈現)
流程的結束步驟,告訴前端要畫成什麼:answerdataemptyconfirmorder_draftorder_created 每條流程的最後一步 前端不做業務判斷,畫什麼由後端決定,兩邊不會各有一套邏輯
Evidence Pool
(證據池)
這一輪取回來的所有東西的集合,每片帶編號、原文、來源、日期、分數 統整只看得到它;右側「依據與來源」面板顯示的就是它 要混不同來源(查詢結果+文件碎片)、編號要穩定才能引用回原文、事後要能稽核
前處理
(Preprocessing)
把人話換成條件:時間詞→日期、俗名→代號、單號補十碼 畫面上的「理解問題」那一步 完全不用模型。規則問題用規則解,零延遲、可測試、結果固定
追問還原 把「第二名呢」補成完整問句 前處理裡面,只在「有前文」且「這句依賴前文」時才呼叫模型(約 140 ms) 意圖分類與 text-to-SQL 都只看得到一句話。不還原的話「第二名呢」會查成完全不相干的東西
統整
(Synthesize)
把證據寫成人看得懂的一段話,每句掛引用編號 最後一步,串流逐字送給前端 它是唯一讓模型寫字的地方,所以規則也下得最重:只看證據、標編號、不准自己算數字
Fixed/Generic/
Dynamic
三種流程型別,差別在「步驟誰決定」 Fixed=人寫死多步;Generic=人寫死但一輪;Dynamic=模型自己規劃,本階段不做 不做 Dynamic 是因為「客戶面前不能讓模型臨場發明查詢步驟」——不可預期、不可重現、出錯不知道怪誰
Session 一場對話。後端每個 session 留最近 20 則,統整時帶最近四輪 追問沿用上一輪期間、attachment 續問都靠它 放在記憶體,因為 sessionId 是前端發的、重新整理就換一顆,後端重啟不會更嚴重
冪等
(Idempotency)
同一個動作做幾次,結果都跟做一次一樣 建單:草稿編號是資料庫的唯一鍵,插得進去才准建單 連點、重送、重整、兩個分頁同時按確認,都只會有一張單。做在資料庫不做在程式判斷,因為程式判斷擋不住同時進來的兩個請求
對帳守衛 建完單之後,拿單據自己印的合計對 SAP 算出的淨額,差超過 0.01 就警告 建單最後一步(2026-09-15 新增) 擋的是欄位檢查看不到的一類錯:品項多讀、少讀、重複讀。實測十份單據錯四份,其中一份正好兩倍

8-2 AI 與模型相關

名詞是什麼哪裡用到為什麼要用
LLM
(大型語言模型)
讀文字、產文字的模型 判意圖、追問還原、翻譯、統整、看圖判讀、標籤對應 這套系統的立場是只在「語意」的地方用它,數字與流程都不交給它
Qwen3.8-27B 阿里巴巴開源的語言模型,270 億參數,有多模態(看得懂圖)版本 上面那六種用法全部是它,同一個端點 開源可自架(資料不出公司)、中英日都行、有看圖能力。整套只養一顆
vLLM 把開源模型架成服務的推論伺服器 192.168.170.31:7100,AI team 維護 提供 OpenAI 相容介面,所以換模型只要改設定檔兩行
OpenAI 相容 介面格式跟 OpenAI 的 API 長得一樣 呼叫 Qwen 的那支程式 不是指會連到 OpenAI。這個詞最容易被誤會成資料外流,講的時候一定要補一句
token 模型處理文字的最小單位,大致是一個詞或幾個字 各種上限:判意圖 16、追問還原 80、看圖 400、統整 1200 它同時是成本與延遲的單位。設上限是為了「這一步不該講那麼多話」
temperature
(溫度)
控制模型有多「隨機」。0=每次都給一樣的答案 判意圖用 0;統整用 0.2 判意圖是單選題要完全穩定;統整要能寫成通順的句子但不要發揮,所以只給 0.2
thinking mode
(思考模式)
模型先自言自語推理一段,再給答案 關掉enable_thinking=false 統整不需要它——證據都給好了。關掉省六成 token,也就是省六成時間
context
(上下文長度)
模型一次最多能讀多少字 這顆是 80k 決定一次能塞多少證據進去。目前五片碎片+一張表遠遠用不完
量化
(NVFP4)
把模型壓小,讓它塞得進顯卡記憶體、跑更快,代價是精度略降 這顆 Qwen 就是量化過的 27B 模型不量化很吃卡。這是自架必然的取捨
prompt 送給模型的那段指示與資料 統整的 prompt 裡有:規則六條、問題、條件、每一片編號證據 「不准亂編」不是模型的天性,是靠 prompt 規則加上「只給它證據」一起做到的
多模態/vision 模型看得懂圖片,不只文字 建單第一步:判斷「這份文件是不是要建訂單」 比先 OCR 再讀文字準(版面、表格、蓋章都看得到)。配額被關時程式自動退回 OCR 路徑
幻覺
(hallucination)
模型憑空編出看起來合理但不存在的內容 這整套架構有一半是在防它 防法三道:只給證據、要求標編號、0 筆根本不呼叫模型(沒被叫醒就沒機會編
RAG 「先檢索、再生成」——先去文件庫找相關段落,再讓模型根據那些段落回答 知識庫那條路。達交率、分批交貨這類「口徑寫在文件裡」的題目 公司內部規範不可能塞進模型的訓練資料。而且要引用得回原文,模型才不能亂講
切片
(chunk)
把一份文件切成一段一段,每段約 450 字,帶著章節路徑 知識庫匯入時切,檢索時是以「片」為單位比對與引用 整份文件太大塞不進模型,也沒辦法精確引用。切片的規則是一片要能單獨讀懂、不跨章節
tf-idf 一種計分方法:一個詞在這一段裡出現、而在其他段落很少出現,就很能代表這一段 目前的文件檢索(實體與雛形用同一套演算法) 純統計、零依賴、速度快、而且可以解釋為什麼這片被選中。代價是只看字面
bigram 把相鄰兩個字當成一個詞。「達交率」→ 達交交率 tf-idf 的中文處理 中文沒有空格。用 bigram 就不需要詞典,也不會把料號、客戶代號斷錯
embedding
(向量)
把文字變成一串數字,意思接近的文字數字也接近 還沒用。AI team 的檢索 API 會用 比的是意思不是字面,「交貨慢了」對得上「延遲交付」。代價是要多一個服務、結果比較難解釋
reranker
(重排)
把初篩出來的幾十片,拿問題跟每一片一起重讀、重新打分 還沒有。契約留了位置 解決的是誤判不是速度:向量相似度會把「講到同一個詞但講的是別的事」排很前面
top-k 取分數最高的前 k 片。這裡 k=5 檢索回傳、進統整的永遠只有 5 片 檢索是漏斗:幾千片→初篩 30→重排取 5。多要幾片是為了給重排器排,不是為了丟進模型
below_threshold
(低於門檻)
撈回來的片段全部低於相關度門檻 觸發時直接回「查無資料」,不呼叫統整 這是「查不到就說查不到」的實作點。也是雛形可以現場亂問一題示範的地方
text-to-SQL 把人話問句轉成 SQL 查詢並執行的服務 AI team 的服務 192.168.170.31:6100。所有數字問題都走它 AI-Brain 不寫 SQL、不連資料庫。一份資料一個來源,不要兩邊各養一套業務口徑
WrenAI 做 text-to-SQL 的開源產品,核心是一層「語意層」 就是上面那個服務的底層 它是右邊泳道的一格能力,不是編排層,也不做統整。這個定位常被搞混
語意層/MDL 告訴模型「這張表是什麼、欄位的中文名、同義詞、指標怎麼算」的定義層 WrenAI 裡面,由 AI team 維護 沒有它,模型面對 VBAKNETWR 這種欄位名根本不知道在幹嘛。 它是準確率的關鍵,也是最大的人工工項
OCR 把圖片上的文字讀出來 建單第二步,同事的 PaddleOCR-VL 服務 192.168.170.28:6600 它回的是「標籤:值」清單,只負責認字,不負責判斷哪個值屬於哪個欄位——那是我們這邊的規則在做
enum 鎖答案 要求模型只能從一份固定清單裡挑一個,不能自由作答 標籤對應那一題:模型只能從欄位名清單裡選 模型只能選、不能寫,所以它不可能發明一個不存在的欄位,也碰不到值

8-3 工程與基礎建設

名詞是什麼哪裡用到為什麼要用
Quarkus 一套 Java 框架,主打啟動快、吃記憶體少 後端整個應用層 實測後端 2 秒就起來。傳統 Java 框架要十幾秒,開發時每改一次都要等
Vue 3 + Quasar 前端框架+元件庫(按鈕、表格、對話框那些現成的東西) 聊天畫面、知識庫頁、草稿卡 元件庫省掉自己刻 UI 的時間。雛形也用同一套(走 CDN),所以兩邊長得一樣
SSE
Server-Sent Events
一條單向的長連線,後端可以一則一則推訊息給前端 整個問答過程:進度、表格、逐字答案、引用、結束 需求正好是單向。比 WebSocket 省(不用連線升級),比一般請求好(不用等全部寫完才給看)
YAML 一種給人讀寫的設定檔格式,靠縮排表示層次 每一條 pipeline 一個 .yml 檔、別名表、知識庫清單 業務口徑與門檻要讓不寫程式的人也看得懂、改得動
REST API 用網址與 HTTP 動詞提供服務的介面約定 POST /api/chatPOST /api/attachments、知識庫的增刪查改 最通用的介面形式,前端、其他系統、測試腳本都接得上
DTO
(資料傳輸物件)
專門用來在系統之間傳遞的資料結構 建單的 OrderDocument:每個欄位標著它在文件上會印的標籤、會落到 SAP 哪裡、必不必填 草稿卡是照這個結構動態畫出來的。改欄位改一處,畫面、驗證、SAP 對應全部跟著改
LRU 「最久沒用到的先丟」的快取淘汰規則 上傳的附件存在記憶體,總量上限 200 MB;對話 session 也是 附件建完單就沒用了,不值得寫進磁碟或資料庫
PostgreSQL 一套開源關聯式資料庫 middledb(SAP 鏡像,AI team 讀)+ order_ledger(建單流水帳,我們寫) 兩張表在同一顆資料庫但用途完全不同,這個區分要講清楚(見 §03
外鍵
(Foreign Key)
資料庫層級的規則:這一欄的值必須在另一張表裡存在 訂單的客戶代號必須在客戶主檔裡、料號必須在料號主檔裡 OCR 辨識出一個不存在的客戶代號,資料庫會直接擋下來,不會寫進一筆孤兒資料
唯一鍵
(Unique)
資料庫層級的規則:這一欄的值不能重複 流水帳的草稿編號 防重複建單就靠它。做在資料庫才擋得住同時進來的兩個請求
OData SAP 對外提供 API 的標準格式 打 S/4HANA 建銷售訂單(API_SALES_ORDER_SRV 是 SAP 官方的標準介面,不是自己挖資料庫。抬頭與明細可以一次送出(deep insert)
憑證釘選
(pinning)
只信任指定的那一張憑證,不接受其他任何憑證 連 SAP 測試機時釘住一張 .pem,只跑 TLS 1.2 測試機用的是自簽憑證。釘住指定那張,比「全部都信」安全得多
OpenTelemetry 一套「產生追蹤資料」的開放標準 每次請求產生 traceId,每一步產生一個 span 它負責「產生」,不負責「存」。所以之後換監控平台只改設定不改程式
traceId
(請求編號)
一次請求的唯一識別碼,128 位元=32 個十六進位字 畫面上可複製的那一串;後端每一行日誌也帶著它 使用者截圖回報,貼進查詢介面就找得到那一次的完整經過
span 一次請求裡的一個小段落(一個步驟、一次外部呼叫) 每一步、每一次呼叫模型或 text-to-SQL 都開一個 有了它才看得出來「這一輪 12 秒,其中 11 秒卡在 text-to-SQL」
EFK Elasticsearch(存與搜)+ Fluent Bit(收集)+ Kibana(看) 請求紀錄的去處 用 Fluent Bit 而不是常見的 Logstash:C 寫的常駐約 5 MB,Logstash 是 Java 要 600 MB 起跳,做的事一樣
JSONL 一行一個 JSON 物件的檔案格式 請求紀錄先落成這種檔,再送去 Elasticsearch 檔案是原始紀錄,Elasticsearch 是可搜尋的副本。所以「檔案 1000 筆、介面 997 筆」是預期行為不是故障
ECS Elastic 的通用欄位命名標準 紀錄的信封部分(時間、traceId、服務名、錯誤)用它的名稱 跨服務才對得起來。但只用信封——這套系統自己的執行軌跡不硬塞進去,那會製造語意錯配

8-4 SAP 與資料

名詞是什麼哪裡用到為什麼要用
S/4HANA SAP 現在這一代的 ERP 系統 資料的源頭;建單的目的地 分析查詢不直連它,只有建單會真的打它的 API
SD SAP 的銷售與配銷模組 middledb 裡那 12 張表全部屬於這個模組 這次 demo 的題目(訂單、出貨、開票)都在這個模組裡
VBAK/VBAP
KNA1/LIKP…
SAP 的表名。VBAK=訂單抬頭、VBAP=訂單明細、KNA1=客戶主檔、 LIKP/LIPS=交貨、VBRK/VBRP=發票、MARA/MAKT=料號 畫面上展開 SQL 就會看到它們 SAP 的表名是德文縮寫,本來就不好懂。這正是需要語意層的原因
中繼庫
(middledb)
SAP 資料的鏡像子集,一顆獨立的 PostgreSQL 192.168.170.31:5432,text-to-SQL 讀它 S/4 不直連是老闆的限制,也是好限制——查詢打在鏡像上不影響生產系統
CDS view SAP 官方提供的資料視圖,已經處理好權限、多語、表間關聯 這次沒有用到——走的是 CSV 匯出 要知道它存在,因為沒有用它就要自己補那四件事(見 §03 那張表)
前導零
(ALPHA)
SAP 把代號補滿固定長度,客戶 4711 存成 0000004711 前處理把「訂單 104705」補成十位數 查錯會回空集合而不是報錯——這種錯最難發現,所以要在入口就補好
銷售組織 1710 SAP 示範資料裡的美國銷售公司 目前資料就只有這一家、幣別 USD 被問「有幾家公司」時要答得出來:示範資料只有一家,不要照舊文件講三家

09那我為什麼要用這套?

最後一定會有人問這個,而且問得很直接。這一節的每個答案都要能講出 「那個替代方案在哪裡會斷掉」,而不是比功能多寡。

陷阱我直接用 WrenAI 不就好了?為什麼還要包一層?
WrenAI 是這套系統右邊泳道的一格能力。它做得很好的事只有一件:把問句變成 SQL。

直接用它,四件事會斷掉:

要做的事只有 WrenAI有 AI-Brain
口徑寫在文件裡的題目
(達交率怎麼算、幾天算閒置)
答不了。它只看得到資料表,看不到公司的規範文件 先查數字、再取規範文件,一起統整,口徑掛引用
非資料的問題
(你是誰、分批交貨要誰核准、上傳訂單建單)
全部落在它的範圍外 意圖分類先分流,各走各的路
查不到時的行為 回 0 筆。實測它把「這個月有多少張訂單」對成別的東西回一列 0, 直接用的話畫面上就會出現「本月 0 張」這個錯誤的業務結論 擋在 gateway:單列且每欄都空才算查到,寧可少答不要講錯
換掉它 畫面、流程、稽核全部綁死在它身上 它只是一個 tool。換成別家或自建,其他一行不動

一句話版本:「WrenAI 回答『資料是什麼』,AI-Brain 回答『這個問題該怎麼被回答』。」

陷阱那用 ChatGPT 企業版/Copilot 不是更快更省?
三個硬性的斷點,而且都不是花錢能解決的。
  1. 資料不能出去。這是前提不是偏好。這套系統的模型、資料庫、OCR 全部在內網網段, 沒有任何一段送到外部雲端。
  2. 它回答不了公司內部的數字。它不知道 VBAK 是什麼、 不知道你們的「達交」怎麼定義、也連不到那顆資料庫。要接上去, 你要做的正好就是這套系統在做的事——語意層、取證、流程。
  3. 它不會說「我查不到」。沒有依據的時候它會寫得很流暢。 這套系統的核心主張是反過來的:查不到就短路,連模型都不叫醒。

可以再補一句軟的:「通用助理解決的是『我不會寫』;這套解決的是『我不知道公司的數字』。 兩者不衝突,但後者只能自己做。」

陷阱SAP 自己就有 AI(Joule),為什麼不等它?
可以等,但有三件事它不會替你做,而那三件正是這個專案的重點。
  • 跨到 SAP 以外 —— 公司的規範文件、SOP、外部新聞不在 SAP 裡。 這套系統的價值有一半在「數字+規範一起回答」。
  • 口徑是你們自己的 —— 「達交」「前十大」「閒置」怎麼算, 沒有任何外部產品知道,只能自己定義並維護。
  • 現在的限制 —— 老闆的限制是不直連 S/4,資料是匯出的鏡像。 在這個前提下,SAP 原廠的方案本來就用不上。

更務實的講法:這套架構的每一格都是可替換的。 哪天原廠方案成熟了,它可以變成右邊泳道的一格能力, 左邊的流程、稽核、知識庫全部沿用。賭的不是哪個模型贏,是流程要握在自己手上。

陷阱做一個 BI 報表不就好了?何必用 AI?
報表回答「已經想好要問的問題」,這套回答「臨時想到的問題」。

兩者不是替代關係:固定要看的指標就該做成報表,快又準,不需要 AI。

這套系統的位置是報表的縫隙:

  • 沒人預先做過的切法 —— 「2022-02 那批延遲是怎麼回事」不會有現成報表。
  • 要跨資料與文件 —— 數字在資料庫、口徑在 SOP,報表工具跨不過去。
  • 問了才知道要問什麼 —— 追問是連續的,報表是一次性的。

而且這套系統不取代報表的權威性——它每個答案都附 SQL 與引用, 正是因為它知道自己不是權威報表。

陷阱有沒有更省的做法?例如只做 OCR 建單那一段
有,而且這是一個誠實的好答案:兩條線本來就可以拆開賣。

兩條線的成本結構完全不同:

建單那條問答那條
最貴的工SAP 介接、主檔對照、欄位規則語意層與業務口徑定義(人工,最大工項)
價值多久看得到快。省的是打單時間,算得出來慢。要先有題目與口徑才驗收得了
風險建錯單。已經有對帳守衛在擋答錯數字。靠攤開 SQL 與引用讓人判斷

所以如果要分階段,先做建單是合理的——它的效益最好量化。 但要講清楚:共用的那一層(意圖、流程、調度、稽核、前端)兩條線都要, 所以先做一條省下來的不是一半,大概是三分之一。

10其他一定會被問的

不屬於單一元件、但幾乎每場都會出現的問題。

陷阱它會不會學我們的資料?會不會越用越聰明?
不會。完全沒有訓練或微調,模型一個字都沒被改過。

這一題答錯的代價很高,因為它同時碰到「資安」與「期待管理」。

  • 模型是固定的。公司的資料只在回答那一瞬間被放進 prompt 裡, 回答完就沒了,不會進到模型的參數裡。
  • 對話也不留。後端的對話紀錄在記憶體,重啟就沒了; 留下來的請求紀錄是給監控用的,不會回頭餵給模型。

那它怎麼變好?靠人改三個地方:語意層的定義、知識庫的文件、流程 YAML 的門檻。 這反而是優點——改哪裡、誰改的、什麼時候改的,全部說得出來, 不像微調完之後沒人知道它為什麼改變了。

陷阱如果它答錯了,要怎麼修?要重新訓練嗎?
不用訓練。先分清楚是哪一種錯,四種錯改四個不同的地方。
症狀是哪一層的錯改哪裡
走錯路(問數字卻去翻文件)意圖或流程選擇流程 YAML 的關鍵字與說明
條件理解錯(期間、客戶抓錯)前處理別名表,或時間詞規則
SQL 查錯表、算錯口徑text-to-SQL 的語意層AI team 的語意層定義
口徑對但說法錯規範文件知識庫那份文件
有依據但寫得不好統整統整的規則(prompt)

能這樣分,本身就是這個架構的賣點。如果整套是一顆模型直接回答, 答錯了只能說「模型不夠好」,沒有第二句可以講。

而且每一次請求的完整經過都留著(問題、條件、SQL、撈到哪幾片、答案、引用), 所以要判斷是哪一層錯,是查得出來的,不用猜。

陷阱怎麼知道它平常有沒有在亂答?
每一次請求留一列完整紀錄,而且留的不是日誌,是整個經過。

一列裡有:問題、抽出的條件、意圖、走哪條流程、每一步耗時、 實際執行的 SQL、撈到的碎片與分數、每一片有沒有被引用、答案、引用編號、狀態。

可以直接查出來的幾種問題:

答案沒掛任何引用          → 模型在自由發揮
回了查無資料的比例        → 覆蓋率不足
某一步超過 10 秒          → 哪個服務在拖
分類方式是「規則(LLM 不可用)」 → 那段時間模型連不上
撈到卻沒被引用的比例      → 檢索品質的訊號

更進一步的用法(還沒做):拿一份情境題庫定期回放, 算 SQL 對不對、引用有沒有掛回、答案有沒有超出證據。 請求紀錄存在的主要理由就是這個,不只是除錯。

陷阱可以多少人同時用?
目前的瓶頸很明確:text-to-SQL 那側的併發上限是 2。

所以「同時問數字的人」超過兩個就會開始排隊。 AI-Brain 這側因此刻意不做任何並行呼叫——多打只會讓對方更慢。

另一個共用瓶頸是那張 GPU:text-to-SQL 產 SQL 與統整寫答案共用它。

誠實的講法:「目前是 demo 規模,沒有做過壓力測試。 瓶頸在哪我們知道(text-to-SQL 併發 2、GPU 共用),要放大是加資源的問題,不是改架構。」

要放大之前已知還要補的:請求紀錄轉送目前沒有上限保護(流量大時會往記憶體堆), 這一點程式註解自己寫著「目前靠流量低不會發生,不是設計保證」。

陷阱資料多久更新一次?是即時的嗎?
不是即時。是 SAP 匯出 CSV 灌進鏡像,而且鏡像是整批重建的。

「整批重建」的意思是:重建時會先刪掉那些鏡像表再重灌, 所以任何直接寫進鏡像表的資料,重建時會一起消失

頻率目前沒有定案,這是要跟資料那條線(Tom/Joey)確認的事。 被問到就照講「目前是匯出的快照,更新頻率還在定」,不要編一個數字。

有一件事是確定的、而且值得講:建單流水帳不受重建影響, 因為重建只刪它自己的表名。這個保證是開發方明確確認過的。

陷阱可以接我們自己的系統嗎?不是 SAP 也行嗎?
可以,而且要換的比想像中少——但要誠實講「換掉的那一塊正好是最貴的」。

不用改的:意圖、流程、調度、證據池、統整、前端、知識庫、監控。

要換的:

  • 資料來源 —— text-to-SQL 指向另一顆資料庫。
  • 語意層 —— 要重新定義那套系統的表與指標。這是最大的工項
  • 建單 —— 換一個 SAP 連線程式的實作,流程不用動。

所以答案是:「架構本身不綁 SAP,但語意層必須重做, 而那正是這類專案最花時間的地方。不要以為換個資料庫就搬得過去。」

陷阱從現在到真的能上線,要多久?
工程的部分不是瓶頸,業務定義才是。這一題要把球誠實地丟回去。

三件事分開講:

  1. 路已經通了 —— 從提問到答案、從上傳圖片到 SAP 建單,整條路都跑得起來, 而且對真機建過單。
  2. 還缺的是資料與定義 —— 語意層要把該有的表放進去、 業務口徑(達交、閒置、前十大)要有人拍板、規範文件要換成真的。
  3. 還缺的是正式化 —— 權限、保存期限、壓力測試、對話紀錄的持久化。 每一項都已經列出來了,不是還沒想到。

最該強調的那句:「沒有定義就沒有正確答案可以驗收。」 這不是工程能解決的,加人加錢都沒用。

陷阱出問題找誰?誰維護?
照分工切,而且分工的邊界就是架構的邊界。
  • 應用層(流程、意圖、調度、前端、知識庫)→ 開發方(Adam)
  • 模型端點、text-to-SQL、語意層、檢索服務 → AI team(Ian)
  • SAP 介接、鏡像資料 → Tom/Brandon
  • 業務口徑與情境定義 → 業務端,沒有人可以代打

怎麼知道是誰的問題?靠請求編號查那一輪的完整經過: 走錯流程是應用層、SQL 查錯是語意層、口徑錯是業務定義。 這套系統的稽核設計,同時也是一套除錯的分工表。

畫面手機可以用嗎?知識庫可以放多少文件?可以匯出嗎?
三個小題一起答。
  • 手機 —— 前端是響應式的,窄螢幕會自動調整(側欄收成窄軌)。沒有專門的 App。
  • 知識庫 —— 目前單檔上限 2 MB,支援 .md 與 .txt,PDF 與 Word 交給檢索服務那邊做。 現在是幾百片的規模,線性掃就夠;上千份時會換成正式的檢索服務。 目前存在記憶體,重啟會重載預設那 15 份——這是明確標示的簡化。
  • 匯出 —— 目前沒有做。表格可以排序、SQL 可以展開複製,但沒有「下載 Excel」。 這是可以加的功能,不是架構限制。

11答不出來時的安全答法

現場一定會有答不出來的。答不出來不扣分,亂答才扣分。

11-1 三種句型

情況句型為什麼有效
知道有這回事,不確定細節 「這一塊是開發方那側的實作,我知道它的做法是 ⋯⋯, 確切的參數我回去確認再回覆你。」 先證明你懂結構,再誠實承認邊界。比硬掰一個數字好太多
完全沒想過 「這個問題很好,我們還沒有評估過。 我把它記下來,跟開發方確認過再回覆。」 「還沒評估」是一個正當狀態。承認它反而顯得這個團隊分得清做過與沒做過
牽涉到別人負責的範圍 「這是 AI team/Tom 那條線的, 我可以說明它跟我們這邊的介面是什麼,細節要問他們比較準。」 不要替別人承諾。分工清楚本來就是這個架構的賣點之一

11-2 現場紅線(絕對不要講的話)

以下每一句都會在後續造成麻煩

11-3 三個可以主動拋出來的亮點

冷場或想把話題帶回強項時用
  1. 「查不到就說查不到」 —— 現場隨口問一個知識庫沒有的問題, 它會回查無資料而不是硬掰。雛形這一段是真的在算的,可以當場換題目試。
  2. 「換一張沒看過的訂單版型」 —— 三層防護:別名表、雙語標籤各試一次、 真的沒看過才問模型一題(而且模型只能選欄位、看不到值)。
  3. 「對帳守衛」 —— 十份單據實測錯四份、一份正好兩倍, 所以加了一道拿單據合計對 SAP 淨額的檢查。 主動講缺陷與對策,比宣稱沒有缺陷可信得多。

11-4 如果對方要求看更底層的東西

陷阱「可以給我看程式嗎/架構文件嗎?」
程式是開發方的 GitLab repo,我方唯讀。要看要走他們那邊。

可以當場開的:實體程式的 /internals 運作說明頁(左上標誌兩秒內點五下)。 但先讀過 §06 那張表——那一頁有五處停在舊版本, 被問到要能說明哪幾處是舊的。

建議不要主動開。它是內部技術文件,含「還沒做的」清單,對外場合通常不演。

12日本落地:裝一台機器過去

「裝在機器上讓日本人開箱即用」「要 training 多久」「要派人駐點多久」—— 這幾題文件裡沒有現成答案,但有明確的拆法。 這一節給的是誠實回答的結構已知會擋住的具體事項,不是承諾數字。

先擋住一個最常見的誤解 被問「training 要多久」時,先確認對方問的是哪一種 這兩件事的答案差很遠,答錯方向會讓後面整段對話歪掉。
陷阱裝一台機器過去,需要裝什麼?
現在是三台內網機器上的五個服務。要收進一台,GPU 是硬條件
元件現在在哪裝箱時的重點
語言模型(Qwen 27B / vLLM).31:7100 要顯卡。27B 就算量化過也吃卡,這是整台機器的成本主軸
text-to-SQL.31:6100 跟模型共用同一張卡,所以規格要一起算
資料庫(鏡像).31:5432 資料量取決於要放幾張表、多久的歷史
OCR.28:6600 另一套模型(PaddleOCR-VL),只有建單那條線需要
AI-Brain 本體+前端本機 最輕的一塊。Java 後端實測 2 秒啟動
監控(EFK)本機 docker 可選。不裝的話請求紀錄仍然會落成檔案

不需要裝的:SAP。建單是打對方既有的 SAP API,分析是查鏡像, 兩者都不需要在這台機器上裝 SAP。

陷阱「開箱即用」現在做得到嗎?
技術上接近,但有四件事現在會擋住,每一件都具體。
  1. 知識庫與對話紀錄在記憶體,重啟會清。 開機會自動重載那 15 份示範文件,所以「開箱能問」沒問題; 但客戶自己上傳的文件重開機就沒了。要落地必須先接上正式的檢索服務或改成持久化。
  2. 雛形需要公有 CDN。函式庫與字型走外網, 對方內網若擋 CDN 會開出一片空白。要交檔出去之前一定要先確認, 或把函式庫抓成本機檔。(實體程式是自己打包的,沒有這個問題。)
  3. SAP 憑證會過期。目前釘選的那張憑證有效期到 2026-11-22 (讀憑證本體確認,不是只看設定檔的註解)。
    但要講準:那是 SAP CAL 示範機的自簽憑證CN=vhcals4hci.dummy.nodomain、簽發者 cal.dummy.nodomain), 不是正式機。所以正確的說法是 「切到客戶自己的 SAP 時,憑證本來就會換掉」—— 到期日是示範環境的限制,不是產品缺陷。 真正要排進維護計畫的是「換憑證這件事有沒有人負責、怎麼換」。
  4. 沒有權限控管。三層都沒有(見 §06)。 自己人 demo 可以,交給客戶天天用之前必須先做。
陷阱日文能用嗎?要做什麼才真的能用?
介面與回答語言已經做好了;真正的工不在翻譯,在資料那一半

已經完成的

  • 介面三語(中/英/日),回答語言跟問句走不跟介面
  • 語言判斷不用模型:有假名→日文;有漢字→看介面;只剩拉丁字母→英文。
  • 日文問句會先翻成中文再走流程,所以中間所有規則一行都不用改
  • 進度文字、固定文案、統整的語言都會跟著換。

還沒完成、而且是真正的工

要做什麼為什麼非做不可誰做
語意層重做 指標定義、欄位中文名、同義詞現在都是照台灣這套資料做的。 換成日本客戶的資料就要重來。這是整個專案最大的人工工項 AI team + 對方的業務
知識庫換成日文文件 設計原則是「資料語言 ≠ 對話語言」,文件本身不翻譯。 所以日本客戶要用,知識庫裡就得是他們自己的日文規範 對方提供
別名表換掉 客戶與商品的俗名對代號,現在是中文的 對方提供主檔
業務口徑拍板 「達交」「前十大」「閒置」在他們公司怎麼算。 沒有定義就沒有正確答案可以驗收 對方的業務,不能代打
雛形腳本三語化 介面切得動,但回答內容還是中文。 日文問句目前會落到檢索、演不出完整那題 我方,10-15 之前

一句話版本:「翻譯不是問題,定義才是。介面與回答的語言已經做好了, 真正要花時間的是把他們的資料與口徑放進語意層——而那件事需要他們的人一起做。」

陷阱要 training 多久?要派人駐點多久?
這是商務與人力的決定,不要在現場給數字。但可以講清楚「什麼決定了它」。

建議的答法

「使用者端幾乎不需要訓練——操作就是一個聊天框。要教的是它答得出什麼、答不出什麼, 那大概是一場說明會的量。

真正需要時間的不是訓練,是把他們的資料與業務口徑放進語意層, 而那件事必須跟他們的業務一起做,不是我們單方面能完成的。 所以駐點多久,取決於他們能投入多少人、多快能拍板定義——這個我們要先一起盤過才估得準。

為什麼不要給數字:這件事的工期不由我方單方面決定。 現場給一個數字,之後對方投入不如預期,超期會被算在我們頭上。

如果一定要給個量級,可以拆成三段講,讓對方自己感覺得到比例:

  • 裝機與跑通 —— 最短的一段。路已經通了,對真機建過單。
  • 語意層與知識庫 —— 最長的一段,而且跟對方投入成正比
  • 正式化(權限、保存期限、壓力測試、持久化)—— 已經列得出清單,不是未知數。

把第二段點名成瓶頸,而且說明它為什麼是雙方共同的工, 比給一個會被拿來對帳的數字安全得多——而且這是真話

陷阱裝過去之後誰維護?連不到我們怎麼辦?
先講已經在系統裡的東西,再講還沒決定的。

已經有的:每一次請求留一列完整紀錄(問題、條件、SQL、撈到什麼、答案、引用、耗時、狀態), 而且畫面上有可複製的請求編號。對方回報問題時只要給那串編號,就查得到那一次的完整經過—— 這是遠端支援最實際的基礎。

還沒決定的(不要自己承諾):

  • 紀錄要不要回傳、回傳到哪(目前含問題與答案的業務內容,要送出內網之前有兩個開關要先關掉)
  • 保存期限與存取權限
  • 更新機制:模型、語意層、知識庫各自怎麼更新
  • SAP 憑證到期(2026-11-22)的更換流程

這幾條列出來本身就是答案的一部分——「知道要做但還沒決定」跟「沒想到」是兩件事, 現場講得出清單,對方就知道是前者。