Files
Neo-ZQYY/docs/database/BD_Manual_ai_tables.md
Neo 70324d8542 chore: 文档与 IDE 配置整理
- .kiro/specs/ → docs/specs/(41 个历史需求 spec 迁移,移除 .config.kiro)
- CLAUDE.md 三层拆分:根文件精简 + apps/backend/CLAUDE.md + .claude/commands/
- 新增 /spec-close、/pre-change 两个工作流命令
- DDL 基线刷新(从测试库重新导出 11 个文件,dws 35→38 表,biz 18→21 表)
- BD_Manual → BD_manual 命名统一(48 个文件)
- 修复 3 处文档与数据库不一致(auth.users.status 默认值、scheduled_tasks 字段、RLS 视图数)
- 新增 BD_manual_public_rbac_tables.md(public schema 8 张 RBAC/工作流表)
- 合并 biz.trigger_jobs 文档(10→12 字段,归档独立文档)
- docs/database/README.md 索引更新

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-06 00:02:37 +08:00

22 KiB
Raw Blame History

BD_Manualbiz Schema AI 表(对话记录 + 消息 + 缓存 + 运行日志 + 调度记录)

目标库:test_zqyy_app(通过 APP_DB_DSN 连接) 迁移脚本:

  • db/zqyy_app/migrations/2026-03-08__create_ai_tables.sql(初始建表)
  • db/zqyy_app/migrations/2026-03-20__rns14_chat_module_extend.sqlRNS1.4 CHAT 扩展)
  • db/zqyy_app/migrations/2026-03-22__p14_ai_module.sqlP14 DashScope 迁移 + 调度器完善)
  • db/zqyy_app/migrations/2026-03-23__p15_ai_monitoring.sqlP15 AI 监控后台 — alert_status + BRIN 索引) 关联 SPEC05-miniapp-ai-integrationP5 AI 集成层)、rns1-chat-integrationRNS1.4 CHAT 对齐与联调收尾)、P14-ai-dashscope-migrationP14 DashScope 迁移)、ai-monitoring-testingP15 AI 监控后台)

1. 变更说明

新增表5 张)

# 表名 用途 字段数(初始→当前) 来源
1 biz.ai_conversations AI 对话记录:每次 AI 调用(用户主动或系统自动)创建一条 8 → 14 P5
2 biz.ai_messages AI 消息记录:对话中的每条消息(输入/输出/系统) 6 → 7 P5
3 biz.ai_cache AI 应用缓存:各应用的结构化输出结果 9 → 10 P5
4 biz.ai_run_logs P14 新增 — AI 运行记录:每次 DashScope API 调用的详细日志 14 → 15 P14, P15
5 biz.ai_trigger_jobs P14 新增 — 调度运行记录:每次 AI 事件触发的编排执行记录 13 P14

RNS1.4 CHAT 模块扩展字段2026-03-20

# 表名 新增字段 用途
1 biz.ai_conversations context_type, context_id, title, last_message, last_message_at 多入口对话复用 + 历史列表展示与排序
2 biz.ai_messages reference_card 引用卡片 JSON客户概览等结构化上下文数据

P14 DashScope 迁移扩展字段2026-03-22

# 表名 新增字段 用途
1 biz.ai_conversations session_id 百炼 session_id格式 conv_{id}_{ts}),仅 App1 使用
2 biz.ai_cache status 缓存状态valid / expired / invalidated / generating

P15 AI 监控后台扩展2026-03-23

# 表名 变更类型 说明
1 biz.ai_run_logs 新增字段 alert_status 告警处理状态NULL / pending / acknowledged / ignored
2 biz.ai_run_logs 新增约束 chk_ai_run_logs_alert_status CHECK (alert_status IS NULL OR alert_status IN ('pending', 'acknowledged', 'ignored'))
3 biz.ai_run_logs 新增部分索引 idx_ai_run_logs_alert (alert_status, created_at DESC) WHERE status IN ('failed', 'timeout', 'circuit_open') — 告警列表查询
4 biz.ai_run_logs 新增 BRIN 索引 idx_ai_run_logs_created_brin BRIN (created_at) WITH (pages_per_range = 32) — Dashboard 聚合优化
5 biz.ai_run_logs 回填 已有 status IN ('failed','timeout','circuit_open') 的记录 alert_status 设为 'pending'

表字段明细

biz.ai_conversations14 字段)

