Files
ewoooc/docs/phase1_db_design_20260503.md
OoO 4648673423 db(p1): ai_calls/mcp_calls/budgets schema + bge-m3 signature
migrations 024/025/026 — 統一 LLM 遙測 + 預算告警 + RAG 一致性護欄
- 024: ai_calls 表 + 5 索引 + 6 CHECK constraint(H1/H2/M3/L3)
- 025: mcp_calls + ai_call_budgets + 10 種子預算(含 ollama_secondary)
- 026: ai_insights.embedding_signature + pgcrypto + CONCURRENTLY index

A11 critic 三輪審查記錄完整保留:
- Phase 1 schema review: 2 BLOCKER + 4 HIGH + 6 MEDIUM 全處理
- Phase 1 final sign-off: 0 BLOCKER + 2 HIGH + 4 MEDIUM
- Phase 6 ADR review: 5 BLOCKER + 6 HIGH 全修

Operation Ollama-First v5.0 / Phase 0+1+6 護欄

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 23:04:42 +08:00

14 KiB
Raw Blame History

Phase 1 DB Design — Operation Ollama-First v5.0

日期2026-05-03 作者A3 db-expert 產出3 個 migration024/025/026+ 設計理由 + 效能評估 依據docs/phase0_audit_report_20260503.md 34 個 LLM 呼叫點 / 11.8% 覆蓋率 狀態SQL 檔已產出於 migrations/未自動 apply,待統帥 review 後手動執行


TL;DR

交付物 路徑 影響
ai_calls 統一 LLM 遙測表 migrations/024_create_ai_calls_table.sql 接 30 個未覆蓋呼叫點
mcp_calls MCP 遙測表 migrations/025_create_mcp_calls_and_budgets.sql Phase 10 預備
ai_call_budgets 預算閾值 同上(含 5 筆種子) Phase 9 預算告警
ai_insights.embedding_signature migrations/026_add_embedding_signature.sql BGE-M3 一致性護欄

結論Schema 設計已完備,無 schema 衝突。A4 接 logger 工作可立即啟動,唯一前置條件是統帥手動 apply 這 3 個 migration。


Section 1 — Schema 設計理由

1.1 ai_calls 欄位選擇邏輯

欄位 為何必要 為何這個型別
id BIGSERIAL 90 天 ~6.5M,年累積會超 INT4 21 億的 3% — 提早用 BIGSERIAL 避免將來改型別 與 mcp_calls 一致
called_at TIMESTAMPTZ 報表查詢核心欄位 用 TIMESTAMPTZ不是 TIMESTAMP因為 momo 三主機跨時區GCP UTC / 188 Asia/Taipei
caller VARCHAR(64) 必白名單管控;新增需 ADR 64 足夠(最長 code_review_elephant 20 字)
provider VARCHAR(32) A1 audit 列舉的 7 種主機標籤 32 足夠
model VARCHAR(128) NIM 模型名可達 50+(如 nvidia/llama-3.3-nemotron-super-49b-v1.5 128 留 buffer
input_tokens / output_tokens Token 日報核心NOT NULL DEFAULT 0 確保 SUM() 不爆 INT 足夠(單次最大 200K一年累積一個 caller 也只到 ~10BINT4 上限 21 億夠)
duration_ms INT 監控 LLM 慢查;可為 NULLAiderHeal 走 SSH 拿不到精確值) INT
status ok/fallback/error/timeout/cache_only — 串接 fallback 鏈關鍵 VARCHAR(16)
fallback_to 「主路徑失敗,下游 caller」串接邏輯下游本身另寫一筆 VARCHAR(64) 同 caller
cost_usd NUMERIC(10,6) Phase 9 預算用6 位小數可記到 $0.000001OpenRouter 細粒計費需要) NUMERIC 不用 FLOAT避免累計誤差
cache_hit BOOLEAN Anthropic prompt cache / Gemini cache成本降 90%)必追蹤 預設 FALSE
rag_hit BOOLEAN Phase 11 RAG 攔截率核心 KPI 預設 FALSE
request_id VARCHAR(64) Code Review 三鏈、Q&A fallback 三層必須 trace 同一邏輯請求 UUID4 takes 36, 加 prefix 也夠
error TEXT 錯誤原文,可長 TEXT
meta JSONB prompt_hash, temperature, top_p, fingerprint, embedding_signature 等彈性擴展 JSONB非 JSON支援索引

