839 lines
48 KiB
Markdown
839 lines
48 KiB
Markdown
# 员工个人 AI 助理 / 个人知识空间专项 TechSpec
|
||
|
||
> 版本:v1.5 | 日期:2026-07-22
|
||
>
|
||
> 归属:《银城员工端 APP 分阶段实施总纲》阶段二
|
||
>
|
||
> 需求基线:《物业 AI 人力资源系统业务需求文档 BRD》4.8
|
||
>
|
||
> 实施边界:首批交付个人资料收藏、检索、带引用问答、工作整理,以及“识别候选记忆 → 用户确认 → 分域持久化 → 可追溯召回”闭环;PPT 生成为 P1;北森、考勤等外部数据归阶段三。
|
||
>
|
||
> v1.1 需求补充:客户明确提出,员工在对话中描述住户需求、待跟进事项或个人经验时,个人助理应识别值得长期保留的信息,返回可编辑确认卡;仅在用户确认后写入对应记忆域,后续问答可按权限召回。模型不得直接修改数据库,提醒必须单独确认。
|
||
>
|
||
> v1.2 实施收口:显式“记一下 / 帮我记 / 保存一下”统一生成 `ASSISTANT_CAPTURE` 确认卡;楼栋、单元、房号和项目均为可补充信息,不再阻断保存。用户必须选择“仅自己保存 / 提交公司处理”;公司处理首批只可靠写入待流转队列,未配置正式接收接口前不得显示“已送达”。音色不在本次范围。
|
||
>
|
||
> v1.3 文档收口:v1.2 描述的是 2026-07-20 已部署行为;多项目工作采集按[《工作助手与今日工作成果迭代计划》](工作助手与今日工作成果迭代计划-20260721.md)执行。个人笔记允许项目为空,项目工作记录必须先按名称选择当前项目;项目编码只作内部授权字段,不由用户输入。
|
||
>
|
||
> v1.4 发布前本地实施快照:项目名称选择、项目化短会话、项目化确认卡、来源快照、业务状态历史、员工今日成果和主管项目成果已完成本地实现、真实 HTTP 与 390×844 验证;该快照记录的是发布前状态,外部线索/工单/考勤投递仍保持 PENDING。
|
||
|
||
> v1.5 发布与本轮回填:v1.4 所列多项目、项目化确认采集、来源/状态、员工今日成果和主管项目成果已于 2026-07-21 部署;成果历史日期选择、服务端拒绝未来日期,以及主管手机号授权兜底已于 2026-07-22 发布,并完成远端服务、schema 与产物匹配复核。外部线索/工单/考勤投递仍保持 PENDING。
|
||
|
||
当前代码状态(2026-07-22 复核):已部署版本包含候选检测、可编辑确认、PRIVATE/COMPANY 持久化、项目名称选择、项目化短会话、`ATTENDANCE/INSPECTION` 分类、来源绑定、状态闭环、员工工作成果和主管项目成果,以及成果历史日期查看、未来日期拒绝和手机号授权兼容。个人文件/网页知识空间、PPT 自动生成、外部线索/工单投递 Worker 和正式回执仍是后续工作。开发者不得从 `PENDING` 推断已派单或已送达。
|
||
|
||
## 0. 交互设计基准
|
||
|
||