字段 类型 约束 说明
id BIGSERIAL PK 自增主键
user_id VARCHAR(50) NOT NULL 用户 ID系统自动调用时为 system
nickname VARCHAR(100) NOT NULL DEFAULT '' 用户昵称
app_id VARCHAR(30) NOT NULL 应用标识app1_chat / app2_finance / app3_clue / app4_analysis / app5_tactics / app6_note / app7_customer / app8_consolidation
site_id BIGINT NOT NULL 门店 ID多门店隔离
source_page VARCHAR(100) 可空 来源页面标识
source_context JSONB 可空 页面上下文 JSON
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() 创建时间
context_type VARCHAR(20) 可空 RNS1.4 新增 — 对话关联上下文类型task / customer / coach / general
context_id VARCHAR(50) 可空 RNS1.4 新增 — 关联上下文 ID
title VARCHAR(200) 可空 RNS1.4 新增 — 对话标题
last_message TEXT 可空 RNS1.4 新增 — 最后一条消息内容摘要截断至100字
last_message_at TIMESTAMPTZ 可空 RNS1.4 新增 — 最后消息时间
session_id VARCHAR(100) 可空 P14 新增 — 百炼 session_id格式 conv_{conversation_id}_{created_timestamp},仅 App1 使用

biz.ai_messages7 字段)

字段 类型 约束 说明
id BIGSERIAL PK 自增主键
conversation_id BIGINT NOT NULL, FK → biz.ai_conversations(id) ON DELETE CASCADE 关联对话
role VARCHAR(10) NOT NULL, CHECK IN ('user', 'assistant', 'system') 消息角色
content TEXT NOT NULL 消息内容
tokens_used INTEGER 可空 本条消息消耗的 token 数
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() 创建时间
reference_card JSONB 可空 RNS1.4 新增 — 引用卡片 JSON{type, title, summary, data},用于展示客户概览等结构化上下文数据

biz.ai_cache10 字段)

字段 类型 约束 说明
id BIGSERIAL PK 自增主键
cache_type VARCHAR(30) NOT NULL, CHECK 7 个枚举值 缓存类型(见下方枚举)
site_id BIGINT NOT NULL 门店 ID多门店隔离
target_id VARCHAR(100) NOT NULL 目标 ID含义因 cache_type 而异
result_json JSONB NOT NULL 结构化输出结果
score INTEGER 可空 评分:仅应用 6 使用1-10 分)
triggered_by VARCHAR(100) 可空 触发来源标识
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() 创建时间
expires_at TIMESTAMPTZ 可空 可选过期时间
status VARCHAR(20) DEFAULT 'valid', CHECK P14 新增 — 缓存状态valid有效/ expired已过期/ invalidated手动失效/ generating生成中

cache_type 枚举值与 target_id 约定

cache_type target_id 格式 示例
app2_finance 时间维度编码 this_month, last_week
app3_clue member_id 12345
app4_analysis {assistant_id}_{member_id} 100_12345
app5_tactics {assistant_id}_{member_id} 100_12345
app6_note_analysis member_id 12345
app7_customer_analysis member_id 12345
app8_clue_consolidated member_id 12345

约束与索引

