AI 智慧報告系統 — 完整 Spec

2026-05-18 · 老闆原話「資料整理層 → AI 回覆整理層 → UI 動態渲染」三層架構 + 冷啟動 + 信任分數 + 像 NotebookLM 一樣動態 widget

先看這裡 — TL;DR

核心原則(老闆原話拆解):
  1. AI 不直接碰資料庫:中間夾「Data Mart Tools」層,AI 只能呼叫白名單 tool function,有 schema validation。
  2. AI 不亂畫 UI:AI 回的不是 HTML,是 Report Manifest JSON(指定挑哪些預製 Widget + 餵什麼資料)。Widget 是 ChefsMate 自製、固定設計、商業報告界慣例的元件庫。
  3. 冷啟動有 fallback:0 天 → industry default,1 個月 → SMA-7 baseline,3 個月 → Ridge regression,1 年 → YoY 對比。每階段對應信任分 tier。
  4. 老闆有切換權:同一問題(來客量分析)可選「綜合 / 天氣 / 節假日」維度,Widget 內建多個 view variant。
  5. NotebookLM 啟發:每個 Widget 有「資料來源 panel」可展開,讓老闆看到「這個洞察根據哪些資料」(信任建立)。
已有可重用的好基礎(2 個):
  1. supabase/functions/report-analytics/index.ts 已實作 7 個演算法(SMA-7 / Shewhart 2σ / EWMA / BOM / Pearson / Ridge),直接當 Layer 1 backbone。
  2. 預算建議 RPC 已有 high/medium/low confidence + INDUSTRY_DEFAULTS fallback,冷啟動 pattern 早就跑通,直接 generalize。
目錄
  1. 完整四層架構
  2. Layer 1 — Data Mart Tools(AI 不直接碰 DB)
  3. Layer 2 — AI Query Orchestrator(意圖分類 + 工具選擇 + 冷啟動 fallback)
  4. Layer 3 — Report Manifest 規格(AI 回的不是 HTML)
  5. Layer 4 — Widget Library(商業報告界元件庫)
  6. 信任分數系統
  7. 冷啟動策略(4 階段)
  8. 完整範例 — 老闆問「明天天氣會不會影響訂位」
  9. Roadmap + Phase 切割
  10. 給老闆的問題

完整四層架構

┌─────────────────────────────────────────────────────────────────┐
│  Layer 4 — UI (Widget Renderer)                                  │
│   - 對話介面 + 預設問題 chip + 動態 widget canvas                │
│   - 每個 widget 來自固定 library,不讓 AI 自由畫                  │
│   - NotebookLM-style「資料來源 panel」可展開                     │
└──────────────────────▲──────────────────────────────────────────┘
                       │ Report Manifest (JSON)
┌──────────────────────┴──────────────────────────────────────────┐
│  Layer 3 — Manifest Generator (AI agent)                         │
│   - Claude / OpenAI 收老闆問題 → 寫 Report Manifest              │
│   - 規範化 schema 約束 LLM 只能輸出合法 Widget IDs               │
│   - 包含 trust_score / data_sources / explanations               │
└──────────────────────▲──────────────────────────────────────────┘
                       │ Tool calls (whitelist functions)
┌──────────────────────┴──────────────────────────────────────────┐
│  Layer 2 — AI Query Orchestrator                                 │
│   - Intent classification(revenue/forecast/comparison/...)      │
│   - Tool selection + parameter validation                        │
│   - Cold start fallback(no data → industry defaults)            │
│   - Trust score 計算(data_volume × algorithm_grade)             │
└──────────────────────▲──────────────────────────────────────────┘
                       │ Named tool functions (schema enforced)
┌──────────────────────┴──────────────────────────────────────────┐
│  Layer 1 — Data Mart Tools(AI 不直接 SQL)                      │
│   - 既有 report-analytics 7 演算法 wrap 成 tool function         │
│   - 新加:weather、holiday、年同期對比、客人 segment、菜單熱賣  │
│   - Materialized views for hot questions                          │
│   - 每個 tool 有明確 input/output schema,RLS 嚴格 gate           │
└──────────────────────▲──────────────────────────────────────────┘
                       │ SQL / RPC
                  ┌────┴─────┐
                  │ Supabase │
                  └──────────┘