1.2 索引設計理由5 個)

Idx Cols 用途 partial?
idx_ai_calls_called_at (called_at DESC) 全表時間切片,日報週報必用
idx_ai_calls_caller_called_at (caller, called_at DESC) TOP caller / 單 caller 趨勢
idx_ai_calls_provider_called_at (provider, called_at DESC) by provider 統計 / 預算追蹤
idx_ai_calls_request_id (request_id) trace 單一 request 全鏈 WHERE request_id IS NOT NULL
idx_ai_calls_status_called_at (status, called_at DESC) 異常監控 WHERE status <> 'ok'90%+ 是 okpartial 大幅縮體)

未建立的索引

  • meta JSONB 的 GIN index — V1 不建。GIN 寫入放大 ~3-5x且尚未確定查詢 patternPhase 5 報表穩定後再評估。
  • model 單欄索引 — 報表需求都會帶 called_at已含 idx_ai_calls_called_at再加 (model, called_at) 在 V1 邊際效益低。

1.3 是否 partition by called_at — 決策:V1 不分區

評估面 數字 結論
月寫入量 50 ins/min × 60 × 24 × 30 ≈ 2.16M 中等
90 天保留量 ~6.5M PostgreSQL 14 單表健康範圍
索引大小估算5 個) ~800MB 在 momo-db 容器資源內
Partition 維護成本 須 cron 自動 CREATE 下月 partition + DROP 過期 +1 維護負擔

決策V1 不分區,但留好觸發升級條件:

  • 觸發升級門檻:月寫入超 5M、單表超 30M、或日報查詢 latency p95 > 500ms
  • 升級路徑DECLARATIVE PARTITIONING by RANGE(called_at) monthly配合 pg_partman

1.4 保留策略 — 90 天 hot dataDELETE 不 archive

選項 優劣 結論
直接 DELETE 簡單free space 由 autovacuum 回收 採用
移到 ai_calls_archive 表 多一份儲存,需另寫查詢
匯出 JSON 到 S3/GCS 完整保留,可重建 Phase 5 後若有合規需求再加

理由ai_calls 是遙測30 天前的單筆價值低trend 已在週報/月報沉澱到 ai_insights。 清理任務scheduler 每日 03:00

DELETE FROM ai_calls WHERE called_at < NOW() - INTERVAL '90 days';

配合 idx_ai_calls_called_at DESC 倒序掃描DELETE 範圍小(每日 ~72k不會 lock。


Section 2 — 是否與既有 schema 衝突

2.1 與 ai_generation_history4 處 ai_routes.py

  • 用途不同ai_generation_history 是 產品功能側is_favorite / is_used / created_by 都是業務欄位)
  • ai_calls 是 基礎設施側遙測
  • 共存策略A4 接 logger 時ai_routes.py 那 4 處 同時雙寫 兩張表(既有 history 不破壞ai_calls 是 superset

2.2 與 ai_usage_trackingdatabase/ai_models.py L72

  • ai_usage_tracking 已存在但完全沒被 30 個呼叫點接入A1 audit 已驗證)
  • 設計欄位service_type / request_type / user_id與 v5.0 戰役所需caller / provider / fallback_to / request_id不符
  • 建議A4 logger 統一寫 ai_callsai_usage_tracking 凍結(不寫入但不刪表,避免 model import 鏈斷裂);待 Phase 5 報表驗證 ai_calls 完整後Phase 12 再 deprecate

2.3 與 ai_insights.embedding_signature

  • 既有 ai_insights 表沒有 embedding_signature 欄位(已驗證 database/ai_models.py:111-151
  • 新增為 NULLmetadata-only ALTER TABLE不鎖表PostgreSQL 11+ 安全)
  • 無衝突

Section 3 — 三個查詢效能預估

模擬負載90 天滿載 ~6.5M 筆,索引 warm。

查詢 1過去 24h 某 caller 的 token 累計 + 成本Telegram 日報)

SELECT
    caller,
    SUM(input_tokens + output_tokens) AS total_tokens,
    SUM(cost_usd)                     AS total_cost,
    COUNT(*)                          AS call_count,
    AVG(duration_ms)                  AS avg_latency
FROM ai_calls
WHERE called_at >= NOW() - INTERVAL '24 hours'
  AND caller = 'openclaw_daily'