约束/索引名 类型 说明
ai_conversations idx_ai_conv_user_site INDEX (user_id, site_id, created_at DESC) — 用户历史对话列表查询
ai_conversations idx_ai_conv_app_site INDEX (app_id, site_id, created_at DESC) — 按应用查询对话
ai_conversations idx_ai_conv_context INDEX条件 RNS1.4(user_id, site_id, context_type, context_id, last_message_at DESC) WHERE context_type IS NOT NULL
ai_conversations idx_ai_conv_last_msg INDEX RNS1.4(user_id, site_id, last_message_at DESC NULLS LAST)
ai_messages FK conversation_id FK biz.ai_conversations(id) ON DELETE CASCADE
ai_messages chk_ai_msg_role CHECK role IN ('user', 'assistant', 'system')
ai_messages idx_ai_msg_conv INDEX (conversation_id, created_at) — 对话消息列表
ai_cache chk_ai_cache_type CHECK 7 个枚举值
ai_cache chk_ai_cache_status CHECK P14status IN ('valid', 'expired', 'invalidated', 'generating')
ai_cache idx_ai_cache_lookup INDEX (cache_type, site_id, target_id, created_at DESC) — 查询最新缓存
ai_cache idx_ai_cache_cleanup INDEX (cache_type, site_id, target_id, created_at) — 清理超限记录
ai_run_logs idx_ai_run_logs_site_app INDEX P14(site_id, app_type)
ai_run_logs idx_ai_run_logs_created INDEX P14(created_at) — Token 预算聚合
ai_run_logs idx_ai_run_logs_status INDEX P14(status)
ai_run_logs chk_ai_run_logs_alert_status CHECK P15alert_status IS NULL OR alert_status IN ('pending', 'acknowledged', 'ignored')
ai_run_logs idx_ai_run_logs_alert INDEX部分 P15(alert_status, created_at DESC) WHERE status IN ('failed', 'timeout', 'circuit_open') — 告警列表查询优化
ai_run_logs idx_ai_run_logs_created_brin BRIN INDEX P15BRIN (created_at) WITH (pages_per_range = 32) — Dashboard 聚合查询优化,适合按时间顺序插入的表
ai_trigger_jobs idx_ai_trigger_jobs_site INDEX P14(site_id, event_type)
ai_trigger_jobs idx_ai_trigger_jobs_dedup INDEX条件 P14(event_type, member_id, site_id, created_at) WHERE status NOT IN ('skipped_duplicate') — 去重
ai_trigger_jobs idx_ai_trigger_jobs_status INDEX P14(status)

biz.ai_run_logs15 字段P14 新增 + P15 扩展)

字段 类型 约束 说明
id BIGSERIAL PK 自增主键
site_id BIGINT NOT NULL 门店 ID
app_type VARCHAR(30) NOT NULL 应用类型app1_chat / app2_finance / ... / app8_consolidate
trigger_type VARCHAR(20) NOT NULL 触发类型user / scheduled / event / forced
member_id BIGINT 可空 会员 ID
request_prompt TEXT 可空 请求 prompt截断前 2000 字符)
response_text TEXT 可空 响应文本
tokens_used INTEGER DEFAULT 0 消耗 token 数
latency_ms INTEGER 可空 调用延迟(毫秒)
status VARCHAR(20) NOT NULL DEFAULT 'pending' 状态pending / running / success / failed / timeout / budget_exceeded
error_message TEXT 可空 错误信息
session_id VARCHAR(100) 可空 百炼 session_id仅 App1
alert_status VARCHAR(20) DEFAULT NULL, CHECK P15 新增 — 告警处理状态NULL非告警记录/ pending待处理/ acknowledged已确认/ ignored已忽略。仅 status IN ('failed','timeout','circuit_open') 的记录才设置此字段
created_at TIMESTAMPTZ NOT NULL DEFAULT now() 创建时间
finished_at TIMESTAMPTZ 可空 完成时间

biz.ai_trigger_jobs13 字段P14 新增)

字段 类型 约束 说明
id BIGSERIAL PK 自增主键
site_id BIGINT NOT NULL 门店 ID
event_type VARCHAR(30) NOT NULL 事件类型consumption / dws_completed / note_created / task_assigned
connector_type VARCHAR(30) DEFAULT 'feiqiu' 连接器类型
member_id BIGINT 可空 会员 ID
payload JSONB 可空 附加数据
status VARCHAR(20) NOT NULL DEFAULT 'pending' 状态pending / running / completed / failed / skipped_duplicate / budget_exceeded
is_forced BOOLEAN DEFAULT false 是否强制执行(跳过去重检查)
app_chain VARCHAR(100) 可空 调用链描述,如 app3→app8→app7
started_at TIMESTAMPTZ 可空 开始时间
finished_at TIMESTAMPTZ 可空 完成时间
error_message TEXT 可空 错误信息
created_at TIMESTAMPTZ NOT NULL DEFAULT now() 创建时间

2. 兼容性影响

