insight_agent_tables.sql 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. -- ============================================================================
  2. -- AI 研判 · 会话与消息(独立存储,不复用 agent_chat_session / agent_message)
  3. --
  4. -- 设计要点(见 continuous-insight-plan.md §4.1):
  5. -- 1) 表级隔离:独立表名 agent_insight_*,与通用对话表物理分离;
  6. -- 2) 案件级隔离:会话行必带 case_id,所有列表查询强制 WHERE case_id = ?;
  7. -- 消息表**冗余 case_id**,保证「越权查询在 SQL 层面就写不出来」;
  8. -- 3) 会话级排序:seq 会话内单调递增 + 唯一,分页排序只认它
  9. -- (id 是随机 UUID 派生、create_at 会同毫秒撞车,都不能用来排序)。
  10. --
  11. -- 执行库:PostgreSQL(master)
  12. --
  13. -- ⚠️ 本脚本只适合「空库首次建表」。
  14. -- 表已存在时 CREATE TABLE IF NOT EXISTS 会**整句跳过**,连内部的
  15. -- uk_aim_session_seq / fk_aim_session 一起跳过(只有语句外的 CREATE INDEX
  16. -- 会被补建)。已有库请改用 insight_agent_tables_align.sql 补齐约束与索引。
  17. -- ============================================================================
  18. -- ============================================================
  19. -- AI 研判 · 会话表
  20. -- ============================================================
  21. CREATE TABLE IF NOT EXISTS agent_insight_session (
  22. id BIGINT PRIMARY KEY, -- 应用侧生成(generateId(),随机非单调,仅作主键)
  23. case_id BIGINT NOT NULL, -- ★ 案件级硬隔离边界
  24. biz_type VARCHAR(32) NOT NULL DEFAULT 'GRAPH_RELATION', -- 研判场景维度(本期恒 GRAPH_RELATION)
  25. scope VARCHAR(16) NOT NULL DEFAULT 'BATCH', -- BATCH | PAIR(预留)
  26. agent_row_id BIGINT, -- 使用的 agent 配置行
  27. model_id BIGINT NOT NULL, -- 创建时定的默认模型,会话内不变
  28. title VARCHAR(128), -- 「对象关系研判 · 2024-12-01 14:32」
  29. context JSONB NOT NULL, -- ★ 查询条件 + 结果快照(动态 sysPrompt 的数据源)
  30. context_hash VARCHAR(64) NOT NULL, -- context 的 sha256,用于同条件复用/去重提示
  31. sys_prompt TEXT NOT NULL, -- ★ 实际使用的完整 sysPrompt,会话内不可变(不下发)
  32. message_count INT NOT NULL DEFAULT 0, -- 消息条数(列表页直读,不 count(*))
  33. last_seq BIGINT NOT NULL DEFAULT 0, -- ★ 会话内消息序号水位(原子分配用)
  34. total_tokens BIGINT NOT NULL DEFAULT 0,
  35. last_message_at TIMESTAMP, -- 最后活动时间(列表排序用)
  36. pinned BOOLEAN NOT NULL DEFAULT FALSE,
  37. status VARCHAR(16) NOT NULL DEFAULT 'ACTIVE', -- ACTIVE | STREAMING | ARCHIVED
  38. create_at TIMESTAMP NOT NULL DEFAULT now(),
  39. update_at TIMESTAMP NOT NULL DEFAULT now()
  40. );
  41. -- 历史列表:WHERE case_id=? AND biz_type=? ORDER BY pinned DESC, last_message_at DESC
  42. CREATE INDEX IF NOT EXISTS idx_ais_case_list
  43. ON agent_insight_session (case_id, biz_type, last_message_at DESC);
  44. -- 同条件复用 / 去重提示:WHERE case_id=? AND context_hash=?
  45. CREATE INDEX IF NOT EXISTS idx_ais_ctx_hash
  46. ON agent_insight_session (case_id, context_hash);
  47. COMMENT ON TABLE agent_insight_session IS 'AI研判会话(独立存储,不复用通用对话表)';
  48. COMMENT ON COLUMN agent_insight_session.case_id IS '案件ID:案件级硬隔离边界,所有查询强制携带';
  49. COMMENT ON COLUMN agent_insight_session.biz_type IS '研判场景:本期恒 GRAPH_RELATION(对象关系分析),为将来同表扩场景预留';
  50. COMMENT ON COLUMN agent_insight_session.scope IS '分析范围:BATCH=当前图谱整体,PAIR=单个节点/关系(预留)';
  51. COMMENT ON COLUMN agent_insight_session.context IS '查询条件+图谱快照(节点/关系),动态系统提示词的数据源';
  52. COMMENT ON COLUMN agent_insight_session.context_hash IS 'context 的 sha256,用于同条件复用与去重提示';
  53. COMMENT ON COLUMN agent_insight_session.sys_prompt IS '会话内实际使用的完整系统提示词,仅运维/追溯读,不通过接口下发';
  54. COMMENT ON COLUMN agent_insight_session.last_seq IS '会话内消息序号水位,消息 seq 由它原子分配';
  55. COMMENT ON COLUMN agent_insight_session.status IS 'ACTIVE | STREAMING(流式进行中,用于并发抢占)| ARCHIVED';
  56. -- ============================================================
  57. -- AI 研判 · 消息表
  58. -- ============================================================
  59. CREATE TABLE IF NOT EXISTS agent_insight_message (
  60. id BIGINT PRIMARY KEY,
  61. session_id BIGINT NOT NULL,
  62. case_id BIGINT NOT NULL, -- ★ 冗余,保证消息查询永远可带 case_id
  63. seq BIGINT NOT NULL, -- ★ 会话内递增,分页排序列
  64. role VARCHAR(16) NOT NULL, -- user | assistant | system
  65. content TEXT, -- 正文
  66. content_type VARCHAR(16) NOT NULL DEFAULT 'text', -- text | insight
  67. message_type VARCHAR(16) NOT NULL DEFAULT 'chat', -- chat | first_round(首轮自动分析) | followup
  68. metadata JSONB, -- 思考过程/中断标记/耗时等轻量字段
  69. tool_events JSONB, -- ★ 工具调用明细(大,列表查询不 select)
  70. output_json JSONB, -- ★ ```insight 结构化产物(首轮 assistant 才有)
  71. token_count INT NOT NULL DEFAULT 0,
  72. reply_to_message_id BIGINT, -- 追问指向的首轮消息(UI 分组用)
  73. starred BOOLEAN NOT NULL DEFAULT FALSE,
  74. status VARCHAR(16) NOT NULL DEFAULT 'DONE', -- DONE | INTERRUPTED
  75. create_at TIMESTAMP NOT NULL DEFAULT now(),
  76. CONSTRAINT uk_aim_session_seq UNIQUE (session_id, seq),
  77. CONSTRAINT fk_aim_session FOREIGN KEY (session_id)
  78. REFERENCES agent_insight_session (id) ON DELETE CASCADE
  79. );
  80. -- 线索聚合(为「线索推送」页预留):按案件捞有结构化产物的消息
  81. CREATE INDEX IF NOT EXISTS idx_aim_output
  82. ON agent_insight_message (case_id, create_at DESC)
  83. WHERE output_json IS NOT NULL;
  84. COMMENT ON TABLE agent_insight_message IS 'AI研判消息(独立存储;case_id 冗余自会话表,用于强制归属过滤)';
  85. COMMENT ON COLUMN agent_insight_message.seq IS '会话内单调序号,分页排序列(勿用 create_at/id 排序)';
  86. COMMENT ON COLUMN agent_insight_message.case_id IS '冗余自会话表:保证消息查询永远可带 case_id 过滤';
  87. COMMENT ON COLUMN agent_insight_message.message_type IS 'chat | first_round(首轮自动分析) | followup';
  88. COMMENT ON COLUMN agent_insight_message.output_json IS '```insight 围栏解析后的结构化产物,仅首轮 assistant 消息有值';
  89. COMMENT ON COLUMN agent_insight_message.status IS 'DONE | INTERRUPTED(用户中止/异常时保留已生成正文)';
  90. -- ============================================================
  91. -- seq 原子分配(说明,非 DDL)
  92. -- 与 INSERT 消息同事务执行,依赖 PG 行级排他锁保证不重号:
  93. -- UPDATE agent_insight_session
  94. -- SET last_seq = last_seq + 1, update_at = now()
  95. -- WHERE id = #{sessionId}
  96. -- RETURNING last_seq;
  97. -- 禁止使用 SELECT max(seq) + 1:READ COMMITTED 下并发会重号。
  98. -- ============================================================