GROUP BY caller;

預期執行計畫

Aggregate
  └─ Index Scan using idx_ai_calls_caller_called_at on ai_calls
       Index Cond: (caller = 'openclaw_daily' AND called_at >= ...)

預期 latency< 5ms單 caller 24h ~144 筆,索引完全命中) 鎖風險:無,純 SELECT。 OLTP 衝擊:無。

查詢 2過去 7 天 by provider 統計(週報)

SELECT
    provider,
    COUNT(*)                          AS call_count,
    SUM(input_tokens + output_tokens) AS total_tokens,
    SUM(cost_usd)                     AS total_cost,
    SUM(CASE WHEN status='error'    THEN 1 ELSE 0 END) AS error_cnt,
    SUM(CASE WHEN status='fallback' THEN 1 ELSE 0 END) AS fallback_cnt,
    SUM(CASE WHEN cache_hit         THEN 1 ELSE 0 END) AS cache_hits
FROM ai_calls
WHERE called_at >= NOW() - INTERVAL '7 days'
GROUP BY provider
ORDER BY total_cost DESC;

預期執行計畫

Sort
  └─ HashAggregate
       └─ Index Scan using idx_ai_calls_provider_called_at on ai_calls
            Index Cond: (called_at >= ...)

預期 latency~50-150ms7 天 ~500k 筆6 個 provider HashAggregate 鎖風險:無。 優化建議:若 latency 退化到 > 200ms可加 covering index (provider, called_at, input_tokens, output_tokens, cost_usd) — V1 先不做。

查詢 3TOP 10 caller by token日報 Section 3

SELECT
    caller,
    SUM(input_tokens + output_tokens) AS total_tokens,
    SUM(cost_usd)                     AS total_cost
FROM ai_calls
WHERE called_at >= NOW() - INTERVAL '24 hours'
GROUP BY caller
ORDER BY total_tokens DESC
LIMIT 10;

預期執行計畫

Limit
  └─ Sort  (top-N)
       └─ HashAggregate
            └─ Index Scan using idx_ai_calls_called_at on ai_calls
                 Index Cond: (called_at >= ...)

預期 latency~30-80ms24h ~72k 筆35 個 caller 鎖風險:無。

查詢效能總表

查詢 預期 latency 主要索引 改善空間
Q1 caller 24h < 5ms idx_ai_calls_caller_called_at 已最佳
Q2 provider 7d 50-150ms idx_ai_calls_provider_called_at 可加 covering index
Q3 TOP-10 caller 24h 30-80ms idx_ai_calls_called_at OK

Section 4 — 寫入吞吐評估

4.1 尖峰負載

  • 峰值50 inserts/min ≈ 0.83 ins/sec
  • 單筆 insert 預估5 個索引 × ~1ms WAL flush ≈ 3-8ms
  • 目標p99 < 50ms (極大 buffer

4.2 風險點

風險 機率 影響 緩解
async fire-and-forget 失敗無告警 log 漏寫 logger 端用 try/except + 告警 channel連續 5 次失敗觸發 Telegram
5 個索引導致寫入放大 同步寫入慢 partial index 已縮減50 ins/min 下不會擠壓 OLTP
autovacuum 跟不上 90 天 DELETE 表膨脹 每日 03:00 DELETE配 autovacuum_scale_factor=0.05

4.3 connection pool 衝擊

A4 logger 採 fire-and-forget(非同步寫,不阻塞 caller須使用獨立 thread + dedicated session pool建議 size=2與主應用 pool 隔離),避免擠壓 OLTP。


Section 5 — 風險與限制

5.1 已知限制

  1. ai_calls 不分區V1:月寫入超 5M 或日報 latency p95 > 500ms 時須升級到 monthly partition
  2. JSONB meta 無 GIN index:未來若要 WHERE meta->>'prompt_hash' = ... 查詢,需另加 GIN
  3. 保留策略硬刪除30+ 天前的個別呼叫無法回溯trend 須先進 ai_insights
  4. ai_call_budgets.provider NULL 唯一性靠部分索引強制PostgreSQL 標準 UNIQUE 不認 NULL

5.2 護欄缺口(待後續 phase 補)

  • Phase 5ai_calls 寫入失敗的告警通道未定(建議走 EventRouter L0
  • Phase 9ai_call_budgets 的 alert_pct 預設 80% 是否合理待實測budget 超標的 hard-stop 邏輯由應用層實作
  • Phase 11embedding_signature 既有 ~XX 萬筆需批次回填(待 SSH 188 跑統計)

5.3 ALTER TABLE 026 安全性確認

  • PostgreSQL 14momo-db 容器版本,待 SSH 確認)
  • 11+ 之後 ADD COLUMN 無 DEFAULT 為 metadata-only不鎖表,不重寫
  • CREATE INDEX CONCURRENTLY 不阻塞既有寫入,但不能在 transaction 內migration 026 註記已標明)