Layer 1 — Data Mart Tools(AI 不直接碰 DB)

原則: AI 永遠不能下 raw SQL。所有資料 access 走「白名單 named tool function」,每個 tool 有明確 input schema + output schema。違反 schema = orchestrator 直接拒絕。

Tool Categories(初版規劃)

類別Tool name已有 / 新加Output schema
營收 / 成本 get_revenue_summary(period, granularity) 新 wrap report-analytics 總營收 / 客單價 / 來客數 / 折扣率
get_cost_breakdown(period) 既有 compute_cost_rate_chart 食材% / 人事% / 營運% / 利潤%
get_revenue_per_guest_trend(days=30) 既有 SMA-7 + percentile 客單價時序 + 百分位帶
get_profit_comparison(period_a, period_b) 既有 EWMA 兩期利潤對比 + 變化率
來客 / 訂位 get_guest_volume(period, dimensions[]) 既有 + 擴充 dimensions 來客數 + 熱力圖 + 維度切片
get_guest_forecast(date_range) 既有 Ridge regression 預測值 + 信賴區間
get_no_show_rate(period) 新(從 reservation_status_history 算) No-show % + 取消 %
get_customer_segments() 既有 Pearson 分群統計
外部因子 get_weather_forecast(restaurant_id, date_range) (對接 CWA 中央氣象局) 溫度 / 雨機率 / 天氣分類
get_holiday_calendar(date_range) (對接政府開放資料) 國定假日 / 連假 / 節氣
get_local_events(restaurant_geocode, date_range) (Phase 2,可接 Google Events API) 附近活動 / 演唱會 / 展覽
關聯分析 compute_correlation(metric, factor[]) 既有 Pearson 擴充 相關係數 + p-value
compare_period(metric, period_a, period_b) 新(YoY / WoW / DoD 通用) 同期對比表
find_outliers(metric, period) 既有 Shewhart 2σ wrap 異常點清單 + 原因 hint
菜單 / 庫存 get_top_selling_items(period, top_n) 熱賣品 ranking + 毛利率
get_dead_inventory(period_days) 新(滯銷品) 低銷量品 + 庫存成本

Tool function 規範(範例)

// tools/get_revenue_summary.ts
export const TOOL_SPEC = {
  name: 'get_revenue_summary',
  description: '取得指定期間總營收 / 客單價 / 來客數',
  parameters: {
    period: { type: 'string', enum: ['today', 'yesterday', 'this_week',
      'last_week', 'this_month', 'last_month', 'custom'] },
    custom_start: { type: 'string', format: 'date', required: false },
    custom_end:   { type: 'string', format: 'date', required: false },
    granularity:  { type: 'string', enum: ['day', 'week', 'month'] },
  },
  output: {
    type: 'object',
    properties: {
      total_revenue:    { type: 'number' },
      guest_count:      { type: 'number' },
      avg_per_guest:    { type: 'number' },
      discount_rate:    { type: 'number' },
      data_points:      { type: 'integer', description: '實際有資料的天數' },
      data_completeness:{ type: 'number',  description: '0-1,期間內有資料天數比' },
    },
  },
}

export async function execute(params, ctx) {
  // 1. 驗證 restaurant_id 屬於 ctx.user
  // 2. 從 materialized view 撈
  // 3. 回 schema-compliant object
}
為什麼這層重要:AI 拿到的不是 raw row,是「已 normalize + 已聚合 + 已附 metadata(data_points / completeness)」的乾淨物件。後續 Layer 2 用這個 metadata 算信任分。AI 也不可能 SQL injection。

Layer 2 — AI Query Orchestrator

意圖分類(Intent Classification)

老闆問題進來,先 LLM 做 lightweight 分類(便宜模型,例 Haiku):