组件 影响
ETL 任务 P14 新增DWS 任务完成后通过 utils/ai_trigger.py 发送 HTTP 触发事件到后端 ai_trigger_jobs,失败不中断 ETL 流程
后端 API 直接依赖。P5 AI 模块(apps/backend/app/ai/基于这些表实现对话持久化、缓存读写、SSE 流式对话等功能
后端 APIRNS1.4 直接依赖。CHAT 模块依赖 ai_conversations 的 5 个 RNS1.4 字段实现多入口对话复用
后端 APIP14 直接依赖ai_run_logs 用于 Token 预算聚合BudgetTrackerai_trigger_jobs 用于事件去重和调度记录;ai_conversations.session_id 用于百炼会话管理;ai_cache.status 用于缓存状态控制
小程序 间接依赖。小程序通过后端 AI API 间接使用对话和缓存数据
管理后台 P15 直接依赖。admin-web AI 监控后台4 个页面)依赖 ai_run_logs.alert_status 实现告警管理(确认/忽略),依赖 BRIN 索引优化 Dashboard 聚合查询性能
member_retention_clue 间接关联。App8 结果同时写入 ai_cachemember_retention_clueP14 实现幂等 DELETE+INSERT

3. 回滚策略

3d. 回滚 P15 AI 监控后台2026-03-23 迁移)

按逆序 DROP 新增索引、约束和字段:

BEGIN;
DROP INDEX IF EXISTS biz.idx_ai_run_logs_created_brin;
DROP INDEX IF EXISTS biz.idx_ai_run_logs_alert;
ALTER TABLE biz.ai_run_logs DROP CONSTRAINT IF EXISTS chk_ai_run_logs_alert_status;
ALTER TABLE biz.ai_run_logs DROP COLUMN IF EXISTS alert_status;
COMMIT;

注意:

  • 回滚后 admin-web AI 监控后台的告警管理功能将不可用
  • Dashboard 聚合查询性能可能下降(失去 BRIN 索引)
  • 回滚不影响 P14 的核心功能(调度器、预算追踪等)

3c. 回滚 P14 DashScope 迁移2026-03-22 迁移)

按逆序 DROP 新增表和字段:

-- 删除 P14 新增约束和字段
ALTER TABLE biz.ai_cache DROP CONSTRAINT IF EXISTS chk_ai_cache_status;
ALTER TABLE biz.ai_cache DROP COLUMN IF EXISTS status;
ALTER TABLE biz.ai_conversations DROP COLUMN IF EXISTS session_id;

-- 删除 P14 新增表
DROP TABLE IF EXISTS biz.ai_trigger_jobs;
DROP TABLE IF EXISTS biz.ai_run_logs;

注意:

  • 回滚后 P14 AI 调度器dispatcher、Token 预算追踪BudgetTracker将无法正常工作
  • ai_run_logsai_trigger_jobs 中的数据将丢失,需先备份
  • 回滚不影响 P5 和 RNS1.4 的功能

3a. 回滚 RNS1.4 CHAT 扩展2026-03-20 迁移)

按逆序 DROP 新增索引和字段:

-- 删除 RNS1.4 新增索引
DROP INDEX IF EXISTS biz.idx_ai_conv_context;
DROP INDEX IF EXISTS biz.idx_ai_conv_last_msg;

-- 回退 ai_messages 新增字段
ALTER TABLE biz.ai_messages DROP COLUMN IF EXISTS reference_card;

-- 回退 ai_conversations 新增字段(逆序)
ALTER TABLE biz.ai_conversations DROP COLUMN IF EXISTS last_message_at;
ALTER TABLE biz.ai_conversations DROP COLUMN IF EXISTS last_message;
ALTER TABLE biz.ai_conversations DROP COLUMN IF EXISTS title;
ALTER TABLE biz.ai_conversations DROP COLUMN IF EXISTS context_id;
ALTER TABLE biz.ai_conversations DROP COLUMN IF EXISTS context_type;

注意:

  • 回滚后 CHAT 模块xcx_chat 路由、chat_service将无法正常工作
  • 如果新字段中已有数据,需先备份再执行回滚
  • 回滚不影响 P5 初始建表的 8 个原始字段

3b. 回滚 P5 初始建表2026-03-08 迁移)

按逆序 DROPCASCADE 处理外键依赖):

-- 删除索引
DROP INDEX IF EXISTS biz.idx_ai_cache_cleanup;
DROP INDEX IF EXISTS biz.idx_ai_cache_lookup;
DROP INDEX IF EXISTS biz.idx_ai_msg_conv;
DROP INDEX IF EXISTS biz.idx_ai_conv_app_site;
DROP INDEX IF EXISTS biz.idx_ai_conv_user_site;

-- 删除表ai_messages 依赖 ai_conversations需先删或用 CASCADE
DROP TABLE IF EXISTS biz.ai_cache CASCADE;
DROP TABLE IF EXISTS biz.ai_messages CASCADE;
DROP TABLE IF EXISTS biz.ai_conversations CASCADE;

