From d9fec80e6cec138c8933f5c0fe7e80abe95ec825 Mon Sep 17 00:00:00 2001 From: let5sne Date: Wed, 15 Jul 2026 00:51:42 +0800 Subject: [PATCH] fix(aihr): version knowledge feedback migrations --- ...ihr_20260715_knowledge_feedback_mysql8.sql | 92 +++++++++++++++++++ docs/BRD_IMPLEMENTATION_AUDIT.md | 2 + docs/BRD_PRODUCTION_MIGRATION_RUNBOOK.md | 6 +- scripts/demo-check.sh | 2 + scripts/tests/aihr-schema-migrations.test.sh | 30 +++++- 5 files changed, 129 insertions(+), 3 deletions(-) create mode 100644 backend/script/sql/update/aihr_20260715_knowledge_feedback_mysql8.sql diff --git a/backend/script/sql/update/aihr_20260715_knowledge_feedback_mysql8.sql b/backend/script/sql/update/aihr_20260715_knowledge_feedback_mysql8.sql new file mode 100644 index 00000000..715b6fa3 --- /dev/null +++ b/backend/script/sql/update/aihr_20260715_knowledge_feedback_mysql8.sql @@ -0,0 +1,92 @@ +-- AIHR 知识反馈与知识缺口日志迁移(MySQL 8.x) +-- 补齐生产不能依赖运行时懒建表的两张治理表;不写入业务数据,可重复执行。 + +CREATE TABLE IF NOT EXISTS `aihr_knowledge_gap` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键', + `tenant_id` varchar(20) DEFAULT '000000' COMMENT '租户编号', + `query_text` varchar(1000) NOT NULL COMMENT '未命中问题', + `category` varchar(100) DEFAULT NULL COMMENT '知识分类', + `position` varchar(80) DEFAULT NULL COMMENT '岗位', + `source` varchar(50) DEFAULT 'knowledge_search' COMMENT '来源', + `status` varchar(30) DEFAULT '待补充' COMMENT '状态', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + PRIMARY KEY (`id`), + KEY `idx_aihr_knowledge_gap_status` (`tenant_id`, `status`, `create_time`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='AI HR 知识缺口日志'; + +CREATE TABLE IF NOT EXISTS `aihr_knowledge_answer_feedback` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键', + `tenant_id` varchar(20) DEFAULT '000000' COMMENT '租户编号', + `query_text` varchar(1000) NOT NULL COMMENT '问题原文', + `query_norm` varchar(500) NOT NULL COMMENT '规范化问题', + `fragment_id` bigint NOT NULL COMMENT '知识片段ID', + `verdict` varchar(10) NOT NULL COMMENT '反馈: up/down', + `category` varchar(100) DEFAULT NULL COMMENT '知识分类', + `position` varchar(80) DEFAULT NULL COMMENT '岗位', + `source` varchar(50) DEFAULT 'knowledge_search' COMMENT '来源', + `review_id` bigint DEFAULT NULL COMMENT '对应SOP问答评审ID', + `review_status` varchar(30) DEFAULT '待复核' COMMENT '复核状态', + `reviewer` varchar(100) DEFAULT NULL COMMENT '复核人', + `reviewed_time` datetime DEFAULT NULL COMMENT '复核时间', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + PRIMARY KEY (`id`), + UNIQUE KEY `uk_aihr_answer_feedback_pair` (`tenant_id`, `query_norm`, `fragment_id`), + KEY `idx_aihr_answer_feedback_verdict` (`tenant_id`, `query_norm`, `fragment_id`, `verdict`), + KEY `idx_aihr_answer_feedback_review` (`tenant_id`, `review_status`, `create_time`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='AI HR 知识答案反馈'; + +SET @aihr_feedback_table_exists := ( + SELECT COUNT(*) + FROM information_schema.TABLES + WHERE TABLE_SCHEMA = DATABASE() + AND TABLE_NAME = 'aihr_knowledge_answer_feedback' +); + +SET @aihr_feedback_review_id_exists := ( + SELECT COUNT(*) + FROM information_schema.COLUMNS + WHERE TABLE_SCHEMA = DATABASE() + AND TABLE_NAME = 'aihr_knowledge_answer_feedback' + AND COLUMN_NAME = 'review_id' +); +SET @aihr_feedback_review_id_ddl := IF( + @aihr_feedback_table_exists = 1 AND @aihr_feedback_review_id_exists = 0, + 'ALTER TABLE aihr_knowledge_answer_feedback ADD COLUMN `review_id` bigint DEFAULT NULL COMMENT ''对应SOP问答评审ID'' AFTER `source`', + 'SELECT 1' +); +PREPARE aihr_feedback_review_id_stmt FROM @aihr_feedback_review_id_ddl; +EXECUTE aihr_feedback_review_id_stmt; +DEALLOCATE PREPARE aihr_feedback_review_id_stmt; + +SET @aihr_feedback_reviewer_exists := ( + SELECT COUNT(*) + FROM information_schema.COLUMNS + WHERE TABLE_SCHEMA = DATABASE() + AND TABLE_NAME = 'aihr_knowledge_answer_feedback' + AND COLUMN_NAME = 'reviewer' +); +SET @aihr_feedback_reviewer_ddl := IF( + @aihr_feedback_table_exists = 1 AND @aihr_feedback_reviewer_exists = 0, + 'ALTER TABLE aihr_knowledge_answer_feedback ADD COLUMN `reviewer` varchar(100) DEFAULT NULL COMMENT ''复核人'' AFTER `review_status`', + 'SELECT 1' +); +PREPARE aihr_feedback_reviewer_stmt FROM @aihr_feedback_reviewer_ddl; +EXECUTE aihr_feedback_reviewer_stmt; +DEALLOCATE PREPARE aihr_feedback_reviewer_stmt; + +SET @aihr_feedback_reviewed_time_exists := ( + SELECT COUNT(*) + FROM information_schema.COLUMNS + WHERE TABLE_SCHEMA = DATABASE() + AND TABLE_NAME = 'aihr_knowledge_answer_feedback' + AND COLUMN_NAME = 'reviewed_time' +); +SET @aihr_feedback_reviewed_time_ddl := IF( + @aihr_feedback_table_exists = 1 AND @aihr_feedback_reviewed_time_exists = 0, + 'ALTER TABLE aihr_knowledge_answer_feedback ADD COLUMN `reviewed_time` datetime DEFAULT NULL COMMENT ''复核时间'' AFTER `reviewer`', + 'SELECT 1' +); +PREPARE aihr_feedback_reviewed_time_stmt FROM @aihr_feedback_reviewed_time_ddl; +EXECUTE aihr_feedback_reviewed_time_stmt; +DEALLOCATE PREPARE aihr_feedback_reviewed_time_stmt; diff --git a/docs/BRD_IMPLEMENTATION_AUDIT.md b/docs/BRD_IMPLEMENTATION_AUDIT.md index c7b85a83..46071179 100644 --- a/docs/BRD_IMPLEMENTATION_AUDIT.md +++ b/docs/BRD_IMPLEMENTATION_AUDIT.md @@ -1,5 +1,7 @@ # BRD 功能审查与未完成项记录 +- 2026-07-15 BRD G3/4.7 生产迁移缺口修复:`aihr_knowledge_gap` 与 `aihr_knowledge_answer_feedback` 此前只在 `AihrSopSeedService` 运行时懒建,生产迁移 Runbook 没有对应版本化脚本,可能出现应用启动前结构缺失、反馈/知识缺口审计不可用。现新增幂等 MySQL 8 迁移,兼容旧反馈表补齐 `review_id/reviewer/reviewed_time`,纳入迁移 Runbook、迁移回归测试和 `demo-check` marker;仅补结构,不写业务数据,尚未执行生产迁移。 + - 2026-07-15 BRD 剩余功能复核:重新核对动态难度、案例视频和 SOP 反馈治理三条链路。场景表已有 `difficulty` 但没有 HR 确认的升降级阈值、候选场景映射和人工关闭规则;案例当前能保存/回放脱敏音频,但没有正式预渲染视频样片及对应学习场景契约;SOP 负反馈队列已有问题、片段、评审状态和人工复核入口,但没有经业务批准的纠正内容、版本替换和署名入库规则。本轮不硬编码业务规则、不用音频冒充视频、不把“标记已复核”伪装成知识修复;以上继续作为 P1/发布前输入项跟踪。 - 2026-07-15 BRD 4.7 知识答案负反馈闭环修复:SOP 检索此前在某问题命中的片段全部被点踩时仍保留原答案,违背“同一问题后续不再推送该条目”的约定;现由共享检索过滤返回无明确依据的答案并保留提示,不再把被点踩片段作为答案证据。新增 `AihrSopSeedServiceTest.allDownVotedHitsAreSuppressed` 和 `demo-check` marker;未修改业务数据,后续仍需正式员工问答样本验证替代答案质量。 diff --git a/docs/BRD_PRODUCTION_MIGRATION_RUNBOOK.md b/docs/BRD_PRODUCTION_MIGRATION_RUNBOOK.md index 3b50b953..6e8169ab 100644 --- a/docs/BRD_PRODUCTION_MIGRATION_RUNBOOK.md +++ b/docs/BRD_PRODUCTION_MIGRATION_RUNBOOK.md @@ -34,6 +34,7 @@ mysql --default-character-set=utf8mb4 "$DB_NAME" < backend/script/sql/update/aih mysql --default-character-set=utf8mb4 "$DB_NAME" < backend/script/sql/update/aihr_20260714_practice_five_dimensions_mysql8.sql mysql --default-character-set=utf8mb4 "$DB_NAME" < backend/script/sql/update/aihr_20260714_daily_drill_score_mode_mysql8.sql mysql --default-character-set=utf8mb4 "$DB_NAME" < backend/script/sql/update/aihr_20260714_sop_requester_identity_mysql8.sql +mysql --default-character-set=utf8mb4 "$DB_NAME" < backend/script/sql/update/aihr_20260715_knowledge_feedback_mysql8.sql mysql --default-character-set=utf8mb4 "$DB_NAME" < backend/script/sql/update/aihr_20260714_org_hire_date_mysql8.sql ``` @@ -49,7 +50,8 @@ FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name IN ( 'aihr_practice_scenario', 'aihr_practice_rubric', 'aihr_practice_rubric_dimension', - 'aihr_practice_audio', 'aihr_practice_audio_upload', 'aihr_practice_calibration' + 'aihr_practice_audio', 'aihr_practice_audio_upload', 'aihr_practice_calibration', + 'aihr_knowledge_gap', 'aihr_knowledge_answer_feedback' ) ORDER BY table_name; @@ -71,7 +73,7 @@ WHERE tenant_id = '000000' AND code IN ('summary_card', 'sop_answer', 'mentor_rewrite', 'review_annotation', 'prep_card', 'supervision_image_analysis_maintenance'); ``` -预期是三张场景/Rubric 表和三张证据表均存在,字段查询覆盖所有列,内置 Prompt 数量为 `6`。这只证明 schema/seed 迁移完成,不证明正式试点完成。 +预期是三张场景/Rubric 表、三张证据表和两张知识治理表均存在,字段查询覆盖所有列,内置 Prompt 数量为 `6`。这只证明 schema/seed 迁移完成,不证明正式试点完成。 ## 迁移后应用回归 diff --git a/scripts/demo-check.sh b/scripts/demo-check.sh index da40848c..2138ade4 100755 --- a/scripts/demo-check.sh +++ b/scripts/demo-check.sh @@ -554,6 +554,8 @@ contains backend/script/sql/update/aihr_20260714_practice_brd_scenarios_mysql8.s contains backend/script/sql/update/aihr_20260714_brd_sop_seed_mysql8.sql "sop_service_promotion_v1" contains backend/script/sql/update/aihr_20260714_brd_sop_seed_mysql8.sql "sop_daily_service_v1" contains backend/script/sql/update/aihr_20260714_prompt_template_seed_mysql8.sql "summary_card" +contains backend/script/sql/update/aihr_20260715_knowledge_feedback_mysql8.sql "aihr_knowledge_gap" +contains backend/script/sql/update/aihr_20260715_knowledge_feedback_mysql8.sql "aihr_knowledge_answer_feedback" contains backend/script/sql/aihr_practice_mysql8.sql "aihr_prompt_template" contains backend/script/sql/aihr_practice_mysql8.sql "summary_card" contains frontend/src/views/train/practice.vue "训练前预习卡" diff --git a/scripts/tests/aihr-schema-migrations.test.sh b/scripts/tests/aihr-schema-migrations.test.sh index 4df322f7..a8affe4c 100755 --- a/scripts/tests/aihr-schema-migrations.test.sh +++ b/scripts/tests/aihr-schema-migrations.test.sh @@ -67,6 +67,34 @@ mysql "$DB" < "$ROOT_DIR/backend/script/sql/update/aihr_20260714_prompt_template prompt_template_count="$(mysql "$DB" -N -B -e "SELECT COUNT(*) FROM aihr_prompt_template WHERE tenant_id='000000';")" test "$prompt_template_count" = '6' +mysql "$DB" < "$ROOT_DIR/backend/script/sql/update/aihr_20260715_knowledge_feedback_mysql8.sql" +mysql "$DB" < "$ROOT_DIR/backend/script/sql/update/aihr_20260715_knowledge_feedback_mysql8.sql" +knowledge_feedback_tables="$(mysql "$DB" -N -B -e "SELECT GROUP_CONCAT(table_name ORDER BY table_name) FROM information_schema.tables WHERE table_schema='$DB' AND table_name IN ('aihr_knowledge_answer_feedback','aihr_knowledge_gap');")" +test "$knowledge_feedback_tables" = 'aihr_knowledge_answer_feedback,aihr_knowledge_gap' + +mysql "$DB" -e "DROP TABLE aihr_knowledge_answer_feedback" +mysql "$DB" <<'SQL' +CREATE TABLE aihr_knowledge_answer_feedback ( + id bigint NOT NULL AUTO_INCREMENT, + tenant_id varchar(20) DEFAULT '000000', + query_text varchar(1000) NOT NULL, + query_norm varchar(500) NOT NULL, + fragment_id bigint NOT NULL, + verdict varchar(10) NOT NULL, + category varchar(100), + position varchar(80), + source varchar(50), + review_status varchar(30), + create_time datetime, + update_time datetime, + PRIMARY KEY (id) +) ENGINE=InnoDB; +SQL +mysql "$DB" < "$ROOT_DIR/backend/script/sql/update/aihr_20260715_knowledge_feedback_mysql8.sql" +mysql "$DB" < "$ROOT_DIR/backend/script/sql/update/aihr_20260715_knowledge_feedback_mysql8.sql" +feedback_review_columns="$(mysql "$DB" -N -B -e "SELECT GROUP_CONCAT(column_name ORDER BY ordinal_position) FROM information_schema.columns WHERE table_schema='$DB' AND table_name='aihr_knowledge_answer_feedback' AND column_name IN ('review_id','reviewer','reviewed_time');")" +test "$feedback_review_columns" = 'review_id,reviewer,reviewed_time' + mysql "$DB" < "$ROOT_DIR/backend/script/sql/update/aihr_20260714_practice_evidence_mysql8.sql" mysql "$DB" < "$ROOT_DIR/backend/script/sql/update/aihr_20260714_practice_evidence_mysql8.sql" evidence_tables="$(mysql "$DB" -N -B -e "SELECT GROUP_CONCAT(table_name ORDER BY table_name) FROM information_schema.tables WHERE table_schema='$DB' AND table_name IN ('aihr_practice_audio','aihr_practice_audio_upload','aihr_practice_calibration');")" @@ -98,4 +126,4 @@ mysql "$DB" < "$ROOT_DIR/backend/script/sql/update/aihr_20260714_org_hire_date_m org_columns="$(mysql "$DB" -N -B -e "SELECT GROUP_CONCAT(column_name ORDER BY ordinal_position) FROM information_schema.columns WHERE table_schema='$DB' AND table_name='aihr_org_snapshot' AND column_name='hire_date';")" test "$org_columns" = 'hire_date' -echo "PASS: AIHR legacy schema migrations are idempotent, including case media and learning fields" +echo "PASS: AIHR legacy schema migrations are idempotent, including case media, learning, and knowledge feedback fields"