Intent觸發詞例對應 tool combo
revenue_lookup今天 / 上週 / 這月 營業額get_revenue_summary
forecast明天 / 下週 / 預測 / 大概多少人get_guest_forecast + get_weather_forecast
compare_period跟去年 / 跟上週比 / 同期compare_period
impact_analysis天氣影響 / 假日 / 雨天 / 影響compute_correlation + get_weather_forecast / get_holiday_calendar
top_items賣得最好 / 熱賣 / 滯銷get_top_selling_items / get_dead_inventory
cost_analysis成本 / 食材% / 利潤get_cost_breakdown
customer_insight客人是誰 / 回流 / 客群get_customer_segments
operations取消率 / no-show / 預訂get_no_show_rate
casual閒聊 / 不在領域內不呼叫 tool,直接 LLM 回答 + 標「未從資料生成」

Tool 選擇 + 參數推導

分類完後,Claude(較強模型)做 multi-tool call:

1老闆問「明天天氣會不會影響訂位」
2Intent = impact_analysis,factor=weather
3Tool plan:
  • get_weather_forecast(date=明天)
  • get_guest_volume(period=過去90天, dimensions=[weather_class])
  • compute_correlation(metric=guest_count, factor=weather)
  • get_guest_forecast(date=明天)
4Orchestrator 並行 call 4 個 tools(parallel,Promise.all)
5結果彙整 → 寫 Report Manifest(下一層)

冷啟動 fallback 規則

Tool 回 data_completenessOrchestrator 行為Manifest 上 widget 顯示
≥ 0.7用真實資料正常 chart + 信任度 高
0.3 - 0.7混合真實 + industry defaultchart + 信任度 中 + 提示「N 天歷史,參考用」
< 0.3純 industry defaultchart + 信任度 低 + 紅字「資料不足,僅為餐飲業平均」
= 0(完全無資料)不畫圖,直接顯示「累積 X 天後可看到結果」EmptyState widget + 預期可解鎖日期

Layer 3 — Report Manifest 規格

關鍵:AI 回的不是 HTML,不是自由 markdown。是嚴格 JSON schema 的 Manifest,UI 才有辦法限制 AI 不亂畫。

Manifest 結構

{
  "version": "1.0",
  "question": "明天天氣會不會影響訂位?",
  "intent": "impact_analysis",
  "trust": {
    "tier": "silver",      // bronze / silver / gold
    "score": 72,           // 0-100
    "reason": "過去 90 天歷史 (data_completeness=0.95) + Pearson r=0.61"
  },
  "summary_md": "**明天降雨機率 70%,根據過去 3 個月資料,雨天訂位平均減少 23%。** 建議:備料量可以調降 10-15%,排班可以少 1 個外場。",
  "sources": [
    { "tool": "get_weather_forecast",  "params": {"date": "2026-05-19"} },
    { "tool": "compute_correlation",   "params": {"metric": "guest_count", "factor": "weather"} },
    { "tool": "get_guest_volume",      "params": {"period": "90d", "dimensions": ["weather_class"]} }
  ],
  "widgets": [
    {
      "id": "w1",
      "type": "KPICard",
      "props": {
        "title": "明天預測來客數",
        "value": "32-38 人",
        "delta": "-25%",
        "delta_label": "vs 一般週六",
        "trust_badge": "silver"
      }
    },
    {
      "id": "w2",
      "type": "InsightCallout",
      "props": {
        "icon": "weather-rain",
        "title": "預估影響",
        "body_md": "降雨機率 70% + 過去雨天平均訂位下降 23%(p<0.01,顯著)。",
        "actions": [
          { "label": "看歷史雨天紀錄", "open_source": "w4" }
        ]
      }
    },
    {
      "id": "w3",
      "type": "BarComparison",
      "props": {
        "title": "雨天 vs 晴天 訂位數對比",
        "series": [
          { "name": "晴天平均", "value": 42 },
          { "name": "雨天平均", "value": 32 }
        ],
        "footnote": "資料區間:2026-02-18 ~ 2026-05-18 (90 天)"
      }
    },
    {
      "id": "w4",
      "type": "DataTableWithFootnote",
      "collapsed": true,        // 預設摺疊,點開才展開
      "props": {
        "headers": ["日期", "天氣", "訂位數", "實到"],
        "rows": [/* ... */],
        "footnote": "來源:reservations + 中央氣象局 CWA API"
      }
    }
  ],
  "dimension_selectors": [        // 老闆可切換 UI 的維度
    {
      "id": "weather-dim",
      "label": "影響因子",
      "options": [
        { "value": "weather",  "label": "天氣",     "active": true },
        { "value": "holiday",  "label": "節假日" },
        { "value": "weekday",  "label": "星期幾" },
        { "value": "combined", "label": "綜合分析" }
      ]
    }
  ],
  "followup_prompts": [
    "那如果是連假?",
    "去年同期(5/19)賣多少?",
    "雨天最賣的菜是?"
  ]
}
嚴格 schema validation:Manifest 從 LLM 出來後,先過 JSON Schema 驗證。任何不認識的 widget type / 不合法 prop 一律 reject,要求 LLM 重新生成。這樣 UI 永遠只渲染白名單 widget,AI 沒辦法注入任意 HTML / JS。