注意:

  • ai_messages 通过 FK 依赖 ai_conversationsCASCADE 会级联删除消息
  • 如果表中已有数据,需先备份再执行回滚
  • 回滚不会删除 biz Schema 本身

4. 验证 SQL

4a. P5 初始建表验证

-- 1. 验证 3 张 AI 表全部存在
SELECT table_name
FROM information_schema.tables
WHERE table_schema = 'biz'
  AND table_name IN ('ai_conversations', 'ai_messages', 'ai_cache')
ORDER BY table_name;
-- 预期:返回 3 行ai_cache, ai_conversations, ai_messages

-- 2. 验证 ai_conversations 字段数量和关键字段
SELECT column_name, data_type, is_nullable
FROM information_schema.columns
WHERE table_schema = 'biz' AND table_name = 'ai_conversations'
ORDER BY ordinal_position;
-- 预期:返回 14 行P5 原始 8 + RNS1.4 新增 5 + P14 session_id = 14

-- 3. 验证 ai_messages 的外键和 CHECK 约束
SELECT conname, contype, pg_get_constraintdef(oid) AS constraint_def
FROM pg_constraint
WHERE conrelid = 'biz.ai_messages'::regclass
ORDER BY conname;
-- 预期:包含 chk_ai_msg_roleCHECK role IN ...)和 ai_messages_conversation_id_fkeyFK → ai_conversations

-- 4. 验证 ai_cache 的 CHECK 约束7 个枚举值)
SELECT conname, pg_get_constraintdef(oid) AS constraint_def
FROM pg_constraint
WHERE conrelid = 'biz.ai_cache'::regclass AND contype = 'c';
-- 预期:返回 2 行chk_ai_cache_type 含 7 个枚举值chk_ai_cache_status 含 4 个状态值)

-- 5. 验证 P5 初始索引全部存在5 个)
SELECT indexname
FROM pg_indexes
WHERE schemaname = 'biz'
  AND indexname IN (
    'idx_ai_conv_user_site', 'idx_ai_conv_app_site',
    'idx_ai_msg_conv',
    'idx_ai_cache_lookup', 'idx_ai_cache_cleanup'
  )
ORDER BY indexname;
-- 预期:返回 5 行

4b. RNS1.4 CHAT 扩展验证

-- 6. 验证 ai_conversations 新增 5 个字段存在
SELECT column_name, data_type, character_maximum_length
FROM information_schema.columns
WHERE table_schema = 'biz' AND table_name = 'ai_conversations'
  AND column_name IN ('context_type', 'context_id', 'title', 'last_message', 'last_message_at');
-- 预期:返回 5 行
--   context_type    | character varying | 20
--   context_id      | character varying | 50
--   title           | character varying | 200
--   last_message    | text              | NULL
--   last_message_at | timestamp with time zone | NULL

-- 7. 验证 ai_messages 新增 reference_card 字段存在
SELECT column_name, data_type
FROM information_schema.columns
WHERE table_schema = 'biz' AND table_name = 'ai_messages'
  AND column_name = 'reference_card';
-- 预期:返回 1 行data_type = 'jsonb'

-- 8. 验证 RNS1.4 新增 2 个索引存在
SELECT indexname, indexdef
FROM pg_indexes
WHERE schemaname = 'biz' AND tablename = 'ai_conversations'
  AND indexname IN ('idx_ai_conv_context', 'idx_ai_conv_last_msg');
-- 预期:返回 2 行
--   idx_ai_conv_context  — 含 WHERE context_type IS NOT NULL 条件
--   idx_ai_conv_last_msg — (user_id, site_id, last_message_at DESC NULLS LAST)

4c. P14 DashScope 迁移验证

-- 9. 验证 ai_run_logs 表存在且字段正确
SELECT column_name, data_type, character_maximum_length
FROM information_schema.columns
WHERE table_schema = 'biz' AND table_name = 'ai_run_logs'
ORDER BY ordinal_position;
-- 预期:返回 15 行

-- 10. 验证 ai_trigger_jobs 表存在且字段正确
SELECT column_name, data_type, character_maximum_length
FROM information_schema.columns
WHERE table_schema = 'biz' AND table_name = 'ai_trigger_jobs'
ORDER BY ordinal_position;
-- 预期:返回 13 行