Section 6 — 部署 Checklist給統帥

執行順序與檢查(憲法 ADR-008 — 部署前必驗):

  • SSH 188 確認 PostgreSQL 版本 ≥ 14migration 026 ALTER TABLE 安全前提)
  • SSH 188 確認 momo-db 磁碟剩餘空間 ≥ 5GB90 天滿載 ~3GB + headroom
  • SSH 188 確認 ai_insights 既有筆數SELECT COUNT(*), COUNT(embedding) FROM ai_insights;(評估 Phase 11 回填工作量)
  • 跑 024psql -U momo -d momo_pro -f migrations/024_create_ai_calls_table.sql
  • 跑 025psql -U momo -d momo_pro -f migrations/025_create_mcp_calls_and_budgets.sql
  • 跑 026 須注意:含 CREATE INDEX CONCURRENTLY不能用 BEGIN/COMMIT 包;用 psql -1 會失敗,須用一般 psql
  • 026 後驗證:\d ai_insights 看到 embedding_signature 欄位 + idx_ai_insights_embedding_signature 索引
  • 跑 sanitySELECT * FROM ai_call_budgets ORDER BY id;(確認 5 筆種子)
  • 通報 A4可開始接 logger

Section 7 — Commit Message 草稿(不自動 commit

db: ai_calls/mcp_calls/budgets schema + bge-m3 signature (Operation Ollama-First v5.0 P1)

- migrations/024: ai_calls 統一 LLM 遙測表 (5 indexes, partial idx for sparse cols)
- migrations/025: mcp_calls + ai_call_budgets (Phase 10/9 預備, 含 5 筆種子預算)
- migrations/026: ai_insights.embedding_signature + partial index (BGE-M3 護欄)
- docs/phase1_db_design_20260503.md: 設計理由 + 查詢效能預估 + 部署 checklist

無 schema 衝突ai_usage_tracking 凍結待 Phase 12 deprecateA4 logger 可啟動。

依據: docs/phase0_audit_report_20260503.md (34 LLM 呼叫點 / 11.8% 覆蓋率)

DB Expert Report最終結論

審查範圍

  • 新增檔案:migrations/024_create_ai_calls_table.sqlmigrations/025_create_mcp_calls_and_budgets.sqlmigrations/026_add_embedding_signature.sql
  • 影響資料表:ai_calls(新)、mcp_calls(新)、ai_call_budgets(新)、ai_insightsADD COLUMN

問題清單

無 BLOCKER。

🟡 NOTE 1 — ai_usage_tracking 重疊

  • 位置:database/ai_models.py:72-109
  • 說明:既有但未被 30 個呼叫點使用,欄位語意不對齊。
  • 風險A4 寫 logger 時若誤雙寫此表會造成數據混亂。
  • 緩解:在設計文 Section 2.2 已明示「凍結Phase 12 再 deprecate」。

🟡 NOTE 2 — Migration 026 不能用 BEGIN/COMMIT 包

  • 位置:migrations/026_add_embedding_signature.sql
  • 說明:CREATE INDEX CONCURRENTLY 不能在 transaction block 內執行。
  • 緩解:已在檔頭註記,部署 checklist 已標明不用 psql -1

效能分析

  • Q1 caller-24h< 5msidx_ai_calls_caller_called_at
  • Q2 provider-7d50-150msidx_ai_calls_provider_called_at + HashAggregate
  • Q3 TOP-10 caller30-80msidx_ai_calls_called_at + Top-N Sort
  • 寫入3-8ms p50p99 < 50ms 達標

結論

APPROVED WITH NOTES — Schema 已備妥,無阻擋 A4 logger 啟動的問題。

回滾路徑

三份 migration 檔頭皆附完整回滾 SQL測試環境可一鍵 DROP。