Layer 4 — Widget Library(商業報告界元件庫)

原則:參考麥肯錫 / BCG / 一般 BI tool(Looker, Mode, Metabase)常用的報告元件,自製 ChefsMate Stitch 風格版。AI 只能挑這些,不能自繪。

初版 Widget 清單(12 個)

KPICard
大數字 + 對比 delta + trust badge。用於 headline 指標(今日營收 / 預測來客)
LineChart
時序曲線 + 可選信賴區間帶。用於趨勢(營收 30 天 / 預測)
BarComparison
兩段時間並排柱狀對比。用於 YoY / WoW / 群組對比
HeatmapDayHour
7×24 熱力圖。用於來客分布、忙碌時段
HeatmapMonth
月曆熱力圖。用於月內密度
WaterfallChart
瀑布圖。用於成本拆解(營收 → 食材 → 人事 → 利潤)
ParetoChart
80/20 分析。用於熱賣品 / 滯銷品
CorrelationScatter
兩變數散布圖 + 趨勢線 + r/p。用於相關分析
InsightCallout
AI 文字洞察區塊 + icon + actions。用於「key takeaway」
DataTableWithFootnote
資料表 + footnote(出處 / 注解)。預設可摺疊。用於 raw data drilldown
DimensionSelector
切維度的 chip group。老闆切之後重打 API 拿新 Manifest
EmptyState
「需累積 X 天資料」的 cold start placeholder + 預期解鎖日期

每個 widget 的通用 props

Prop說明
trust_badgebronze / silver / gold,右上角顯示
source_ref對應 Manifest.sources index — 點 icon 展開 source panel(NotebookLM 風)
collapsed預設摺疊?常用於 DataTable raw 資料
annotationAI 加的小說明(底部 caption)

NotebookLM-style source panel

畫面下方拉開的 panel:

w2 InsightCallout 的資料來源:

  • get_weather_forecast → 中央氣象局 CWA API(2026-05-19 預報)
  • compute_correlation → reservations 表(90 天) × weather 表(90 天),Pearson r = 0.61, p = 0.003
  • get_guest_volume → reservations 表(2026-02-18 ~ 2026-05-18)

信任分數系統

計算公式:

trust_score =
    data_volume_score    × 0.50     # 你有多少歷史資料?
  + algorithm_grade      × 0.30     # 用什麼演算法計算?
  + statistical_quality  × 0.20     # p-value / R² / 異常率

data_volume_score

歷史資料天數分數tier
0 天0
1-7 天25bronze
8-30 天50bronze/silver
31-90 天75silver
91-365 天90silver/gold
365+ 天100gold(可做 YoY)

algorithm_grade

演算法分數說明
純 industry default0沒有 personalize
簡單平均 / 中位數30baseline
SMA-7(7 日移動平均)60有 smoothing
Shewhart 2σ / EWMA75有統計檢驗
Ridge regression / Bayesian90學習模型
外接 LLM 解釋(non-numerical)50解釋性高但無 ground truth

tier 對應

