# prop-ai-hr 数据质量与脏数据治理专项审计
> 实施状态(2026-08-02):本报告正文保留改造前的只读审计基线。当前工作树已在本地完成 P0 主门禁,并落地 P1 的版本化规范化、独立隐私脱敏派生与复扫、结构感知切片、SimHash 近重复、异步语义重复候选、同名版本冲突、确定性 claim 级冲突证据、带管理端人工审核的版本化术语表,以及 P2 的索引死信健康度、真实召回证据、答案争议回到具体 chunk/asset 的人工 `KEEP/WITHDRAW` 闭环、持久化质量告警、Actuator 健康项和可失败的黄金检索评测门禁。`dq-gate-v3` 还会以软 reason code 标记页码、重复页眉页脚、领域无关、案例上下文缺失和孤立片段,不改写原文、不自动拒绝或批准。历史附件可通过只读预览和带 manifest 的 CLI 按游标恢复纳管;任何历史数据都不能自动批准。AI 整理案例会永久保存 synthetic、模型/生成器、prompt 版本、原始音频和人工审核 provenance。100–300 条真实业务黄金集标注、复杂适用条件阈值标定、生产告警平台接入和全量历史重清洗尚未完成。该状态不代表生产部署或业务资料已获批准。
>
> 快照说明:正文中的“本地 MinIO 为空、Qdrant collection 不存在”等数据是第一阶段只读审计时的基线,不是 2026-08-01 本地 E2E 完成后的运行状态;最新实施证据见第 19 节。
> 审计日期:2026-08-01
> 审计方式:代码、SQL 迁移、测试及本地运行数据的只读审计
> 审计结论适用范围:当前工作区(包括审计时已经存在、尚未提交的引用定位器改动)与本机开发数据快照;不等同于生产数据全量结论
> 第一阶段变更边界:只生成本报告,未修改业务代码、配置、数据库、对象存储或向量索引;后续本地实施状态见第 19 节
## 1. 执行摘要
当前系统已经具备若干有价值的局部控制:知识查询以服务端计算“租户 + 调用应用 + 主体授权”的空间交集;文件接入有大小/解析失败处理和文件、文本哈希精确去重;正式制度查询有来源权威性、版本、审批、生效和失效日期门禁;个人知识有私有对象存储、所有权校验、精确哈希去重、发布审核和确定性脱敏;陪练场景有内容版本、哈希和高风险双人审核;考试发布和显式记忆也有人工或用户确认。
但这些控制没有形成统一的数据质量生命周期。普通企业资料的主路径实际是:上传或导入后,只要解析出非空文本,就直接切片写入 `aihr_knowledge_fragment`,随后向量化并可被普通检索使用。该路径没有通用的隐私检查、领域验证、上下文完整性检查、近重复/语义重复、质量原因码、隔离区或人工批准门禁。结论是:**当前存在 `RAW/PARSED -> INDEXED` 直接路径,目标生命周期并未全局落地。**
最高风险还包括:个人经验经一次发布审核后直接写入企业知识表;模型整理或兜底总结可直接把案例标成“已入库”;考试生成从租户全部片段取材,未复用文档批准/有效期门禁;向量删除失败仅尽力忽略,没有持久化重试;查询审计没有记录具体片段修订,错误答案无法从 `request_id` 稳定反查污染版本。普通企业 RAG 还把片段原文直接拼进提示词,缺少个人问答路径已有的“来源是不可信数据、不得执行其中指令”边界。
本地只读快照进一步证明风险已经落地,而不只是理论可能:1,046 个附件全部处于“已解析”,8,607 个片段中检测到 1,897 个全局精确重复余量、1,178 个疑似页码/分页噪声命中、19 个含 UTF-8 替换字符的片段、6 个找不到附件的片段;1,207 个上传任务中 94 个失败,失败率 7.79%。正式来源治理仅覆盖 10 个附件,约占附件数 0.96%。本地 Qdrant collection 不存在,本地两个 MinIO bucket 均无对象,因此本机数据库中的原文可恢复性和向量一致性无法成立。一次真实移动端请假/考勤问题还召回了招聘、垃圾站保洁、防汛等无关引用,属于已观察到的检索相关性失败。
建议按最小增量方式修复,不整体重写现有知识平台:保留 `sys_oss`、`aihr_knowledge_*` 和现有权限模型,新增不可变原始资产、版本、质量评估、问题明细、审核决策、片段修订、血缘和索引 outbox 侧表。生产检索只允许读取 `PUBLISHED` 且版本有效的片段修订;普通上传、个人发布、案例和 AI 生成内容统一先进入隔离/待审区。P0 应优先关闭新污染入口、建立可靠撤回与片段级审计,再迁移历史数据。
## 2. 审计方法与边界
### 2.1 审计方法
1. 由 HTTP Controller 反向跟踪上传、导入、检索、案例、考试、陪练、个人知识、记忆和反馈到 Service、SQL 与存储对象。
2. 检查解析器、文本规范化、切片、哈希去重、embedding、Qdrant payload/filter、删除与重建代码。
3. 检查知识、个人知识、案例、陪练、考试、记忆、反馈、组织快照相关建表和增量迁移。
4. 检查现有单元测试中对租户、所有权、审批、去重、正式制度和失败路径的断言。
5. 对本机 MySQL、Qdrant 和 MinIO 做只读计数、孤儿关系、重复、字符异常及运行状态检查;未读取或披露业务正文、姓名、手机号和密钥。
### 2.2 证据口径与限制
- 文件行号指向审计时工作区,不保证后续代码变更后仍保持相同行号。
- 本地数据库来自当前开发环境,只说明本地快照;不能外推为生产全量数据质量。
- 本地 MinIO 无对象、Qdrant collection 不存在,因此未能验证远端原文件完整性、生产向量数量和线上删除一致性。
- “有”表示所审计主路径存在明确、不可绕过的控制;“部分”表示只覆盖特定格式、来源、意图或入口;“无”表示未找到足够代码证据。
- 当前未发现独立训练流水线。本文所称“训练集/评测集泄漏”同时覆盖陪练、考试、评分、案例等可被误作训练或评测语料的业务数据。
## 3. 当前数据血缘图
```mermaid
flowchart LR
A["原始来源
企业文件/ZIP/本地目录/API
个人文本/文件/URL
案例录音/用户对话/组织 API"]
B["接入与暂存
Controller + UploadQueue
sys_oss / staging_path / personal MinIO"]
C["解析
Tika / OCR / 视频抽帧 / ASR / URL fetch"]
D["规范化与分类
换行+trim / LLM或规则分类
文件与文本哈希精确去重"]
E["切片
空段落 + 字符硬切 + overlap"]
F["事实存储
aihr_knowledge_attach
aihr_knowledge_fragment
个人/案例/陪练/考试/记忆表"]
G["向量化
embedding provider
Qdrant aihr_knowledge"]
H["检索
MySQL FULLTEXT/LIKE + Qdrant
tenant + app + principal space"]
I["模型生成
RAG 答案/案例总结/考试题/评分/记忆草稿"]
J["用户交互
问师傅/案例/陪练/考试/反馈"]
K["回流
query log/answer feedback/review
practice session/calibration/memory"]
A --> B --> C --> D --> E --> F --> G --> H --> I --> J --> K
K -. "当前无统一批准后回流" .-> F
C -. "非空即可" .-> E
F -. "普通资料无文档批准过滤" .-> H
```
### 3.1 企业知识主链路
| 节点 | 实际入口、函数与存储 | 证据 |
|---|---|---|
| 接入 | `POST /api/knowledge/doc/upload-async`;`AihrSopController.uploadAsync` 调用 `AihrUploadQueueService.enqueue`。另有同步 `/doc/upload`、本地目录 `/doc/import-local` 和 `/doc/import-local-task` 运维入口 | `backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/controller/AihrSopController.java:73`、`:188`、`:206`、`:212` |
| 队列 | `AihrUploadQueueService.processItem` 从 `aihr_knowledge_upload_item.staging_path` 取文件,转入 `processStagedDocument`,结果仅以片段数是否大于 0 判定完成 | `backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrUploadQueueService.java:350`、`:388`、`:396` |
| 解析 | 普通文档走 `TikaKnowledgeDocumentParser`;图片走视觉 OCR,视频走关键帧/转写相关分支。Tika 输出全文、metadata 和按行段;嵌入文档明确不解析 | `backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/knowledge/parse/TikaKnowledgeDocumentParser.java:117`、`:132`、`:166`;`backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrSopSeedService.java:4022`、`:4050`、`:4092` |
| 清洗 | `normalizeExtractedText` 只统一换行并 `trim`;没有通用页眉页脚、页码、水印、控制字符、PII 或领域规则 | `backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrSopSeedService.java:4226` |
| 分类/去重 | 计算文件 SHA-256、MD5、文本 SHA-256;通过 `duplicateHit` 复用精确重复附件;分类 insight 可来自模型或兜底 | `backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrSopSeedService.java:1262`、`:1263`、`:1727`、`:1755` |
| 切片 | `split` 按空段落组块,超长内容按字符硬切,并加 overlap;片段无独立修订号/规则版本 | `backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrSopSeedService.java:4240`、`:4252`、`:4264` |
| 原文/附件 | 原文件通常写 `sys_oss`,文档成员写 `aihr_knowledge_attach`;其 `status=2` 仅表示解析完成,不是质量批准 | `backend/script/sql/aihr_knowledge_mysql8.sql:34`、`:43`;`backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrSopSeedService.java:1279`、`:1282` |
| 片段 | 删除同文档旧片段后,直接插入 `aihr_knowledge_fragment`,随后标记附件已解析 | `backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrSopSeedService.java:1296`、`:1299`、`:1308` |
| 定位 | 当前工作区新增 `aihr_knowledge_fragment_locator`;企业导入仍丢弃解析器 segments,定位回填主要以切片序号模拟段落,不能证明 PDF 页/PPT 页/Excel 行 | `backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrSopSeedService.java:4091`、`:4095`;`backend/script/sql/aihr_knowledge_mysql8.sql:95` |
| 向量化 | 每个片段 embedding 后 upsert Qdrant,payload 为 `tenant_id/knowledge_id/category/doc_id/idx/embedding_model` | `backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrSopSeedService.java:2269`、`:3737`、`:3757` |
| 检索 | `/api/knowledge/search` 进入统一查询;MySQL FULLTEXT、LIKE、向量结果都以租户和授权空间为核心条件 | `backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/controller/AihrSopController.java:105`;`backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrSopSeedService.java:3052`、`:3103`、`:3164` |
| 权限 | 服务端计算应用空间、主体授权空间、请求空间的交集;Qdrant 过滤包含租户和空间 ID | `backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/knowledge/service/AihrKnowledgeAccessService.java:23`、`:57`、`:66`;`backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrSopSeedService.java:3945` |
| 生成 | 检索片段拼入企业 RAG prompt,模型生成答案;引用再从片段表 hydrate | `backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrSopSeedService.java:3331`;`backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/knowledge/service/AihrKnowledgeQueryService.java:648` |
| 回流 | 写 `aihr_knowledge_query_log`、`aihr_sop_answer_review`、`aihr_knowledge_answer_feedback`;差评只屏蔽相同规范化问题与片段组合 | `backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/knowledge/service/AihrKnowledgeQueryAuditService.java:23`;`backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrSopSeedService.java:2975` |
### 3.2 特殊来源与生成链路
| 数据流 | 当前实际路径 | 是否进入企业可信区 |
|---|---|---|
| 正式制度 | 普通知识接入后,另由 `aihr_knowledge_source_governance` 登记 `APPROVED`、版本、生效/失效日期;只有识别为正式制度意图时附加过滤 | 特殊意图受控;普通检索仍可能命中相同片段。证据:`backend/script/sql/update/aihr_20260730_formal_knowledge_source_governance_mysql8.sql:5`;`backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/knowledge/service/AihrKnowledgeQueryService.java:662` |
| 个人知识 | `POST /api/aihr/personal-assistant/items/text|file|url` -> 私有 item/fragment;HR/超级管理员审核发布 -> 脱敏后的 fragment 直接复制到企业知识表 | 是,审批后直接写企业表,但绕过通用附件/版本/质量/重新解析链。证据:`backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/personal/controller/PersonalAssistantController.java:89`、`:94`、`:103`;`backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/personal/service/PersonalPublishService.java:107`、`:232` |
| 案例录音 | `/api/knowledge/case/upload` -> OSS + ASR -> `aihr_case_record`;`organize` 用模型或本地兜底总结;`curate` 只进入候选池;`review` 完成业务审核;`publish` 在来源授权、脱敏、适用岗位、版本和负责人齐全后才标记 `knowledge_status=PUBLISHED` | 员工列表/详情只读取 `knowledge_status=PUBLISHED`,审核通过不会自动进入正式知识库。迁移:`backend/script/sql/update/aihr_20260802_case_experience_governance_mysql8.sql`;服务:`backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrCaseService.java` |
| AI 考试题 | `AihrExamService.generateDraft` 从租户片段抽取 grounding,模型/规则生成草稿;主管创建并发布考试 | 不直接自动发布,但 grounding 未要求来源批准、附件有效或授权空间。证据:`backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/learning/AihrExamService.java:185`、`:482`、`:541` |
| 陪练 | 用户回答、音频、LLM/seed 评分写 session/assignment;可选 calibration 保存人工校准 | 不写企业知识表,但属于运行/评测数据,当前缺少统一 synthetic、置信度、模型版本和数据用途隔离。证据:`backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrPracticeSeedService.java:1513`;`backend/script/sql/aihr_practice_mysql8.sql:27`、`:168` |
| 陪练场景 | 场景有草稿、待业务审核、已发布、已下线;高风险需不同用户双审并校验内容版本/哈希 | 局部强控制。证据:`backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrPracticeSeedService.java:599`、`:675`、`:696`;`backend/script/sql/aihr_practice_mysql8.sql:184` |
| 显式记忆 | 模型/规则先给候选项,用户确认后进入 PRIVATE;COMPANY 捕获保持 `PENDING`;召回走独立记忆表 | 当前未直接写企业知识片段,控制较好。证据:`backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/memory/AihrMemoryService.java:517`、`:859`、`:900` |
| 组织 API 同步 | `/api/aihr/org/sync-changes` 写组织快照;要求显式 dry-run,重复成员和异常数据可 fail closed | 影响身份/授权而非知识正文;属于重要旁路数据。证据:`backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/controller/AihrOrgSyncController.java:24`、`:39`;`backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrOrgSyncService.java:208`、`:301` |
## 4. 当前数据对象和存储结构
| 数据域 | 主要对象/表 | 当前角色与关键缺口 |
|---|---|---|
| 原文件 | `sys_oss`、MinIO `ruoyi` | 保存对象与扩展元数据;没有独立不可变业务资产版本、采集来源可信等级和保留策略。`sys_oss.ext1` 中有文件/文本哈希和自动分类元数据,但更新失败被忽略:`AihrSopSeedService.java:1813-1826`。 |
| 企业空间 | `aihr_knowledge_info`、`aihr_knowledge_category`、`aihr_knowledge_acl` | 空间状态为 `DRAFT/ACTIVE/DISABLED`,是空间级开关,不是文档/片段质量状态:`backend/script/sql/aihr_knowledge_mysql8.sql:4`、`:11`。 |
| 企业附件 | `aihr_knowledge_attach` | 只有解析状态 `0/1/2/3`;`2=已解析` 被界面称作“可引用资料”,不代表质量批准:`backend/script/sql/aihr_knowledge_mysql8.sql:34`、`:43`;`AihrSopSeedService.java:1830-1843`。 |
| 企业片段 | `aihr_knowledge_fragment`、`aihr_knowledge_fragment_locator` | 正文、embedding、doc/idx 和定位;无来源版本、质量状态、原因码、规则版本、有效期、synthetic/runtime 标记和修订历史:`backend/script/sql/aihr_knowledge_mysql8.sql:73`、`:95`。 |
| 正式来源 | `aihr_knowledge_source_governance` | 有来源 ID、附件、版本、权威类型、生命周期、生效/失效、内容哈希;只覆盖正式制度专用路径:`backend/script/sql/update/aihr_20260730_formal_knowledge_source_governance_mysql8.sql:5-30`。 |
| 应用与授权 | `aihr_knowledge_app`、`aihr_knowledge_app_space`、`aihr_knowledge_space_grant` | 支持租户、应用、主体授权交集;这是访问控制,不替代内容质量审批:`backend/script/sql/aihr_knowledge_mysql8.sql:249`、`:266`、`:288`。 |
| 处理任务 | `aihr_knowledge_upload_item`、`aihr_knowledge_import_task` | 记录等待/处理中/完成/失败和错误文本;没有阶段级质量结果、reason code 列表、检测器版本和人工处置:`backend/script/sql/aihr_knowledge_mysql8.sql:149`、`:228`。 |
| 查询与反馈 | `aihr_knowledge_query_log`、`aihr_sop_answer_review`、`aihr_knowledge_answer_feedback`、`aihr_knowledge_gap` | 有请求、状态、来源类型、提示词版本和特定 query-fragment 差评;缺精确使用片段修订、排名、模型/embedding 版本、答案 hash 及处置闭环:`backend/script/sql/aihr_knowledge_mysql8.sql:300`;`backend/script/sql/aihr_practice_mysql8.sql:283`、`:296`、`:318`。 |
| 个人知识 | `aihr_personal_item`、`aihr_personal_fragment`、OCR job/page、cleanup job、publish request | 所有权、私有存储、精确 hash、处理和发布状态较完整;但批准发布时仍复制进通用企业片段,丢失完整个人来源版本链:`backend/script/sql/aihr_personal_knowledge_mysql8.sql:35`、`:64`、`:132`、`:190`。 |
| 案例 | `aihr_case_record` | 原转写、AI 总结、主管点评和状态同表;状态主要是流程展示,不足以区分 raw/trusted/synthetic:`backend/script/sql/aihr_practice_mysql8.sql:4-24`。 |
| 陪练与评分 | `aihr_practice_session`、`assignment`、`calibration`、`scenario`、`rubric` | 保存回答、AI 分数、规则兜底、人审校准及内容版本;运行数据和评测用途没有统一数据资产标记:`backend/script/sql/aihr_practice_mysql8.sql:27`、`:137`、`:168`、`:184`。 |
| 考试 | `aihr_onboard_exam*` | 草稿/发布、题目正确答案、员工答案和得分;AI 题来源未绑定具体已批准 chunk revision:`backend/script/sql/update/aihr_20260717_learning_closure_mysql8.sql:102`、`:161`、`:189`。 |
| 记忆 | `aihr_service_memory*`、assistant capture | 候选、确认、拒绝、过期和公司 pending 独立于知识片段,边界相对清晰:`backend/script/sql/aihr_service_memory_mysql8.sql:14`。 |
## 5. 信任边界分析
| 内容类型 | 是否存在直接进入可信/生产使用区的路径 | 现有控制 | 结论与证据 |
|---|---|---|---|
| 未审核上传文件 | 是 | 角色限制、非空、解析状态、精确重复 | 非空即写片段并 embedding,无通用审批:`AihrSopController.java:73-84`;`AihrSopSeedService.java:1243-1308`。P0。 |
| OCR 结果 | 是 | 图片/视频无结果可待处理;个人 PDF 有分页失败状态 | 企业 OCR 有文本即可进入同一片段链,未保留置信度和逐页证据:`AihrSopSeedService.java:673`、`:4050`。P0。 |
| 录音转写 | 部分是 | 案例上传需登录/项目权限 | 转写进入案例,整理/入库无前置质量审核:`AihrCaseController.java:53-74`;`AihrCaseService.java:96-124`。P1。 |
| 员工个人经验 | 是 | 个人区隔离;发布需 HR/超级管理员审核和确定性脱敏 | 一次批准后直接复制到企业知识表,不走版本/质量链:`PersonalPublishService.java:107-159`、`:232-264`。P0。 |
| 信息不完整案例 | 是 | 可由主管事后点评 | `curate` 不检查必填证据、上下文、结论依据,直接标已入库:`AihrCaseService.java:107-124`。P1。 |
| 用户回答 | 否(企业知识),是(运行/评分表) | 身份、会话和项目范围;部分人工校准 | 没有发现自动写入知识片段的路径;但评分/未来训练用途无统一 consent/purpose/split 标记:`aihr_practice_mysql8.sql:27-75`、`:168-182`。P1。 |
| 模型回答 | 否(企业知识),是(日志/评审) | 有引用和问答评审表 | 未发现自动提升为企业知识;审计却不能稳定记录用过的 chunk revision:`AihrKnowledgeQueryAuditService.java:23-37`。P1。 |
| AI 生成案例 | 是(案例库) | 操作者需有案例管理权限 | 模型失败还会用本地兜底,随后可直接已入库;没有 synthetic 标记和批准门:`AihrCaseService.java:96-124`。P0/P1 边界,按 P1 排期但必须与 P0 门禁一起封堵。 |
| AI 生成标准答案/考试题 | 否(自动发布),但来源可污染 | 生成草稿后由主管创建/发布,试卷总分等有校验 | grounding 从全部租户片段读取,未过滤批准、空间和附件有效性:`AihrExamService.java:482-568`;发布控制:`:185-251`。P1。 |
| AI 生成评分 | 是(业务结果) | `score_mode`、rubric snapshot、可选 calibration | LLM 失败退 seed,结果直接用于 session/assignment;人审不是强制,缺模型/置信度/异常 reason:`AihrPracticeSeedService.java:1513-1539`;`aihr_practice_mysql8.sql:157-177`。P1。 |
| 旧版本制度 | 是,普通检索可命中 | 正式制度意图有版本、生效/失效门禁 | 门禁只在 `formalPolicyOnly` 分支,普通检索不要求治理行:`AihrKnowledgeQueryService.java:648-713`。P0。 |
| 来源不明数据 | 是 | 文件名、OSS、remark、部分 hash | 普通片段不要求来源所有者、权威性、版本、采集时间和适用范围。P0。 |
| 跨租户数据 | 主查询未发现直接路径;索引漂移仍有残余风险 | SQL tenant 条件、空间交集、Qdrant tenant filter | 服务端隔离较强:`AihrKnowledgeAccessService.java:23-104`;`AihrSopSeedService.java:3945-3956`。但向量删除失败无可靠补偿,必须做一致性审计。P1。 |
## 6. 脏数据类型覆盖矩阵
| 脏数据类型 | 是否已处理 | 处理位置/方式 | 可绕过路径 | 风险 | 代码证据 |
|---|---|---|---|---|---|
| 空内容 | 部分 | Tika 空文本抛错;企业保存拒绝 blank;图片/视频无视觉结果保持待处理 | 仅检查整体非空,极短、只有页眉页脚或无语义文本仍可入库 | 中 | `TikaKnowledgeDocumentParser.java:117-124`;`AihrSopSeedService.java:1250-1256` |
| 乱码和解析失败 | 部分 | 解析异常、大小限制、任务失败/重试 | 未检测替换字符、控制字符、异常编码比例;本地有 19 个含 `U+FFFD` 片段 | 高 | `TikaKnowledgeDocumentParser.java:105-123`;`AihrUploadQueueService.java:410-417` |
| 文档缺页 | 无(通用) | 个人 PDF OCR 有 page/job 状态和 partial | 企业 Tika 丢失真实分页结构,也没有声明页数与解析页数比对 | 高 | `TikaKnowledgeDocumentParser.java:128-143`;`PersonalPdfOcrService.java:436-444` |
| 精确重复 | 部分 | 企业文件/文本 SHA-256;个人内容 hash | 片段级重复、不同包装/页眉差异、跨空间重复仍存在;本地全局重复余量 1,897 | 中 | `AihrSopSeedService.java:1262-1267`、`:1755-1788`;`PersonalIngestionService.java:171-203` |
| 近重复 | 无 | 未发现 MinHash/SimHash/edit distance 规则 | 改空格、页眉、格式或少量措辞即可绕过精确 hash | 高 | `AihrSopSeedService.java:1262-1267` |
| 语义重复 | 无 | 未发现聚类/相似度阻断或审核队列 | 同义改写、不同专家复述都能并存并进入召回 | 高 | `AihrSopSeedService.java:1296-1306` |
| 来源不明 | 部分 | OSS、文件名、docId、remark;正式制度有 source registry | 普通资料、个人发布生成的企业片段不要求权威来源和稳定版本 | 严重 | `aihr_knowledge_mysql8.sql:34-92`;`PersonalPublishService.java:232-254` |
| 领域无关 | 无(通用) | LLM/规则自动分类只决定空间/标签 | 分类结果不形成阻断或 reason code;已观察到跨主题错误召回 | 严重 | `AihrSopSeedService.java:1263-1269`、`:1296-1308` |
| 上下文不完整 | 无 | 切片带 overlap;回答提示要求依据片段 | 字符硬切、表格/页码结构丢失,无法验证片段是否自洽 | 高 | `AihrSopSeedService.java:4240-4269`;`aihr_20260725_sop_answer_partial_evidence_prompt_mysql8.sql:7-8` |
| 结论无依据 | 部分 | RAG prompt 要求只基于片段;正式制度再做相关证据判断 | 原片段自身可能无来源/不可信;案例总结、考试题和评分可由模型/兜底直接产生 | 严重 | `AihrKnowledgeQueryService.java:704-710`;`AihrCaseService.java:96-124` |
| 错误标签 | 无(通用) | insight 保存 `classifiedBy/reason/tags` | 没有确定性校验、人工确认状态和标签版本;分类失败不阻断入库 | 高 | `AihrSopSeedService.java:1264-1269`、`:1818-1824` |
| 制度过期 | 部分 | 正式制度意图检查 `APPROVED`、生效/失效和版本 | 普通知识查询、考试 grounding 不执行该条件 | 严重 | `AihrKnowledgeQueryService.java:662-680`;`AihrExamService.java:482-538` |
| 多版本冲突 | 部分 | 正式制度 `source_id/source_version` 唯一登记;陪练场景有版本/hash | 普通资料无 supersedes/有效期;新上传不会自动下线旧版 | 严重 | `aihr_20260730_formal_knowledge_source_governance_mysql8.sql:8-27`;`aihr_knowledge_mysql8.sql:34-92` |
| 多专家意见冲突 | 无 | 未发现 claim/观点级冲突模型和仲裁状态 | 多份专家经验可同时发布/召回,无法表达适用条件和异议 | 高 | `PersonalPublishService.java:232-264` |
| 未脱敏个人信息 | 部分 | 个人发布使用确定性 sanitizer;工作投稿另有隐私警告 | 普通企业上传/OCR/ASR 无通用 PII 扫描;上传角色可信不能代替内容脱敏 | 严重 | `PersonalPublishService.java:139-151`;`PersonalPromptSanitizer.java:10-62` |
| 跨租户数据 | 有(检索主链)/部分(索引一致性) | SQL tenant、应用/主体/请求空间交集、Qdrant tenant payload/filter | 删除失败、历史错误 payload 或旁路直写需靠对账发现;当前无 outbox/reconciler | 高 | `AihrKnowledgeAccessService.java:23-104`;`AihrSopSeedService.java:3737-3748`、`:3945-3956` |
| 提示词注入 | 部分 | 个人 QA 明确把来源当不可信并 XML 隔离 | 企业 RAG 将片段原文直接拼入 prompt,未找到等价指令隔离 | 严重 | `PersonalAnswerService.java:249-274`;`AihrSopSeedService.java:3331-3381` |
| AI 合成数据污染 | 部分 | 考试先草稿后人工发布;记忆需确认 | 案例自动“已入库”;个人发布/企业片段无统一 `is_synthetic/generator`;LLM 分类无版本化门禁 | 严重 | `AihrCaseService.java:96-124`;`AihrExamService.java:185-251` |
| 运行日志回流污染 | 部分 | 当前未发现 query log、agent run 自动写入企业片段;记忆独立且需确认 | 缺统一 data purpose 和 lineage,未来离线导出/训练难以防误用;案例和陪练运行表仍可被当语料 | 高 | `aihr_knowledge_mysql8.sql:300-372`;`AihrMemoryService.java:859-942` |
| 训练集和评测集泄漏 | 无 | 未发现正式 split registry、样本 hash、时间切分或用途限制 | 考题、参考答案、员工答案、AI 评分、案例同处业务库,离线抽取无法证明隔离 | 高 | `aihr_20260717_learning_closure_mysql8.sql:151-200`;`aihr_practice_mysql8.sql:137-182` |
## 7. P0、P1、P2 问题清单
### P0:必须先阻止新增污染或越权可信化
**P0-1 普通资料非空即可进入生产片段和索引。** 解析、切片、写 MySQL、embedding 在同一保存流程连续执行,缺少 `PRIVACY_CHECKED -> DOMAIN_VALIDATED -> QUALITY_EVALUATED -> APPROVED` 门禁。证据:`AihrUploadQueueService.java:350-417`;`AihrSopSeedService.java:1243-1314`、`:2269-2312`。影响所有普通文件、OCR/视频文本、同步上传和运维导入。
**P0-2 生产检索不要求文档/片段批准与有效版本。** 普通 FULLTEXT、LIKE、向量 hydrate 仅约束租户/空间等条件;只有正式制度意图附加 governance 条件。证据:`AihrSopSeedService.java:2949-2972`、`:3052-3200`;`AihrKnowledgeQueryService.java:648-713`。旧制度、低质量和待处置片段可被正常问答使用。
**P0-3 个人发布可直接污染企业可信表。** 审核与脱敏值得保留,但发布器直接新建企业空间并写 `aihr_knowledge_fragment`,没有附件、不可变来源版本、质量评估、重切片或索引生命周期。证据:`PersonalPublishService.java:107-159`、`:232-264`。
**P0-4 撤回与向量删除不是可靠事务。** 文档解绑先删 MySQL,Qdrant 删除异常被捕获并忽略;没有 durable outbox、重试、死信和对账修复。证据:`AihrSopSeedService.java:842-881`、`:3763-3780`。结果可能是 SQL 已撤回但向量仍残留,且无法证明最终一致。
**P0-5 来源、版本和可追溯性不足。** 普通片段没有稳定 source/version、有效期、适用范围、规则版本和修订;当前 locator 也不能恢复真实 PDF 页/PPT 页/Excel 行。证据:`aihr_knowledge_mysql8.sql:34-119`;`TikaKnowledgeDocumentParser.java:117-143`;`AihrSopSeedService.java:4091-4122`。
**P0-6 企业 RAG 缺少来源指令隔离。** 个人 QA 明确声明来源不可信并转义,企业 RAG 没有等价边界,恶意文档可尝试覆盖系统指令。证据:`PersonalAnswerService.java:249-274`;`AihrSopSeedService.java:3331-3381`。
### P1:P0 门禁建立后立即治理
**P1-1 清洗和结构恢复过弱。** 目前主要是换行/trim 与字符切片,不能处理页眉页脚、目录、水印、表格、OCR 置信度、控制字符和段落重复。本地 1,178 个疑似页码噪声、19 个替换字符、195 个小于 40 字片段构成直接证据。代码:`AihrSopSeedService.java:4226-4269`。
**P1-2 只有精确文档去重,没有近重复、语义重复和冲突检测。** 本地 8,607 个片段中,全局精确重复余量 1,897,同空间 560,同文档 422。代码:`AihrSopSeedService.java:1262-1267`、`:1755-1788`。
**P1-3 AI/兜底案例可直接标“已入库”。** 主管 review 是事后评论,不是发布前审核;缺 synthetic、generator、grounding 和证据完整性。证据:`AihrCaseService.java:96-138`、`:299-333`。
**P1-4 AI 考试题的 grounding 绕过知识批准和授权范围。** 草稿发布有人审,但底层素材来自租户全部片段,可能吸收过期、跨岗位或未批准内容。证据:`AihrExamService.java:482-568`。
**P1-5 AI 评分被作为业务结果,校准非强制。** LLM 与 seed fallback 都生成实际分数,需记录模型、prompt/rubric、置信度、fallback reason 并对高风险结果抽审/强审。证据:`AihrPracticeSeedService.java:1513-1539`;`aihr_practice_mysql8.sql:168-182`。
**P1-6 查询审计无法反查确切污染修订。** 日志只存问题 hash、空间、来源类型、状态、时延和 prompt version,不存 fragment revision IDs、排名、分数、答案 hash、生成模型。证据:`AihrKnowledgeQueryAuditService.java:23-37`;`aihr_knowledge_mysql8.sql:300-317`。
**P1-7 反馈没有形成源数据隔离闭环。** downvote 只屏蔽“相同规范化问题 + fragment”组合,不会降低全局质量状态、隔离来源或触发再审。证据:`AihrSopSeedService.java:2975-3010`;`aihr_practice_mysql8.sql:318-337`。
**P1-8 数据质量监控不足。** 处理概览只有完成、处理中、失败、片段和 embedding 数,并把解析成功称为“可引用资料”;没有重复率、乱码率、PII、过期、隔离、索引漂移、审批时长和质量告警。证据:`AihrSopSeedService.java:1830-1873`。
### P2:治理能力完善与运营优化
**P2-1 缺 claim/观点级冲突模型。** 制度冲突、专家意见冲突只能靠文档级人工发现,无法让检索优先选择当前有效结论。
**P2-2 缺统一数据用途和同意记录。** 用户回答、对话、音频、评分、日志虽然没有自动进入企业知识,但没有统一的 `purpose/consent/retention/training_eligible` 控制,未来离线使用容易污染训练和评测。
**P2-3 缺独立基准数据集与回归门禁。** 现有测试覆盖若干权限和业务状态,但未发现跨格式脏数据 corpus、检索黄金集、跨租户 canary、污染注入和 train/eval 泄漏检测套件。
**P2-4 局部状态语义不统一。** 附件“已解析”、案例“已入库”、个人 item “READY”、空间“ACTIVE”、场景“已发布”分别由业务模块定义,无法回答一个资产是否已清洗、已批准、已索引、已失效。
## 8. 重点架构问题逐项结论
| # | 问题 | 结论 |
|---|---|---|
| 1 | `RAW -> INDEXED` 直接路径 | **存在。** 普通资料非空后写片段并 embedding:`AihrSopSeedService.java:1243-1308`。 |
| 2 | `MODEL_OUTPUT -> TRUSTED_KNOWLEDGE` 直接路径 | **存在于案例;个人发布存在人工批准后直写。** 案例模型/兜底总结可直接已入库:`AihrCaseService.java:96-124`。模型回答和显式记忆未发现直接写企业片段。 |
| 3 | raw/trusted/synthetic/runtime 混表或混 collection | **存在混合。** `aihr_knowledge_fragment` 没有 trust/origin 字段;个人发布片段与上传片段混用;案例 raw transcript、AI summary、review 同表。Qdrant 只有默认 collection。 |
| 4 | 单一 `is_clean`/综合分,缺原因码 | **不是“只有 is_clean”,而是通用质量状态和原因码整体缺失。** 上传 error 和反馈 reason 只覆盖局部故障/回答反馈。 |
| 5 | 无来源、版本、范围、有效期 | **普通资料存在。** 正式制度和陪练场景是局部例外。 |
| 6 | 发布后不能撤回或不能同步清索引 | **可发起解绑,但不能保证同步清除。** Qdrant 删除失败被忽略,无持久重试:`AihrSopSeedService.java:3763-3780`。 |
| 7 | 清洗覆盖原始内容 | **原文件通常保存在 OSS,未发现清洗回写覆盖对象。** 但本地 MinIO 为空,且缺不可变业务版本约束,不能证明所有历史原文可恢复。 |
| 8 | LLM 是唯一质量判断者 | **部分存在。** 自动分类/案例总结缺人工质量门;考试发布和高风险场景有人审。 |
| 9 | LLM 自行删除、批准或发布 | **未发现 LLM 直接调用删除/批准 API。** 但服务代码会把 LLM/兜底案例结果直接置为已入库,效果等价于缺前置人审。 |
| 10 | 清洗规则修改后无法识别旧规则版本 | **存在。** 片段无 parser/normalizer/chunker/rule version。locator 仅有自身 `locator_version`。 |
| 11 | 错误回答无法反查具体污染 chunk | **存在。** 引用响应含 fragment ID,但持久 query log 不保存片段修订集合:`AihrKnowledgeQueryAuditService.java:23-37`。 |
| 12 | 多租户只在前端/Prompt | **否。** SQL、应用/主体授权交集和 Qdrant filter 均在服务端;残余风险是索引漂移与旁路数据而非纯前端隔离。 |
## 9. 建议的数据状态机
目标状态机是数据资产的统一治理主状态,不替换上传任务、OCR job 等技术状态。
```mermaid
stateDiagram-v2
[*] --> RAW
RAW --> PARSED: parser 成功,保留原文与解析产物
RAW --> QUARANTINED: 空/损坏/恶意文件
PARSED --> NORMALIZED: 确定性清洗完成
NORMALIZED --> CLASSIFIED: 来源/领域/范围分类
CLASSIFIED --> DEDUPLICATED: 精确/近似/语义去重
DEDUPLICATED --> PRIVACY_CHECKED: PII 与秘密检查
PRIVACY_CHECKED --> DOMAIN_VALIDATED: 领域和适用范围验证
DOMAIN_VALIDATED --> QUALITY_EVALUATED: 结构/依据/时效/冲突评分
QUALITY_EVALUATED --> QUARANTINED: 阻断 reason code
QUALITY_EVALUATED --> REVIEW_PENDING: 需人工判断
QUALITY_EVALUATED --> APPROVED: 低风险自动规则通过
REVIEW_PENDING --> APPROVED: 授权审核人批准
REVIEW_PENDING --> QUARANTINED: 驳回/待补充
APPROVED --> PUBLISHED: outbox 索引成功并校验
PUBLISHED --> DEPRECATED: 撤回/过期/被新版本替代
QUARANTINED --> PARSED: 修复原始来源后新建版本
DEPRECATED --> REVIEW_PENDING: 新修订重新走完整检查
```
强制不变量:
1. 原始对象和原始 hash 不可覆盖;重传、重解析、重新清洗都创建新 `data_version`。
2. `PUBLISHED` 的前置条件是 `APPROVED`、无阻断 reason、来源可追溯、租户和适用范围完整、未过期、索引 upsert 成功。
3. 生产 FULLTEXT、LIKE、向量检索和所有下游 grounding 只读取 `PUBLISHED` 的 `chunk_revision`。
4. `SYNTHETIC`、`RUNTIME`、`QUARANTINE` 永不进入生产 collection;AI 生成内容默认 `REVIEW_PENDING`。
5. `DEPRECATED` 立即从检索可见集合移除,并通过 outbox 幂等删除向量;物理保留历史用于审计。
6. 状态转换由确定性规则和授权人完成;LLM 只能提出标签/风险建议,不能执行批准、发布、删除。
## 10. 建议的数据表和字段
优先采用旁路增量表,避免直接重构现有所有业务表。
| 建议表 | 关键字段 | 作用 |
|---|---|---|
| `aihr_data_asset` | `id, tenant_id, asset_type, source_type, source_owner, source_system, source_uri_redacted, raw_oss_id, raw_sha256, captured_at, retention_class, consent_scope, created_by` | 一份不可变原始资产的稳定身份;`raw_sha256` + 租户唯一,禁止 update 原始对象。 |
| `aihr_data_version` | `id, asset_id, version_no, parent_version_id, source_version, authority_type, applicability_json, effective_at, expires_at, parser_version, normalizer_version, classifier_version, dedupe_version, privacy_rule_version, quality_rule_version, lifecycle_status, origin_type, synthetic, generator_model, prompt_version, superseded_by` | 每次解析/清洗/规则升级产生版本,承载完整生命周期。 |
| `aihr_quality_assessment` | `id, version_id, stage, detector_code, detector_version, score, decision, assessed_at, run_id, metrics_json` | 一次检测运行;允许多个维度,不以一个 `quality_score` 代替原因。 |
| `aihr_quality_issue` | `id, assessment_id, version_id, chunk_revision_id, reason_code, severity, blocking, location_json, evidence_hash, status, resolved_by, resolved_at` | 结构化问题明细和定位;敏感 evidence 只存 hash/脱敏摘要。 |
| `aihr_review_decision` | `id, version_id, decision, reviewer_user_id, reviewer_role, comment, content_hash, decided_at, previous_decision_id` | 人工批准/驳回/撤回,绑定当时内容 hash,内容变化后自动失效。 |
| `aihr_chunk_revision` | `id, version_id, tenant_id, knowledge_id, doc_id, chunk_key, revision_no, content, content_sha256, locator_json, parent_chunk_id, lifecycle_status, effective_at, expires_at, created_at` | 生产片段的不可变修订;现有 fragment ID 可作为迁移映射,不再原地覆盖。 |
| `aihr_lineage_edge` | `from_type, from_id, to_type, to_id, relation, pipeline_run_id, created_at` | 表达 `raw -> parsed -> normalized -> chunk -> embedding -> answer/exam/case/score` 血缘。 |
| `aihr_index_outbox` | `id, tenant_id, chunk_revision_id, collection, operation, generation, payload_sha256, status, attempts, next_retry_at, last_error_code, created_at, completed_at` | MySQL 事务内登记 UPSERT/DELETE,worker 幂等执行、重试、死信和对账。 |
| `aihr_query_evidence` | `request_id, rank, chunk_revision_id, retrieval_mode, retrieval_score, rerank_score, payload_generation, cited, created_at` | 从错误答案反查精确污染修订和召回排名。 |
| `aihr_dataset_membership` | `dataset_id, version_id/chunk_revision_id, split, purpose, snapshot_at, content_sha256, approval_id` | 管理 TRAIN/VALIDATION/TEST/GOLDEN,防止内容 hash 跨 split 和时间穿越。 |
字段约束建议:所有业务主键关联同时携带/校验 `tenant_id`;`lifecycle_status` 用 CHECK 或受控枚举;`PUBLISHED` 需要唯一有效版本;`effective_at < expires_at`;`synthetic=true` 必须有 generator;`origin_type` 至少区分 `ENTERPRISE_SOURCE/PERSONAL_EXPERIENCE/SYNTHETIC/RUNTIME/EXTERNAL_API`。
## 11. 建议的 reason code
reason code 必须一对多记录,包含 `severity`、`blocking`、检测器版本和证据位置。首批至少支持:
| 类别 | reason code |
|---|---|
| 解析完整性 | `PARSE_EMPTY`, `PARSE_FAILED`, `PARSE_TRUNCATED`, `PAGE_COUNT_MISMATCH`, `EMBEDDED_CONTENT_SKIPPED` |
| 编码/OCR/ASR | `ENCODING_REPLACEMENT_CHAR`, `UNICODE_CONTROL_CHAR`, `OCR_LOW_CONFIDENCE`, `OCR_PARTIAL`, `ASR_LOW_CONFIDENCE`, `ASR_SPEAKER_UNCERTAIN` |
| 清洗与结构 | `HEADER_FOOTER_NOISE`, `PAGINATION_NOISE`, `TOC_NOISE`, `WATERMARK_NOISE`, `TABLE_STRUCTURE_LOST`, `CHUNK_TOO_SHORT`, `CHUNK_CONTEXT_BROKEN` |
| 重复 | `EXACT_DUPLICATE`, `NEAR_DUPLICATE`, `SEMANTIC_DUPLICATE` |
| 来源与版本 | `SOURCE_UNKNOWN`, `SOURCE_HASH_MISMATCH`, `SOURCE_VERSION_MISSING`, `SOURCE_UNAVAILABLE`, `SUPERSEDED_VERSION` |
| 业务质量 | `DOMAIN_IRRELEVANT`, `CONTEXT_INCOMPLETE`, `UNSUPPORTED_CLAIM`, `LABEL_CONFLICT`, `APPLICABILITY_MISSING` |
| 时效与冲突 | `POLICY_EXPIRED`, `VERSION_CONFLICT`, `EXPERT_CONFLICT` |
| 安全与隔离 | `PII_DETECTED`, `SECRET_DETECTED`, `CROSS_TENANT_REFERENCE`, `PROMPT_INJECTION_SUSPECTED` |
| 来源污染 | `SYNTHETIC_UNDECLARED`, `RUNTIME_DATA_CONTAMINATION`, `TRAIN_EVAL_LEAKAGE` |
| 索引一致性 | `INDEX_UPSERT_FAILED`, `INDEX_DELETE_FAILED`, `INDEX_DRIFT`, `INDEX_PAYLOAD_INVALID` |
默认阻断发布的 reason:所有 parse failure、page mismatch、source unknown/version missing、PII/secret、cross-tenant、prompt injection、undeclared synthetic、runtime contamination、train/eval leakage、expired policy、unsupported claim 和 index drift。`CHUNK_TOO_SHORT` 等可配置为告警,但不得被单一总分抵消严重问题。
## 12. 数据隔离和向量索引方案
1. MySQL 事实源分层:raw/parsed/quality/review/chunk revision 分表;现有 `aihr_knowledge_fragment` 在过渡期只作为兼容发布视图或发布投影,不再接受任意入口直写。
2. 逻辑 collection 至少分 `aihr_knowledge_prod`、`aihr_knowledge_quarantine`、`aihr_knowledge_synthetic`、`aihr_knowledge_runtime`。最小 P0 可先只建立 prod,其他状态完全不入向量库;不要用 payload flag 作为唯一隔离。
3. prod payload 必须包含 `tenant_id, knowledge_id, asset_id, data_version_id, chunk_revision_id, lifecycle_status, source_version, effective_at, expires_at, applicability_hash, index_generation, embedding_model`。
4. Qdrant 查询仍保留 tenant + allowed knowledge IDs filter,同时增加 `lifecycle_status=PUBLISHED` 和 generation;从 MySQL hydrate 时再次校验发布/有效期,防止 stale vector 绕过。
5. 所有 upsert/delete 先与状态变更同事务写 `aihr_index_outbox`;worker 使用确定性 point ID(基于 chunk revision)和 generation 幂等处理。失败指数退避,超过阈值进入 dead letter 并告警。
6. 定时 reconciler 对比 MySQL `PUBLISHED` 修订与 Qdrant point:多余点发 DELETE,缺失/哈希不一致发 UPSERT;输出 `INDEX_DRIFT`,不得静默修复后不留审计。
7. 撤回顺序:MySQL 先将版本标为 `DEPRECATED` 使 hydrate 立即不可见,再提交 DELETE outbox;物理删除原文件需满足保留期和引用计数,不与检索撤回绑定。
## 13. 历史数据迁移与重新清洗方案
1. **冻结新增污染**:先上线检索发布门和新导入 `REVIEW_PENDING` 默认值;在此之前不要批量重建向量,否则会扩大污染面。
2. **只读盘点**:按租户导出附件、片段、OSS、正式治理、空间授权和 Qdrant manifest,只记录 ID/hash/计数,不导出敏感正文到报告。
3. **建立资产映射**:以 `tenant_id + oss_id/file hash/doc_id` 回填 `aihr_data_asset/version`。能找到原文件的版本标 `RAW`;找不到原文件的 6 个孤儿片段及其他不可恢复项先 `QUARANTINED/SOURCE_UNAVAILABLE`,不得假定可信。
4. **保留旧数据**:原 `aihr_knowledge_fragment` 和 `sys_oss` 只读保留;新 parser/normalizer/chunker 输出新 version/chunk revision,不 UPDATE 覆盖旧正文。
5. **分批重处理**:优先正式制度、安全/消防/财务/人事等高风险空间,再处理高频引用和普通空间。每批记录 pipeline/rule versions、输入/输出 hash 和问题明细。
6. **去重与版本归并**:先精确 hash,再近重复,最后语义候选;自动检测只生成 duplicate group,版本冲突和专家冲突由业务审核人决定 authoritative/superseded。
7. **隐私与领域门禁**:确定性 PII/秘密/注入规则先跑,LLM 仅作为补充风险信号;命中阻断项进入隔离。
8. **人工审核**:给审核人显示原始文件、解析差异、清洗差异、重复组、适用范围、有效期和 reason codes;批准绑定 content hash。
9. **双写验证**:候选 prod collection 建新 generation,以 shadow query 与黄金集比较;不切换用户流量。
10. **原子切换与回滚**:达到验收标准后切换 active generation;旧 generation 保留约定窗口,可即时切回。切换后再按 outbox 清理旧点。
本地快照迁移基线:附件 1,046、片段 8,607、locator 0、上传任务 1,207(完成 1,113、失败 94)、embedded 3,893。重清洗后应分别对账,不得把“有 embedding”当作“已批准”。
## 14. 自动检测与人工审核边界
| 能力 | 自动化可决定 | 必须人工决定 |
|---|---|---|
| 技术完整性 | 文件 hash、MIME、大小、解析异常、页数比、乱码、OCR/ASR 置信度阈值 | 低置信度页面是否可由原件补正 |
| 清洗 | 确定性移除已验证的页眉页脚/页码副本,并保留 diff | 表格语义重构、歧义段落合并、事实改写 |
| 去重 | 精确重复可自动归组;近/语义重复生成候选 | 哪个版本权威、是否合并、是否存在适用范围差异 |
| 隐私 | 规则/NER 检测和默认阻断;自动遮罩仅生成候选版本 | 高风险 PII、商业秘密是否允许发布及适用范围 |
| 领域与依据 | 分类器/LLM 给相关度、claim-evidence 候选和 reason | 边界业务、制度解释、冲突结论、例外条款 |
| 发布 | 系统验证前置条件、角色、双审、hash 未变化 | 授权审核人批准;高风险制度至少双人或法务/业务责任人审核 |
| AI 内容 | 强制标 synthetic、绑定模型/prompt/grounding | 案例、标准答案、题目、评分用于正式业务前的责任人确认 |
| 删除/撤回 | 系统执行幂等状态变更、outbox 和对账 | 业务撤回决定;LLM 无权批准、发布或删除 |
LLM 输出永远是检测信号或草稿,不是唯一审批证据。任何自动低风险批准都必须基于可解释、版本化的确定性规则,并允许抽样复核和一键撤回。
## 15. 测试数据集设计
建立不含真实个人信息的版本化测试 corpus,每条样本有 `sample_id`、租户、来源类型、期望状态、期望 reason codes、期望 locator、期望可检索范围和 content hash。
1. 格式集:原生/扫描 PDF、缺页 PDF、含附件 PDF、DOCX 页眉页脚/批注、PPTX 多页、XLSX 多 sheet/合并单元格、TXT/CSV 编码变体、图片、长短音频、视频关键帧。
2. 噪声集:页码、水印、目录、重复页、零宽字符、`U+FFFD`、乱码、空文档、超长段、极短段、表格错序。
3. 重复集:字节相同、文本相同格式不同、页眉不同、少量改写、语义同义、同文档重复段、多版本制度。
4. 信任集:未知来源、过期制度、冲突制度、专家冲突、缺少适用范围、无依据结论、AI 合成未标记。
5. 安全集:合成手机号/证件/住址/邮箱、内部密钥样式、跨租户 canary、文档内提示词注入和工具调用诱导。
6. 检索黄金集:物业高频问题、无答案问题、正式制度问题、跨岗位/项目问题;每题标 allowed/forbidden chunk revisions 和最低 nDCG/Recall。
7. 回流集:用户回答、模型回答、差评、日志、记忆草稿、已确认 private/company pending,验证均不进入 prod knowledge。
8. 数据集隔离集:相同/近似 content hash 跨 train/validation/test,验证构建任务 fail closed。
## 16. 单元测试、集成测试和 E2E 测试方案
### 16.1 单元测试
- parser:格式、字符编码、页数、embedded exclusion、超限、空内容和 locator 准确性。
- normalizer:保留原文、确定性 diff、页眉页脚/页码规则、Unicode 控制字符和规则版本。
- dedupe:精确、近似、语义阈值边界;同内容不同适用范围不能自动合并。
- privacy/security:合成 PII、秘密、prompt injection;阻断 reason 不能被质量总分覆盖。
- state machine:非法跳转(尤其 `RAW/PARSED -> PUBLISHED`)必须失败;审批必须绑定当前 content hash。
- retrieval predicate:所有检索实现和 exam/case grounding 只能访问 `PUBLISHED`、未过期、授权范围内的 revision。
- outbox:幂等 upsert/delete、重试、generation、死信和并发状态转换。
### 16.2 集成测试
- MySQL + MinIO + Qdrant:上传后未批准时 MySQL/Qdrant 均不可检索;批准后只出现目标 revision;撤回后 SQL 立即不可见、Qdrant 最终删除。
- 模拟 Qdrant 500/超时:状态不谎报成功,outbox 可重试,reconciler 能发现并修复 drift。
- 多租户:同 docId、同 fragment text、同 point ID 场景下,用 tenant canary 验证 SQL、Qdrant、hydrate、下载全链路隔离。
- 规则升级:同一 raw 产生新 version,旧 PUBLISHED 继续可回滚;切换后查询审计只记录新 revision。
- 个人发布、案例、考试:统一进入 `REVIEW_PENDING`,不得直接写 prod;grounding 只能来自批准版本。
- 反馈闭环:达到阈值生成 quality issue/再审,不直接由模型或单个用户删除内容。
### 16.3 E2E 测试
1. 管理员上传一份包含 PII、过期版本和注入文本的文件,确认隔离页显示 reason codes、原文/清洗 diff,用户端搜不到。
2. 审核通过干净新版本,用户端在授权租户/岗位/项目能检索并看到正确页/段定位;其他租户不可见。
3. 撤回文档,在 MySQL 可见性切断后立即查询无结果;等待 outbox 后 Qdrant point 为 0,并保留完整审计。
4. 用真实业务黄金问题在 `390x844` 移动端跑问师傅主路径,验证引用相关、可打开原文定位、无无关主题结果。
5. 生成案例/考试题/评分,验证 synthetic/model/prompt/grounding 元数据存在,未人审内容不进入正式案例/试卷/生产统计。
现有测试应保留并扩展,例如正式制度过滤 `AihrSopSeedServiceTest.java:505`、个人精确去重 `PersonalIngestionServiceTest.java:134-182`、个人发布审核 `PersonalPublishServiceTest.java:58-64`、跨身份 fail closed `OrgSnapshotEnterpriseKnowledgeAccessPolicyTest.java:94-108`。它们证明局部控制,但不是全局 DQ 门禁测试。
## 17. 可量化验收标准
| 类别 | P0 上线门槛 | 稳态目标 |
|---|---|---|
| 生命周期 | 100% 新资产不能从 `RAW/PARSED` 直接到 prod;100% prod chunk revision 有批准记录 | 非法状态跳转测试 100% 拦截 |
| 血缘 | 100% prod chunk 可追溯到 tenant、raw asset/hash、version、规则版本、审核人 | 任一 `request_id` 5 分钟内反查全部 chunk revisions、排名和答案 hash |
| 来源/版本 | 高风险制度 100% 有 source/version/effective/expiry/authority | 过期或被替代版本召回率 0 |
| 隐私 | 阻断测试集 PII/secret 召回率 0;人工批准例外有审计 | PII 检测 recall >= 99%,precision >= 95%(在标注集) |
| 重复 | 新数据精确重复自动发现率 100% | 近重复 recall >= 95%;prod 同版本精确重复余量 0 |
| 解析 | 空/失败/缺页/替换字符阻断准确率 100% | `U+FFFD` prod 片段 0;page count mismatch prod 0 |
| 检索质量 | 跨租户 canary 泄漏 0;非 PUBLISHED 命中 0 | 黄金集 Recall@5 >= 90%,nDCG@5 >= 0.85;无关引用率 <= 5% |
| 索引一致性 | DELETE/UPSERT 失败均有 outbox 与告警;不静默丢失 | MySQL-Qdrant drift <= 0.1%,P0 delete 99% 在 5 分钟内收敛,最长 30 分钟 |
| 人工审核 | 高风险内容 100% 人审;高风险制度/场景双审身份不同 | 审核决定 100% 绑定 content hash,变更后旧批准自动失效 |
| AI 内容 | AI 案例/题目/答案/评分 100% 标 synthetic、model、prompt、grounding | 未批准 synthetic 进入 prod 数量 0 |
| 回流/数据集 | runtime/user interaction 自动进入 prod 数量 0 | train/eval content hash 交集 0;每次构建生成可审计 manifest |
| 可恢复性 | 100% 新资产原始对象存在且 hash 校验通过 | 原文抽检 100% 可恢复;不存在无来源 prod orphan |
上线前还应以本地当前值建立下降基线:上传失败率 7.79%、全局重复余量 1,897、页码类噪声 1,178、替换字符片段 19、孤儿片段 6。不能通过删除统计口径来“达标”,必须保留迁移前后 manifest 和 reason 分布。
## 18. 最小修改文件清单、实施风险与回滚
### 18.1 最小 P0 修改文件清单(审计建议;当前本地实施映射见第 19 节)
| 范围 | 最小改动 |
|---|---|
| SQL 迁移 | 新增一个 `backend/script/sql/update/aihr__data_quality_lifecycle_mysql8.sql`,创建 asset/version/assessment/issue/review/chunk revision/lineage/index outbox/query evidence 表和必要索引;不破坏现有表。 |
| 上传编排 | `AihrUploadQueueService.java`:完成条件改为“解析产物已进入治理状态”,不再以 fragment_count > 0 代表可引用。 |
| 解析/保存 | `AihrSopSeedService.java`:保存 immutable raw/version;停止普通入口直写生产片段/直接 embedding;发布、撤回只生成 outbox。 |
| 文档解析 | `ParsedDocument.java`、`TikaKnowledgeDocumentParser.java`:保留真实结构/页数/segment locator 和 parser version;显式记录 embedded skipped、truncated 等 reason。 |
| 查询 | `AihrKnowledgeQueryService.java` 与 `AihrSopSeedService.java`:所有 FULLTEXT/LIKE/vector/hydrate 统一要求 PUBLISHED revision 与有效期;企业 prompt 增加不可信来源隔离。 |
| 审计 | `AihrKnowledgeQueryAuditService.java`:新增 query evidence 批量写入、答案 hash、生成/检索模型版本。 |
| 向量 | 可在现有 service 内先加 `AihrIndexOutboxService/Worker/Reconciler`,后续再拆模块;所有 point 使用 revision/generation。 |
| 特殊入口 | `PersonalPublishService.java`、`AihrCaseService.java`、`AihrExamService.java`:改为创建待审版本,复用同一发布门和批准 grounding。 |
| API/管理端 | `AihrSopController.java` 及管理端资料处理页:增加质量详情、reason、审核、撤回/重处理;不恢复目录导入 UI。 |
| 测试 | 扩展 knowledge/personal/case/exam tests;新增 lifecycle、quality detector、outbox、reconciliation、cross-tenant E2E 和 corpus fixtures。 |
### 18.2 实施风险
- 加发布过滤后,历史片段默认都不满足 `PUBLISHED`,直接启用会造成检索结果骤降。必须先 inventory/backfill,并按风险分空间灰度。
- 重解析会改变 chunk ID、引用和排序;需要 `legacy_fragment_id -> chunk_revision_id` 映射与引用兼容期。
- 新旧 collection 双写会增加 embedding 成本和资源;必须按 hash 跳过未变化版本,并设置批次限流。
- 自动 PII/领域规则存在误报;默认隔离虽安全,但可能形成审核积压,需要容量、SLA 和批量归组能力。
- MinIO 原文件缺失的历史资料无法可靠重建定位与质量证据;不得从现有片段反向伪造“原始版本”。
- 对案例、考试和个人发布统一加门禁会改变运营流程,应在 API 中显式返回 `REVIEW_PENDING`,不能继续显示“已入库/已发布”。
### 18.3 回滚方案
1. 数据库采用纯新增迁移;旧表和原始对象不删除、不覆盖。应用回滚时可忽略新表。
2. 新检索以 feature flag/active generation 切换;回滚只切回旧 generation,不重新导入或覆盖数据。
3. 新旧索引并存一个约定窗口;任何质量或召回回归先停新发布 worker,再切回旧读路径。
4. outbox 操作幂等;回滚应用版本不能删除未完成事件。恢复后由兼容 worker 继续消费或人工批准重放。
5. 历史 migration batch 有 manifest、输入/输出 hash、状态和 rollback generation;只撤销“可见性/索引指针”,不物理删除审计链。
6. P0 安全不变量不得作为普通回滚项:跨租户过滤、非 PUBLISHED 隔离、PII/secret 阻断、撤回后 hydrate 校验必须保持 fail closed。
---
**最终判断:** 当前系统不是“完全没有治理”,而是存在多个质量不同、彼此不统一的局部生命周期。正式制度、个人知识、陪练场景、考试和记忆分别实现了部分正确控制,但企业通用知识主链仍把“解析成功”近似等同于“可引用”。在完成 P0 之前,不应把现有 `aihr_knowledge_fragment` 或默认 Qdrant collection 定义为经过审核的可信知识区,也不应将其直接作为训练集或评测集来源。
## 19. 审计后本地实施映射(2026-08-02)
本节只说明审计后工作树的本地实现,不改写前述审计时证据,也不代表生产部署。
| 审计问题 | 当前本地措施 | 状态 |
|---|---|---|
| `RAW -> INDEXED` | 上传、个人投稿和 AI 整理内容先创建不可变 asset/version/chunk revision;只有人工批准后创建生产 fragment 与 UPSERT outbox | 已实现并有门禁测试 |
| `MODEL_OUTPUT -> TRUSTED` | synthetic/用户交互默认不可信;模型不能自行批准、删除或发布 | 已实现 |
| 软问题可绕过 | 发布后端接受 reason code 后重新统计全部 `OPEN SOFT`,仍有遗漏即拒绝 | 已实现并有回归测试 |
| 清洗覆盖原文 | NFKC/控制字符/空白规范化只生成 `normalize-v2` 新版本;保存 extractor/cleaner/chunker 版本 | 已实现 |
| 规范化正文携带个人信息进入下游 | `privacy-redaction-v1` 生成独立 `redacted_content/redacted_source_name` 并保存派生 hash、隐私状态、规则版本和分类计数;解析/规范化正文只作受控审计证据,chunk、语义分析、模型调用、发布和引用标题只消费 `CLEAN/REDACTED` 派生内容;复扫残留以 `PII_DETECTED` 阻断 | 已实现;管理端提供脱敏预览,规则升级需生成新派生版本并重新审核 |
| 同名上传覆盖来源 | 取消附件文件名唯一约束;每次接入创建独立 attachment/doc/asset,精确重复只复用只读 OSS 对象 | 已实现并有迁移契约测试 |
| 结构与重复 | 标题、段落、Q&A、SOP 步骤切片;保存结构画像和 64 位 SimHash;异步 embedding 仅生成语义候选,本地降级显式标记 | 已实现;真实业务阈值待标定 |
| 旧制度冲突 | 同租户同名已发布资料内容不同产生 `VERSION_CONFLICT`;规范性知识必须显式 `supersedesAssetId`,同事务撤回旧资产 | 已实现并有回归测试 |
| 制度/专家 claim 冲突 | 确定性提取正反约束和数值 claim,只与同租户已发布 claim 比较;人工逐条确认、误报或解决,未裁决阻断发布 | 已实现基础规则;复杂条件与多专家关系待扩充 |
| 撤回后向量残留 | MySQL 立即切断生产可见性,DELETE outbox 最多重试 8 次后进入 `DEAD_LETTER`;提供 `index-health` | 已实现;生产告警接入待做 |
| 知识空间解绑绕过撤回 | 已批准或已发布资产解绑前必须由当前人工操作人走统一 `WITHDRAW`;OSS 孤儿清理同时检查附件与治理资产引用,核验失败时保留原件 | 已实现并有回归测试 |
| 错误答案无法定位污染 chunk | query evidence 保存实际 rank/score/channel/used;差评带 requestId 关联 fragment、chunk revision、asset/version | 已实现 |
| 用户反馈自动影响可信数据 | 反馈只创建 `DOWNSTREAM_ANSWER_DISPUTED`;人工 `KEEP` 保留,`WITHDRAW` 调统一撤回 | 已实现并有回归测试 |
| 缺测试基线 | 增加 PII、secret、提示词注入、synthetic、无来源历史数据黄金夹具及生命周期/证据/反馈单测 | 已实现首批;真实业务标注集待扩充 |
| 历史片段伪造来源 | `/quality/legacy/stage` 不复制旧 fragment 作为事实;存在同租户 OSS 原件时下载到受限临时文件并重新解析,不存在或不可读时创建 `QUARANTINED / SOURCE_UNAVAILABLE` 版本 | 已实现并有游标、隔离测试;全量迁移待人工分批执行 |
| Agent 反馈缺少真实检索血缘 | Agent run 只保存内部 `KNOWLEDGE:` 引用,不保存问题/答案/附件;反馈在同租户内解析到真实 query evidence 和 fragment | 已实现并通过本地真实链路验证 |
| 缺生产质量告警 | `aihr_quality_alert` 保存稳定告警码、严重级别、证据、次数和打开/解决时间;定时扫描覆盖索引漂移、死信、血缘、开放问题、过期资料和查询证据,Actuator 暴露 `aihrKnowledgeQuality` | 已在本地实现并验证迁移幂等;外部告警平台接入待生产运维配置 |
| 缺可重复检索质量评测 | `scripts/evaluate-knowledge-quality.mjs` 计算 Recall@K、MRR、nDCG@K、跨租户禁止片段泄漏率和无证据率,不记录令牌或问题正文 | 工具和示例契约已实现;真实业务黄金集仍需专家标注后才能形成验收结论 |
| 上传失败时绕过生命周期 | 上传、批量上传和媒体重处理不再回退为直接写 `aihr_knowledge_fragment`/embedding/Qdrant;生命周期服务不可用时返回 503 | 已实现;必须保持 fail-closed |
| 只在初次检索检查发布状态 | 检索引用水合、引用详情、相邻片段和原件下载均独立复核当前版本、`PUBLISHED`、`HUMAN_VERIFIED`、`production/ACTIVE` 和有效期 | 已实现并有回归测试 |
| 历史向量与生产向量混算 | 新向量 payload 固定带 `dataset_code=production`、`PUBLISHED`、`HUMAN_VERIFIED`;查询、重建和健康计数只处理这些点,未纳管片段单列 `UNGOVERNED_LEGACY_FRAGMENTS` | 已实现;旧点暂不物理删除,待历史纳管完成后按 manifest 处置 |
| 页码、页眉和上下文噪声只定义未检测 | `dq-gate-v3` 以版本化确定性规则生成 `PAGINATION_NOISE/HEADER_FOOTER_NOISE/DOMAIN_IRRELEVANT/CONTEXT_INCOMPLETE/CHUNK_CONTEXT_BROKEN` 软问题 | 已实现并有门禁测试;阈值仍需真实语料标定,算法不自动清洗原文 |
| 历史纳管缺少断点恢复 | `scripts/stage-legacy-knowledge.mjs` 默认 dry-run;带 token 时先调用只读 `/legacy/preview`,显式 `--execute` 才分批写入;manifest 不保存正文/token,失败 ID 不推进恢复游标 | 已实现并有 Java/Node 测试;尚未对 1,046 份附件执行 |
| 评测不能作为发布门禁 | 评测契约区分 answerable/no-answer,统计并可分别设置 Recall/MRR/nDCG、禁止来源泄漏、错误来源和无答案误召回阈值;任一阈值失败退出码为 2 | 已实现并有 Node 测试;示例仅为模板,不能冒充人工黄金集 |
| 业务黑话缺少治理 | 新增不可变版本术语表和管理端入口,支持草稿、批准、驳回、新修订与停用;只有同租户人工 `ACTIVE` 版本按项目/角色扩展召回查询,definition 不作为事实注入 Prompt | 已实现服务端 API、管理端、检索接入和迁移;词条内容尚待业务审核录入 |
| AI 案例审核后丢失合成身份 | 案例整理记录 synthetic、generator/model、prompt version、grounding OSS、摘要 hash、reviewer/time;“已入库”仍是人工批准的合成案例 | 已实现并有迁移与单测,不等同于权威知识 |
本地真实链路已经验证:一次 Agent 查询能够从 `aihr_agent_run.result_ref` 反查知识请求、召回证据和具体 fragment,并将“未解决”反馈落为 `DOWNSTREAM_ANSWER_DISPUTED`;一次已发布资产撤回后,MySQL 生产 fragment 与 locator 被移除,数据集成员停用,DELETE outbox 成功,Qdrant 对应点为 0,同时 asset/version/chunk revision/原件审计链保留。隐私链路另以访谈类测试资料验证:原始/规范化正文保留审计内容,脱敏正文、派生 chunk、摘要、标签、归类理由和响应 snippet 不再包含已识别姓名或手机号,审核页只显示脱敏预览;`PII_REDACTED` 作为处理证据保留,残留 PII 才触发硬门禁。最后一次快照保留 2 个 `REVIEW_PENDING / UNTRUSTED` 测试资产,生产 fragment、生产成员、outbox 与 Qdrant 生产点均为 0。2026-08-02 收尾时本地后端未运行,因此这些是最后已记录快照,不是实时状态;未重置数据库,也未覆盖从 YCWY 同步的资料。
当前仍不得宣称完成的事项:历史 1,046 份附件未完成逐份来源/版本复核;缺失 MinIO 原件的历史片段无法恢复真实来源;业务术语尚未由责任人录入并审核;语义阈值、噪声阈值与复杂 claim 适用条件尚未用真实业务黄金集标定;生产 Qdrant 一致性、外部告警送达、黄金集 Recall/nDCG、无答案误召回与误隔离率尚未按真实标注集验收。
## 20. 综合改进方案与实施顺序
### 20.1 对其它 Agent 建议的取舍
| 建议 | 结论 | 在本项目中的正确用法 |
|---|---|---|
| OCR 除噪、术语表、结构化 Q&A/SOP | 采用 | 作为 `PARSED -> NORMALIZED/CLASSIFIED` 的候选产物,保留原文、规则版本和差异;仍需质量门禁与人工批准。 |
| 用 AI 把乱码整理成 JSON 后入向量库 | 不能直接采用 | AI 只能生成 `synthetic_unverified` 候选和清洗建议;不得覆盖原件,也不得自动进入生产索引。 |
| 固定使用 500–800 字、重叠 100 字 | 不作为全局规则 | 先按标题、段落、Q&A、SOP 步骤和页码结构切片,再用黄金集标定不同文档类型的长度和重叠。 |
| 标题、岗位、场景 metadata filter | 采用 | metadata 必须由服务端从已审核资产生成,并与租户、空间、项目、岗位、有效期过滤同时执行,不能信任客户端标签。 |
| HyDE | 暂不进入 P0 | 它可能提高召回,也可能放大查询假设和错误制度;只能在人工黄金集上与基线做 A/B,对无答案率和错误来源率设置回退门槛。 |
| Prompt 强制引用、资料不足时拒答 | 采用但不视为安全边界 | 服务端先完成发布状态与权限过滤并记录召回证据;Prompt 只约束表达,不能替代数据准入、权限或撤回。 |
| 覆盖旧文件做“一劳永逸”清洗 | 拒绝 | 原始对象不可变;新清洗结果生成新版本,批准后通过 `supersedesAssetId` 失效旧版本。 |
### 20.2 最合适的落地顺序
1. **P0 新污染止血(本地代码已完成,尚未生产发布)**:保持所有接入 fail-closed;生产检索、引用详情和下载只认当前人工批准版本;向量写入、查询、删除和计数只认生产标签;撤回先切断 MySQL 可见性,再由 outbox 删除向量。
2. **P0 生产前准备**:在结构副本按顺序执行 `aihr_20260801` 至 `aihr_20260814` 迁移并做幂等验证;备份生产数据库;部署后先验证空候选不可检索、隐私状态未完成或复扫残留 PII 的候选不可发布、批准后可检索、撤回后不可检索和跨租户负例。未通过时只回滚应用可见性,不删除原件和审计表。
3. **P0 历史资料分批纳管**:按租户和 `attachmentId` 游标盘点 1,046 份附件,以 MinIO 原件为唯一重解析依据;建议每批 20–50 份。每批执行“重解析 -> 自动检测 -> 人工审核 -> 小范围发布 -> 标准题回归”,禁止自动批准或把 8,607 个旧片段反向伪造成原始来源。
4. **P1 内容质量提升**:先处理现行制度和高频 SOP,再处理专家访谈、案例和 OCR 材料;建立术语表、适用范围、有效期、版本替代、结构化步骤和正反例标签。AI 只辅助提取、纠错候选和冲突发现,最终事实与适用范围由人确认。
5. **P1 检索标定**:业务专家标注 100–300 条黄金问题,覆盖有答案、无答案、旧制度、冲突制度、多租户、岗位/项目差异和 OCR 噪声。先调结构切片、metadata filter、混合召回和 rerank,再评估 HyDE;没有 Recall/nDCG、错误来源率和无证据率数据,不宣称“更准确”。
6. **P2 质量闭环**:把错误回答通过 `requestId -> evidence -> fragment -> version -> asset -> source` 定位到污染源;人工决定 `KEEP/WITHDRAW`,随后重建受影响生产点并运行回归集。告警平台接入 `DEAD_LETTER`、索引漂移、发布血缘缺口、过期资料和跨租户 canary。
### 20.3 决策原则
最优先的不是让模型“更会猜”,而是让系统能够证明每条生产内容为何可信、适用于谁、何时有效、由谁批准,并能在发现问题后立即停止检索和追溯原件。在此基础上再做 OCR 除噪、结构化、检索参数和 Prompt 优化,收益才可测量且不会形成新的自污染。