-- 11. 验证 ai_run_logs 索引(含 PK
SELECT indexname FROM pg_indexes
WHERE schemaname = 'biz' AND tablename = 'ai_run_logs';
-- 预期6 行PK + 3 P14 索引 + 2 P15 索引)

-- 12. 验证 ai_trigger_jobs 索引(含去重部分索引)
SELECT indexname FROM pg_indexes
WHERE schemaname = 'biz' AND tablename = 'ai_trigger_jobs';
-- 预期4 行PK + 3 个索引)

-- 13. 验证 ai_conversations.session_id 字段
SELECT column_name, data_type, character_maximum_length
FROM information_schema.columns
WHERE table_schema = 'biz' AND table_name = 'ai_conversations'
  AND column_name = 'session_id';
-- 预期1 行varchar(100)

-- 14. 验证 ai_cache.status 字段 + CHECK 约束
SELECT column_name, data_type, column_default
FROM information_schema.columns
WHERE table_schema = 'biz' AND table_name = 'ai_cache'
  AND column_name = 'status';
-- 预期1 行varchar(20)default 'valid'

SELECT conname FROM pg_constraint
WHERE conrelid = 'biz.ai_cache'::regclass AND conname = 'chk_ai_cache_status';
-- 预期1 行

4d. P15 AI 监控后台验证

-- 15. 验证 ai_run_logs.alert_status 字段存在
SELECT column_name, data_type, character_maximum_length, column_default
FROM information_schema.columns
WHERE table_schema = 'biz' AND table_name = 'ai_run_logs'
  AND column_name = 'alert_status';
-- 预期1 行varchar(20)default NULL

-- 16. 验证 alert_status CHECK 约束
SELECT conname, pg_get_constraintdef(oid) AS constraint_def
FROM pg_constraint
WHERE conrelid = 'biz.ai_run_logs'::regclass
  AND conname = 'chk_ai_run_logs_alert_status';
-- 预期1 行CHECK (alert_status IS NULL OR alert_status IN ('pending', 'acknowledged', 'ignored'))

-- 17. 验证 P15 新增索引(部分索引 + BRIN 索引)
SELECT indexname, indexdef
FROM pg_indexes
WHERE schemaname = 'biz' AND tablename = 'ai_run_logs'
  AND indexname IN ('idx_ai_run_logs_alert', 'idx_ai_run_logs_created_brin');
-- 预期2 行
--   idx_ai_run_logs_alert       — 含 WHERE status IN ('failed', 'timeout', 'circuit_open')
--   idx_ai_run_logs_created_brin — USING brin

-- 18. 验证 ai_run_logs 总索引数P14 3个 + P15 2个 + PK = 6
SELECT indexname FROM pg_indexes
WHERE schemaname = 'biz' AND tablename = 'ai_run_logs';
-- 预期6 行

-- 19. 验证回填结果:失败/超时/熔断记录的 alert_status 应为 'pending'
SELECT COUNT(*) AS unset_alerts
FROM biz.ai_run_logs
WHERE status IN ('failed', 'timeout', 'circuit_open')
  AND alert_status IS NULL;
-- 预期0所有失败记录已回填为 'pending'

P15 admin API 查询模式说明

P15 admin-web AI 监控后台引入以下典型查询模式:

查询场景 SQL 模式 使用索引
Dashboard 今日统计 SELECT COUNT(*), AVG(latency_ms) FROM ai_run_logs WHERE created_at >= 今日零点 idx_ai_run_logs_created_brin
Dashboard 7天趋势 SELECT date_trunc('day', created_at), COUNT(*) FROM ai_run_logs WHERE created_at >= 7天前 GROUP BY 1 idx_ai_run_logs_created_brin
告警列表 SELECT * FROM ai_run_logs WHERE status IN ('failed','timeout','circuit_open') AND alert_status = 'pending' ORDER BY created_at DESC idx_ai_run_logs_alert
告警确认/忽略 UPDATE ai_run_logs SET alert_status = 'acknowledged' WHERE id = ? PK
调用记录分页 SELECT * FROM ai_run_logs WHERE site_id = ? AND app_type = ? ORDER BY created_at DESC LIMIT ? OFFSET ? idx_ai_run_logs_site_app
Token 预算聚合 SELECT SUM(tokens_used) FROM ai_run_logs WHERE created_at >= 今日零点 AND status = 'success' idx_ai_run_logs_created (B-tree)