tier分數區間視覺老闆看到的暗示
gold85+金色徽章「這個你可以放心參考做決策」
silver60-84銀色徽章「方向對,細節可能 ±15%」
bronze30-59銅色徽章「參考用,資料還在累積」
< 30「資料不足」灰標不顯示數字,改顯示「再 N 天可看到結果」
跟既有 confidence 系統的整合: 現有 report-analytics RPC 已回 high/medium/low,直接 map:high=gold, medium=silver, low=bronze。smart-seating 用 0.3-1.0 numeric 也直接 ×100 映射。不重複造輪。

冷啟動策略(4 階段)

階段歷史能回答什麼不能回答什麼UI 預設
Day 0(註冊當天) 「餐飲業平均食材成本約 30-35%,你的目標應該設多少?」
純 industry default + LLM 知識
YoY / 趨勢 / 預測 歡迎卡 + 「累積 7 天可看到第一份報告」countdown
Week 1-4(1 個月內) 7-30 天 當期營收統計 / 熱賣前 5 / 簡單平均對比 顯著性檢驗 / 預測模型(資料太少) bronze 標籤普遍 + 提示「資料累積中」
Month 2-3 30-90 天 SMA-7 趨勢 / EWMA 平滑 / 簡單 Pearson 相關 YoY 對比 / 罕見事件預測 silver 大宗 + 部分 gold(營收統計類)
3 個月+ 90 天以上 Ridge regression 預測 / 顯著性檢驗 / 細分群分析 (到 365 天前)YoY 對比 主要 gold + 少量 silver
1 年+ 365 天以上 YoY / 節氣循環 / 多年趨勢 全 gold

Cold start 技巧

  1. Industry defaults JSON:把餐飲業常見 KPI(食材 30%、人事 25%、利潤 10%、客單 NT$280)寫成可 hot-update 的 config(老闆可改)。
  2. Seed 老闆設定:onboarding 問「你的店是什麼類型?(輕食 / 中餐 / 異國 / 居酒屋)」,根據類型套不同 default。
  3. 邊用邊累積:每張單 / 每次關帳都餵進 Data Mart materialized view,信任分隨時間自動升級。
  4. 透明告知:每個冷啟動的洞察都明標「行業基準 / 你的歷史」,不藏。

完整範例 — 老闆問「明天天氣會不會影響訂位」

End-to-end flow(7 步)

1UI:老闆在戰情室問答 input 打「明天會下雨嗎,訂位會影響嗎?」→ 送 POST /api/smart-report/ask
2Orchestrator:Intent classifier(Claude Haiku)分類 = impact_analysis(factor=weather)
3Tool planning:Claude Sonnet 寫 plan,呼叫 4 個 tools:get_weather_forecast / get_guest_volume / compute_correlation / get_guest_forecast
4Tools 並行執行(Layer 1):
  • get_weather_forecast(date=tomorrow) → CWA API → {temp: 24, rain_prob: 70%, class: "rain"}
  • get_guest_volume(period=90d, dim=[weather_class]) → reservations × weather join → {sunny_avg: 42, rainy_avg: 32}
  • compute_correlation(guest_count, weather) → {r: -0.61, p: 0.003, n: 90}
  • get_guest_forecast(date=tomorrow) → Ridge → {predicted: 35, lower: 32, upper: 38}
5Trust score 計算:data_volume=75(90 天) × 0.5 + algorithm=90(Ridge) × 0.3 + p_value=95(0.003) × 0.2 = 72 = silver
6Manifest generation:Claude Sonnet 用 tools 結果 + trust score 寫 Manifest JSON(4 widgets:KPICard / InsightCallout / BarComparison / DataTableWithFootnote)
7UI render:Manifest 過 JSON Schema validate → 渲染 4 個 widget,老闆看到結果 + 可切「天氣/節假日/星期幾」維度

老闆看到的畫面(概念)

━━━ 戰情室 / 智慧報告 ━━━

明天會下雨嗎,訂位會影響嗎?

明天預測來客數 silver
32-38 人
↓ 比一般週六少 25%
📊 預估影響
明天降雨機率 70%,過去 90 天雨天平均訂位減少 23%(p<0.01)。建議備料量降 10-15%、外場可少 1 人。 查看資料來源 →
雨天 vs 晴天 對比
[BarComparison: 晴天 42 人 / 雨天 32 人]
切換維度:天氣 節假日 星期幾 綜合