|
||
|
||
设计资产:[personal-assistant-work-helper-voice-first-v2.png](prototypes/personal-assistant-work-helper-voice-first-v2.png)
|
||
|
||
多项目与今日成果联合高保真资产:[work-assistant-project-context-v3.png](prototypes/work-assistant-project-context-v3.png),仓库绝对路径为 `/Users/yuanjiantsui/dev/11-project/wygj/docs/prototypes/work-assistant-project-context-v3.png`;逐状态运行截图路径见[迭代计划 §1.5](工作助手与今日工作成果迭代计划-20260721.md#15-本地运行视觉证据390844)。
|
||
|
||
该图是阶段二「问」页和确认记忆流程的实现参考,不是当前生产截图。后续 Agent 实施 `mobile-uni/src/pages/user/sop/index.vue` 与记忆确认卡时应遵守以下不变量:
|
||
|
||
1. 页面标题保持“问 · 数字师傅”,一级只区分“工作助手 / 查全网”,不增加“个人助理”一级 Tab。
|
||
2. 工作助手自动在已授权的个人资料、项目记录和企业知识中路由;首屏主路径不要求一线员工选择资料域,高级筛选只能放入次级入口。
|
||
3. 会话保持语音优先:输入区默认“按住说话”,键盘为切换能力;师傅回复优先显示语音条,正文可通过“转文字”展开。
|
||
4. ASR 转写以普通用户消息进入同一会话;候选检测不得绕过当前会话、登录态或项目权限。
|
||
5. 确认卡至少展示系统建议类型、对象、事项、可见范围、明确回访日期和“加入跟进提醒”选项;缺少房号等信息只作弱提示。
|
||
6. `ASSISTANT_CAPTURE` 卡必须提供“修改 / 暂不保存 / 仅自己保存 / 提交公司处理”四个明确动作;旧项目服务卡继续保留“确认保存”。保存和提醒分别确认。
|
||
7. 回答或保存结果只展示实际使用的来源,不得暗示已查询未命中的资料,更不得自动把内部内容转发到全网。
|
||
|
||
若设计图中的示例文案、间距或字段与本文的数据权限、安全、状态机或 API 约束冲突,以本文约束为准;视觉实现应继续复用现有 `ChatComposer`、女性数字师傅头像和「今日 / 练 / 问 / 我」底栏。
|
||
|
||
## 1. 目标与非目标
|
||
|
||
### 1.1 目标
|
||
|
||
为每名已登录员工提供与企业知识库隔离的个人知识空间,支持:
|
||
|
||
1. 收藏个人文字、文件、图片和网页链接。
|
||
2. 自动解析正文、生成摘要与主题标签。
|
||
3. 按日期、主题、来源和关键词检索个人资料。
|
||
4. 默认由“工作助手”在个人资料、项目业务记忆和企业知识之间自动路由并展示实际来源;资料范围只作为次级高级筛选。
|
||
5. 输出结论、行动项和待确认事项,并逐条展示引用来源。
|
||
6. 删除个人资料时同步清理关系库、对象存储和向量索引。
|
||
7. 从文字或 ASR 转写中识别服务线索、住户画像、优秀案例、个人想法、待跟进事项和工作记录,返回可编辑确认卡。
|
||
8. 用户确认保存范围:`PRIVATE` 仅本人可见;`COMPANY` 进入企业待流转队列。项目服务旧记录继续按项目权限独立保存和检索。
|
||
9. 后续问答可召回已确认记忆,并展示来源消息、记录时间、当前状态和可见范围。
|
||
10. 对确认后的修改保留版本历史;提醒时间与长期保存分别确认。
|
||
|
||
### 1.2 非目标
|
||
|
||
- 阶段二首批不生成 PPT 文件,只生成可编辑汇报提纲。
|
||
- 不读取北森、考勤、请假、任职等阶段三外部数据。
|
||
- 不做通用网盘、多人协作文档、在线 Office 编辑和自动对外发送。
|
||
- 不允许个人资料自动进入企业知识库。
|
||
- 不通过“收藏网页”绕过登录、付费墙、企业内网或版权限制。
|
||
- 不复用企业知识表增加 `scope_type` 来承载个人数据。
|
||
- 不把普通聊天历史自动升级为长期记忆,不在用户确认前写入个人或项目长期记忆表。
|
||
- 不允许 LLM 直接执行 SQL、更新业务实体、创建提醒或对外发送消息;模型只生成结构化候选草稿。
|
||
- 不把 `COMPANY/PENDING` 描述成已生成工单、已上报或已送达;正式接收端、认证和回执协议确定后才启用投递 Worker。
|
||
- 不把住户服务事实只存入员工私人空间;这类记录属于项目业务域,员工调岗后仍按项目权限保留。
|
||
- 阶段二首批不替代权威房屋、住户、工单或 CRM 主数据;未接入权威主数据时不得伪造住户身份。
|
||
|
||
## 2. 核心架构决策
|
||
|
||
### 2.1 处理能力复用,数据物理分域
|
||
|
||
| 能力 | 复用方式 | 隔离要求 |
|
||
|---|---|---|
|
||
| 文件上传与 OSS | 复用 `ISysOssService` | 使用私有前缀 `personal/{tenantId}/{userId}/{itemId}/` |
|
||
| 文档解析 | 从 `AihrSopSeedService` 抽取无状态解析组件 | 解析结果只能写个人表 |
|
||
| Embedding / Rerank / LLM | 复用现有模型配置与成本闸门 | 调用前按个人资料规则脱敏,不写企业片段表 |
|
||
| 全文检索 | 使用个人片段表 MySQL Fulltext | 查询必须包含 `tenant_id + owner_user_id` |
|
||
| 向量检索 | 新建 `aihr_personal_knowledge` collection | Qdrant filter 必须包含 `tenant_id + owner_user_id` |
|
||
| 企业知识检索 | 调用现有企业 RAG 服务 | 继续执行企业知识密级、项目和角色权限 |
|
||
| 项目业务记忆 | 独立 `aihr_service_memory` 关系表;关系库检索为 2026-07-19 最小切片,Qdrant 仅列为后续增强 | 查询必须包含 `tenant_id + project_code`,不得写入个人或企业知识表 |
|
||
| 对话统一采集 | `aihr_memory_candidate` 暂存确认卡,确认后写 `aihr_assistant_capture` | `PRIVATE` 仅按 owner 查询;`COMPANY` 以 outbox 状态流转,不允许前端伪造已送达 |
|
||
|
||
禁止将个人资料写入:
|
||
|
||
- `aihr_knowledge_info`
|
||
- `aihr_knowledge_attach`
|
||
- `aihr_knowledge_fragment`
|
||
- 企业 Qdrant collection `aihr_knowledge`
|
||
|
||
### 2.2 检索流程
|
||
|
||
```text
|
||
用户问题 + scopeMode(AUTO / MANUAL) + scope(personal / project_service / enterprise)
|
||
→ 从移动端 token 取得 tenantId、userId、extPartyId
|
||
→ AUTO: 意图路由只在三个内部授权域中选择;MANUAL: 校验用户指定的内部范围
|
||
→ 校验日期、itemIds、知识范围和配额
|
||
→ personal: 个人 Fulltext + 个人 Qdrant(强制 owner filter)
|
||
→ project_service: 首批用关系库检索并强制 project_code filter;后续再叠加独立 Qdrant
|
||
→ enterprise: 企业 Fulltext + 企业 Qdrant(强制企业权限)
|
||
→ mixed: 所选域分别检索并授权后融合,不做跨域原始结果直连
|
||
→ Rerank
|
||
→ LLM 生成答案
|
||
→ 返回 citations,每条标记 PERSONAL / PROJECT_SERVICE / ENTERPRISE / WEB
|
||
→ 保存会话、答案、引用和 prompt/model 版本
|
||
```
|
||
|
||
`AUTO` 永远不包含公网查询。内部域没有命中时只返回“是否查全网”的用户操作建议,不得把原问题、住户信息或项目数据自动转发到全网 AI。
|
||
|
||
### 2.3 模块边界
|
||
|
||
后端新增独立包,避免继续扩大 `AihrSopSeedService`:
|
||
|
||
```text
|
||
org.dromara.aihr.personal
|
||
├── controller/PersonalAssistantController.java
|
||
├── domain/PersonalAssistantDto.java
|
||
├── service/PersonalSpaceService.java
|
||
├── service/PersonalIngestionService.java
|
||
├── service/PersonalRetrievalService.java
|
||
├── service/PersonalAnswerService.java
|
||
├── service/PersonalCleanupService.java
|
||
├── service/PersonalUrlFetchService.java
|
||
├── memory/MemoryCandidateService.java
|
||
├── memory/MemoryConfirmationService.java
|
||
├── memory/ServiceMemoryService.java
|
||
├── memory/ServiceMemoryRetrievalService.java
|
||
└── support/PersonalKnowledgeProperties.java
|
||
```
|
||
|
||
解析器抽为共享、无状态能力:
|
||
|
||
```text
|
||
org.dromara.aihr.knowledge.parse
|
||
├── KnowledgeDocumentParser.java
|
||
├── ParsedDocument.java
|
||
└── KnowledgeChunker.java
|
||
```
|
||
|
||
共享解析器只接受文件/字节和解析参数,只返回内存对象,不知道企业表、个人表或 Qdrant collection。
|
||
|
||
### 2.4 确认式长期记忆
|
||
|
||
个人助理统一承接三层记忆,但持久化边界不同:
|
||
|
||
| 记忆层 | 用途 | 生命周期与事实源 |
|
||
|---|---|---|
|
||
| 对话上下文 | 理解“刚才那位住户”等短期指代 | 仅进入受限上下文窗口;会话历史不自动成为长期记忆 |
|
||
| 个人工作记忆 | 员工自己的经验、灵感、工作方法 | 用户确认后写入 `aihr_personal_item`,默认仅本人可见 |
|
||
| 项目业务记忆 | 住户需求、服务事实、待跟进事项 | 用户确认后写入 `aihr_service_memory`,按租户 + 项目 + 角色授权共享 |
|
||
|
||
写入流程固定为:
|
||
|
||
```text
|
||
文字输入 / 语音 ASR 转写
|
||
→ 规则预筛(明确“记一下”等意图,或同时出现对象 + 需求/跟进事实)
|
||
→ 服务端先提取并令牌化楼栋、单元、房号、姓名、电话等标识
|
||
→ 当前 P0 用确定性规则建议类型和分类;后续模型只能输出符合 JSON Schema 的候选建议
|
||
→ 服务端校验当前租户、项目、重复记录、权限和敏感字段
|
||
→ 显式“记一下”始终持久化 DRAFT;项目/楼栋/单元/房号缺失只列为可选补充项
|
||
→ 用户修改并选择 PRIVATE / COMPANY(携带幂等键和 expectedVersion)
|
||
→ 确定性 Service 写 `aihr_assistant_capture`;PRIVATE 记为 NOT_REQUIRED,COMPANY 记为 PENDING
|
||
→ 正式企业接收端接入后,由独立投递 Worker 消费 PENDING 并记录回执;当前不得假投递
|
||
→ 如用户另行确认 followUpAt,则进入“今日安排”;不默认创建提醒
|
||
```
|
||
|
||
约束:
|
||
|
||
1. 候选检测可自动发生,但任何置信度都不得跳过用户确认。
|
||
2. DRAFT 候选只为跨刷新恢复确认卡,不进入检索和回答;忽略或过期后清理草稿内容。
|
||
3. 同一来源消息和候选哈希在有效期内只展示一次,避免重复打扰。
|
||
4. 当前仓库没有权威房屋/住户主数据。首批允许保存经员工确认的可选项目、楼栋、单元、房号定位;缺少这些字段仍可保存,但不得据此虚构或合并住户身份。
|
||
5. 关系数据库是事实源,向量索引只负责召回;索引写入失败不得丢失已确认记录,可重试重建。
|
||
|
||
## 3. 身份、权限与数据隔离
|
||
|
||
### 3.1 所有者身份
|
||
|
||
- `owner_user_id`:本地 `sys_user.user_id`,作为阶段二强制所有权键。
|
||
- `owner_ext_party_id`:可空,保存组织快照外部主体 ID,供阶段三身份迁移使用。
|
||
- `tenant_id`:沿用 RuoYi 多租户上下文。
|
||
- Controller 不接受客户端提供的 `ownerUserId`、`tenantId`。
|
||
- Service 每次查询都从当前登录态取得 `tenant_id + user_id`,不得只按主键查询。
|
||
|
||
### 3.2 访问矩阵
|
||
|
||
| 操作 | 本人 | 普通主管 | HR/运营 | 系统管理员 |
|
||
|---|---:|---:|---:|---:|
|
||
| 查看个人资料正文 | ✅ | ❌ | ❌ | ❌(默认) |
|
||
| 查看个人资料数量/处理状态 | ✅ | ❌ | 聚合且脱敏 | 聚合且脱敏 |
|
||
| 删除本人资料 | ✅ | ❌ | ❌ | ❌(默认) |
|
||
| 申请分享/企业入库 | ✅ | ❌ | 审核申请 | 审核申请 |
|
||
| 紧急审计查看 | ❌ | ❌ | 需 `aihr:personal:audit`、工单号和原因 | 同左 |
|
||
|
||
紧急审计必须记录审计人、目标用户、itemId、原因、工单号、时间和结果;正文不写入审计日志。
|
||
|
||
### 3.3 防越权规则
|
||
|
||
1. 所有 `/api/aihr/personal-assistant/**` 接口必须登录,不使用 `@SaIgnore`。
|
||
2. 单项读取、删除、重试必须使用 `WHERE id=? AND tenant_id=? AND owner_user_id=?`。
|
||
3. Qdrant 查询必须同时过滤 `tenant_id` 和 `owner_user_id`。
|
||
4. 企业知识结果进入融合前必须经过企业权限过滤;客户端传来的 fragmentId 不能直接作为引用。
|
||
5. 个人资料转企业知识必须复制经审核后的脱敏版本,不能把个人 item 直接改成企业 scope。
|
||
6. 自动化测试必须使用两个用户交叉访问,验证列表、详情、检索、向量和删除均返回不可见。
|
||
|
||
### 3.4 项目业务记忆权限
|
||
|
||
1. 个人笔记允许 `project_code` 为空;晨会、巡检、业主服务、画像、线索等项目工作记录必须先选择当前项目。
|
||
2. 客户端展示员工有权限的项目名称下拉列表,不展示或要求手输项目编码;选择结果可携带内部项目标识,服务端必须按当前登录员工的有效项目任职重新解析并校验,不能信任客户端字段。
|
||
3. 项目授权沿用 `aihr_org_snapshot.project_code` 和现有知识授权口径;同一员工的多项目成员关系按 `tenant_id + project_code + ext_party_id` 保留,客户端不得指定越权项目。
|
||
4. 项目业务记忆的列表、详情、修改和召回必须同时过滤 `tenant_id + project_code`,创建人不因“本人记录”获得跨项目访问权。
|
||
5. 住户姓名、电话、身份证件和健康信息不作为自由文本检索字段;首批优先保存房屋定位、需求摘要、跟进状态和必要说明。
|
||
6. 发送外部模型前先由服务端提取并令牌化可识别信息;模型输出不得覆盖服务端保存的主体定位。
|
||
7. 员工修改已确认记录必须携带 `expectedVersion`,成功后新增版本快照,不原地抹除历史。
|
||
8. 项目业务记忆不能通过个人资料删除接口删除;作废使用 `VOID` 状态并保留操作人、原因和版本记录。
|
||
|
||
## 4. 数据模型
|
||
|
||
初始化 SQL:`backend/script/sql/aihr_personal_knowledge_mysql8.sql`。
|
||
|
||
### 4.1 `aihr_personal_space`
|
||
|
||
每个租户内每名员工一条。
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
|---|---|---|
|
||
| id | bigint PK | 主键 |
|
||
| tenant_id | varchar(20) | 租户 |
|
||
| owner_user_id | bigint | 本地用户 ID |
|
||
| owner_ext_party_id | varchar(100) null | 外部主体 ID |
|
||
| status | varchar(20) | ACTIVE / FROZEN / DELETING |
|
||
| quota_bytes | bigint | 默认 524288000(500MB) |
|
||
| used_bytes | bigint | 已用空间,事务内维护 |
|
||
| item_count | int | 未删除资料数 |
|
||
| create_time/update_time | datetime | 审计时间 |
|
||
|
||
约束:`UNIQUE(tenant_id, owner_user_id)`。
|
||
|
||
### 4.2 `aihr_personal_item`
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
|---|---|---|
|
||
| id | bigint PK | 资料 ID |
|
||
| tenant_id/space_id/owner_user_id | bigint/varchar | 冗余所有权键,便于强制过滤 |
|
||
| source_type | varchar(20) | TEXT / FILE / IMAGE / URL |
|
||
| capture_channel | varchar(20) | TEXT / VOICE / UPLOAD / SHARE;语音保存 ASR 文本,不把音频文件冒充正文 |
|
||
| title | varchar(500) | 标题 |
|
||
| original_url | varchar(2000) null | 原网页地址 |
|
||
| oss_id | bigint null | 原文件或网页快照 OSS ID |
|
||
| mime_type | varchar(100) | MIME |
|
||
| size_bytes | bigint | 原始大小 |
|
||
| content_hash | varchar(64) | SHA-256 去重 |
|
||
| status | varchar(20) | QUEUED / PARSING / READY / FAILED / DELETING / DELETED |
|
||
| error_code/error_message | varchar | 可公开的失败信息,不存堆栈 |
|
||
| attempt_count | int | 解析尝试次数,默认 0,每次执行前加 1 |
|
||
| summary | text | 自动摘要 |
|
||
| tags_json | json | 主题标签数组 |
|
||
| captured_at | datetime | 内容产生/网页抓取时间 |
|
||
| parsed_at | datetime null | 解析完成时间 |
|
||
| deleted_at | datetime null | 逻辑删除时间 |
|
||
| create_time/update_time | datetime | 审计时间 |
|
||
|
||
索引:
|
||
|
||
- `(tenant_id, owner_user_id, status, create_time)`
|
||
- `(tenant_id, owner_user_id, captured_at)`
|
||
- `(space_id, content_hash)`
|
||
|
||
### 4.3 `aihr_personal_fragment`
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
|---|---|---|
|
||
| id | bigint PK | 片段 ID |
|
||
| tenant_id/space_id/owner_user_id/item_id | bigint/varchar | 所有权与父项 |
|
||
| idx | int | 片段序号 |
|
||
| content | text | 正文片段 |
|
||
| token_count | int | token 数 |
|
||
| embedding_json | longtext null | Qdrant 不可用时的本地兜底 |
|
||
| embedding_model | varchar(100) null | 模型 |
|
||
| embedding_time | datetime null | 向量时间 |
|
||
| create_time | datetime | 创建时间 |
|
||
|
||
约束:`UNIQUE(item_id, idx)`;Fulltext 索引仅覆盖个人表。
|
||
|
||
### 4.4 `aihr_personal_chat_session` 与 `aihr_personal_chat_message`
|
||
|
||
Session 保存 `id/tenant_id/owner_user_id/title/default_scope_mode/default_scope_json/create_time/update_time`;`default_scope_mode` 默认 AUTO。
|
||
|
||
Message 保存:
|
||
|
||
- `session_id/owner_user_id/role`
|
||
- `content`
|
||
- `scope_json`
|
||
- `citations_json`
|
||
- `model_name/prompt_version`
|
||
- `input_tokens/output_tokens/latency_ms`
|
||
- `create_time`
|
||
|
||
个人消息只允许本人读取和删除;运营报表仅统计数量、token 和延迟,不读取 content。
|
||
|
||
### 4.5 `aihr_personal_publish_request`(P1)
|
||
|
||
个人资料申请进入团队或企业知识库的审核记录:`item_id/applicant_user_id/target_scope/reason/status/reviewer_user_id/review_comment/review_time/published_knowledge_id`。
|
||
|
||
状态固定为 `PENDING / APPROVED / REJECTED / CANCELLED`。批准后生成新的企业知识附件和片段,保留来源链,不改变个人 item 所有权。
|
||
|
||
### 4.6 `aihr_personal_audit_log`
|
||
|
||
紧急审计专用不可变日志:`tenant_id/auditor_user_id/target_owner_user_id/item_id/action/reason/ticket_no/result/create_time`。日志不保存个人正文、附件 URL、问题或答案内容;业务接口不提供更新和删除操作。
|
||
|
||
### 4.7 `aihr_memory_candidate`
|
||
|
||
确认卡草稿表,不属于长期记忆,也不进入全文/向量索引。
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
|---|---|---|
|
||
| id | bigint PK | 候选 ID |
|
||
| tenant_id/owner_user_id/project_code | varchar | 当前身份与候选项目范围;项目键使用现有组织快照的 `project_code`,不是自造数值 ID |
|
||
| source_conversation_id/source_request_id | varchar(64) | 来源短会话与本次问答请求;当前「问」链没有持久化消息 ID |
|
||
| candidate_hash | varchar(64) | 来源 + 规范化草稿哈希,用于防重复 |
|
||
| memory_type | varchar(30) | SERVICE_LEAD / RESIDENT_PROFILE / CASE / PERSONAL_NOTE / FOLLOW_UP / PROJECT_NOTE |
|
||
| target_domain | varchar(30) | 新候选为 ASSISTANT_CAPTURE;确认后记录结果映射为 PERSONAL / COMPANY;旧记录兼容 PROJECT_SERVICE |
|
||
| status | varchar(20) | NEEDS_INPUT / DRAFT / CONFIRMED / DISMISSED / EXPIRED |
|
||
| draft_json | json | 可编辑结构化草稿;不得包含未脱敏模型原始响应 |
|
||
| missing_fields_json | json | 仍需追问的字段 |
|
||
| confidence | decimal(5,4) | 只决定是否建议展示,不决定自动保存 |
|
||
| version | int | 乐观锁版本,从 1 开始 |
|
||
| confirm_idempotency_key/confirm_request_hash | varchar | 确认写入的稳定幂等键及请求内容哈希 |
|
||
| target_id | bigint null | 确认后生成的个人 item 或业务记忆 ID |
|
||
| expires_at/confirmed_at | datetime null | 草稿过期与确认时间 |
|
||
| create_time/update_time | datetime | 审计时间 |
|
||
|
||
约束:`UNIQUE(tenant_id, owner_user_id, source_request_id, candidate_hash)`;DRAFT 默认 24 小时过期,DISMISSED/EXPIRED 的 `draft_json` 在 24 小时内物理清理。
|
||
|
||
### 4.8 `aihr_assistant_capture`
|
||
|
||
用户确认后的统一采集事实源。核心字段为 `tenant_id/owner_user_id/project_code/save_scope/suggested_type/building_name/unit_name/room_no/category/summary/detail/occurred_at/follow_up_at/work_date/business_status/source_snapshot_json/source_conversation_id/source_request_id/delivery_status/delivery_attempts/next_delivery_at/external_record_id/last_error/confirm_idempotency_key/confirm_request_hash/version/create_time/update_time`。
|
||
|
||
- `save_scope=PRIVATE` 时 `delivery_status=NOT_REQUIRED`,查询必须同时带 `tenant_id + owner_user_id`。
|
||
- `save_scope=COMPANY` 时首批写 `delivery_status=PENDING`;`DELIVERED` 只能由拿到外部成功回执的投递 Worker 更新。
|
||
- `confirm_idempotency_key` 在租户和 owner 范围唯一,确认事务先写采集记录再关闭候选,任一步失败整体回滚。
|
||
- `business_status` 固定为 `RECORDED/PENDING/IN_PROGRESS/COMPLETED/VOID`;状态历史保留原状态、目标状态、操作人、说明和时间,状态幂等键不得跨记录或目标状态复用。
|
||
- `source_snapshot_json` 只保存最小必要来源快照和受保护 OSS 引用,源文件通过重新鉴权接口交付,不保存公开 URL。
|
||
- 表内不保存原始录音、模型原始输出或伪造的住户主体 ID;音色不属于本表和本次实现。
|
||
|
||
### 4.9 `aihr_service_memory`
|
||
|
||
项目共享的住户需求和待跟进事实,不放入个人知识表。
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
|---|---|---|
|
||
| id | bigint PK | 业务记忆 ID |
|
||
| tenant_id/project_code | varchar | 租户与现有项目授权键 |
|
||
| subject_type | varchar(20) | RESIDENT / LOCATION |
|
||
| resident_external_id | varchar(100) null | 仅权威住户主数据接入后保存;不得自行生成 |
|
||
| building_name/unit_name/room_no | varchar | 员工确认的结构化房屋定位 |
|
||
| category | varchar(50) | 需求分类,例如养老咨询、维修、投诉、增值服务 |
|
||
| title/summary/detail | varchar/text | 标题、最小必要摘要与说明 |
|
||
| status | varchar(20) | OPEN / IN_PROGRESS / RESOLVED / VOID |
|
||
| occurred_at | datetime | 事件发生或获知时间 |
|
||
| follow_up_at | datetime null | 用户单独确认的跟进时间;空值不产生提醒 |
|
||
| source_conversation_id/source_request_id | varchar(64) | 可追溯来源 |
|
||
| created_by/confirmed_by | bigint | 记录人与确认人 |
|
||
| version | int | 当前乐观锁版本,从 1 开始 |
|
||
| create_time/update_time | datetime | 审计时间 |
|
||
|
||
索引至少包含 `(tenant_id, project_code, status, follow_up_at)`、`(tenant_id, project_code, building_name, unit_name, room_no)`;首批关系库检索覆盖 `title/summary/detail`,后续若启用向量检索,payload 强制包含 `tenant_id + project_code + memory_id + status`。
|
||
|
||
### 4.10 `aihr_service_memory_version`
|
||
|
||
每次确认修改、状态变更或作废都追加版本:`memory_id/version/snapshot_json/change_type/change_reason/operator_user_id/create_time`。快照只保存业务字段,不复制姓名、电话等无关标识;`UNIQUE(memory_id, version)`。
|
||
|
||
## 5. Qdrant 与 OSS 设计
|
||
|
||
### 5.1 Qdrant
|
||
|
||
- 完整阶段目标:个人资料使用 `aihr_personal_knowledge` collection;项目业务记忆使用独立 `aihr_service_memory` collection,两者不混 collection。
|
||
- 确认式统一采集和兼容项目服务记录只使用 MySQL 关系库,不创建新的 Qdrant collection;不得因未做向量化而回退到无权限过滤的企业 collection。
|
||
- 向量维度:跟随当前启用的 vector 模型;模型或维度变化使用独立重建任务。
|
||
- 个人 payload:`tenant_id`、`owner_user_id`、`space_id`、`item_id`、`fragment_id`、`source_type`、`captured_at`;必建 index 为 `tenant_id`、`owner_user_id`、`item_id`。
|
||
- 项目业务记忆后续 payload:`tenant_id`、`project_code`、`memory_id`、`status`、`occurred_at`、`updated_at`;必建 index 为 `tenant_id`、`project_code`、`memory_id`、`status`。
|
||
- 个人查询无 owner filter、项目业务查询无 project_code filter 时,检索服务直接拒绝执行并记录安全日志。
|
||
- `aihr_memory_candidate` 的任何状态都不写 Qdrant;只有关系库确认事务提交成功后才异步索引目标记录。
|
||
|
||
### 5.2 OSS
|
||
|
||
- 路径:`personal/{tenantId}/{userId}/{itemId}/{safeFileName}`。
|
||
- bucket 保持私有;下载只能通过鉴权接口返回短时签名 URL。
|
||
- 原文件、网页正文快照和生成导出文件使用不同子目录。
|
||
- 文件名、Content-Type 和 multipart header 继续执行 CRLF 清洗。
|
||
- `sys_oss.ext1` 只保存解析状态和 personal itemId,不保存个人正文或手机号。
|
||
|
||
## 6. API 契约
|
||
|
||
统一前缀:`/api/aihr/personal-assistant`。响应沿用 `R<T>`。
|
||
|
||
### 6.1 空间与资料
|
||
|
||
| 方法 | 路径 | 请求/说明 |
|
||
|---|---|---|
|
||
| GET | `/space` | 当前用户空间、配额、已用量、资料数 |
|
||
| GET | `/items` | `pageNum/pageSize/status/sourceType/dateFrom/dateTo/keyword` |
|
||
| POST | `/items/text` | `{title, content, capturedAt?, tags?}` |
|
||
| POST | `/items/file` | multipart `file`, `title?`, `capturedAt?` |
|
||
| POST | `/items/url` | `{url, title?, capturedAt?}`,异步抓取 |
|
||
| GET | `/items/{id}` | 详情、解析状态、摘要、标签;所有权校验 |
|
||
| POST | `/items/{id}/retry` | 仅 FAILED 可重试 |
|
||
| DELETE | `/items/{id}` | 返回 cleanupJobId,进入 DELETING |
|
||
| GET | `/items/{id}/download-url` | 返回 5 分钟私有签名 URL |
|
||
|
||
创建响应:
|
||
|
||
```json
|
||
{
|
||
"itemId": 1201,
|
||
"status": "QUEUED",
|
||
"duplicateOf": null
|
||
}
|
||
```
|
||
|
||
### 6.2 搜索与问答
|
||
|
||
`POST /search`
|
||
|
||
```json
|
||
{
|
||
"queryText": "7月1日至7月10日我收藏了哪些保洁管理资料",
|
||
"scope": ["PERSONAL"],
|
||
"dateFrom": "2026-07-01",
|
||
"dateTo": "2026-07-10",
|
||
"itemIds": [],
|
||
"limit": 10
|
||
}
|
||
```
|
||
|
||
`POST /ask`
|
||
|
||
```json
|
||
{
|
||
"sessionId": null,
|
||
"queryText": "结合我的资料和企业制度,整理本周保洁管理改进建议",
|
||
"scopeMode": "AUTO",
|
||
"scope": [],
|
||
"dateFrom": "2026-07-01",
|
||
"dateTo": "2026-07-10",
|
||
"itemIds": [],
|
||
"outputFormat": "ACTION_PLAN"
|
||
}
|
||
```
|
||
|
||
响应:
|
||
|
||
```json
|
||
{
|
||
"sessionId": 301,
|
||
"answer": "结论……\n行动项……\n待确认事项……",
|
||
"resolvedScopes": ["PERSONAL", "ENTERPRISE"],
|
||
"citations": [
|
||
{
|
||
"domain": "PERSONAL",
|
||
"sourceId": "item:1201:fragment:3",
|
||
"title": "保洁班组周记录.xlsx",
|
||
"excerpt": "……",
|
||
"capturedAt": "2026-07-08T09:30:00"
|
||
},
|
||
{
|
||
"domain": "ENTERPRISE",
|
||
"sourceId": "knowledge:1:fragment:88",
|
||
"title": "住宅保洁作业标准",
|
||
"excerpt": "……",
|
||
"capturedAt": null
|
||
}
|
||
],
|
||
"model": "configured-chat-model",
|
||
"promptVersion": "personal_assistant_v1"
|
||
}
|
||
```
|
||
|
||
若无可用引用,返回明确的“当前资料中没有足够依据”,不得生成无引用的业务结论。
|
||
|
||
`scopeMode=AUTO` 时服务端只在 PERSONAL / PROJECT_SERVICE / ENTERPRISE 三个内部域路由,并在响应返回 `resolvedScopes`;`scopeMode=MANUAL` 时 `scope` 至少包含一个内部域。`PROJECT_SERVICE` 结果必须在融合前按当前项目权限过滤;引用额外返回 `status/occurredAt/updatedAt`,使用户能区分历史记录与当前状态。`POST /ask` 可在正常答案外返回一个 `memoryCandidate`,但不能因生成答案成功而自动确认候选。
|
||
|
||
### 6.3 会话
|
||
|
||
| 方法 | 路径 | 说明 |
|
||
|---|---|---|
|
||
| GET | `/sessions` | 当前用户会话列表 |
|
||
| GET | `/sessions/{id}` | 消息与引用 |
|
||
| DELETE | `/sessions/{id}` | 删除本人会话与消息 |
|
||
|
||
### 6.4 分享与导出(P1)
|
||
|
||
| 方法 | 路径 | 说明 |
|
||
|---|---|---|
|
||
| POST | `/items/{id}/publish-requests` | 申请进入团队/企业知识库 |
|
||
| GET | `/publish-requests` | 本人申请进度 |
|
||
| GET | `/admin/publish-requests` | HR/运营按 PENDING/APPROVED/REJECTED 查询审核列表 |
|
||
| POST | `/admin/publish-requests/{id}/review` | HR/运营批准或驳回;批准后生成脱敏企业知识副本 |
|
||
| POST | `/exports/outline` | 生成可编辑汇报大纲 |
|
||
| POST | `/exports/pptx` | 根据已确认大纲和模板异步生成 PPTX |
|
||
| GET | `/exports/{id}` | 生成状态与下载地址 |
|
||
|
||
### 6.5 运营聚合与紧急审计
|
||
|
||
| 方法 | 路径 | 说明 |
|
||
|---|---|---|
|
||
| GET | `/admin/metrics` | 仅返回用户数、资料数、状态、容量、失败率等聚合信息,不返回标题和正文 |
|
||
| POST | `/admin/items/{id}/audit-view` | 需要 `aihr:personal:audit` 权限、非空工单号和原因;先写审计日志,再返回一次性详情 |
|
||
| GET | `/admin/audit-logs` | 按审计人、目标用户、工单号和时间查询不可变日志 |
|
||
|
||
紧急审计接口与员工接口使用不同 Controller;超级管理员也不能绕过权限、工单号和原因校验。
|
||
|
||
### 6.6 确认式记忆
|
||
|
||
候选确认沿用 `/api/aihr/personal-assistant`;项目业务记忆使用独立前缀 `/api/aihr/service-memories`。
|
||
|
||
| 方法 | 路径 | 说明 |
|
||
|---|---|---|
|
||
| GET | `/memory-candidates?status=DRAFT` | 恢复当前用户尚未过期的确认卡 |
|
||
| POST | `/memory-candidates/{id}/confirm` | 提交编辑后的草稿、`expectedVersion`、`idempotencyKey`;分域写入 |
|
||
| POST | `/memory-candidates/{id}/dismiss` | 明确不保存;同源候选本会话不再提示 |
|
||
| GET | `/assistant-captures?saveScope=PRIVATE|COMPANY&limit=50` | 查看本人的已确认记录及公司流转状态 |
|
||
| POST | `/assistant-captures/{id}/status` | 带 `businessStatus/note/idempotencyKey` 推进本地处理状态 |
|
||
| GET | `/assistant-captures/{id}/status-history` | 查看状态审计历史 |
|
||
| GET | `/assistant-captures/{id}/source` | 重新鉴权读取确认记录绑定的原始媒体 |
|
||
| POST | `/api/aihr/work-results/mine/generate` | 按员工、项目和自然日幂等生成今日成果 |
|
||
| GET | `/api/aihr/work-results/project` | 主管按目标项目权限查看团队当日成果 |
|
||
| GET | `/api/aihr/service-memories` | 按当前项目、状态、日期、楼栋/单元/房号查询 |
|
||
| GET | `/api/aihr/service-memories/{id}` | 项目权限内查看详情、来源和版本 |
|
||
| PATCH | `/api/aihr/service-memories/{id}` | 携带 `expectedVersion` 修改必要字段或状态并生成版本 |
|
||
|
||
确认请求示例:
|
||
|
||
```json
|
||
{
|
||
"idempotencyKey": "01J-memory-confirm-301",
|
||
"expectedVersion": 1,
|
||
"saveScope": "COMPANY",
|
||
"draft": {
|
||
"projectCode": "YC-RESIDENTIAL-03",
|
||
"buildingName": "3栋",
|
||
"unitName": "2单元",
|
||
"roomNo": "1201",
|
||
"category": "服务线索",
|
||
"summary": "住户希望了解社区可提供的养老服务",
|
||
"occurredAt": "2026-07-19T14:00:00+08:00",
|
||
"workDate": "2026-07-19",
|
||
"businessStatus": "PENDING",
|
||
"followUpAt": null
|
||
},
|
||
"enableReminder": false
|
||
}
|
||
```
|
||
|
||
服务端必须忽略请求中的 `projectCode` 作为授权依据,仅用它与当前登录态可访问项目做一致性校验;个人笔记可省略该字段,项目工作记录不得省略。确认成功返回 `targetDomain=PERSONAL|COMPANY/targetId/version`;同一 `idempotencyKey` 重放必须返回同一结果,不重复创建记录,同一键配不同请求体必须拒绝。
|
||
|
||
## 7. 网页采集安全
|
||
|
||
`PersonalUrlFetchService` 必须执行:
|
||
|
||
1. 仅允许 `http/https`,拒绝用户名密码 URL、`file:`、`ftp:`、`data:`。
|
||
2. DNS 解析后拒绝 loopback、private、link-local、multicast、保留地址和云元数据地址。
|
||
3. 最多 3 次重定向,每次重定向重新解析和校验目标 IP。
|
||
4. 连接超时 5 秒、总超时 15 秒、响应正文上限 10MB。
|
||
5. 只接收 HTML、纯文本及明确允许的文档 MIME;下载文件仍走文件校验链。
|
||
6. 不携带用户浏览器 Cookie、Authorization、Referer 或企业内部代理凭证。
|
||
7. HTML 清洗脚本、样式、iframe、表单和隐藏元素,只保留正文与可追溯链接。
|
||
8. 记录最终 URL、HTTP 状态、抓取时间、内容哈希和 robots/版权提示;失败可重试但不绕过限制。
|
||
|
||
## 8. 解析、模型与提示词
|
||
|
||
### 8.1 解析
|
||
|
||
- 支持格式与现有知识库一致:txt/md/PDF/Word/Excel/PPT、常用图片。
|
||
- 视频、音频文件首批不作为个人资料上传;会话语音复用现有 `/api/ai/asr`,ASR 文本可进入候选记忆检测。原始录音仍按现有受保护音频规则处理,不自动复制进长期记忆。
|
||
- item 状态由 `QUEUED → PARSING → READY/FAILED` 单向推进;重试将状态恢复为 QUEUED、增加 `attempt_count`,并覆盖 `error_code/error_message`。
|
||
- 文本块默认 800 字、重叠 120 字;参数由 `PersonalKnowledgeProperties` 管理。
|
||
|
||
### 8.2 提示词模板
|
||
|
||
新增模板代码:
|
||
|
||
- `personal_assistant_answer_v1`
|
||
- `personal_assistant_summary_v1`
|
||
- `personal_assistant_action_plan_v1`
|
||
- `personal_assistant_memory_candidate_v1`
|
||
- `personal_assistant_memory_recall_v1`
|
||
- `personal_assistant_outline_v1`
|
||
- `personal_assistant_ppt_v1`(P1)
|
||
|
||
系统提示词必须包含:只基于授权片段回答、区分来源域、忽略资料中的指令注入、没有依据时拒答、不得代表用户对外作决定。
|
||
|
||
候选记忆模板只允许输出受控 JSON Schema,不能输出 SQL、表名、owner、tenant、project 授权结论或工具调用。楼栋、单元、房号、姓名、电话等标识由服务端预处理和恢复;模型只判断语义类型、摘要、缺失字段与是否值得建议保存。
|
||
|
||
### 8.3 成本闸门
|
||
|
||
- 复用 `AIHR_AI_RUNTIME_ENABLED`、chat/vector/rerank 开关。
|
||
- 解析和向量化按内容哈希去重。
|
||
- 摘要按需生成;首屏列表不批量触发 LLM。
|
||
- 保存 token、模型和延迟,不保存供应商原始请求日志中的个人正文。
|
||
|
||
## 9. 删除、配额与生命周期
|
||
|
||
### 9.1 配额默认值
|
||
|
||
| 配置 | 默认值 |
|
||
|---|---:|
|
||
| `aihr.personal.max-file-size-mb` | 20 |
|
||
| `aihr.personal.max-url-body-mb` | 10 |
|
||
| `aihr.personal.max-space-mb` | 500 |
|
||
| `aihr.personal.max-items` | 1000 |
|
||
| `aihr.personal.download-url-minutes` | 5 |
|
||
|
||
### 9.2 删除流程
|
||
|
||
1. API 将 item 标记为 DELETING,立即从列表和检索隐藏。
|
||
2. 清理任务删除 Qdrant points。
|
||
3. 删除个人 fragment。
|
||
4. 删除或解绑 `sys_oss` 对象。
|
||
5. 将 item 标记为 DELETED,仅保留无正文的审计元数据。
|
||
6. 清理任务幂等重试,24 小时内完成物理内容清理。
|
||
|
||
用户账号冻结后禁止访问个人空间;阶段三接入权威离职状态后,默认冻结 30 天,允许用户或经授权管理员导出,期满清理。该天数必须可配置。
|
||
|
||
### 9.3 候选与业务记忆生命周期
|
||
|
||
- DRAFT 候选默认 24 小时过期,不进入任何检索索引;NEEDS_INPUT 仅兼容旧候选。
|
||
- DISMISSED/EXPIRED 候选的结构化草稿在 24 小时内清理,只保留候选 ID、状态、来源消息 ID 和时间戳用于防重复。
|
||
- 个人记忆沿用个人 item 删除链路。
|
||
- 项目业务记忆不因创建员工离职而删除;按项目业务保留策略管理,首批只允许 `VOID` 作废并保留版本。
|
||
- `follow_up_at` 到期只进入员工端“今日安排”查询;推送通知、短信或自动派单不在首批范围。
|
||
- 统一采集 `PRIVATE` 记录只按 owner 保存;`COMPANY/PENDING` 保留到企业流转成功或人工关闭,失败只更新重试状态,不丢记录。
|
||
|
||
## 10. 前端设计
|
||
|
||
本节视觉与交互基准见:[工作助手语音优先与确认记忆设计图](prototypes/personal-assistant-work-helper-voice-first-v2.png)。该图对应现有微信式会话的升级目标,不代表另建页面。
|
||
|
||
### 10.1 页面与入口
|
||
|
||
`mobile-uni` 新增:
|
||
|
||
```text
|
||
src/pages/user/sop/index.vue 既有微信式会话,升级为工作助手主入口
|
||
src/pages/user/assistant/library.vue 个人资料列表
|
||
src/pages/user/assistant/item.vue 资料详情与解析状态
|
||
src/pages/user/assistant/capture.vue 文字、文件、链接收藏
|
||
src/pages/user/assistant/sessions.vue 历史会话
|
||
src/pages/user/assistant/memories.vue 待确认、个人记忆与项目跟进记录
|
||
src/services/personal-assistant.ts API 客户端
|
||
```
|
||
|
||
入口策略:一级只提供用户任务导向的“工作助手 / 查全网”。“工作助手”复用员工端「问」页现有微信式会话,在个人资料、项目记录和企业知识之间自动路由;回答以引用徽标说明实际使用范围。输入区仅提供次级“资料范围:自动”入口,专业用户需要时才切换为手动筛选。不新增个人助理 Tab 或第五个底部 Tab;“我”页提供“我的资料与记忆”管理入口。
|
||
|
||
### 10.2 关键交互
|
||
|
||
- 上传后立即返回列表并显示解析状态,不阻塞页面等待解析。
|
||
- 每条答案引用显示域徽标:我的资料、项目记录、企业 SOP;外部网页只在独立“查全网”入口展示。
|
||
- 工作助手默认 `scopeMode=AUTO`,自动路由仅限本人和当前项目可访问的内部域;界面展示 `依据:企业 SOP · 项目记录 · 我的资料` 等实际命中来源。
|
||
- “资料范围”是次级设置而非一级 Tab;手动模式才允许选择个人资料、项目记录或企业知识。
|
||
- “查全网”保持独立入口和接口。内部资料无命中时只显示“是否查全网”,必须由用户点击后才进入外部查询;包含住户或项目内部信息时不得自动带入原问题。
|
||
- 每条用户文字或 ASR 转写完成后可触发候选检测;普通问答不得频繁弹卡,同源候选被忽略后本会话不再提示。
|
||
- 统一采集确认卡必须展示系统建议类型、对象定位、摘要、保存范围、记录时间和可选跟进时间,并提供“修改 / 暂不保存 / 仅自己保存 / 提交公司处理”。
|
||
- 项目、楼栋、单元或房号不足时只显示“可继续补充”,不阻断保存;未接入权威住户主数据时不得把模糊描述保存成确定身份。
|
||
- 保存与提醒是两个独立选择;未填写 `followUpAt` 不创建提醒或今日任务。
|
||
- 项目业务记忆引用必须展示来源时间、当前状态和最后更新时间;历史状态不能冒充当前事实。
|
||
- 删除前明确提示会删除附件、解析正文和搜索索引。
|
||
- 资料详情允许修正标题、时间和标签,不允许直接编辑解析正文。
|
||
- P1 PPT 生成必须先展示可编辑大纲和模板选择,再提交异步任务。
|
||
|
||
## 11. 错误码与降级
|
||
|
||
| 业务码 | 含义 | 前端动作 |
|
||
|---|---|---|
|
||
| `PERSONAL_SPACE_QUOTA_EXCEEDED` | 空间或条目配额超限 | 显示用量并引导删除 |
|
||
| `PERSONAL_ITEM_NOT_FOUND` | 不存在或无权访问 | 统一显示不存在,不泄露归属 |
|
||
| `PERSONAL_ITEM_NOT_READY` | 仍在解析 | 展示状态并允许刷新 |
|
||
| `PERSONAL_PARSE_FAILED` | 解析失败 | 展示可公开原因和重试 |
|
||
| `PERSONAL_URL_BLOCKED` | URL 被安全策略拦截 | 明确不能访问该地址 |
|
||
| `PERSONAL_NO_CITATION` | 无足够资料支撑 | 不生成业务结论 |
|
||
| `ENTERPRISE_SCOPE_FORBIDDEN` | 无企业知识范围权限 | 保留个人结果,提示企业范围不可用 |
|
||
| `PERSONAL_AI_DISABLED` | AI 成本闸门关闭 | 仍允许收藏和关键词检索,暂停摘要/问答 |
|
||
| `MEMORY_CANDIDATE_NEEDS_INPUT` | 旧候选对象或必要字段不完整 | 兼容展示为可编辑卡;统一采集的新 DRAFT 不以位置缺失阻断保存 |
|
||
| `MEMORY_CANDIDATE_EXPIRED` | 确认草稿已过期 | 基于原消息重新识别,不直接写入 |
|
||
| `MEMORY_CONFIRM_CONFLICT` | 版本冲突或幂等键对应不同内容 | 刷新确认卡,禁止覆盖 |
|
||
| `SERVICE_MEMORY_PROJECT_FORBIDDEN` | 当前用户无项目访问权 | 统一显示不可访问,不泄露记录存在性 |
|
||
| `SERVICE_MEMORY_SUBJECT_AMBIGUOUS` | 住户/房屋定位不足或冲突 | 要求补充房号或选择权威主体 |
|
||
|
||
企业检索失败时,mixed 查询可返回仍然可用且已授权的个人/项目业务结果并标记降级;任一域权限校验失败时不得用其他域结果掩盖越权错误。
|
||
|
||
## 12. 测试策略
|
||
|
||
### 12.1 单元测试
|
||
|
||
- owner/tenant 条件生成与空 owner 拒绝。
|
||
- URL IP 分类、重定向二次校验、正文上限。
|
||
- 文件哈希去重与配额计算。
|
||
- 引用域序列化和无引用拒答。
|
||
- 删除任务幂等性。
|
||
- prompt injection 文本不得改变系统指令。
|
||
- 规则预筛不会把普通问答误判为候选;明确“记一下”必定进入候选检测。
|
||
- 模型候选输出不能覆盖服务端解析的 tenant、project、楼栋、单元和房号。
|
||
- DRAFT、CONFIRMED、DISMISSED、EXPIRED 状态转换只允许规定方向;NEEDS_INPUT 仅兼容旧候选。
|
||
- 同一确认幂等键只生成一个目标记录;版本冲突不覆盖较新业务记忆。
|
||
- 裸房号只在楼栋/单元上下文后识别,年份、时长、金额不能误判为房号。
|
||
- 相同会话中重复表达同一显式记录更新原卡;“另外记 / 再记一条 / 新的一条”生成新卡。
|
||
|
||
### 12.2 集成测试
|
||
|
||
- MySQL:两个用户创建、列表、详情、搜索、删除互不可见。
|
||
- Qdrant:未带 owner filter 的调用被拒绝;用户 A 不返回用户 B point。
|
||
- OSS:签名 URL 只能由本人生成;删除后对象不可访问。
|
||
- mixed:个人和企业结果分别授权、融合、引用域正确。
|
||
- confirmed memory:未确认不写个人 item、业务记忆或向量;确认后按目标域写入并返回可追溯来源。
|
||
- project service:两个项目交叉读取、修改和召回均不可见;创建人调岗后不保留越权访问。
|
||
- version:每次修改和作废均追加版本,旧版本可审计但不参与当前状态回答。
|
||
- PII:外部模型请求只含令牌化定位,姓名、电话和房号原值不出现在供应商请求体。
|
||
- 成本闸门关闭:收藏与关键词检索可用,LLM 能力明确降级。
|
||
|
||
### 12.3 浏览器 E2E
|
||
|
||
1. 手机号登录并确认岗位。
|
||
2. 收藏一段文字、一个 PDF 和一个公开网页。
|
||
3. 查看 QUEUED/PARSING/READY 状态变化。
|
||
4. 按日期查询资料。
|
||
5. 分别执行个人、企业、混合问答。
|
||
6. 检查引用徽标和原始来源。
|
||
7. 删除资料并确认列表、问答和下载均不可再访问。
|
||
8. 切换另一手机号,确认看不到前一用户的资料、标题和会话。
|
||
9. 语音说“帮我记一下三栋 3203 需要保洁服务”,检查缺少单元时仍出现可确认卡且只作可选提示。
|
||
10. 分别执行“暂不保存 / 仅自己保存 / 提交公司处理”,验证前者不落长期表、私有记录仅本人可见、公司记录显示 PENDING 而非已送达。
|
||
11. 确认时不设置跟进日期,验证不会生成今日任务;另建一条带 `followUpAt` 的记录,验证只出现一次。
|
||
12. 双击确认或重放请求,验证只创建一条记录;修改后验证版本递增且旧状态不被当作当前答案。
|
||
|
||
## 13. 非功能指标
|
||
|
||
| 指标 | 验收线 |
|
||
|---|---|
|
||
| 跨用户数据泄漏 | 0;自动越权矩阵 100% 通过 |
|
||
| 支持样本解析成功率 | ≥95%(排除加密/损坏文件) |
|
||
| 关键词/向量检索 P95 | ≤2.5 秒 |
|
||
| AI 回答 P95 | ≤8 秒;超时明确提示可重试 |
|
||
| 引用可访问率 | 100%,且当前用户有权访问 |
|
||
| 删除可见性 | API 成功后立即隐藏 |
|
||
| 物理内容清理 | 24 小时内完成 |
|
||
| URL 私网/元数据地址拦截 | 100% |
|
||
| 未确认候选进入长期存储/检索 | 0 |
|
||
| 确认接口重复创建 | 0;幂等测试 100% 通过 |
|
||
| 跨项目业务记忆泄漏 | 0;项目越权矩阵 100% 通过 |
|
||
| 当前状态回答可追溯 | 100% 返回来源时间、状态和最后更新时间 |
|
||
|
||
## 14. 里程碑与发布闸门
|
||
|
||
### M0:安全与数据地基
|
||
|
||
- 独立表、独立 Qdrant collection、私有 OSS 前缀。
|
||
- 两用户越权测试、URL SSRF 测试、删除测试先行。
|
||
|
||
### M1:资料收藏与解析
|
||
|
||
- 文字、文件、图片、网页链接收藏。
|
||
- 异步解析状态、失败重试、配额和列表。
|
||
|
||
### M2:个人检索与问答
|
||
|
||
- 日期/主题/来源检索。
|
||
- 个人问答、引用、会话和成本统计。
|
||
|
||
### M3:确认式长期记忆
|
||
|
||
- 文字/ASR 候选识别、信息补充、确认卡、忽略和过期。
|
||
- 个人记忆与项目业务记忆分域写入、幂等确认、版本和受控召回。
|
||
- `followUpAt` 经单独确认进入“今日安排”,不做推送或自动派单。
|
||
|
||
### M4:企业知识授权融合
|
||
|
||
- 企业知识权限过滤。
|
||
- 个人/项目业务/企业三域分别授权后融合和引用域标记。
|
||
|
||
### M5:移动端闭环与试点
|
||
|
||
- 员工端页面、真实浏览器 E2E、20 名试点员工。
|
||
- 试点期间不开放分享/企业入库和 PPT 文件生成。
|
||
|
||
### M6:P1 增强
|
||
|
||
- 分享/企业入库审核。
|
||
- 周报月报、汇报提纲、PPTX 异步生成。
|
||
|
||
发布硬闸门:跨用户越权测试、SSRF 测试、删除链路、引用权限和真实浏览器闭环任一未通过,不得进入试点。
|
||
|
||
## 15. 实施文件清单
|
||
|
||
预计新增:
|
||
|
||
- `backend/script/sql/aihr_personal_knowledge_mysql8.sql`
|
||
- `backend/script/sql/aihr_service_memory_mysql8.sql`
|
||
- `backend/script/sql/update/aihr_20260719_service_memory_mysql8.sql`(确认候选、统一采集和兼容项目服务记录的生产增量)
|
||
- `backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/personal/**`
|
||
- `backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/memory/**`(候选识别、确认编排与项目业务记忆)
|
||
- `backend/ruoyi-modules/ruoyi-aihr/src/test/java/org/dromara/aihr/personal/**`
|
||
- `backend/ruoyi-modules/ruoyi-aihr/src/test/java/org/dromara/aihr/memory/**`
|
||
- `mobile-uni/src/pages/user/assistant/*.vue`
|
||
- `mobile-uni/src/services/personal-assistant.ts`
|
||
- `mobile-uni/tests/personal-assistant.test.mjs`
|
||
|
||
预计修改:
|
||
|
||
- `backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrSopSeedService.java`(仅抽取解析能力,不加入个人业务)
|
||
- `backend/script/sql/aihr_knowledge_mysql8.sql`(仅共享解析迁移兼容时调整)
|
||
- `mobile-uni/src/pages.json`
|
||
- `mobile-uni/src/pages/user/sop/index.vue`
|
||
- `mobile-uni/src/types/api.ts`
|
||
- `scripts/reset-dev-db.sh`
|
||
- `docs/API_INTEGRATION.md`
|
||
- `docs/DEV_SETUP.md`
|
||
- `docs/DEMO_ACCEPTANCE.md`
|
||
|
||
## 16. 决策摘要
|
||
|
||
1. 个人知识和企业知识物理分域,不采用共享表 `scope_type`。
|
||
2. 文件解析、模型和成本闸门复用,存储和检索索引不复用。
|
||
3. 本地 `user_id` 是阶段二所有权键,`ext_party_id` 只作阶段三迁移锚点。
|
||
4. Mixed 检索先分域授权,再融合结果。
|
||
5. 个人资料默认私有,分享和企业入库走 P1 审核链。
|
||
6. PPT 是 P1,不阻塞阶段二首批。
|
||
7. 北森、考勤等外部个人数据属于阶段三。
|
||
8. 对话历史不是长期记忆;只有用户确认的候选才能进入统一采集或兼容项目业务记忆。
|
||
9. 统一采集由用户选择 PRIVATE / COMPANY;COMPANY 先进入可靠待流转状态,不能用前端成功提示代替外部回执。
|
||
10. 模型只生成结构化草稿,主体解析、授权、幂等、版本和数据库写入全部由确定性服务完成。
|
||
11. 保存和提醒分别确认;未设置 `followUpAt` 不产生今日任务、推送或自动派单。
|
||
12. 当前没有权威住户主数据时不伪造主体 ID;无法唯一定位不阻断记录一般事项,但不得将其解释为确定住户档案。
|
||
13. 用户界面不暴露系统的三域架构作为一级选择;一级只保留“工作助手 / 查全网”,内部来源默认自动路由并以引用透明展示。
|
||
14. 公网查询永不由 AUTO 触发;必须由用户明确进入“查全网”,且不得自动携带住户或项目内部信息。
|