-
Notifications
You must be signed in to change notification settings - Fork 51
Expand file tree
/
Copy pathinitV2.sql
More file actions
4977 lines (4669 loc) · 339 KB
/
Copy pathinitV2.sql
File metadata and controls
4977 lines (4669 loc) · 339 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
-- ============================================================================
-- 睿池 ReachAI — 首次上线统一初始化脚本
-- 数据库:reach_ai(五服务第一阶段共用同一库;旧 ai-agent-service module 已删除)
--
-- 本脚本是当前唯一 SQL 基线,已合并历史服务目录和历史 upgrade 脚本中的表、
-- 补列、补索引、种子数据和必要清理结果。根目录 sql/ 保留 initV2.sql、
-- README.md 与当前仍需应用的 upgrade 脚本;后续 schema/索引/种子变化仍需
-- 新增当次 upgrade 脚本,确认已并入基线且开发/测试库不再需要后再清理。
--
-- 幂等设计:
-- - 建库 / 建表统一 IF NOT EXISTS;
-- - 列 / 索引增加走 information_schema 先判后执行的存储过程;
-- - sideEffect 回填 UPDATE 写明白了"仅覆盖 NULL/空/WRITE",重复跑不会覆盖人工修正值。
--
-- 执行方式:
-- mysql -uroot -p < sql/initV2.sql
--
-- 首次上线后,常规业务建议通过应用的 Liquibase/Flyway 管理后续增量,
-- 本脚本仍可重复执行用于"对齐基线",但生产变更请先备份。
-- ============================================================================
CREATE DATABASE IF NOT EXISTS `reach_ai`
DEFAULT CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;
USE `reach_ai`;
-- ----------------------------------------------------------------------------
-- 共用工具过程:add_col_if_absent / add_idx_if_absent
-- - MySQL 5.7 不支持 IF NOT EXISTS 语法在 ALTER TABLE ADD COLUMN / INDEX 上,
-- 统一封成两个存储过程,避免"首次跑和二次跑行为不一致"。
-- ----------------------------------------------------------------------------
DROP PROCEDURE IF EXISTS add_col_if_absent;
DROP PROCEDURE IF EXISTS add_idx_if_absent;
DROP PROCEDURE IF EXISTS add_unique_idx_if_absent;
DELIMITER $$
CREATE PROCEDURE add_col_if_absent(
IN p_table VARCHAR(64),
IN p_column VARCHAR(64),
IN p_definition TEXT
)
BEGIN
IF NOT EXISTS (
SELECT 1 FROM information_schema.columns
WHERE table_schema = DATABASE()
AND table_name = p_table
AND column_name = p_column
) THEN
SET @sql = CONCAT('ALTER TABLE `', p_table, '` ADD COLUMN `', p_column, '` ', p_definition);
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END IF;
END$$
CREATE PROCEDURE add_idx_if_absent(
IN p_table VARCHAR(64),
IN p_index VARCHAR(64),
IN p_columns VARCHAR(255)
)
BEGIN
IF NOT EXISTS (
SELECT 1 FROM information_schema.statistics
WHERE table_schema = DATABASE()
AND table_name = p_table
AND index_name = p_index
) THEN
SET @sql = CONCAT('CREATE INDEX `', p_index, '` ON `', p_table, '` (', p_columns, ')');
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END IF;
END$$
CREATE PROCEDURE add_unique_idx_if_absent(
IN p_table VARCHAR(64),
IN p_index VARCHAR(64),
IN p_columns VARCHAR(255)
)
BEGIN
IF NOT EXISTS (
SELECT 1 FROM information_schema.statistics
WHERE table_schema = DATABASE()
AND table_name = p_table
AND index_name = p_index
) THEN
SET @sql = CONCAT('CREATE UNIQUE INDEX `', p_index, '` ON `', p_table, '` (', p_columns, ')');
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END IF;
END$$
DELIMITER ;
-- ============================================================================
-- 零、模型中心 V2(当前归属 reachai-model-service:发布目录、可执行实例与官方来源日同步证据)
-- ============================================================================
CREATE TABLE IF NOT EXISTS `model_template` (
`id` VARCHAR(64) NOT NULL PRIMARY KEY,
`name` VARCHAR(128) NOT NULL COMMENT 'Template display name',
`provider` VARCHAR(64) NOT NULL COMMENT 'Provider key, e.g. openai/tongyi/deepseek',
`model_type` VARCHAR(32) NOT NULL COMMENT 'LLM / EMBEDDING / RERANKER',
`model_name` VARCHAR(128) NOT NULL COMMENT 'Default upstream model name',
`protocol` VARCHAR(32) NOT NULL DEFAULT 'OPENAI_COMPATIBLE' COMMENT 'Only OPENAI_COMPATIBLE in V2 phase 1',
`connection_defaults_json` MEDIUMTEXT DEFAULT NULL COMMENT 'Non-secret connection defaults (baseUrl/paths/authHeader/authPrefix)',
`credential_schema_json` MEDIUMTEXT DEFAULT NULL COMMENT 'Credential field schema; never stores real secrets',
`default_options_json` MEDIUMTEXT DEFAULT NULL COMMENT 'Default model options JSON',
`params_schema_json` MEDIUMTEXT DEFAULT NULL COMMENT 'UI parameter schema JSON',
`capabilities_json` MEDIUMTEXT DEFAULT NULL COMMENT 'Capability metadata JSON',
`source_key` VARCHAR(96) DEFAULT NULL COMMENT 'Last official catalog source key',
`lifecycle_status` VARCHAR(24) NOT NULL DEFAULT 'UNKNOWN' COMMENT 'UNKNOWN / PREVIEW / ACTIVE / DEPRECATED / RETIRED',
`recommendation_status` VARCHAR(24) NOT NULL DEFAULT 'UNASSESSED' COMMENT 'UNASSESSED / EVAL_VERIFIED / MANUAL',
`recommendation_tier` VARCHAR(24) DEFAULT NULL COMMENT 'Optional governed recommendation tier; never set by catalog AI alone',
`recommendation_reason` VARCHAR(1000) DEFAULT NULL COMMENT 'EvalOps or manual recommendation evidence summary',
`official_positioning` VARCHAR(512) DEFAULT NULL COMMENT 'Factual positioning extracted from official source',
`released_at` DATE DEFAULT NULL,
`deprecated_at` DATE DEFAULT NULL,
`retire_at` DATE DEFAULT NULL,
`replacement_model_name` VARCHAR(128) DEFAULT NULL,
`last_seen_at` DATETIME DEFAULT NULL COMMENT 'Last time exact model id appeared in a successful source snapshot',
`last_verified_at` DATETIME DEFAULT NULL COMMENT 'Last successful official-source verification',
`source_url` VARCHAR(1000) DEFAULT NULL,
`source_revision` CHAR(64) DEFAULT NULL COMMENT 'Official normalized source SHA-256',
`sync_managed` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '1=created by catalog sync; 0=bootstrap/manual template',
`icon_key` VARCHAR(64) DEFAULT NULL COMMENT 'Local icon key',
`enabled` TINYINT(1) NOT NULL DEFAULT 1 COMMENT '1=enabled in catalog',
`sort_order` INT NOT NULL DEFAULT 0 COMMENT 'Catalog sort order ascending',
`remark` VARCHAR(512) DEFAULT NULL,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
UNIQUE KEY `uk_model_template_catalog_key` (`provider`, `model_type`, `model_name`),
KEY `idx_model_template_provider` (`provider`),
KEY `idx_model_template_type` (`model_type`),
KEY `idx_model_template_enabled_sort` (`enabled`, `sort_order`),
KEY `idx_model_template_lifecycle` (`lifecycle_status`, `enabled`),
KEY `idx_model_template_verified` (`last_verified_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Platform model catalog templates (no secrets)';
CREATE TABLE IF NOT EXISTS `model_instance` (
`id` VARCHAR(64) NOT NULL PRIMARY KEY,
`name` VARCHAR(128) NOT NULL COMMENT 'Human-readable model instance name',
`provider` VARCHAR(64) NOT NULL COMMENT 'Provider key',
`model_type` VARCHAR(32) NOT NULL COMMENT 'LLM / EMBEDDING / RERANKER',
`model_name` VARCHAR(128) NOT NULL COMMENT 'Upstream model name',
`protocol` VARCHAR(32) NOT NULL DEFAULT 'OPENAI_COMPATIBLE' COMMENT 'Only OPENAI_COMPATIBLE in V2 phase 1',
`project_code` VARCHAR(64) DEFAULT NULL COMMENT 'NULL = global; non-null reserved for future project scope',
`project_scope_key` VARCHAR(64) AS (IFNULL(`project_code`, '')) STORED COMMENT 'Generated unique-scope key from project_code',
`connection_config_json` MEDIUMTEXT DEFAULT NULL COMMENT 'Encrypted full connection config JSON (aesgcm:)',
`default_options_json` MEDIUMTEXT DEFAULT NULL COMMENT 'Default runtime options JSON',
`params_schema_json` MEDIUMTEXT DEFAULT NULL COMMENT 'UI parameter schema JSON',
`status` VARCHAR(32) NOT NULL DEFAULT 'ACTIVE' COMMENT 'ACTIVE / DISABLED / ARCHIVED',
`last_test_status` VARCHAR(32) NOT NULL DEFAULT 'UNKNOWN' COMMENT 'UNKNOWN / SUCCESS / FAILED',
`last_test_at` DATETIME DEFAULT NULL,
`last_test_latency_ms` BIGINT DEFAULT NULL,
`last_test_error` VARCHAR(1024) DEFAULT NULL COMMENT 'Truncated sanitized test error',
`remark` VARCHAR(512) DEFAULT NULL,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
UNIQUE KEY `uk_model_instance_name_scope` (`name`, `project_scope_key`),
KEY `idx_model_instance_provider` (`provider`),
KEY `idx_model_instance_type` (`model_type`),
KEY `idx_model_instance_status` (`status`),
KEY `idx_model_instance_project` (`project_code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Executable model instances bound by stable id (no template_id)';
CREATE TABLE IF NOT EXISTS `model_catalog_source` (
`id` BIGINT NOT NULL AUTO_INCREMENT,
`source_key` VARCHAR(96) NOT NULL,
`provider` VARCHAR(64) NOT NULL,
`name` VARCHAR(128) NOT NULL,
`source_kind` VARCHAR(24) NOT NULL COMMENT 'OFFICIAL_PAGE / STRUCTURED_API',
`source_url` VARCHAR(1000) NOT NULL,
`allowed_host` VARCHAR(255) NOT NULL COMMENT 'Must also pass the code-owned official host allowlist',
`content_format` VARCHAR(16) NOT NULL COMMENT 'HTML / MARKDOWN / JSON / TEXT',
`auth_type` VARCHAR(32) NOT NULL DEFAULT 'NONE' COMMENT 'NONE or a code-owned provider credential mapping; never a secret',
`trust_level` VARCHAR(24) NOT NULL DEFAULT 'OFFICIAL',
`enabled` TINYINT(1) NOT NULL DEFAULT 1,
`sort_order` INT NOT NULL DEFAULT 0,
`last_http_etag` VARCHAR(512) DEFAULT NULL,
`last_http_modified` VARCHAR(128) DEFAULT NULL,
`last_content_sha256` CHAR(64) DEFAULT NULL,
`last_checked_at` DATETIME DEFAULT NULL,
`last_success_at` DATETIME DEFAULT NULL,
`last_error_code` VARCHAR(96) DEFAULT NULL,
`last_error_message` VARCHAR(2000) DEFAULT NULL,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_model_catalog_source_key` (`source_key`),
KEY `idx_model_catalog_source_poll` (`enabled`, `sort_order`, `id`),
KEY `idx_model_catalog_source_provider` (`provider`, `enabled`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Official model catalog source metadata; contains no credentials';
CREATE TABLE IF NOT EXISTS `model_catalog_setting` (
`id` TINYINT NOT NULL COMMENT 'Singleton row; always 1',
`auto_sync_enabled` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '0=manual only; 1=create automatic daily slots',
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Model catalog synchronization settings';
INSERT INTO `model_catalog_setting` (`id`, `auto_sync_enabled`)
VALUES (1, 0)
ON DUPLICATE KEY UPDATE `id` = VALUES(`id`);
CREATE TABLE IF NOT EXISTS `model_catalog_sync_run` (
`id` BIGINT NOT NULL AUTO_INCREMENT,
`source_id` BIGINT NOT NULL,
`business_date` DATE NOT NULL COMMENT 'Daily idempotency slot in configured business time zone',
`trigger_type` VARCHAR(24) NOT NULL COMMENT 'STARTUP / DAILY / MANUAL',
`status` VARCHAR(24) NOT NULL COMMENT 'PENDING / RETRY / LEASED / RUNNING / SUCCESS / NO_CHANGE / DEAD',
`attempt_count` INT NOT NULL DEFAULT 0,
`max_attempts` INT NOT NULL DEFAULT 3,
`available_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`lease_owner` VARCHAR(128) DEFAULT NULL,
`lease_token` VARCHAR(64) DEFAULT NULL,
`leased_until` DATETIME DEFAULT NULL,
`http_status` INT DEFAULT NULL,
`content_sha256` CHAR(64) DEFAULT NULL,
`snapshot_id` BIGINT DEFAULT NULL,
`analysis_status` VARCHAR(32) NOT NULL DEFAULT 'PENDING' COMMENT 'PENDING / ANALYZING / DETERMINISTIC / AI_SUCCESS / SKIPPED_UNCHANGED',
`candidate_count` INT NOT NULL DEFAULT 0,
`published_count` INT NOT NULL DEFAULT 0,
`review_count` INT NOT NULL DEFAULT 0,
`last_error_code` VARCHAR(96) DEFAULT NULL,
`last_error_message` VARCHAR(2000) DEFAULT NULL,
`started_at` DATETIME DEFAULT NULL,
`completed_at` DATETIME DEFAULT NULL,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_model_catalog_sync_day` (`source_id`, `business_date`),
KEY `idx_model_catalog_sync_poll` (`status`, `available_at`, `id`),
KEY `idx_model_catalog_sync_lease` (`status`, `leased_until`, `id`),
KEY `idx_model_catalog_sync_history` (`source_id`, `business_date`, `id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='One leased model catalog synchronization slot per official source and business day';
CREATE TABLE IF NOT EXISTS `model_catalog_snapshot` (
`id` BIGINT NOT NULL AUTO_INCREMENT,
`source_id` BIGINT NOT NULL,
`source_url` VARCHAR(1000) NOT NULL,
`content_sha256` CHAR(64) NOT NULL COMMENT 'SHA-256 of normalized public source content',
`content_type` VARCHAR(255) DEFAULT NULL,
`content_size_bytes` INT NOT NULL,
`normalized_content` MEDIUMTEXT NOT NULL COMMENT 'Public untrusted source normalized to text/JSON; scripts are never executed',
`response_headers_json` TEXT DEFAULT NULL COMMENT 'Allowlisted ETag/Last-Modified/content headers only',
`analysis_json` MEDIUMTEXT DEFAULT NULL COMMENT 'Strict analyzer output; candidate evidence, not direct instructions',
`parser_version` VARCHAR(64) NOT NULL,
`fetched_at` DATETIME NOT NULL,
`analyzed_at` DATETIME DEFAULT NULL,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_model_catalog_snapshot_hash` (`source_id`, `content_sha256`),
KEY `idx_model_catalog_snapshot_time` (`source_id`, `fetched_at`, `id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Immutable normalized official model source snapshot and bounded AI analysis';
CREATE TABLE IF NOT EXISTS `model_catalog_change` (
`id` BIGINT NOT NULL AUTO_INCREMENT,
`run_id` BIGINT NOT NULL,
`snapshot_id` BIGINT NOT NULL,
`source_id` BIGINT NOT NULL,
`provider` VARCHAR(64) NOT NULL,
`model_name` VARCHAR(128) NOT NULL,
`model_type` VARCHAR(32) NOT NULL,
`change_type` VARCHAR(32) NOT NULL COMMENT 'DISCOVERED / METADATA_UPDATED / LIFECYCLE_CHANGED / OBSERVED',
`proposed_json` MEDIUMTEXT NOT NULL,
`evidence_json` MEDIUMTEXT NOT NULL COMMENT 'Source URL/hash/excerpt; no credentials',
`confidence` DECIMAL(6,4) NOT NULL,
`validation_status` VARCHAR(24) NOT NULL COMMENT 'VALID / REJECTED',
`publish_status` VARCHAR(24) NOT NULL COMMENT 'PUBLISHED / NO_CHANGE / REVIEW_REQUIRED',
`published_template_id` VARCHAR(64) DEFAULT NULL,
`review_reason` VARCHAR(1000) DEFAULT NULL,
`published_at` DATETIME DEFAULT NULL,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_model_catalog_change_candidate` (`run_id`, `provider`, `model_name`, `model_type`),
KEY `idx_model_catalog_change_review` (`publish_status`, `created_at`, `id`),
KEY `idx_model_catalog_change_template` (`published_template_id`, `created_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Validated model catalog candidate diff and publication evidence';
INSERT INTO `model_catalog_source`
(`source_key`, `provider`, `name`, `source_kind`, `source_url`, `allowed_host`,
`content_format`, `auth_type`, `trust_level`, `enabled`, `sort_order`)
VALUES
('openai-models', 'openai', 'OpenAI 模型目录', 'OFFICIAL_PAGE',
'https://developers.openai.com/api/docs/models/all.md', 'developers.openai.com',
'MARKDOWN', 'NONE', 'OFFICIAL', 1, 10),
('openai-deprecations', 'openai', 'OpenAI 模型弃用公告', 'OFFICIAL_PAGE',
'https://developers.openai.com/api/docs/deprecations.md', 'developers.openai.com',
'MARKDOWN', 'NONE', 'OFFICIAL', 1, 20),
('tongyi-releases', 'tongyi', '阿里云百炼模型上架与更新', 'OFFICIAL_PAGE',
'https://help.aliyun.com/zh/model-studio/newly-released-models', 'help.aliyun.com',
'HTML', 'NONE', 'OFFICIAL', 1, 110),
('tongyi-retirements', 'tongyi', '阿里云百炼模型下线机制', 'OFFICIAL_PAGE',
'https://help.aliyun.com/zh/model-studio/model-depreciation', 'help.aliyun.com',
'HTML', 'NONE', 'OFFICIAL', 1, 120),
('anthropic-models', 'anthropic', 'Anthropic Claude 模型目录', 'OFFICIAL_PAGE',
'https://platform.claude.com/docs/en/models/overview', 'platform.claude.com',
'HTML', 'NONE', 'OFFICIAL', 1, 210),
('anthropic-deprecations', 'anthropic', 'Anthropic Claude 模型弃用公告', 'OFFICIAL_PAGE',
'https://platform.claude.com/docs/en/about-claude/model-deprecations', 'platform.claude.com',
'HTML', 'NONE', 'OFFICIAL', 1, 220),
('gemini-models', 'gemini', 'Google Gemini 模型目录', 'OFFICIAL_PAGE',
'https://ai.google.dev/gemini-api/docs/models', 'ai.google.dev',
'HTML', 'NONE', 'OFFICIAL', 1, 310),
('deepseek-models', 'deepseek', 'DeepSeek 模型目录', 'OFFICIAL_PAGE',
'https://api-docs.deepseek.com/api/list-models/', 'api-docs.deepseek.com',
'HTML', 'NONE', 'OFFICIAL', 1, 410)
ON DUPLICATE KEY UPDATE
`provider` = VALUES(`provider`),
`name` = VALUES(`name`),
`source_kind` = VALUES(`source_kind`),
`source_url` = VALUES(`source_url`),
`allowed_host` = VALUES(`allowed_host`),
`content_format` = VALUES(`content_format`),
`auth_type` = VALUES(`auth_type`),
`trust_level` = VALUES(`trust_level`),
`sort_order` = VALUES(`sort_order`),
`updated_at` = CURRENT_TIMESTAMP;
-- Catalog seeds live only in model_template. Fresh DBs may have zero model_instance rows.
INSERT IGNORE INTO `model_template`
(`id`, `name`, `provider`, `model_type`, `model_name`, `protocol`,
`connection_defaults_json`, `credential_schema_json`, `default_options_json`, `params_schema_json`,
`capabilities_json`, `icon_key`, `enabled`, `sort_order`, `remark`)
VALUES
-- OpenAI
('tpl-openai-gpt-5-2', 'OpenAI GPT-5.2', 'openai', 'LLM', 'gpt-5.2', 'OPENAI_COMPATIBLE',
'{"baseUrl":"https://api.openai.com/v1","chatPath":"/chat/completions","authHeader":"Authorization","authPrefix":"Bearer "}',
'[{"key":"apiKey","label":"API Key","required":true,"secret":true}]',
'{"temperature":0.7,"max_tokens":4096}', '[]',
'{"supportsTools":true,"supportsStreaming":true}', 'openai', 1, 10,
'OpenAI frontier LLM template.'),
('tpl-openai-gpt-4-1-mini', 'OpenAI GPT-4.1 Mini', 'openai', 'LLM', 'gpt-4.1-mini', 'OPENAI_COMPATIBLE',
'{"baseUrl":"https://api.openai.com/v1","chatPath":"/chat/completions","authHeader":"Authorization","authPrefix":"Bearer "}',
'[{"key":"apiKey","label":"API Key","required":true,"secret":true}]',
'{"temperature":0.7,"max_tokens":4096}', '[]',
'{"supportsTools":true,"supportsStreaming":true}', 'openai', 1, 20,
'OpenAI small general LLM template.'),
('tpl-openai-embedding-3-large', 'OpenAI Embedding 3 Large', 'openai', 'EMBEDDING', 'text-embedding-3-large', 'OPENAI_COMPATIBLE',
'{"baseUrl":"https://api.openai.com/v1","embeddingPath":"/embeddings","authHeader":"Authorization","authPrefix":"Bearer "}',
'[{"key":"apiKey","label":"API Key","required":true,"secret":true}]',
'{}', '[]',
'{"supportsEmbedding":true,"expectedDimension":3072}', 'openai', 1, 30,
'OpenAI high-quality text embedding template.'),
('tpl-openai-embedding-3-small', 'OpenAI Embedding 3 Small', 'openai', 'EMBEDDING', 'text-embedding-3-small', 'OPENAI_COMPATIBLE',
'{"baseUrl":"https://api.openai.com/v1","embeddingPath":"/embeddings","authHeader":"Authorization","authPrefix":"Bearer "}',
'[{"key":"apiKey","label":"API Key","required":true,"secret":true}]',
'{}', '[]',
'{"supportsEmbedding":true,"expectedDimension":1536}', 'openai', 1, 40,
'OpenAI cost-effective text embedding template.'),
-- Alibaba Cloud Model Studio / DashScope
('tpl-tongyi-qwen3-max', '通义千问 Qwen3-Max', 'tongyi', 'LLM', 'qwen3-max', 'OPENAI_COMPATIBLE',
'{"baseUrl":"https://dashscope.aliyuncs.com/compatible-mode/v1","chatPath":"/chat/completions","authHeader":"Authorization","authPrefix":"Bearer "}',
'[{"key":"apiKey","label":"API Key","required":true,"secret":true}]',
'{"temperature":0.7,"max_tokens":4096}', '[]',
'{"supportsTools":true,"supportsStreaming":true}', 'tongyi', 1, 110,
'Alibaba Cloud flagship Qwen LLM template.'),
('tpl-tongyi-qwen-plus', '通义千问 Qwen Plus', 'tongyi', 'LLM', 'qwen-plus', 'OPENAI_COMPATIBLE',
'{"baseUrl":"https://dashscope.aliyuncs.com/compatible-mode/v1","chatPath":"/chat/completions","authHeader":"Authorization","authPrefix":"Bearer "}',
'[{"key":"apiKey","label":"API Key","required":true,"secret":true}]',
'{"temperature":0.7,"max_tokens":4096}', '[]',
'{"supportsTools":true,"supportsStreaming":true}', 'tongyi', 1, 120,
'Alibaba Cloud balanced Qwen LLM template.'),
('tpl-tongyi-embedding-v4', '通义文本向量 V4', 'tongyi', 'EMBEDDING', 'text-embedding-v4', 'OPENAI_COMPATIBLE',
'{"baseUrl":"https://dashscope.aliyuncs.com/compatible-mode/v1","embeddingPath":"/embeddings","authHeader":"Authorization","authPrefix":"Bearer "}',
'[{"key":"apiKey","label":"API Key","required":true,"secret":true}]',
'{}', '[]',
'{"supportsEmbedding":true,"expectedDimension":1024}', 'tongyi', 1, 130,
'Alibaba Cloud text embedding template.'),
-- Anthropic
('tpl-anthropic-opus-4-7', 'Claude Opus 4.7', 'anthropic', 'LLM', 'claude-opus-4-7', 'OPENAI_COMPATIBLE',
'{"baseUrl":"https://api.anthropic.com/v1","chatPath":"/chat/completions","authHeader":"Authorization","authPrefix":"Bearer "}',
'[{"key":"apiKey","label":"API Key","required":true,"secret":true}]',
'{"temperature":0.7,"max_tokens":4096}', '[]',
'{"openaiCompatibleLayer":true,"supportsStreaming":true}', 'anthropic', 1, 210,
'Anthropic Claude via official OpenAI-compatible endpoint. Not full Messages API parity; tool calling and advanced features depend on Anthropic OpenAI compat layer limits.'),
('tpl-anthropic-sonnet-4-6', 'Claude Sonnet 4.6', 'anthropic', 'LLM', 'claude-sonnet-4-6', 'OPENAI_COMPATIBLE',
'{"baseUrl":"https://api.anthropic.com/v1","chatPath":"/chat/completions","authHeader":"Authorization","authPrefix":"Bearer "}',
'[{"key":"apiKey","label":"API Key","required":true,"secret":true}]',
'{"temperature":0.7,"max_tokens":4096}', '[]',
'{"openaiCompatibleLayer":true,"supportsStreaming":true}', 'anthropic', 1, 220,
'Anthropic Claude via official OpenAI-compatible endpoint. Not full Messages API parity; tool calling and advanced features depend on Anthropic OpenAI compat layer limits.'),
('tpl-anthropic-haiku-4-5', 'Claude Haiku 4.5', 'anthropic', 'LLM', 'claude-haiku-4-5', 'OPENAI_COMPATIBLE',
'{"baseUrl":"https://api.anthropic.com/v1","chatPath":"/chat/completions","authHeader":"Authorization","authPrefix":"Bearer "}',
'[{"key":"apiKey","label":"API Key","required":true,"secret":true}]',
'{"temperature":0.7,"max_tokens":4096}', '[]',
'{"openaiCompatibleLayer":true,"supportsStreaming":true}', 'anthropic', 1, 230,
'Anthropic Claude via official OpenAI-compatible endpoint. Not full Messages API parity; tool calling and advanced features depend on Anthropic OpenAI compat layer limits.'),
-- Google Gemini
('tpl-gemini-2-5-pro', 'Gemini 2.5 Pro', 'gemini', 'LLM', 'gemini-2.5-pro', 'OPENAI_COMPATIBLE',
'{"baseUrl":"https://generativelanguage.googleapis.com/v1beta/openai","chatPath":"/chat/completions","authHeader":"Authorization","authPrefix":"Bearer "}',
'[{"key":"apiKey","label":"API Key","required":true,"secret":true}]',
'{"temperature":0.7,"max_tokens":4096}', '[]',
'{"supportsTools":true,"supportsStreaming":true}', 'gemini', 1, 310,
'Google Gemini advanced reasoning template.'),
('tpl-gemini-2-5-flash', 'Gemini 2.5 Flash', 'gemini', 'LLM', 'gemini-2.5-flash', 'OPENAI_COMPATIBLE',
'{"baseUrl":"https://generativelanguage.googleapis.com/v1beta/openai","chatPath":"/chat/completions","authHeader":"Authorization","authPrefix":"Bearer "}',
'[{"key":"apiKey","label":"API Key","required":true,"secret":true}]',
'{"temperature":0.7,"max_tokens":4096}', '[]',
'{"supportsTools":true,"supportsStreaming":true}', 'gemini', 1, 320,
'Google Gemini price-performance template.'),
('tpl-gemini-embedding', 'Gemini Embedding', 'gemini', 'EMBEDDING', 'gemini-embedding-001', 'OPENAI_COMPATIBLE',
'{"baseUrl":"https://generativelanguage.googleapis.com/v1beta/openai","embeddingPath":"/embeddings","authHeader":"Authorization","authPrefix":"Bearer "}',
'[{"key":"apiKey","label":"API Key","required":true,"secret":true}]',
'{}', '[]',
'{"supportsEmbedding":true,"expectedDimension":3072}', 'gemini', 1, 330,
'Google Gemini embedding template.'),
-- DeepSeek
('tpl-deepseek-v4-pro', 'DeepSeek V4 Pro', 'deepseek', 'LLM', 'deepseek-v4-pro', 'OPENAI_COMPATIBLE',
'{"baseUrl":"https://api.deepseek.com","chatPath":"/chat/completions","authHeader":"Authorization","authPrefix":"Bearer "}',
'[{"key":"apiKey","label":"API Key","required":true,"secret":true}]',
'{"max_tokens":16384,"thinking":{"type":"enabled"},"reasoning_effort":"high"}', '[]',
'{"supportsTools":true,"supportsStreaming":true,"supportsReasoning":true}', 'deepseek', 1, 410,
'DeepSeek reasoning-capable LLM template.'),
('tpl-deepseek-v4-flash', 'DeepSeek V4 Flash', 'deepseek', 'LLM', 'deepseek-v4-flash', 'OPENAI_COMPATIBLE',
'{"baseUrl":"https://api.deepseek.com","chatPath":"/chat/completions","authHeader":"Authorization","authPrefix":"Bearer "}',
'[{"key":"apiKey","label":"API Key","required":true,"secret":true}]',
'{"temperature":0.7,"max_tokens":8192,"thinking":{"type":"disabled"}}', '[]',
'{"supportsTools":true,"supportsStreaming":true}', 'deepseek', 1, 420,
'DeepSeek fast LLM template.'),
-- Moonshot / Kimi
('tpl-kimi-k2-6', 'Kimi K2.6', 'kimi', 'LLM', 'kimi-k2.6', 'OPENAI_COMPATIBLE',
'{"baseUrl":"https://api.moonshot.ai/v1","chatPath":"/chat/completions","authHeader":"Authorization","authPrefix":"Bearer "}',
'[{"key":"apiKey","label":"API Key","required":true,"secret":true}]',
'{"temperature":0.7,"max_tokens":4096}', '[]',
'{"supportsTools":true,"supportsStreaming":true}', 'kimi', 1, 510,
'Moonshot current Kimi family template; verify account model access.'),
('tpl-kimi-moonshot-128k', 'Moonshot v1 128K', 'kimi', 'LLM', 'moonshot-v1-128k', 'OPENAI_COMPATIBLE',
'{"baseUrl":"https://api.moonshot.ai/v1","chatPath":"/chat/completions","authHeader":"Authorization","authPrefix":"Bearer "}',
'[{"key":"apiKey","label":"API Key","required":true,"secret":true}]',
'{"temperature":0.7,"max_tokens":4096}', '[]',
'{"supportsTools":true,"supportsStreaming":true}', 'kimi', 1, 520,
'Moonshot long-context text generation template.'),
-- SiliconFlow
('tpl-siliconflow-qwen3-32b', '硅基流动 Qwen3 32B', 'siliconflow', 'LLM', 'Qwen/Qwen3-32B', 'OPENAI_COMPATIBLE',
'{"baseUrl":"https://api.siliconflow.cn/v1","chatPath":"/chat/completions","authHeader":"Authorization","authPrefix":"Bearer "}',
'[{"key":"apiKey","label":"API Key","required":true,"secret":true}]',
'{"temperature":0.7,"max_tokens":4096}', '[]',
'{"supportsTools":true,"supportsStreaming":true}', 'siliconflow', 1, 610,
'SiliconFlow open model LLM template.'),
('tpl-siliconflow-deepseek-v3-1', '硅基流动 DeepSeek V3.1', 'siliconflow', 'LLM', 'deepseek-ai/DeepSeek-V3.1', 'OPENAI_COMPATIBLE',
'{"baseUrl":"https://api.siliconflow.cn/v1","chatPath":"/chat/completions","authHeader":"Authorization","authPrefix":"Bearer "}',
'[{"key":"apiKey","label":"API Key","required":true,"secret":true}]',
'{"temperature":0.7,"max_tokens":4096}', '[]',
'{"supportsTools":true,"supportsStreaming":true}', 'siliconflow', 1, 620,
'SiliconFlow DeepSeek hosted LLM template.'),
('tpl-siliconflow-bge-m3', '硅基流动 BGE-M3 向量', 'siliconflow', 'EMBEDDING', 'BAAI/bge-m3', 'OPENAI_COMPATIBLE',
'{"baseUrl":"https://api.siliconflow.cn/v1","embeddingPath":"/embeddings","authHeader":"Authorization","authPrefix":"Bearer "}',
'[{"key":"apiKey","label":"API Key","required":true,"secret":true}]',
'{}', '[]',
'{"supportsEmbedding":true,"expectedDimension":1024}', 'siliconflow', 1, 630,
'SiliconFlow embedding template.'),
('tpl-siliconflow-bge-reranker', '硅基流动 BGE 重排', 'siliconflow', 'RERANKER', 'BAAI/bge-reranker-v2-m3', 'OPENAI_COMPATIBLE',
'{"baseUrl":"https://api.siliconflow.cn/v1","rerankPath":"/rerank","authHeader":"Authorization","authPrefix":"Bearer "}',
'[{"key":"apiKey","label":"API Key","required":true,"secret":true}]',
'{}', '[]',
'{"supportsRerank":true}', 'siliconflow', 1, 640,
'SiliconFlow reranker template.'),
-- Azure OpenAI
('tpl-azure-gpt-4-1', 'Azure OpenAI GPT-4.1', 'azure-openai', 'LLM', 'gpt-4.1', 'OPENAI_COMPATIBLE',
'{"baseUrl":"https://{resource}.openai.azure.com/openai/v1","chatPath":"/chat/completions","authHeader":"Authorization","authPrefix":"Bearer "}',
'[{"key":"apiKey","label":"API Key","required":true,"secret":true}]',
'{"temperature":0.7,"max_tokens":4096}', '[]',
'{"supportsTools":true,"supportsStreaming":true}', 'azure-openai', 1, 710,
'Azure OpenAI deployment template; replace model_name with your deployment if needed.'),
('tpl-azure-embedding-3-large', 'Azure OpenAI Embedding 3 Large', 'azure-openai', 'EMBEDDING', 'text-embedding-3-large', 'OPENAI_COMPATIBLE',
'{"baseUrl":"https://{resource}.openai.azure.com/openai/v1","embeddingPath":"/embeddings","authHeader":"Authorization","authPrefix":"Bearer "}',
'[{"key":"apiKey","label":"API Key","required":true,"secret":true}]',
'{}', '[]',
'{"supportsEmbedding":true,"expectedDimension":3072}', 'azure-openai', 1, 720,
'Azure OpenAI embedding template; replace model_name with your deployment if needed.'),
-- Tencent Hunyuan
('tpl-hunyuan-turbos', '腾讯混元 TurboS', 'tencent-hunyuan', 'LLM', 'hunyuan-turbos', 'OPENAI_COMPATIBLE',
'{"baseUrl":"https://api.hunyuan.cloud.tencent.com/v1","chatPath":"/chat/completions","authHeader":"Authorization","authPrefix":"Bearer "}',
'[{"key":"apiKey","label":"API Key","required":true,"secret":true}]',
'{"temperature":0.7,"max_tokens":4096}', '[]',
'{"supportsTools":true,"supportsStreaming":true}', 'tencent-hunyuan', 1, 810,
'Tencent Hunyuan high-speed LLM template. Verify exact endpoint and model access.'),
('tpl-hunyuan-lite', '腾讯混元 Lite', 'tencent-hunyuan', 'LLM', 'hunyuan-lite', 'OPENAI_COMPATIBLE',
'{"baseUrl":"https://api.hunyuan.cloud.tencent.com/v1","chatPath":"/chat/completions","authHeader":"Authorization","authPrefix":"Bearer "}',
'[{"key":"apiKey","label":"API Key","required":true,"secret":true}]',
'{"temperature":0.7,"max_tokens":4096}', '[]',
'{"supportsTools":true,"supportsStreaming":true}', 'tencent-hunyuan', 1, 820,
'Tencent Hunyuan lightweight LLM template. Verify exact endpoint and model access.'),
-- Baidu Qianfan
('tpl-qianfan-ernie-4-5-turbo', '千帆 ERNIE 4.5 Turbo', 'qianfan', 'LLM', 'ernie-4.5-turbo-128k', 'OPENAI_COMPATIBLE',
'{"baseUrl":"https://qianfan.baidubce.com/v2","chatPath":"/chat/completions","authHeader":"Authorization","authPrefix":"Bearer "}',
'[{"key":"apiKey","label":"API Key","required":true,"secret":true}]',
'{"temperature":0.7,"max_tokens":4096}', '[]',
'{"supportsTools":true,"supportsStreaming":true}', 'qianfan', 1, 910,
'Baidu Qianfan ERNIE template. Verify exact account endpoint and model access.'),
('tpl-qianfan-embedding-v1', '千帆 Embedding V1', 'qianfan', 'EMBEDDING', 'embedding-v1', 'OPENAI_COMPATIBLE',
'{"baseUrl":"https://qianfan.baidubce.com/v2","embeddingPath":"/embeddings","authHeader":"Authorization","authPrefix":"Bearer "}',
'[{"key":"apiKey","label":"API Key","required":true,"secret":true}]',
'{}', '[]',
'{"supportsEmbedding":true,"expectedDimension":384}', 'qianfan', 1, 920,
'Baidu Qianfan embedding template. Verify exact account endpoint and model access.'),
-- Volcano Engine / Doubao
('tpl-doubao-seed-1-6', '火山方舟 Doubao Seed 1.6', 'volcengine', 'LLM', 'doubao-seed-1-6', 'OPENAI_COMPATIBLE',
'{"baseUrl":"https://ark.cn-beijing.volces.com/api/v3","chatPath":"/chat/completions","authHeader":"Authorization","authPrefix":"Bearer "}',
'[{"key":"apiKey","label":"API Key","required":true,"secret":true}]',
'{"temperature":0.7,"max_tokens":4096}', '[]',
'{"supportsTools":true,"supportsStreaming":true}', 'volcengine', 1, 1010,
'Volcano Engine Ark Doubao LLM template. Replace with your endpoint model id if needed.'),
('tpl-doubao-embedding-large', '火山方舟 Doubao Embedding Large', 'volcengine', 'EMBEDDING', 'doubao-embedding-large-text-240915', 'OPENAI_COMPATIBLE',
'{"baseUrl":"https://ark.cn-beijing.volces.com/api/v3","embeddingPath":"/embeddings","authHeader":"Authorization","authPrefix":"Bearer "}',
'[{"key":"apiKey","label":"API Key","required":true,"secret":true}]',
'{}', '[]',
'{"supportsEmbedding":true,"expectedDimension":2048}', 'volcengine', 1, 1020,
'Volcano Engine Ark embedding template. Replace with your endpoint model id if needed.'),
-- Local / self-hosted
('tpl-ollama-qwen3-32b', 'Ollama Qwen3 32B', 'ollama', 'LLM', 'qwen3:32b', 'OPENAI_COMPATIBLE',
'{"baseUrl":"http://localhost:11434/v1","chatPath":"/chat/completions","authHeader":"Authorization","authPrefix":"Bearer "}',
'[{"key":"apiKey","label":"API Key","required":false,"secret":true}]',
'{"temperature":0.7,"max_tokens":4096}', '[]',
'{"supportsTools":true,"supportsStreaming":true,"local":true}', 'ollama', 1, 1110,
'Local Ollama template; enable only when local model is pulled.'),
('tpl-vllm-qwen3-32b', 'vLLM Qwen3 32B', 'vllm', 'LLM', 'Qwen/Qwen3-32B', 'OPENAI_COMPATIBLE',
'{"baseUrl":"http://localhost:8000/v1","chatPath":"/chat/completions","authHeader":"Authorization","authPrefix":"Bearer "}',
'[{"key":"apiKey","label":"API Key","required":false,"secret":true}]',
'{"temperature":0.7,"max_tokens":4096}', '[]',
'{"supportsTools":true,"supportsStreaming":true,"local":true}', 'vllm', 1, 1120,
'Self-hosted vLLM template; set baseUrl/modelName to deployed model.');
-- ============================================================================
-- 一、知识库模块(当前归属 reachai-knowledge-service,历史 v1 + v2)
-- ============================================================================
CREATE TABLE IF NOT EXISTS `knowledge_base` (
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键',
`name` VARCHAR(128) NOT NULL COMMENT '知识库名称',
`code` VARCHAR(64) NOT NULL COMMENT '知识库编码(对应 Milvus collection 名称)',
`description` VARCHAR(512) DEFAULT NULL COMMENT '描述',
`embedding_model_instance_id` VARCHAR(64) DEFAULT NULL COMMENT 'Embedding model instance id',
`rerank_model_instance_id` VARCHAR(64) DEFAULT NULL COMMENT 'Rerank model instance id',
`llm_model_instance_id` VARCHAR(64) DEFAULT NULL COMMENT 'LLM model instance id for answer generation',
`dimension` INT DEFAULT 1536 COMMENT '向量维度',
`chunk_size` INT DEFAULT 500 COMMENT 'knowledge_chunk 切分大小(字符数)',
`chunk_overlap` INT DEFAULT 50 COMMENT 'knowledge_chunk 重叠大小(字符数)',
`split_type` VARCHAR(32) DEFAULT 'FIXED' COMMENT '切分策略: FIXED / PARAGRAPH / SEMANTIC',
`status` TINYINT DEFAULT 1 COMMENT '状态: 0-禁用 1-启用',
`create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_code` (`code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='知识库';
CREATE TABLE IF NOT EXISTS `knowledge_file_info` (
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键',
`file_id` VARCHAR(128) NOT NULL COMMENT '文件业务ID(对外暴露)',
`knowledge_base_id` BIGINT NOT NULL COMMENT '所属知识库ID',
`file_name` VARCHAR(256) DEFAULT NULL COMMENT '文件名称',
`file_type` VARCHAR(32) DEFAULT NULL COMMENT '文件类型',
`file_size` BIGINT DEFAULT 0 COMMENT '文件大小(字节)',
`chunk_count` INT DEFAULT 0 COMMENT 'knowledge_chunk 数量',
`status` TINYINT DEFAULT 0 COMMENT '状态: 0-处理中 1-已完成 2-失败',
`raw_text` LONGTEXT DEFAULT NULL COMMENT '清洗后的检索文本快照;重新解析必须使用 source_object_key',
`source_object_key` VARCHAR(512) DEFAULT NULL COMMENT '上传原件的对象存储 key',
`source_content_type` VARCHAR(128) DEFAULT NULL COMMENT '上传时声明的 MIME',
`source_sha256` CHAR(64) DEFAULT NULL COMMENT '上传原件 SHA-256',
`parse_provider` VARCHAR(32) DEFAULT NULL COMMENT 'JAVA_FAST / DOCLING',
`parse_provider_version` VARCHAR(64) DEFAULT NULL COMMENT '解析 Provider 版本',
`parse_artifact_object_key` VARCHAR(512) DEFAULT NULL COMMENT '结构化解析 JSON 的对象存储 key',
`import_job_id` VARCHAR(64) DEFAULT NULL COMMENT '产生文件记录的导入任务',
`create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_knowledge_file_file_id` (`file_id`),
KEY `idx_kb_id` (`knowledge_base_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='文件信息';
CREATE TABLE IF NOT EXISTS `knowledge_document_import_job` (
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键',
`job_id` VARCHAR(64) NOT NULL COMMENT '对外导入任务ID',
`file_id` VARCHAR(128) NOT NULL COMMENT '完成后对应 knowledge_file_info.file_id',
`replace_file_id` VARCHAR(128) DEFAULT NULL COMMENT '完成后被替换的旧文件ID',
`knowledge_base_id` BIGINT NOT NULL COMMENT '所属知识库ID',
`knowledge_base_code` VARCHAR(64) NOT NULL COMMENT '提交时知识库编码快照',
`tenant_id` VARCHAR(96) NOT NULL DEFAULT 'default' COMMENT 'Control 已验证租户快照',
`created_by_actor_id` VARCHAR(128) DEFAULT NULL COMMENT 'Control 已验证任务创建用户',
`workspace_id` VARCHAR(64) NOT NULL DEFAULT 'default' COMMENT '知识库 workspace 授权快照',
`project_code` VARCHAR(64) DEFAULT NULL COMMENT '知识库 project 授权快照',
`resource_scope` VARCHAR(20) NOT NULL DEFAULT 'WORKSPACE' COMMENT 'SHARED / WORKSPACE / PROJECT 授权快照',
`file_name` VARCHAR(256) NOT NULL COMMENT '原始文件名',
`file_type` VARCHAR(32) NOT NULL COMMENT '严格检测后的格式',
`content_type` VARCHAR(128) DEFAULT NULL COMMENT '上传时声明 MIME',
`file_size` BIGINT NOT NULL DEFAULT 0 COMMENT '原件字节数',
`source_object_key` VARCHAR(512) NOT NULL COMMENT '原件对象存储 key',
`source_sha256` CHAR(64) DEFAULT NULL COMMENT '原件 SHA-256',
`provider_type` VARCHAR(32) NOT NULL COMMENT 'JAVA_FAST / DOCLING',
`provider_version` VARCHAR(64) DEFAULT NULL COMMENT '实际解析版本',
`parse_artifact_object_key` VARCHAR(512) DEFAULT NULL COMMENT '结构化解析 JSON 工件 key',
`status` VARCHAR(32) NOT NULL COMMENT 'QUEUED/PARSING/PARSED/INDEXING/COMPLETED/RETRY_WAIT/FAILED/CANCELLED',
`stage` VARCHAR(32) NOT NULL COMMENT '当前阶段',
`chunk_strategy` VARCHAR(32) NOT NULL DEFAULT 'fixed_length' COMMENT '切分策略',
`chunk_size` INT NOT NULL DEFAULT 500 COMMENT '切分大小',
`chunk_overlap` INT NOT NULL DEFAULT 50 COMMENT '切分重叠',
`extra_params_json` MEDIUMTEXT DEFAULT NULL COMMENT '非秘密扩展处理参数',
`auto_commit` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '解析成功后是否自动向量入库',
`attempt_count` INT NOT NULL DEFAULT 0 COMMENT '同一 Provider 的解析尝试数',
`max_attempts` INT NOT NULL DEFAULT 3 COMMENT '最大解析尝试数',
`error_code` VARCHAR(64) DEFAULT NULL COMMENT '稳定错误码',
`error_message` VARCHAR(1024) DEFAULT NULL COMMENT '脱敏且截断的错误详情',
`next_attempt_at` DATETIME DEFAULT NULL COMMENT '重试可执行时间',
`lease_owner` VARCHAR(128) DEFAULT NULL COMMENT '短租约 worker',
`lease_until` DATETIME DEFAULT NULL COMMENT '短租约截止时间',
`parsed_at` DATETIME DEFAULT NULL COMMENT '结构化结果持久化时间',
`completed_at` DATETIME DEFAULT NULL COMMENT '索引完成时间',
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_knowledge_document_import_job_id` (`job_id`),
KEY `idx_knowledge_document_import_status_retry` (`status`, `next_attempt_at`),
KEY `idx_knowledge_document_import_autocommit` (`status`, `auto_commit`, `parsed_at`),
UNIQUE KEY `uk_knowledge_document_import_file_id` (`file_id`),
KEY `idx_knowledge_document_import_kb` (`knowledge_base_id`, `create_time`),
KEY `idx_knowledge_document_import_actor` (`tenant_id`, `created_by_actor_id`, `create_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='知识文档原件、解析工件和入库任务状态';
CREATE TABLE IF NOT EXISTS `knowledge_chunk` (
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键',
`file_id` VARCHAR(128) NOT NULL COMMENT '所属文件ID',
`knowledge_base_id` BIGINT NOT NULL COMMENT '所属知识库ID',
`content` TEXT NOT NULL COMMENT '文本内容',
`chunk_index` INT DEFAULT 0 COMMENT 'knowledge_chunk 在文件内的序号',
`vector_id` VARCHAR(256) DEFAULT NULL COMMENT 'Milvus 中的向量 ID',
`collection_name` VARCHAR(64) DEFAULT NULL COMMENT '关联的 collection 名称',
`element_type` VARCHAR(32) DEFAULT NULL COMMENT '结构化解析元素类型',
`section_path` VARCHAR(1024) DEFAULT NULL COMMENT '元素标题路径',
`source_locator_json` MEDIUMTEXT DEFAULT NULL COMMENT '页/幻灯片/单元格/坐标来源锚点',
`create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_knowledge_chunk_file_index` (`file_id`, `chunk_index`),
KEY `idx_kb_id` (`knowledge_base_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='文本块';
CREATE TABLE IF NOT EXISTS `knowledge_user_file_permission` (
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键',
`user_id` VARCHAR(128) NOT NULL COMMENT '用户ID',
`file_id` VARCHAR(128) NOT NULL COMMENT '文件业务ID',
`permission_type` VARCHAR(16) DEFAULT 'read' COMMENT '权限类型: read / write / admin',
`create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_user_file` (`user_id`, `file_id`),
KEY `idx_user_id` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户文件权限';
-- Knowledge operations upgrade: enterprise scope, retrieval policy, direct return and rerank switches.
CALL add_col_if_absent('knowledge_base', 'workspace_id', 'VARCHAR(64) NOT NULL DEFAULT ''default'' COMMENT ''workspace isolation key'' AFTER `description`');
CALL add_col_if_absent('knowledge_base', 'project_code', 'VARCHAR(64) DEFAULT NULL COMMENT ''owning ReachAI project code'' AFTER `workspace_id`');
CALL add_col_if_absent('knowledge_base', 'scope', 'VARCHAR(20) NOT NULL DEFAULT ''WORKSPACE'' COMMENT ''SHARED / WORKSPACE / PROJECT'' AFTER `project_code`');
CALL add_col_if_absent('knowledge_base', 'search_mode', 'VARCHAR(20) NOT NULL DEFAULT ''hybrid'' COMMENT ''vector / keyword / hybrid'' AFTER `split_type`');
CALL add_col_if_absent('knowledge_base', 'top_k', 'INT NOT NULL DEFAULT 5 COMMENT ''default retrieval topK'' AFTER `search_mode`');
CALL add_col_if_absent('knowledge_base', 'similarity_threshold', 'FLOAT NOT NULL DEFAULT 0.5 COMMENT ''default retrieval threshold'' AFTER `top_k`');
CALL add_col_if_absent('knowledge_base', 'direct_return_enabled', 'TINYINT(1) NOT NULL DEFAULT 1 COMMENT ''enable direct paragraph return'' AFTER `similarity_threshold`');
CALL add_col_if_absent('knowledge_base', 'direct_return_threshold', 'FLOAT NOT NULL DEFAULT 0.9 COMMENT ''direct return threshold'' AFTER `direct_return_enabled`');
CALL add_col_if_absent('knowledge_base', 'rerank_enabled', 'TINYINT(1) NOT NULL DEFAULT 1 COMMENT ''enable rerank'' AFTER `direct_return_threshold`');
CALL add_col_if_absent('knowledge_base', 'vector_weight', 'FLOAT NOT NULL DEFAULT 0.7 COMMENT ''hybrid vector weight'' AFTER `rerank_enabled`');
CALL add_col_if_absent('knowledge_base', 'keyword_weight', 'FLOAT NOT NULL DEFAULT 0.3 COMMENT ''hybrid keyword weight'' AFTER `vector_weight`');
CALL add_col_if_absent('knowledge_chunk', 'title', 'VARCHAR(256) DEFAULT NULL COMMENT ''paragraph title'' AFTER `content`');
CALL add_col_if_absent('knowledge_chunk', 'hit_count', 'INT NOT NULL DEFAULT 0 COMMENT ''retrieval hit count'' AFTER `collection_name`');
CALL add_col_if_absent('knowledge_chunk', 'enabled', 'TINYINT(1) NOT NULL DEFAULT 1 COMMENT ''paragraph enabled flag'' AFTER `hit_count`');
CALL add_col_if_absent('knowledge_file_info', 'source_object_key', 'VARCHAR(512) DEFAULT NULL COMMENT ''上传原件的对象存储 key'' AFTER `raw_text`');
CALL add_col_if_absent('knowledge_file_info', 'source_content_type', 'VARCHAR(128) DEFAULT NULL COMMENT ''上传时声明的 MIME'' AFTER `source_object_key`');
CALL add_col_if_absent('knowledge_file_info', 'source_sha256', 'CHAR(64) DEFAULT NULL COMMENT ''上传原件 SHA-256'' AFTER `source_content_type`');
CALL add_col_if_absent('knowledge_file_info', 'parse_provider', 'VARCHAR(32) DEFAULT NULL COMMENT ''JAVA_FAST / DOCLING'' AFTER `source_sha256`');
CALL add_col_if_absent('knowledge_file_info', 'parse_provider_version', 'VARCHAR(64) DEFAULT NULL COMMENT ''解析 Provider 版本'' AFTER `parse_provider`');
CALL add_col_if_absent('knowledge_file_info', 'parse_artifact_object_key', 'VARCHAR(512) DEFAULT NULL COMMENT ''结构化解析 JSON 的对象存储 key'' AFTER `parse_provider_version`');
CALL add_col_if_absent('knowledge_file_info', 'import_job_id', 'VARCHAR(64) DEFAULT NULL COMMENT ''产生文件记录的导入任务'' AFTER `parse_artifact_object_key`');
CALL add_col_if_absent('knowledge_chunk', 'element_type', 'VARCHAR(32) DEFAULT NULL COMMENT ''结构化解析元素类型'' AFTER `collection_name`');
CALL add_col_if_absent('knowledge_chunk', 'section_path', 'VARCHAR(1024) DEFAULT NULL COMMENT ''元素标题路径'' AFTER `element_type`');
CALL add_col_if_absent('knowledge_chunk', 'source_locator_json', 'MEDIUMTEXT DEFAULT NULL COMMENT ''页/幻灯片/单元格/坐标来源锚点'' AFTER `section_path`');
CALL add_idx_if_absent('knowledge_base', 'idx_kb_workspace_scope', '`workspace_id`, `scope`');
CALL add_idx_if_absent('knowledge_base', 'idx_kb_project_code', '`project_code`');
CALL add_idx_if_absent('knowledge_chunk', 'idx_kb_enabled', '`knowledge_base_id`, `enabled`');
CALL add_idx_if_absent('knowledge_chunk', 'idx_kb_hit_count', '`knowledge_base_id`, `hit_count`');
CALL add_unique_idx_if_absent('knowledge_file_info', 'uk_knowledge_file_file_id', '`file_id`');
CALL add_unique_idx_if_absent('knowledge_document_import_job', 'uk_knowledge_document_import_file_id', '`file_id`');
CALL add_unique_idx_if_absent('knowledge_chunk', 'uk_knowledge_chunk_file_index', '`file_id`, `chunk_index`');
CALL add_idx_if_absent('knowledge_chunk', 'idx_kb_created', '`knowledge_base_id`, `create_time`');
CALL add_idx_if_absent('knowledge_file_info', 'idx_kb_file_created', '`knowledge_base_id`, `create_time`');
CALL add_idx_if_absent('knowledge_file_info', 'idx_knowledge_file_import_job', '`import_job_id`');
CREATE TABLE IF NOT EXISTS `knowledge_tag` (
`id` BIGINT NOT NULL AUTO_INCREMENT,
`knowledge_base_id` BIGINT NOT NULL,
`target_type` VARCHAR(32) NOT NULL DEFAULT 'KNOWLEDGE',
`target_id` VARCHAR(128) DEFAULT NULL,
`tag_key` VARCHAR(64) NOT NULL,
`tag_value` VARCHAR(128) NOT NULL,
`tag_group` VARCHAR(64) NOT NULL DEFAULT '默认',
`color` VARCHAR(32) NOT NULL DEFAULT '#409EFF',
`description` VARCHAR(512) DEFAULT NULL,
`parent_id` BIGINT DEFAULT NULL,
`sort_order` INT NOT NULL DEFAULT 0,
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `idx_kb_target` (`knowledge_base_id`, `target_type`, `target_id`),
KEY `idx_tag` (`tag_key`, `tag_value`),
KEY `idx_kb_tag_library` (`knowledge_base_id`, `tag_group`, `tag_key`, `tag_value`),
KEY `idx_kb_target_tag` (`knowledge_base_id`, `target_type`, `tag_key`, `tag_value`),
KEY `idx_parent` (`parent_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='knowledge operation tags';
CALL add_col_if_absent('knowledge_tag', 'tag_group', 'VARCHAR(64) NOT NULL DEFAULT ''默认'' COMMENT ''tag group'' AFTER `tag_value`');
CALL add_col_if_absent('knowledge_tag', 'color', 'VARCHAR(32) NOT NULL DEFAULT ''#409EFF'' COMMENT ''display color'' AFTER `tag_group`');
CALL add_col_if_absent('knowledge_tag', 'description', 'VARCHAR(512) DEFAULT NULL COMMENT ''tag description'' AFTER `color`');
CALL add_col_if_absent('knowledge_tag', 'parent_id', 'BIGINT DEFAULT NULL COMMENT ''parent tag id'' AFTER `description`');
CALL add_col_if_absent('knowledge_tag', 'sort_order', 'INT NOT NULL DEFAULT 0 COMMENT ''display order'' AFTER `parent_id`');
CALL add_idx_if_absent('knowledge_tag', 'idx_kb_tag_library', '`knowledge_base_id`, `tag_group`, `tag_key`, `tag_value`');
CALL add_idx_if_absent('knowledge_tag', 'idx_kb_target_tag', '`knowledge_base_id`, `target_type`, `tag_key`, `tag_value`');
CALL add_idx_if_absent('knowledge_tag', 'idx_parent', '`parent_id`');
CREATE TABLE IF NOT EXISTS `knowledge_question` (
`id` BIGINT NOT NULL AUTO_INCREMENT,
`knowledge_base_id` BIGINT NOT NULL,
`chunk_id` BIGINT DEFAULT NULL,
`question` VARCHAR(512) NOT NULL,
`hit_count` INT NOT NULL DEFAULT 0,
`source` VARCHAR(32) NOT NULL DEFAULT 'MANUAL',
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `idx_kb_chunk` (`knowledge_base_id`, `chunk_id`),
KEY `idx_question` (`question`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='knowledge question to paragraph mapping';
CREATE TABLE IF NOT EXISTS `knowledge_hit_log` (
`id` BIGINT NOT NULL AUTO_INCREMENT,
`knowledge_base_id` BIGINT NOT NULL,
`chunk_id` BIGINT DEFAULT NULL,
`query_text` VARCHAR(1024) NOT NULL,
`search_mode` VARCHAR(20) DEFAULT NULL,
`score` FLOAT DEFAULT NULL,
`direct_return` TINYINT(1) NOT NULL DEFAULT 0,
`trace_id` VARCHAR(128) DEFAULT NULL,
`user_id` VARCHAR(128) DEFAULT NULL,
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `idx_kb_time` (`knowledge_base_id`, `create_time`),
KEY `idx_trace` (`trace_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='knowledge retrieval hit log';
CALL add_idx_if_absent('knowledge_hit_log', 'idx_chunk_time', '`chunk_id`, `create_time`');
CALL add_idx_if_absent('knowledge_hit_log', 'idx_kb_score_time', '`knowledge_base_id`, `score`, `create_time`');
-- ============================================================================
-- 二、业务语义索引模块(历史 v3)
-- ============================================================================
CREATE TABLE IF NOT EXISTS `knowledge_business_index` (
`id` BIGINT AUTO_INCREMENT PRIMARY KEY,
`project_id` BIGINT DEFAULT NULL COMMENT '所属项目',
`project_code` VARCHAR(96) DEFAULT NULL COMMENT '所属项目编码',
`environment` VARCHAR(32) DEFAULT NULL COMMENT '环境',
`tenant_id` VARCHAR(96) DEFAULT NULL COMMENT '租户',
`index_code` VARCHAR(64) NOT NULL COMMENT '索引编码,唯一标识,对应 Milvus Collection 名称',
`index_name` VARCHAR(128) NOT NULL COMMENT '索引显示名称',
`source_system` VARCHAR(64) NOT NULL COMMENT '来源系统标识,如 material_system、contract_system',
`text_template` TEXT NOT NULL COMMENT '文本拼接模板,如:物资名称:{name},规格:{spec}',
`field_schema` JSON NOT NULL COMMENT '字段定义 JSON,描述模板中各占位符对应的字段名、标签、类型、是否必填等',
`embedding_model_instance_id` VARCHAR(64) DEFAULT NULL COMMENT 'Embedding model instance id',
`dimension` INT NOT NULL DEFAULT 1536 COMMENT '向量维度,需与 Embedding 模型输出一致',
`chunk_size` INT NOT NULL DEFAULT 500 COMMENT '附件切分大小(字符数)',
`chunk_overlap` INT NOT NULL DEFAULT 50 COMMENT '附件切分重叠(字符数)',
`split_type` VARCHAR(32) NOT NULL DEFAULT 'FIXED' COMMENT '附件切分策略: FIXED / PARAGRAPH / SEMANTIC',
`status` VARCHAR(16) NOT NULL DEFAULT 'ACTIVE' COMMENT '状态: ACTIVE-启用 / INACTIVE-停用',
`remark` VARCHAR(512) DEFAULT NULL COMMENT '备注说明',
`agent_memory_enabled` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '是否允许生成非权威 Agent 业务记忆引用',
`resolver_capability_key` VARCHAR(128) DEFAULT NULL COMMENT '按当前业务身份回源并重新鉴权的 Capability key',
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
UNIQUE KEY `uk_index_code` (`index_code`),
KEY `idx_biz_agent_memory` (`tenant_id`, `project_code`, `agent_memory_enabled`, `status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='业务语义索引注册表';
CREATE TABLE IF NOT EXISTS `knowledge_business_index_record` (
`id` BIGINT AUTO_INCREMENT PRIMARY KEY,
`index_code` VARCHAR(64) NOT NULL COMMENT '所属索引编码',
`biz_id` VARCHAR(128) NOT NULL COMMENT '业务主键(由业务系统定义,如合同编号、物资编号)',
`biz_type` VARCHAR(64) DEFAULT NULL COMMENT '业务子类型(可选,业务系统自定义分类)',
`search_text` TEXT NOT NULL COMMENT '由模板渲染生成的索引文本',
`fields_json` JSON DEFAULT NULL COMMENT '业务系统推送的原始字段(便于模板变更后重建索引)',
`metadata_json` JSON DEFAULT NULL COMMENT '元数据(搜索结果中回显的摘要信息,不参与语义搜索)',
`source_version` VARCHAR(128) DEFAULT NULL COMMENT '业务源版本;Agent 回源时用于新鲜度校验',
`source_updated_at` DATETIME DEFAULT NULL COMMENT '业务源更新时间;不替代 source_version',
`owner_user_id` VARCHAR(64) DEFAULT NULL COMMENT '数据所有者用户 ID(用于权限过滤)',
`owner_org_id` VARCHAR(64) DEFAULT NULL COMMENT '数据所属组织 ID(用于权限过滤)',
`vector_id` VARCHAR(128) DEFAULT NULL COMMENT '主记录在 Milvus 中的向量 ID',
`has_attachment` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '是否包含附件:0-无 1-有',
`status` VARCHAR(16) NOT NULL DEFAULT 'ACTIVE' COMMENT '状态: ACTIVE-正常 / DELETED-已删除',
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
UNIQUE KEY `uk_index_biz` (`index_code`, `biz_id`),
INDEX `idx_owner_org` (`index_code`, `owner_org_id`),
INDEX `idx_owner_user` (`index_code`, `owner_user_id`),
INDEX `idx_biz_source_version` (`index_code`, `biz_id`, `source_version`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='业务索引记录表';
CREATE TABLE IF NOT EXISTS `knowledge_business_index_attachment` (
`id` BIGINT AUTO_INCREMENT PRIMARY KEY,
`index_code` VARCHAR(64) NOT NULL COMMENT '所属索引编码',
`biz_id` VARCHAR(128) NOT NULL COMMENT '关联的业务主键',
`record_id` BIGINT NOT NULL COMMENT '关联 knowledge_business_index_record.id',
`file_name` VARCHAR(256) NOT NULL COMMENT '附件原始文件名',
`file_type` VARCHAR(32) DEFAULT NULL COMMENT '文件类型(pdf / docx / txt 等)',
`raw_text` MEDIUMTEXT DEFAULT NULL COMMENT '附件解析后的完整原始文本(用于重建索引)',
`chunk_index` INT NOT NULL COMMENT '切分序号(从 0 开始)',
`chunk_content` TEXT NOT NULL COMMENT '切分后的文本片段',
`vector_id` VARCHAR(128) DEFAULT NULL COMMENT '该 Chunk 在 Milvus 中的向量 ID',
`status` VARCHAR(16) NOT NULL DEFAULT 'ACTIVE',
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
INDEX `idx_biz` (`index_code`, `biz_id`),
INDEX `idx_record` (`record_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='附件索引表(Chunk 级别)';
-- ============================================================================
-- 三、Tool 扫描模块:项目 / 模块 / 扫描工具(历史 v1 + v5 + v6 + v7)
-- ============================================================================
CREATE TABLE IF NOT EXISTS `capability_scan_project` (
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键',
`name` VARCHAR(128) NOT NULL COMMENT '项目名称',
`base_url` VARCHAR(256) NOT NULL COMMENT '项目域名',
`context_path` VARCHAR(128) NOT NULL DEFAULT '' COMMENT '公共路径前缀',
`scan_path` VARCHAR(512) NOT NULL COMMENT '磁盘扫描目录',
`scan_type` VARCHAR(32) NOT NULL COMMENT '扫描方式: openapi/controller/auto',
`spec_file` VARCHAR(256) DEFAULT NULL COMMENT 'OpenAPI 规范文件相对路径',
`tool_count` INT NOT NULL DEFAULT 0 COMMENT '扫描发现的接口数',
`status` VARCHAR(32) NOT NULL DEFAULT 'created' COMMENT '状态: created/scanning/scanned/failed',
`error_message` TEXT DEFAULT NULL COMMENT '失败原因',
`auth_type` VARCHAR(32) NOT NULL DEFAULT 'none' COMMENT '鉴权: none / api_key',
`auth_api_key_in` VARCHAR(16) DEFAULT NULL COMMENT 'api_key 时: header / query',
`auth_api_key_name` VARCHAR(128) DEFAULT NULL COMMENT 'API Key 参数名',
`auth_api_key_value` TEXT DEFAULT NULL COMMENT 'API Key 参数值',
`scan_settings` JSON DEFAULT NULL COMMENT '扫描项 JSON 配置',
`last_scanned_at` DATETIME DEFAULT NULL COMMENT '上次成功扫描时间(增量基线)',
`create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_scan_project_name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='扫描项目表';
-- 已存在、且建表时尚无鉴权列的旧库:由下列调用补齐;新库建表已含四列,此处为幂等 no-op
CALL add_col_if_absent('capability_scan_project', 'auth_type', 'VARCHAR(32) NOT NULL DEFAULT ''none'' COMMENT ''鉴权: none / api_key'' AFTER `error_message`');
CALL add_col_if_absent('capability_scan_project', 'auth_api_key_in', 'VARCHAR(16) DEFAULT NULL COMMENT ''api_key 时: header / query'' AFTER `auth_type`');
CALL add_col_if_absent('capability_scan_project', 'auth_api_key_name', 'VARCHAR(128) DEFAULT NULL COMMENT ''API Key 参数名'' AFTER `auth_api_key_in`');
CALL add_col_if_absent('capability_scan_project', 'auth_api_key_value', 'TEXT DEFAULT NULL COMMENT ''API Key 参数值'' AFTER `auth_api_key_name`');
CALL add_col_if_absent('capability_scan_project', 'scan_settings', 'JSON DEFAULT NULL COMMENT ''扫描项 JSON 配置'' AFTER `auth_api_key_value`');
CALL add_col_if_absent('capability_scan_project', 'last_scanned_at', 'DATETIME DEFAULT NULL COMMENT ''上次成功扫描时间(增量基线)'' AFTER `scan_settings`');
CREATE TABLE IF NOT EXISTS `capability_scan_module` (
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键',
`project_id` BIGINT NOT NULL COMMENT '所属扫描项目',
`name` VARCHAR(128) NOT NULL COMMENT '模块唯一名,默认=Controller 类名',
`display_name` VARCHAR(256) DEFAULT NULL COMMENT '用户可编辑显示名',
`source_classes` TEXT DEFAULT NULL COMMENT '合并后聚合的 Controller 类名 JSON 数组',
`create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_scan_module_project_name` (`project_id`, `name`),
KEY `idx_scan_module_project` (`project_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='扫描项目模块表';
CREATE TABLE IF NOT EXISTS `capability_scan_project_tool` (
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键',
`project_id` BIGINT NOT NULL COMMENT '扫描项目 ID',
`module_id` BIGINT DEFAULT NULL COMMENT '扫描模块 ID',
`name` VARCHAR(128) NOT NULL COMMENT '项目内工具名(snake_case)',
`title` VARCHAR(192) NOT NULL COMMENT '用户可读的简短工具名称',
`description` TEXT NOT NULL COMMENT '描述',
`parameters_json` TEXT DEFAULT NULL COMMENT '参数定义 JSON',
`source` VARCHAR(32) NOT NULL DEFAULT 'scanner' COMMENT '来源: scanner',
`source_location` VARCHAR(512) DEFAULT NULL COMMENT '来源定位',
`http_method` VARCHAR(8) DEFAULT NULL COMMENT 'HTTP 方法',
`base_url` VARCHAR(256) DEFAULT NULL COMMENT '目标服务基础地址',
`context_path` VARCHAR(128) DEFAULT NULL COMMENT '服务公共前缀',
`endpoint_path` VARCHAR(256) DEFAULT NULL COMMENT '接口路径',
`request_body_type` VARCHAR(256) DEFAULT NULL COMMENT '请求体类型',
`response_type` VARCHAR(256) DEFAULT NULL COMMENT '响应类型',
`ai_description` VARCHAR(1024) DEFAULT NULL COMMENT 'AI 摘要(冗余)',
`capability_metadata_json` MEDIUMTEXT DEFAULT NULL COMMENT '@ReachCapability 能力声明元数据 JSON',
`sensitive_data_json` TEXT DEFAULT NULL COMMENT '敏感数据扫描结果 JSON',
`enabled` TINYINT NOT NULL DEFAULT 0 COMMENT '是否启用',
`global_tool_definition_id` BIGINT DEFAULT NULL COMMENT '已注册为全局 capability_tool_definition.id,未注册为 NULL',
`create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_project_tool_name` (`project_id`, `name`),
KEY `idx_project_id` (`project_id`),
KEY `idx_module_id` (`module_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='扫描项目接口(未注册为全局 Tool 前)';
CALL add_col_if_absent('capability_scan_project_tool', 'title', 'VARCHAR(192) DEFAULT NULL COMMENT ''用户可读的简短工具名称'' AFTER `name`');
UPDATE `capability_scan_project_tool` SET `title` = `name` WHERE `title` IS NULL OR TRIM(`title`) = '';
ALTER TABLE `capability_scan_project_tool` MODIFY COLUMN `title` VARCHAR(192) NOT NULL COMMENT '用户可读的简短工具名称';
CALL add_col_if_absent('capability_scan_project_tool', 'capability_metadata_json', 'MEDIUMTEXT DEFAULT NULL COMMENT ''@ReachCapability 能力声明元数据 JSON'' AFTER `ai_description`');
CALL add_col_if_absent('capability_scan_project_tool', 'sensitive_data_json', 'TEXT DEFAULT NULL COMMENT ''敏感数据扫描结果 JSON'' AFTER `capability_metadata_json`');
CALL add_col_if_absent('capability_scan_project_tool', 'removed_from_source', 'TINYINT NOT NULL DEFAULT 0 COMMENT ''1=扫描或 SDK 源中已无此接口(墓碑行,可能仍关联全局 Tool)'' AFTER `global_tool_definition_id`');
CALL add_col_if_absent('capability_scan_project_tool', 'removed_at', 'DATETIME DEFAULT NULL COMMENT ''标记为从源移除的时间'' AFTER `removed_from_source`');
CREATE TABLE IF NOT EXISTS `capability_semantic_doc` (
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键',
`level` VARCHAR(16) NOT NULL COMMENT '层级: project / module / tool',
`project_id` BIGINT DEFAULT NULL COMMENT '归属项目 ID',
`module_id` BIGINT DEFAULT NULL COMMENT '归属模块 ID(level=module/tool 时有值)',
`tool_id` BIGINT DEFAULT NULL COMMENT '归属工具 ID(level=tool 时有值)',
`content_md` MEDIUMTEXT DEFAULT NULL COMMENT 'LLM 生成/人工编辑后的 Markdown 文档',
`prompt_version` VARCHAR(32) DEFAULT NULL COMMENT '生成使用的 prompt 版本',
`model_name` VARCHAR(64) DEFAULT NULL COMMENT '生成使用的模型名',
`token_usage` INT NOT NULL DEFAULT 0 COMMENT '单次生成消耗的 total_tokens',
`status` VARCHAR(16) NOT NULL DEFAULT 'draft' COMMENT '状态: draft / generated / edited',
`create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_semantic_doc_ref` (`level`, `project_id`, `module_id`, `tool_id`),
KEY `idx_semantic_doc_project` (`project_id`),
KEY `idx_semantic_doc_module` (`module_id`),
KEY `idx_semantic_doc_tool` (`tool_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='三层语义文档表';
-- ============================================================================
-- 四、Tool 能力表
-- ============================================================================
CREATE TABLE IF NOT EXISTS `capability_tool_definition` (
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键',
`name` VARCHAR(128) NOT NULL COMMENT '能力唯一标识 (snake_case)',
`title` VARCHAR(192) NOT NULL COMMENT '用户可读的简短工具名称',
`description` TEXT NOT NULL COMMENT '能力描述',
`ai_description` MEDIUMTEXT DEFAULT NULL COMMENT 'LLM 生成的业务语义描述(Agent 运行时优先使用)',
`capability_metadata_json` MEDIUMTEXT DEFAULT NULL COMMENT '@ReachCapability 能力声明元数据 JSON',
`parameters_json` TEXT DEFAULT NULL COMMENT '参数定义 JSON',
`source` VARCHAR(32) NOT NULL DEFAULT 'manual' COMMENT '来源: code/scanner/manual',
`source_location` VARCHAR(512) DEFAULT NULL COMMENT '来源详情',
`http_method` VARCHAR(8) DEFAULT NULL COMMENT 'HTTP 方法',
`base_url` VARCHAR(256) DEFAULT NULL COMMENT '目标服务基础地址',
`context_path` VARCHAR(128) DEFAULT NULL COMMENT '服务公共前缀',
`endpoint_path` VARCHAR(256) DEFAULT NULL COMMENT '接口路径 (不含 contextPath)',
`request_body_type` VARCHAR(256) DEFAULT NULL COMMENT '请求体类型',
`response_type` VARCHAR(256) DEFAULT NULL COMMENT '响应类型',
`project_id` BIGINT DEFAULT NULL COMMENT '关联的扫描项目 ID',
`module_id` BIGINT DEFAULT NULL COMMENT '所属模块(capability_scan_module.id)',
`enabled` TINYINT NOT NULL DEFAULT 1 COMMENT '是否启用',
`side_effect` VARCHAR(24) NOT NULL DEFAULT 'WRITE' COMMENT '副作用等级: NONE / READ_ONLY / IDEMPOTENT_WRITE / WRITE / IRREVERSIBLE',
`create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_name` (`name`),
KEY `idx_project_id` (`project_id`),
KEY `idx_tool_module_id` (`module_id`),
KEY `idx_enabled` (`enabled`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Tool 能力表';
-- 兼容老库:如果 capability_tool_definition 已存在但缺少当前基线列,这里补齐(CREATE TABLE IF NOT EXISTS 不会重建)
CALL add_col_if_absent('capability_tool_definition', 'title', 'VARCHAR(192) DEFAULT NULL COMMENT ''用户可读的简短工具名称'' AFTER `name`');
UPDATE `capability_tool_definition` SET `title` = `name` WHERE `title` IS NULL OR TRIM(`title`) = '';
ALTER TABLE `capability_tool_definition` MODIFY COLUMN `title` VARCHAR(192) NOT NULL COMMENT '用户可读的简短工具名称';
CALL add_col_if_absent('capability_tool_definition', 'ai_description', 'MEDIUMTEXT DEFAULT NULL COMMENT ''LLM 生成的业务语义描述'' AFTER `description`');
CALL add_col_if_absent('capability_tool_definition', 'capability_metadata_json', 'MEDIUMTEXT DEFAULT NULL COMMENT ''@ReachCapability 能力声明元数据 JSON'' AFTER `ai_description`');
CALL add_col_if_absent('capability_tool_definition', 'project_id', 'BIGINT DEFAULT NULL COMMENT ''关联的扫描项目 ID'' AFTER `response_type`');
CALL add_col_if_absent('capability_tool_definition', 'module_id', 'BIGINT DEFAULT NULL COMMENT ''所属模块'' AFTER `project_id`');
CALL add_col_if_absent('capability_tool_definition', 'side_effect', 'VARCHAR(24) NOT NULL DEFAULT ''WRITE'' COMMENT ''副作用等级'' AFTER `enabled`');
CALL add_idx_if_absent('capability_tool_definition', 'idx_project_id', 'project_id');
CALL add_idx_if_absent('capability_tool_definition', 'idx_tool_module_id', 'module_id');
CALL add_idx_if_absent('capability_tool_definition', 'idx_enabled', 'enabled');
-- ============================================================================
-- 五、Runtime 根运行事实与执行子事件
-- ============================================================================
CREATE TABLE IF NOT EXISTS `runtime_internal_auth_nonce` (
`nonce` VARCHAR(128) NOT NULL COMMENT 'Control→Runtime HMAC nonce',
`caller` VARCHAR(96) NOT NULL COMMENT '调用方服务 ID',
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '写入时间',
PRIMARY KEY (`nonce`),
KEY `idx_runtime_internal_auth_nonce_created` (`created_at`)