想再問:那如果是連假? / 去年同期賣多少? / 雨天最賣的菜是?

Roadmap + Phase 切割

Phase範圍預估時程產出
Phase 0(基礎)
1-2 週
把現有 report-analytics 7 個演算法 wrap 成 tool function 規格,定義 input/output schema。建立 Data Mart materialized views。 1-2 週 Tool registry + schema validator
Phase 1(MVP)
2-3 週
5 個 widget(KPICard / LineChart / BarComparison / InsightCallout / EmptyState)+ Orchestrator + 接 Claude API + 信任分數 + 5 個 intent(revenue / forecast / compare / impact / casual) 2-3 週 能問 5 類問題,動態 render 5 種 widget
Phase 2(擴充)
2 週
剩下 7 個 widget + 接 CWA 天氣 + 政府假日 API + dimension selector 切換 2 週 外部因子完整接
Phase 3(NotebookLM-style)
1-2 週
每個 widget 加 source panel / 老闆可 pin 報告 / 可分享 link / followup_prompts chip 1-2 週 互動性接近 NotebookLM
Phase 4(進階)
後續
多店比較 / 集團報告 / Audio overview(TTS)/ 自動生成 weekly digest email 後續

關鍵風險 + 緩解

風險緩解
LLM 成本失控Intent classifier 用便宜 Haiku;只有 manifest 生成用 Sonnet;cache 同問題 24h
LLM 幻覺(編造數字)Manifest 內的數字必須引用 Layer 1 tool result,prompt 嚴格約束「不可自己算 / 不可猜測」;Schema validator 拒絕沒有 source 的 widget
冷啟動資料不足 → 老闆覺得沒用明顯標 tier;industry default 也是有用洞察;onboarding 問店類預載對應 default
老闆問題分類錯Intent classifier 不確定時走「general」走 LLM 自由回答 + 標「無法用資料生成」
UI 元件不夠用 → AI 想自繪Widget library 漸進擴充;不夠用先用 InsightCallout 文字 + 圖片連結 fallback,絕不放 raw HTML

給老闆的問題(等老闆 confirm 才開工 Phase 0)

  1. LLM 用哪家?
    • Claude(Anthropic)— tool-use 最強,文字解釋自然,費用中等
    • OpenAI GPT-4o-mini + GPT-4o
    • Google Gemini
    • 建議:Claude Haiku(分類)+ Sonnet(manifest 生成),理由是已有 token、Tool use schema 最穩
  2. 戰情室擺哪?
    • POS 既有戰情室 tab(Phase 4 已有 ReportAPIClient,容易擴)
    • 客人端 web 老闆專屬頁面(更新即時但要重做 auth)
    • 建議:POS 戰情室 tab
  3. 第一波支持哪 5 類問題?(MVP 範圍)
    • 建議:revenue_lookup / forecast / compare_period / impact_analysis / top_items
    • 另一選項:top_items 換 customer_insight
  4. 冷啟動 industry default 來源:
    • 我手寫一份(基於餐飲業常識,可後續優化)
    • 找台灣餐飲協會 / 經濟部公開資料(較費時)
    • 建議:手寫 v1,後續更新
  5. 「老闆切換維度」UX:
    • 切換 chip → 同畫面重打 API 拿新 Manifest(精準但慢)
    • 切換 chip → 客戶端 instant filter(快但 widget 要 pre-compute 所有維度)
    • 建議:預設 reply 多帶 1-2 個常見維度,切換瞬間切;冷門維度才打 API
  6. NotebookLM 啟發要做多深?
    • 淺:每個 widget 有 source panel 可展開
    • 中:加 pin、分享、followup chip(完整 Phase 3)
    • 深:Audio overview(Phase 4 後續)
    • 建議:Phase 3 做到中,深的看後續
ChefsMate Spec · 2026-05-18 · 老闆「智慧報告系統」完整 spec · 等老闆 confirm 後開 Phase 0